ID: 16960 Updated by: [EMAIL PROTECTED] Reported By: [EMAIL PROTECTED] -Status: Open +Status: Assigned Bug Type: Feature/Change Request Operating System: All PHP Version: 4.0CVS-2002-05-02 -Assigned To: +Assigned To: thekid
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