]> granicus.if.org Git - php/commitdiff
Fixing memory leak.
authorFrank M. Kromann <fmk@php.net>
Tue, 5 Jun 2001 21:09:50 +0000 (21:09 +0000)
committerFrank M. Kromann <fmk@php.net>
Tue, 5 Jun 2001 21:09:50 +0000 (21:09 +0000)
Fixing mssql_pconnect to work with ISAPI
Adding MSSQL_NUM, MSSQL_ASSOC and MSSQL_BOTH so the extension will be more compatible with MySQL

ext/mssql/php_mssql.c
ext/mssql/php_mssql.h

index 61870726b7714cfa18ee5aaaa4f78113646e5fd9..fad5894c0c9b2a3bdc8c8194c8ddebb7aeaa35a6 100644 (file)
 #if HAVE_MSSQL
 #define SAFE_STRING(s) ((s)?(s):"")
 
-static int le_result, le_link, le_plink;
+#define MSSQL_ASSOC            1<<0
+#define MSSQL_NUM              1<<1
+#define MSSQL_BOTH             (MSSQL_ASSOC|MSSQL_NUM)
+
+static int le_result, le_link, le_plink, le_statement;
 
 static void php_mssql_get_column_content_with_type(mssql_link *mssql_ptr,int offset,zval *result, int column_type);
 static void php_mssql_get_column_content_without_type(mssql_link *mssql_ptr,int offset,zval *result, int column_type);
 
+static void _mssql_bind_hash_dtor(void *data);
+static unsigned char a3_arg_force_ref[] = { 3, BYREF_NONE, BYREF_NONE, BYREF_FORCE };
+
 function_entry mssql_functions[] = {
        PHP_FE(mssql_connect,                           NULL)
        PHP_FE(mssql_pconnect,                          NULL)
@@ -66,6 +73,9 @@ function_entry mssql_functions[] = {
        PHP_FE(mssql_next_result,                       NULL)
        PHP_FE(mssql_min_error_severity,        NULL)
        PHP_FE(mssql_min_message_severity,      NULL)
+       PHP_FE(mssql_init,                                      NULL)
+       PHP_FE(mssql_bind,                                      a3_arg_force_ref)
+       PHP_FE(mssql_execute,                           NULL)
        {NULL, NULL, NULL}
 };
 
@@ -116,6 +126,7 @@ PHP_INI_BEGIN()
        STD_PHP_INI_ENTRY_EX("mssql.min_message_severity",      "10",   PHP_INI_ALL,    OnUpdateInt,    cfg_min_message_severity,       zend_mssql_globals,             mssql_globals,  display_link_numbers)
        STD_PHP_INI_BOOLEAN("mssql.compatability_mode",         "0",    PHP_INI_ALL,    OnUpdateBool,   compatability_mode,                     zend_mssql_globals,             mssql_globals)
        STD_PHP_INI_ENTRY_EX("mssql.connect_timeout",           "5",    PHP_INI_ALL,    OnUpdateInt,    connect_timeout,                        zend_mssql_globals,             mssql_globals,  display_link_numbers)
+       STD_PHP_INI_ENTRY_EX("mssql.timeout",                           "60",   PHP_INI_ALL,    OnUpdateInt,    timeout,                                        zend_mssql_globals,             mssql_globals,  display_link_numbers)
        STD_PHP_INI_ENTRY_EX("mssql.textsize",                          "-1",   PHP_INI_ALL,    OnUpdateInt,    textsize,                                       zend_mssql_globals,             mssql_globals,  display_text_size)
        STD_PHP_INI_ENTRY_EX("mssql.textlimit",                         "-1",   PHP_INI_ALL,    OnUpdateInt,    textlimit,                                      zend_mssql_globals,             mssql_globals,  display_text_size)
        STD_PHP_INI_ENTRY_EX("mssql.batchsize",                         "0",    PHP_INI_ALL,    OnUpdateInt,    batchsize,                                      zend_mssql_globals,             mssql_globals,  display_link_numbers)
@@ -183,6 +194,16 @@ static void _free_result(mssql_result *result, int free_fields)
        }
 }
 
