#16960 [Opn->Asn]: [Sybase-CT] sybase_fetch_row() and types

From: Date: Tue, 29 Oct 2002 21:08:31 +0000
Subject: #16960 [Opn->Asn]: [Sybase-CT] sybase_fetch_row() and types
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-23654@lists.php.net to get a copy of this message
 ID:               16960
 Updated by:       thekid@php.net
 Reported By:      thekid@thekid.de
-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] thekid@thekid.de

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] thekid@thekid.de

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



Thread (8 messages)

« previous php.bugs (#23654) next »