ID: 16960 Updated by: [EMAIL PROTECTED] Reported By: [EMAIL PROTECTED] -Status: Assigned +Status: Closed Bug Type: Feature/Change Request Operating System: All PHP Version: 4.0CVS-2002-05-02 Assigned To: thekid New Comment:
This bug has been fixed in CVS. In case this was a PHP problem, snapshots of the sources are packaged every three hours; this change will be in the next snapshot. You can grab the snapshot at http://snaps.php.net/. In case this was a documentation problem, the fix will show up soon at http://www.php.net/manual/. In case this was a PHP.net website problem, the change will show up on the PHP.net site and on the mirror sites in short time. Thank you for the report, and for helping us make PHP better. Committed numerous changes to ext/sybase_ct, see CVS log for ext/sybase_ct/php_sybase_ct.c and ext/sybase_ct/php_sybase_ct.h Previous Comments: ------------------------------------------------------------------------ [2002-06-10 18:43:18] [EMAIL PROTECTED] Sorry, here's an example script for sybase_set_message_handler(): <?php function sybase_error($msgnumber, $severity, $state, $line, $text) { if (5701 == $msgnumber) return; // Changed database context to ... if (257 == $msgnumber) return FALSE; // Implicit conversion... printf( "Caught Sybase Server Message #%d [Severity %d, state %d] at line %d\n'%s'\n\n", $msgnumber, $severity, $state, $line, chop($text) ); } sybase_set_message_handler('sybase_error'); $dbh= sybase_connect([...]); // Erroneous call sybase_query('select @does_not_exist'); // Another erroneous call, assume foo_id is numeric(10) // This will result in an "...implicit conversion..." // which is not handled by the above function sybase_query('select * from foo where foo_id= "1"'); ?> The output is: -------------------------------------------------------- Caught Sybase Server Message #137 [Severity 15, state 2] at line 1 'Must declare variable '@does_not_exist'.' <br /> <b>Warning</b>: Sybase: Server message #257: Implicit conversion from datatype 'VARCHAR' to 'NUMERIC' is not allowed. Use the CONVERT function to run this query. (severity 16, procedure N/A) in <b>/usr/home/thekid/devel/php/sybase_test.php</b> on line <b>23</b><br /> -------------------------------------------------------- ------------------------------------------------------------------------ [2002-06-10 15:50:15] [EMAIL PROTECTED] With this last patch, you will be able to handle all of sybase's error messages via a callback function. This comes in quite handy when having to check for deadlocks (the 1205:-)). $deadlock= strstr($php_errormsg, 'deadlock'); is, of course, possible right now, but in my eyes not a very generalistic way of going about it... --- php4-200205012100/ext/sybase_ct/php_sybase_ct.h Thu Feb 28 09:38:19 2002 +++ __build__/ext/sybase_ct/php_sybase_ct.h Mon Jun 10 21:32:25 2002 @@ -45,6 +45,7 @@ PHP_FUNCTION(sybase_num_fields); PHP_FUNCTION(sybase_fetch_row); PHP_FUNCTION(sybase_fetch_array); +PHP_FUNCTION(sybase_fetch_assoc); PHP_FUNCTION(sybase_fetch_object); PHP_FUNCTION(sybase_data_seek); PHP_FUNCTION(sybase_result); @@ -53,7 +54,7 @@ PHP_FUNCTION(sybase_min_client_severity); PHP_FUNCTION(sybase_min_server_severity); PHP_FUNCTION(sybase_fetch_field); - +PHP_FUNCTION(sybase_set_message_handler); #include <ctpublic.h> @@ -66,6 +67,7 @@ char *hostname; char *server_message; long min_server_severity, min_client_severity; + zval *callback_name; CS_CONTEXT *context; ZEND_END_MODULE_GLOBALS(sybase) @@ -93,7 +95,6 @@ int cur_row,cur_field; int num_rows,num_fields; } sybase_result; - #ifdef ZTS # define SybCtG(v) TSRMG(sybase_globals_id, zend_sybase_globals *, v) --- php4-200205012100/ext/sybase_ct/php_sybase_ct.c Tue Mar 12 21:34:06 2002 +++ __build__/ext/sybase_ct/php_sybase_ct.c Wed May 8 04:12:38 2002 @@ -48,6 +48,7 @@ PHP_FE(sybase_num_fields, NULL) PHP_FE(sybase_fetch_row, NULL) PHP_FE(sybase_fetch_array, NULL) + PHP_FE(sybase_fetch_assoc, NULL) PHP_FE(sybase_fetch_object, NULL) PHP_FE(sybase_data_seek, NULL) PHP_FE(sybase_fetch_field, NULL) @@ -56,23 +57,26 @@ PHP_FE(sybase_affected_rows, NULL) PHP_FE(sybase_min_client_severity, NULL) PHP_FE(sybase_min_server_severity, NULL) + PHP_FE(sybase_set_message_handler, NULL) - PHP_FALIAS(mssql_connect, sybase_connect, NULL) - PHP_FALIAS(mssql_pconnect, sybase_pconnect, NULL) - PHP_FALIAS(mssql_close, sybase_close, NULL) - PHP_FALIAS(mssql_select_db, sybase_select_db, NULL) - PHP_FALIAS(mssql_query, sybase_query, NULL) + PHP_FALIAS(mssql_set_message_handler, sybase_set_message_handler, NULL) + PHP_FALIAS(mssql_connect, sybase_connect, NULL) + PHP_FALIAS(mssql_pconnect, sybase_pconnect, NULL) + PHP_FALIAS(mssql_close, sybase_close, NULL) + PHP_FALIAS(mssql_select_db, sybase_select_db, NULL) + PHP_FALIAS(mssql_query, sybase_query, NULL) PHP_FALIAS(mssql_free_result, sybase_free_result, NULL) PHP_FALIAS(mssql_get_last_message, sybase_get_last_message,NULL) - PHP_FALIAS(mssql_num_rows, sybase_num_rows, NULL) + PHP_FALIAS(mssql_num_rows, sybase_num_rows, NULL) PHP_FALIAS(mssql_num_fields, sybase_num_fields, NULL) - PHP_FALIAS(mssql_fetch_row, sybase_fetch_row, NULL) + PHP_FALIAS(mssql_fetch_row, sybase_fetch_row, NULL) PHP_FALIAS(mssql_fetch_array, sybase_fetch_array, NULL) + PHP_FALIAS(mssql_fetch_assoc, sybase_fetch_assoc, NULL) PHP_FALIAS(mssql_fetch_object, sybase_fetch_object, NULL) - PHP_FALIAS(mssql_data_seek, sybase_data_seek, NULL) + PHP_FALIAS(mssql_data_seek, sybase_data_seek, NULL) PHP_FALIAS(mssql_fetch_field, sybase_fetch_field, NULL) PHP_FALIAS(mssql_field_seek, sybase_field_seek, NULL) - PHP_FALIAS(mssql_result, sybase_result, NULL) + PHP_FALIAS(mssql_result, sybase_result, NULL) PHP_FALIAS(mssql_affected_rows, sybase_affected_rows, NULL) PHP_FALIAS(mssql_min_client_severity, sybase_min_client_severity, NULL) PHP_FALIAS(mssql_min_server_severity, sybase_min_server_severity, NULL) @@ -199,12 +203,36 @@ } +/* {{{ proto void sybase_set_message_handler(mixed error_func) + Set the error handler, to be called when a server message is raise */ +PHP_FUNCTION(sybase_set_message_handler) +{ + char *c; + int c_len; + + if( + (ZEND_NUM_ARGS() != 1) || + (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &c, &c_len)!= SUCCESS)) + { + WRONG_PARAM_COUNT; + } + + /* + * Is it a good idea to put this in sybase_globals? + */ + MAKE_STD_ZVAL(SybCtG(callback_name)); + ZVAL_STRINGL(SybCtG(callback_name), c, c_len, 1); + + RETURN_TRUE; +} +/* }}} */ + static CS_RETCODE CS_PUBLIC _client_message_handler(CS_CONTEXT *context, CS_CONNECTION *connection, CS_CLIENTMSG *errmsg) { TSRMLS_FETCH(); if (CS_SEVERITY(errmsg->msgnumber) >= SybCtG(min_client_severity)) { - php_error(E_WARNING, "Sybase: Client message: %s (severity %d)", errmsg->msgstring, CS_SEVERITY(errmsg->msgnumber)); + php_error(E_WARNING, "Sybase: Client message: %s (severity %d)", errmsg->msgstring, CS_SEVERITY(errmsg->msgnumber)); } STR_FREE(SybCtG(server_message)); SybCtG(server_message) = estrdup(errmsg->msgstring); @@ -227,13 +255,61 @@ static CS_RETCODE CS_PUBLIC _server_message_handler(CS_CONTEXT *context, CS_CONNECTION *connection, CS_SERVERMSG *srvmsg) { + zval *retval = NULL; + zval severity, msgnumber, state, line, text; + zval *ptrs[5]= {&msgnumber, &severity, &state, &line, &text}; + zval **args[5]= {&ptrs[0], &ptrs[1], &ptrs[2], &ptrs[3], &ptrs[4]}; + int handled; + TSRMLS_FETCH(); if (srvmsg->severity >= SybCtG(min_server_severity)) { - php_error(E_WARNING, "Sybase: Server message: %s (severity %d, procedure %s)", - srvmsg->text, srvmsg->severity, ((srvmsg->proclen>0) ? srvmsg->proc : "N/A")); + handled= 0; + if (SybCtG(callback_name) != NULL) { + INIT_ZVAL(msgnumber); + INIT_ZVAL(severity); + INIT_ZVAL(state); + INIT_ZVAL(line); + INIT_ZVAL(text); + + ZVAL_LONG(&msgnumber, srvmsg->msgnumber); + ZVAL_LONG(&severity, srvmsg->severity); + ZVAL_LONG(&state, srvmsg->state); + ZVAL_LONG(&line, srvmsg->line); + ZVAL_STRING(&text, srvmsg->text, 0); + + if (call_user_function_ex(CG(function_table), NULL, SybCtG(callback_name), &retval, 5, args, 0, NULL TSRMLS_CC)== FAILURE) { + php_error(E_WARNING, "Sybase: Cannot call the messagehandler %s", Z_STRVAL_P(SybCtG(callback_name))); + } + + /* + * Returning FALSE, the user function indicates it can't cope + * with this error. Any other return value will be ignored. + * + */ + if (retval) { + handled= ( + (Z_TYPE_P(retval) != IS_BOOL) || + (Z_BVAL_P(retval) != 0) + ); + zval_ptr_dtor(&retval); + } + + } + if (!handled) { + php_error( + E_WARNING, + "Sybase: Server message #%d: %s (severity %d, +procedure %s)", + srvmsg->msgnumber, + srvmsg->text, + srvmsg->severity, + ((srvmsg->proclen>0) ? srvmsg->proc : "N/A") + ); + } + } STR_FREE(SybCtG(server_message)); + SybCtG(server_message) = estrdup(srvmsg->text); /* If this is a deadlock message, set the connection's deadlock flag @@ -267,7 +343,7 @@ static void php_sybase_init_globals(zend_sybase_globals *sybase_globals) { - long timeout; + long timeout, packet_size; if (cs_ctx_alloc(CTLIB_VERSION, &sybase_globals->context)!=CS_SUCCEED || ct_init(sybase_globals->context, CTLIB_VERSION)!=CS_SUCCEED) { return; @@ -316,7 +392,19 @@ php_error(E_WARNING, "Sybase: Unable to set timeout"); } } + + /* + * Packet size + */ + if (cfg_get_long("sybct.packet_size", &packet_size)==SUCCESS) { + CS_INT cs_packet_size = packet_size; + if (ct_config(sybase_globals->context, CS_SET, CS_PACKETSIZE, &cs_packet_size, CS_UNUSED, NULL)!=CS_SUCCEED) { + php_error(E_WARNING, "Sybase: Unable to set timeout"); + } + } + + sybase_globals->num_persistent=0; + sybase_globals->callback_name = NULL; } @@ -366,6 +454,7 @@ PHP_RSHUTDOWN_FUNCTION(sybase) { efree(SybCtG(appname)); + if (NULL != SybCtG(callback_name)) zval_ptr_dtor(&SybCtG(callback_name)); STR_FREE(SybCtG(server_message)); return SUCCESS; } @@ -893,8 +982,8 @@ static sybase_result * php_sybase_fetch_result_set (sybase_link *sybase_ptr) { + sybase_result *result; int num_fields; - sybase_result *result; char **tmp_buffer; CS_INT *lengths; CS_SMALLINT *indicators; @@ -920,7 +1009,6 @@ result->sybase_ptr = sybase_ptr; result->cur_field=result->cur_row=result->num_rows=0; result->num_fields = num_fields; - tmp_buffer = (char **) emalloc(sizeof(char *)*num_fields); lengths = (CS_INT *) emalloc(sizeof(CS_INT)*num_fields); indicators = (CS_SMALLINT *) emalloc(sizeof(CS_INT)*num_fields); @@ -953,33 +1041,33 @@ break; case CS_SMALLINT_TYPE: datafmt[i].maxlength = 7; - numerics[i] = 1; + numerics[i] = 1; break; case CS_INT_TYPE: datafmt[i].maxlength = 12; - numerics[i] = 1; + numerics[i] = 1; break; case CS_REAL_TYPE: case CS_FLOAT_TYPE: datafmt[i].maxlength = 24; - numerics[i] = 1; - break; + numerics[i] = 2; + break; case CS_MONEY_TYPE: case CS_MONEY4_TYPE: datafmt[i].maxlength = 24; - numerics[i] = 0; + numerics[i] = 2; break; case CS_DATETIME_TYPE: case CS_DATETIME4_TYPE: datafmt[i].maxlength = 30; numerics[i] = 0; - break; + break; case CS_NUMERIC_TYPE: case CS_DECIMAL_TYPE: datafmt[i].maxlength = datafmt[i].precision + 3; - numerics[i] = 1; + numerics[i] = (datafmt[i].scale == 0) ? 1 : 2; // +numeric(10) vs numeric(10, 1) break; - default: + default: datafmt[i].maxlength++; numerics[i] = 0; break; @@ -1004,11 +1092,20 @@ result->data[i] = (pval *) emalloc(sizeof(pval)*num_fields); for (j=0; j<num_fields; j++) { if (indicators[j] == -1) { /* null value */ - ZVAL_FALSE(&result->data[i][j]); + ZVAL_NULL(&result->data[i][j]); } else { Z_STRLEN(result->data[i][j]) = lengths[j]-1; /* we don't need the NULL in the length */ Z_STRVAL(result->data[i][j]) = estrndup(tmp_buffer[j], lengths[j]); Z_TYPE(result->data[i][j]) = IS_STRING; + + /* Here we go, i want those types!:-) + * Perhaps there is a nicer way of doing this, instead +of making strings first + * and then converting them back, but I'm a +Zend-API-lamer. + */ + switch (numerics[j]) { + case 1: convert_to_long(&result->data[i][j]); break; + case 2: convert_to_double(&result->data[i][j]); numerics[j]= 1; break; + } } } } @@ -1021,7 +1118,7 @@ j=0; for (i=0; i<num_fields; i++) { char computed_buf[16]; - + if (datafmt[i].namelen>0) { result->fields[i].name = estrndup(datafmt[i].name, datafmt[i].namelen); } else { @@ -1133,7 +1230,6 @@ */ if (ct_results(sybase_ptr->cmd, &restype)!=CS_SUCCEED) { ct_cancel(NULL, sybase_ptr->cmd, CS_CANCEL_ALL); - sybase_ptr->dead = 1; RETURN_FALSE; } @@ -1192,9 +1288,9 @@ case CS_CURSOR_RESULT: case CS_PARAM_RESULT: case CS_ROW_RESULT: - /* Unexpected results, cancel them. */ case CS_STATUS_RESULT: - ct_cancel(NULL, sybase_ptr->cmd, CS_CANCEL_CURRENT); + /* Discard... */ + // ct_cancel(NULL, sybase_ptr->cmd, CS_CANCEL_CURRENT); break; default: @@ -1371,8 +1467,9 @@ { pval *sybase_result_index; sybase_result *result; - int i; + int i, j; pval *tmp; + char name[32]; if (ZEND_NUM_ARGS()!=1 || getParameters(ht, 1, &sybase_result_index)==FAILURE) { WRONG_PARAM_COUNT; @@ -1388,6 +1485,7 @@ RETURN_FALSE; } + j= 1; for (i=0; i<result->num_fields; i++) { ALLOC_ZVAL(tmp); *tmp = result->data[result->cur_row][i]; @@ -1399,20 +1497,76 @@ } zend_hash_index_update(Z_ARRVAL_P(return_value), i, (void *) &tmp, sizeof(pval *), NULL); tmp->refcount++; - zend_hash_update(Z_ARRVAL_P(return_value), result->fields[i].name, strlen(result->fields[i].name)+1, (void *) &tmp, sizeof(pval *), NULL); + if (zend_hash_exists(Z_ARRVAL_P(return_value), result->fields[i].name, strlen(result->fields[i].name)+1)) { + snprintf(name, 32, "%s%d", result->fields[i].name, j); + j++; + zend_hash_update(Z_ARRVAL_P(return_value), name, +strlen(name)+1, (void *) &tmp, sizeof(pval *), NULL); + } else { + zend_hash_update(Z_ARRVAL_P(return_value), result->fields[i].name, strlen(result->fields[i].name)+1, (void *) &tmp, sizeof(pval *), NULL); + } } result->cur_row++; } +static void php_sybase_fetch_assoc(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *sybase_result_index; + sybase_result *result; + int i, j; + pval *tmp; + char name[32]; + + if (ZEND_NUM_ARGS()!=1 || getParameters(ht, 1, &sybase_result_index)==FAILURE) { + WRONG_PARAM_COUNT; + } + + ZEND_FETCH_RESOURCE(result, sybase_result *, &sybase_result_index, -1, "Sybase result", le_result); + + if (result->cur_row >= result->num_rows) { + RETURN_FALSE; + } + + if (array_init(return_value)==FAILURE) { + RETURN_FALSE; + } + + j= 1; + for (i=0; i<result->num_fields; i++) { + ALLOC_ZVAL(tmp); + *tmp = result->data[result->cur_row][i]; + INIT_PZVAL(tmp); + if (PG(magic_quotes_runtime) && Z_TYPE_P(tmp) == IS_STRING) { + Z_STRVAL_P(tmp) = php_addslashes(Z_STRVAL_P(tmp), +Z_STRLEN_P(tmp), &Z_STRLEN_P(tmp), 0 TSRMLS_CC); + } else { + pval_copy_constructor(tmp); + } + if (zend_hash_exists(Z_ARRVAL_P(return_value), result->fields[i].name, strlen(result->fields[i].name)+1)) { + snprintf(name, 32, "%s%d", result->fields[i].name, j); + j++; + zend_hash_update(Z_ARRVAL_P(return_value), name, +strlen(name)+1, (void *) &tmp, sizeof(pval *), NULL); + } else { + zend_hash_update(Z_ARRVAL_P(return_value), result->fields[i].name, strlen(result->fields[i].name)+1, (void *) &tmp, sizeof(pval *), NULL); + } + } + result->cur_row++; +} /* {{{ proto object sybase_fetch_object(int result) Fetch row as object */ PHP_FUNCTION(sybase_fetch_object) { - php_sybase_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU); + php_sybase_fetch_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU); if (Z_TYPE_P(return_value)==IS_ARRAY) { object_and_properties_init(return_value, ZEND_STANDARD_CLASS_DEF_PTR, Z_ARRVAL_P(return_value)); } +} +/* }}} */ + +/* {{{ proto array sybase_fetch_assoc(int result) + Fetch row as array */ +PHP_FUNCTION(sybase_fetch_assoc) +{ + php_sybase_fetch_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU); } /* }}} */ ------------------------------------------------------------------------ The remainder of the comments for this report are too long. To view the rest of the comments, please view the bug report online at http://bugs.php.net/16960 -- Edit this bug report at http://bugs.php.net/?id=16960&edit=1