From f8a697e2e8d9119eb96d8d039eec9848e53de4c1 Mon Sep 17 00:00:00 2001 From: "Frank M. Kromann" Date: Tue, 5 Jun 2001 21:09:50 +0000 Subject: [PATCH] Fixing memory leak. 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 | 603 +++++++++++++++++++++++++++++++++++++----- ext/mssql/php_mssql.h | 18 +- 2 files changed, 559 insertions(+), 62 deletions(-) diff --git a/ext/mssql/php_mssql.c b/ext/mssql/php_mssql.c index 61870726b7..fad5894c0c 100644 --- a/ext/mssql/php_mssql.c +++ b/ext/mssql/php_mssql.c @@ -36,11 +36,18 @@ #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; inum_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; inum_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, ¶m_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, ¶m_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, ¶m_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, ¶m_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; ibatchsize = 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; ilink,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 diff --git a/ext/mssql/php_mssql.h b/ext/mssql/php_mssql.h index 72d3a6a32d..4fab922cd1 100644 --- a/ext/mssql/php_mssql.h +++ b/ext/mssql/php_mssql.h @@ -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; -- 2.40.0