+static void _free_mssql_statement(mssql_statement *statement)
+{
+       if (statement->binds) {
+               zend_hash_destroy(statement->binds);
+               efree(statement->binds);
+       }
+       
+       efree(statement);
+}
+
 static void _free_mssql_result(zend_rsrc_list_entry *rsrc)
 {
        mssql_result *result = (mssql_result *)rsrc->ptr;
@@ -223,11 +244,31 @@ static void _close_mssql_plink(zend_rsrc_list_entry *rsrc)
 
        dbclose(mssql_ptr->link);
        dbfreelogin(mssql_ptr->login);
-       efree(mssql_ptr);
+       free(mssql_ptr);
        MS_SQL_G(num_persistent)--;
        MS_SQL_G(num_links)--;
 }
 
+static mssql_statement* _mssql_get_statement(zval **stmt)
+{
+       mssql_statement *statement;
+
+       statement = (mssql_statement *) zend_fetch_resource(stmt, -1, "MS SQL-Statement", NULL, 1, le_statement);
+
+       if (statement) {
+               return statement;
+       } else {
+               return (mssql_statement *) NULL;
+       }
+}
+
+static void _mssql_bind_hash_dtor(void *data)
+{
+       mssql_bind *bind= (mssql_bind *) data;
+
+       zval_ptr_dtor(&(bind->zval));
+}
+
 static void php_mssql_init_globals(zend_mssql_globals *mssql_globals)
 {
        long compatability_mode;
@@ -248,6 +289,7 @@ PHP_MINIT_FUNCTION(mssql)
 
        REGISTER_INI_ENTRIES();
 
+       le_statement = register_list_destructors(_free_mssql_statement, NULL);
        le_result = zend_register_list_destructors_ex(_free_mssql_result, NULL, "mssql result", module_number);
        le_link = zend_register_list_destructors_ex(_close_mssql_link, NULL, "mssql link", module_number);
        le_plink = zend_register_list_destructors_ex(NULL, _close_mssql_plink, "mssql link persistent", module_number);
@@ -257,6 +299,21 @@ PHP_MINIT_FUNCTION(mssql)
                return FAILURE;
        }
 
+       /* BEGIN MSSQL data types for mssql_bind */
+       REGISTER_LONG_CONSTANT("MSSQL_ASSOC", MSSQL_ASSOC, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("MSSQL_NUM", MSSQL_NUM, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("MSSQL_BOTH", MSSQL_BOTH, CONST_CS | CONST_PERSISTENT);
+
+       REGISTER_LONG_CONSTANT("SQLTEXT",SQLTEXT, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("SQLVARCHAR",SQLVARCHAR, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("SQLCHAR",SQLCHAR, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("SQLINT1",SQLINT1, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("SQLINT2",SQLINT2, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("SQLINT4",SQLINT4, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("SQLBIT",SQLBIT, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("SQLFLT8",SQLFLT8, CONST_CS | CONST_PERSISTENT);
+       /* END MSSQL data types for mssql_sp_bind */
+
        dberrhandle((DBERRHANDLE_PROC) php_mssql_error_handler);
        dbmsghandle((DBMSGHANDLE_PROC) php_mssql_message_handler);
 
@@ -282,6 +339,8 @@ PHP_RINIT_FUNCTION(mssql)
        MS_SQL_G(min_message_severity) = MS_SQL_G(cfg_min_message_severity);
        if (MS_SQL_G(connect_timeout) < 1) MS_SQL_G(connect_timeout) = 1;
        dbsetlogintime(MS_SQL_G(connect_timeout));
+       if (MS_SQL_G(timeout) < 0) MS_SQL_G(timeout) = 60;
+       dbsettime(MS_SQL_G(timeout));
 
        return SUCCESS;
 }
@@ -317,7 +376,7 @@ PHP_MINFO_FUNCTION(mssql)
 
 }
 
-void php_mssql_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent)
+static void php_mssql_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent)
 {
        char *user, *passwd, *host;
        char *hashed_details;
@@ -462,13 +521,12 @@ void php_mssql_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent)
                        }
 
                        /* hash it up */
-                       mssql_ptr = (mssql_link *) emalloc(sizeof(mssql_link));
+                       mssql_ptr = (mssql_link *) malloc(sizeof(mssql_link));
                        memcpy(mssql_ptr, &mssql, sizeof(mssql_link));
                        new_le.type = le_plink;
                        new_le.ptr = mssql_ptr;
                        if (zend_hash_update(&EG(persistent_list), hashed_details, hashed_details_length + 1, &new_le, sizeof(list_entry), NULL)==FAILURE) {
-                               new_le.refcount++;
-                               efree(mssql_ptr);
+                               free(mssql_ptr);
                                efree(hashed_details);
                                dbfreelogin(mssql.login);
                                RETURN_FALSE;
@@ -584,7 +642,6 @@ void php_mssql_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent)
                new_index_ptr.ptr = (void *) return_value->value.lval;
                new_index_ptr.type = le_index_ptr;
                if (zend_hash_update(&EG(regular_list), hashed_details, hashed_details_length + 1,(void *) &new_index_ptr, sizeof(list_entry),NULL)==FAILURE) {
-                       new_index_ptr.refcount++;
                        efree(hashed_details);
                        RETURN_FALSE;
                }
@@ -705,7 +762,7 @@ PHP_FUNCTION(mssql_select_db)
 static void php_mssql_get_column_content_with_type(mssql_link *mssql_ptr,int offset,zval *result, int column_type)
 {
        if (dbdatlen(mssql_ptr->link,offset) == 0) {
-               var_reset(result);
+               ZVAL_NULL(result);
                return;
        }
 
@@ -780,7 +837,7 @@ static void php_mssql_get_column_content_with_type(mssql_link *mssql_ptr,int off
 static void php_mssql_get_column_content_without_type(mssql_link *mssql_ptr,int offset,zval *result, int column_type)
 {
        if (dbdatlen(mssql_ptr->link,offset) == 0) {
-               var_reset(result);
+               ZVAL_NULL(result);
                return;
        }
 
@@ -1100,55 +1157,39 @@ PHP_FUNCTION(mssql_num_fields)
 
 /* }}} */
 
-/* {{{ proto array mssql_fetch_row(int result_id)
-   Returns an array of the current row in the result set specified by result_id */
-PHP_FUNCTION(mssql_fetch_row)
+static void php_mssql_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, int result_type)
 {
-       zval **mssql_result_index;
-       int i;
-       mssql_result *result;
-       zval *field_content;
-       MSSQLLS_FETCH();
-
-       if (ZEND_NUM_ARGS()!=1 || zend_get_parameters_ex(1, &mssql_result_index)==FAILURE) {
-               WRONG_PARAM_COUNT;
-       }
-
-       ZEND_FETCH_RESOURCE(result, mssql_result *, mssql_result_index, -1, "MS SQL-result", le_result);        
-       
-       if (result->cur_row >= result->num_rows) {
-               RETURN_FALSE;
-       }
-       
-       array_init(return_value);
-       for (i=0; i<result->num_fields; i++) {
-               MAKE_STD_ZVAL(field_content);
-               *field_content = result->data[result->cur_row][i];
-               ZVAL_COPY_CTOR(field_content);
-               zend_hash_index_update(return_value->value.ht, i, (void *) &field_content, sizeof(zval *), NULL);
-               field_content->refcount++;
-       }
-       result->cur_row++;
-}
-
-/* }}} */
-
-static void php_mssql_fetch_hash(INTERNAL_FUNCTION_PARAMETERS)
-{
-       zval **mssql_result_index;
+       zval **mssql_result_index, **resulttype = NULL;
        mssql_result *result;
        int i;
-       zval *tmp;
        MSSQLLS_FETCH();
        PLS_FETCH();
 
        
-       if (ZEND_NUM_ARGS()!=1 || zend_get_parameters_ex(1, &mssql_result_index)==FAILURE) {
-               WRONG_PARAM_COUNT;
+
+       switch (ZEND_NUM_ARGS()) {
+               case 1:
+                       if (zend_get_parameters_ex(1, &mssql_result_index)==FAILURE) {
+                               RETURN_FALSE;
+                       }
+                       if (!result_type) {
+                               result_type = MSSQL_BOTH;
+                       }
+                       break;
+               case 2:
+                       if (zend_get_parameters_ex(2, &mssql_result_index, &resulttype)==FAILURE) {
+                               RETURN_FALSE;
+                       }
+                       convert_to_long_ex(resulttype);
+                       result_type = (*resulttype)->value.lval;
+                       break;
+               default:
+                       WRONG_PARAM_COUNT;
+                       break;
        }
 
        ZEND_FETCH_RESOURCE(result, mssql_result *, mssql_result_index, -1, "MS SQL-result", le_result);        
-       
+
        if (result->cur_row >= result->num_rows) {
                RETURN_FALSE;
        }
@@ -1158,25 +1199,57 @@ static void php_mssql_fetch_hash(INTERNAL_FUNCTION_PARAMETERS)
        }
        
        for (i=0; i<result->num_fields; i++) {
-               MAKE_STD_ZVAL(tmp);
-               *tmp = result->data[result->cur_row][i];
-               ZVAL_COPY_CTOR(tmp);
-               if (PG(magic_quotes_runtime) && tmp->type == IS_STRING) {
-                       tmp->value.str.val = php_addslashes(tmp->value.str.val, tmp->value.str.len, &tmp->value.str.len,1);
+               if (Z_TYPE(result->data[result->cur_row][i]) != IS_NULL) {
+                       char *data;
+                       int data_len;
+                       int should_copy;
+
+                       if (PG(magic_quotes_runtime) && Z_TYPE(result->data[result->cur_row][i]) == IS_STRING) {
+                               data = php_addslashes(Z_STRVAL(result->data[result->cur_row][i]), Z_STRLEN(result->data[result->cur_row][i]), &result->data[result->cur_row][i].value.str.len, 1);
+                               should_copy = 0;
+                       }
+                       else
+                       {
+                               data = Z_STRVAL(result->data[result->cur_row][i]);
+                               data_len = Z_STRLEN(result->data[result->cur_row][i]);
+                               should_copy = 1;
+                       }
+
+
+                       if (result_type & MSSQL_NUM) {
+                               add_index_stringl(return_value, i, data, data_len, should_copy);
+                               should_copy = 1;
+                       }
+                       
+                       if (result_type & MSSQL_ASSOC) {
+                               add_assoc_stringl(return_value, result->fields[i].name, data, data_len, should_copy);
+                       }
+               }
+               else
+               {
+                       if (result_type & MSSQL_NUM)
+                               add_index_null(return_value, i);
+                       if (result_type & MSSQL_ASSOC)
+                               add_assoc_null(return_value, result->fields[i].name);
                }
-               zend_hash_index_update(return_value->value.ht, i, (void *) &tmp, sizeof(zval *), NULL);
-               tmp->refcount++;
-               zend_hash_update(return_value->value.ht, result->fields[i].name, strlen(result->fields[i].name)+1, (void *) &tmp, sizeof(zval *), NULL);
-               tmp->refcount++;
        }
        result->cur_row++;
 }
 
-/* {{{ proto object mssql_fetch_object(int result_id)
+/* {{{ proto array mssql_fetch_row(int result_id [, int result_type])
+   Returns an array of the current row in the result set specified by result_id */
+PHP_FUNCTION(mssql_fetch_row)
+{
+       php_mssql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, MSSQL_NUM);
+}
+
+/* }}} */
+
+/* {{{ proto object mssql_fetch_object(int result_id [, int result_type])
    Returns a psuedo-object of the current row in the result set specified by result_id */
 PHP_FUNCTION(mssql_fetch_object)
 {
-       php_mssql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU);
+       php_mssql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, MSSQL_ASSOC);
        if (return_value->type==IS_ARRAY) {
                return_value->type=IS_OBJECT;
                return_value->value.obj.properties = return_value->value.ht;
@@ -1186,11 +1259,11 @@ PHP_FUNCTION(mssql_fetch_object)
 
 /* }}} */
 
-/* {{{ proto array mssql_fetch_array(int result_id)
+/* {{{ proto array mssql_fetch_array(int result_id [, int result_type])
    Returns an associative array of the current row in the result set specified by result_id */
 PHP_FUNCTION(mssql_fetch_array)
 {
-       php_mssql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU);
+       php_mssql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, MSSQL_ASSOC);
 }
 
 /* }}} */
@@ -1631,4 +1704,412 @@ PHP_FUNCTION(mssql_min_message_severity)
 }
 /* }}} */
 
+/* {{{ proto int mssql_init(string sp_name [, int conn_id])
+   Initializes a stored procedure or a remote stored procedure  */
+PHP_FUNCTION(mssql_init)
+{
+       zval **sp_name, **mssql_link_index;
+       mssql_link *mssql_ptr;
+       mssql_statement *statement;
+       int id;
+       MSSQLLS_FETCH();
+       
+       switch(ZEND_NUM_ARGS()) {
+               case 1:
+                       if (zend_get_parameters_ex(1, &sp_name)==FAILURE) {
+                               RETURN_FALSE;
+                       }
+                       id = php_mssql_get_default_link(INTERNAL_FUNCTION_PARAM_PASSTHRU MSSQLLS_CC);
+                       CHECK_LINK(id);
+                       break;
+
+               case 2:
+                       if (zend_get_parameters_ex(2, &sp_name, &mssql_link_index)==FAILURE) {
+                               RETURN_FALSE;
+                       }
+                       id = -1;
+                       break;
+
+               default:
+                       WRONG_PARAM_COUNT;
+                       break;
+       }
+
+       ZEND_FETCH_RESOURCE2(mssql_ptr, mssql_link *, mssql_link_index, id, "MS SQL-Link", le_link, le_plink);
+       
+       convert_to_string_ex(sp_name);
+       
+       if (dbrpcinit(mssql_ptr->link, (*sp_name)->value.str.val,0)==FAIL) {
+               php_error(E_WARNING,"MS SQL:  unable to init stored procedure");
+               RETURN_FALSE;
+       }
+
+       statement=NULL;
+       statement = ecalloc(1,sizeof(mssql_statement));
+       
+       if (statement!=NULL) {
+               statement->link = mssql_ptr;
+               statement->executed=FALSE;
+       }
+       else {
+               php_error(E_WARNING,"mssql_init: unable to allocate statement");
+               RETURN_FALSE;
+       }
+
+       statement->id = zend_list_insert(statement,le_statement);
+       
+       RETURN_RESOURCE(statement->id);
+}
+/* }}} */
+
+/* {{{ proto int mssql_bind(int stmt, string param_name, mixed var, int type 
+               [, int is_output[, int is_null[, int maxlen]])
+   Adds a parameter to a stored procedure or a remote stored procedure  */
+PHP_FUNCTION(mssql_bind)
+{
+       int     type, is_output, is_null, datalen, maxlen;
+       zval **stmt, **param_name, **var, **yytype;
+       mssql_link *mssql_ptr;
+       mssql_statement *statement;
+       mssql_bind bind,*bindp;
+       int id, status;
+
+       LPBYTE value;
+       MSSQLLS_FETCH();
+
+       id=0;
+       status=0;
+
+       /* BEGIN input validation */
+       switch(ZEND_NUM_ARGS()) {
+               case 4: 
+                       if (zend_get_parameters_ex(4, &stmt, &param_name, &var, &yytype)==FAILURE) {
+                               RETURN_FALSE;
+                       }
+                       convert_to_long_ex(yytype);
+                       type=(*yytype)->value.lval;
+                       is_null=FALSE;
+                       is_output=FALSE;
+                       maxlen=-1;
+       
+                       break;
+                                               
+               case 5: {
+                       zval **yyis_output;
+
+                               if (zend_get_parameters_ex(5, &stmt, &param_name, &var, &yytype, &yyis_output)==FAILURE) {
+                                       RETURN_FALSE;
+                               }
+                               convert_to_long_ex(yytype);
+                               convert_to_long_ex(yyis_output);
+                               type=(*yytype)->value.lval;
+                               is_null=FALSE;
+                               is_output=(*yyis_output)->value.lval;
+                               maxlen=-1;      
+                       }
+                       break;  
+
+               case 6: {
+                               zval **yyis_output, **yyis_null;
+
+                               if (zend_get_parameters_ex(6, &stmt, &param_name, &var, &yytype, &yyis_output, &yyis_null)==FAILURE) {
+                                       RETURN_FALSE;
+                               }
+                               convert_to_long_ex(yytype);
+                               convert_to_long_ex(yyis_output);
+                               convert_to_long_ex(yyis_null);
+                               type=(*yytype)->value.lval;
+                               is_output=(*yyis_output)->value.lval;
+                               is_null=(*yyis_null)->value.lval;
+                               maxlen=-1;
+                       }
+                       break;
+               
+               case 7: {
+                               zval **yyis_output, **yyis_null, **yymaxlen;
+
+                               if (zend_get_parameters_ex(7, &stmt, &param_name, &var, &yytype, &yyis_output, &yyis_null, &yymaxlen)==FAILURE) {
+                                       RETURN_FALSE;
+                               }
+                               convert_to_long_ex(yytype);
+                               convert_to_long_ex(yyis_output);
+                               convert_to_long_ex(yyis_null);
+                               convert_to_long_ex(yymaxlen);
+                               type=(*yytype)->value.lval;
+                               is_output=(*yyis_output)->value.lval;
+                               is_null=(*yyis_null)->value.lval;
+                               maxlen=(*yymaxlen)->value.lval;                         
+                       }
+                       break;  
+               
+               default:
+                       WRONG_PARAM_COUNT;
+                       break;
+       }
+       /* END input validation */
+       
+       statement = _mssql_get_statement(stmt);
+       if (statement==NULL) {
+               RETURN_FALSE;
+       }
+       mssql_ptr=statement->link;
+
+       /* modify datalen and maxlen according to dbrpcparam documentation */
+       if ( (type==SQLVARCHAR) || (type==SQLCHAR) || (type==SQLTEXT) ) {       /* variable-length type */
+               if (is_null) {
+                       maxlen=0;
+                       datalen=0;
+               }
+               else {
+                       convert_to_string_ex(var);
+                       datalen=(*var)->value.str.len;
+                       value=(LPBYTE)(*var)->value.str.val;
+               }
+       }
+       else    {       /* fixed-length type */
+               if (is_null)    {
+                       datalen=0;
+               }
+               else {
+                       datalen=-1;
+               }
+               maxlen=-1;
+
+               switch (type)   {
+
+                       case SQLFLT8:
+                               convert_to_double_ex(var);
+                               value=(LPBYTE)(&(*var)->value.dval);
+                               break;
+
+                       case SQLINT1:
+                       case SQLINT2:
+                       case SQLINT4:
+                               convert_to_long_ex(var);
+                               value=(LPBYTE)(&(*var)->value.lval);
+                               break;
+
+                       default:
+                               php_error(E_WARNING,"mssql_bind: unsupported type");
+                               RETURN_FALSE;
+                               break;
+               }
+       }
+
+       convert_to_string_ex(param_name);
+       
+       if (is_output) {
+               status=DBRPCRETURN;
+       }
+       
+       /* hashtable of binds */
+       if (! statement->binds) {
+               statement->binds = emalloc(sizeof(HashTable));
+               zend_hash_init(statement->binds, 13, NULL, _mssql_bind_hash_dtor, 0);
+       }
+
+       memset((void*)&bind,0,sizeof(mssql_bind));
+       zend_hash_add(statement->binds,(*param_name)->value.str.val,(*param_name)->value.str.len,&bind,sizeof(mssql_bind),(void **)&bindp);
+       bindp->zval=*var;
+       zval_add_ref(var);
+
+       /* no call to dbrpcparam if RETVAL */
+       if ( strcmp("RETVAL",(*param_name)->value.str.val)!=0 ) {                                               
+               if (dbrpcparam(mssql_ptr->link, (*param_name)->value.str.val, (BYTE)status, type, maxlen, datalen, (LPCBYTE)value)==FAIL) {
+                       php_error(E_WARNING,"MS SQL:  Unable to set parameter");
+                       RETURN_FALSE;
+               }
+       }
+
+       RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto int mssql_execute(int stmt)
+   Executes a stored procedure on a MS-SQL server database */
+PHP_FUNCTION(mssql_execute)
+{
+       zval **stmt;
+       int retvalue,retval_results;
+       mssql_link *mssql_ptr;
+       mssql_statement *statement;
+       mssql_bind *bind;
+       mssql_result *result;
+       int num_fields,num_rets,type;   
+       int blocks_initialized=1;
+       int i,j;
+       int *column_types;
+       int batchsize;
+       int ac = ZEND_NUM_ARGS();
+       char *parameter;
+       MSSQLLS_FETCH();
+
+       batchsize = MS_SQL_G(batchsize);
+       if (ac !=1 || zend_get_parameters_ex(1, &stmt)==FAILURE) {
+        WRONG_PARAM_COUNT;
+    }
+
+       statement = _mssql_get_statement(stmt);
+       if (statement==NULL) {
+               RETURN_FALSE;
+       }
+       mssql_ptr=statement->link;
+
+       if (dbrpcexec(mssql_ptr->link)==FAIL || dbsqlok(mssql_ptr->link)==FAIL) {
+               php_error(E_WARNING,"MS SQL:  stored procedure execution failed.");
+               RETURN_FALSE;
+       }
+
+       retval_results=dbresults(mssql_ptr->link);
+
+       if (retval_results==FAIL) {
+               php_error(E_WARNING,"MS SQL:  could not retrieve results");
+               RETURN_FALSE;
+       }
+
+       /* The following is just like mssql_query, fetch all rows from the server into 
+        *      the row buffer. We add here the RETVAL and OUTPUT parameters stuff
+        */
+       result=NULL;
+       /* if multiple recordsets in a stored procedure were supported, we would 
+          use a "while (retval_results!=NO_MORE_RESULTS)" instead an "if" */
+       if (retval_results==SUCCEED) {
+               if ( (retvalue=(dbnextrow(mssql_ptr->link)))!=NO_MORE_ROWS ) {
+                       num_fields = dbnumcols(mssql_ptr->link);
+                       if (num_fields <= 0) {
+                               RETURN_TRUE;
+                       }
+                       
+                       result = (mssql_result *) emalloc(sizeof(mssql_result));
+                       column_types = (int *) emalloc(sizeof(int) * num_fields);
+                       for (i=0; i<num_fields; i++) {
+                               column_types[i] = coltype(i+1);
+                       }
+                       
+                       result->batchsize = batchsize;
+                       result->data = (zval **) emalloc(sizeof(zval *)*MSSQL_ROWS_BLOCK);
+                       result->mssql_ptr = mssql_ptr;
+                       result->cur_field=result->cur_row=result->num_rows=0;
+                       result->num_fields = num_fields;
+
+                       result->num_rows = _mssql_fetch_batch(mssql_ptr, result, retvalue);
+               
+                       result->fields = (mssql_field *) emalloc(sizeof(mssql_field)*num_fields);
+                       j=0;
+                       for (i=0; i<num_fields; i++) {
+                               char *fname = (char *)dbcolname(mssql_ptr->link,i+1);
+                               char computed_buf[16];
+                               
+                               if (*fname) {
+                                       result->fields[i].name = estrdup(fname);
+                               } else {
+                                       if (j>0) {
+                                               snprintf(computed_buf,16,"computed%d",j);
+                                       } else {
+                                               strcpy(computed_buf,"computed");
+                                       }
+                                       result->fields[i].name = estrdup(computed_buf);
+                                       j++;
+                               }
+                               result->fields[i].max_length = dbcollen(mssql_ptr->link,i+1);
+                               result->fields[i].column_source = estrdup(dbcolsource(mssql_ptr->link,i+1));
+                               if (!result->fields[i].column_source) {
+                                       result->fields[i].column_source = empty_string;
+                               }
+                               result->fields[i].type = column_types[i];
+                               /* set numeric flag */
+                               switch (column_types[i]) {
+                                       case SQLINT1:
+                                       case SQLINT2:
+                                       case SQLINT4:
+                                       case SQLFLT8:
+                                       case SQLNUMERIC:
+                                       case SQLDECIMAL:
+                                               result->fields[i].numeric = 1;
+                                               break;
+                                       case SQLCHAR:
+                                       case SQLVARCHAR:
+                                       case SQLTEXT:
+                                       default:
+                                               result->fields[i].numeric = 0;
+                                               break;
+                               }
+                       }
+                       efree(column_types);
+               }
+               retval_results=dbresults(mssql_ptr->link);
+       }
+       
+       if (retval_results==SUCCEED) {
+               php_error(E_WARNING,"mssql_execute:  multiple recordsets from a stored procedure not supported yet! (Skipping...)");
+               retval_results=dbresults(mssql_ptr->link);
+               
+               while (retval_results==SUCCEED) {
+                       retval_results=dbresults(mssql_ptr->link);
+               }
+       }
+
+       if (retval_results==NO_MORE_RESULTS) {
+               /* Now to fetch RETVAL and OUTPUT values*/
+               num_rets = dbnumrets(mssql_ptr->link);
+               
+               if (num_rets!=0) {
+                       for (i = 1; i <= num_rets; i++) {
+                               parameter=(char*)dbretname(mssql_ptr->link, i);
+                               type=dbrettype(mssql_ptr->link, i);
+                                                       
+                               if (statement->binds!=NULL ) {  /*      Maybe a non-parameter sp        */
+                                       if (zend_hash_find(statement->binds, parameter, strlen(parameter), (void**)&bind)==SUCCESS) {
+                                               switch (type) {
+                                                       case SQLBIT:
+                                                       case SQLINT1:
+                                                       case SQLINT2:
+                                                       case SQLINT4:
+                                                               convert_to_long_ex(&bind->zval);
+                                                               bind->zval->value.lval=*((int *)(dbretdata(mssql_ptr->link,i)));
+                                                               break;
+                               
+                                                       case SQLFLT8:
+                                                               convert_to_double_ex(&bind->zval);
+                                                               bind->zval->value.dval=*((double *)(dbretdata(mssql_ptr->link,i)));
+                                                               break;
+
+                                                       case SQLCHAR:
+                                                       case SQLVARCHAR:
+                                                       case SQLTEXT:
+                                                               convert_to_string_ex(&bind->zval);
+                                                               bind->zval->value.str.len=dbretlen(mssql_ptr->link,i);
+                                                               bind->zval->value.str.val = estrndup(dbretdata(mssql_ptr->link,i),bind->zval->value.str.len);
+                                                               break;
+                                               }
+                                       }
+                                       else {
+                                               php_error(E_WARNING,"mssql_execute: an output parameter variable was not provided");
+                                       }
+                               }
+                       }
+               }
+               
+               if (statement->binds!=NULL ) {  /*      Maybe a non-parameter sp        */
+                       if (zend_hash_find(statement->binds, "RETVAL", 6, (void**)&bind)==SUCCESS) {
+                               if (dbhasretstat(mssql_ptr->link)) {
+                                       convert_to_long_ex(&bind->zval);
+                                       bind->zval->value.lval=dbretstatus(mssql_ptr->link);
+                               }
+                               else {
+                                       php_error(E_WARNING,"mssql_execute: stored procedure has no return value. Nothing was returned into RETVAL");
+                               }
+                       }
+               }
+       }
+
+       if (result==NULL) {
+               RETURN_TRUE;    /* no recordset returned ...*/
+       }
+       else {
+               ZEND_REGISTER_RESOURCE(return_value, result, le_result);
+       }
+}
+/* }}} */
+
 #endif
index 72d3a6a32dcceede336975fd37ae0b4bf2214ca3..4fab922cd15075a40e6ab7f283503f4f732c161d 100644 (file)
@@ -80,6 +80,9 @@ PHP_FUNCTION(mssql_result);
 PHP_FUNCTION(mssql_next_result);
 PHP_FUNCTION(mssql_min_error_severity);
 PHP_FUNCTION(mssql_min_message_severity);
+PHP_FUNCTION(mssql_init);
+PHP_FUNCTION(mssql_bind);
+PHP_FUNCTION(mssql_execute);
 
 typedef struct mssql_link {
        LOGINREC *login;
@@ -87,6 +90,19 @@ typedef struct mssql_link {
        int valid;
 } mssql_link;
 
+typedef struct mssql_statement {
+       int id;
+       mssql_link *link;
+       HashTable *binds;
+       int executed;
+} mssql_statement;
+
+typedef struct {
+       
+       zval *zval;
+       /* TODO: more data for special types (BLOBS, NUMERIC...) */
+} mssql_bind;
+
 ZEND_BEGIN_MODULE_GLOBALS(mssql)
        long default_link;
        long num_links,num_persistent;
@@ -96,7 +112,7 @@ ZEND_BEGIN_MODULE_GLOBALS(mssql)
        char *server_message;
        long min_error_severity, min_message_severity;
        long cfg_min_error_severity, cfg_min_message_severity;
-       long compatability_mode, connect_timeout;
+       long compatability_mode, connect_timeout, timeout;
        void (*get_column_content)(mssql_link *mssql_ptr,int offset,pval *result,int column_type);
        long textsize, textlimit, batchsize;
        HashTable *resource_list, *resource_plist;