php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #48675 sybase_ct does not support multiple result sets returned by stored procedures
Submitted: 2009-06-24 13:38 UTC Modified: 2015-02-18 07:44 UTC
Votes:37
Avg. Score:4.8 ± 0.6
Reproduced:35 of 35 (100.0%)
Same Version:6 (17.1%)
Same OS:2 (5.7%)
From: lo at readyon dot com Assigned:
Status: Wont fix Package: Sybase-ct (ctlib) related
PHP Version: 5.2.10 OS: Mac OS X 10.5.8 (9L31a)
Private report: No CVE-ID: None
 [2009-06-24 13:38 UTC] lo at readyon dot com
Description:
------------
Sybase CTLib does not support fetching more than one result set from a 
stored procedure. This seems to be a long standing issue detailed in the 
closed (status: bogus) issue #26636 and others, detailed in the user 
comments on the page http://us3.php.net/manual/en/function.sybase-
query.php. 


Reproduce code:
---------------
$conn = sybase_connect($server, $user, $pass);
sybase_select_db($db, $conn);
$result = sybase_query("sp_help $table", $conn);
do {
  echo "Next result set...\n";
  while ($row = sybase_fetch_assoc($result)) {
    echo "  - fetched row...\n";
  }
} while ($result = sybase_next_result($conn)); // <- No such function

Expected result:
----------------
Many result sets, for example:

Next result set...
  - fetched row
Next result set...
  - fetched row
  - fetched row
  - fetched row
  - fetched row
  - fetched row
  - fetched row
Next result set...
  - fetched row
  - fetched row
Next result set...
  - fetched row
  - fetched row
Next result set...
  - fetched row
Next result set...
  - fetched row
Next result set...
  - fetched row
Next result set...
  - fetched row
Next result set...
  - fetched row
Next result set...
  - fetched row


Actual result:
--------------
Next result set...
  - fetched row

Then no supported function sybase_next_result().

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2009-06-24 13:40 UTC] lo at readyon dot com
Here is a patch to add support for sybase_next_result() for 5.2.9:

diff -rupN ../orig/php-5.2.9/ext/sybase_ct/php_sybase_ct.c 
ext/sybase_ct/php_sybase_ct.c
--- ../orig/php-5.2.9/ext/sybase_ct/php_sybase_ct.c	2008-12-31 
05:17:46.000000000 -0600
+++ ext/sybase_ct/php_sybase_ct.c	2009-06-24 08:28:52.000000000 
-0500
@@ -47,8 +47,9 @@ zend_function_entry sybase_functions[] =
 	PHP_FE(sybase_close, NULL)
 	PHP_FE(sybase_select_db, NULL)
 	PHP_FE(sybase_query, NULL)
-	PHP_FE(sybase_unbuffered_query, NULL)
 	PHP_FE(sybase_free_result, NULL)
+	PHP_FE(sybase_unbuffered_query, NULL)
+	PHP_FE(sybase_next_result, NULL)
 	PHP_FE(sybase_get_last_message, NULL)
 	PHP_FE(sybase_num_rows, NULL)
 	PHP_FE(sybase_num_fields, NULL)
@@ -73,6 +74,7 @@ zend_function_entry sybase_functions[] =
 	PHP_FALIAS(mssql_select_db, sybase_select_db, NULL)
 	PHP_FALIAS(mssql_query, sybase_query, NULL)
 	PHP_FALIAS(mssql_unbuffered_query, sybase_unbuffered_query, 
NULL)
+	PHP_FALIAS(mssql_next_result, sybase_next_result, 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)
@@ -1052,7 +1054,8 @@ static int php_sybase_finish_results(syb
 	efree_n(result->numerics);
 	efree_n(result->types);
 	for (i=0; i<result->num_fields; i++) {
-		efree(result->tmp_buffer[i]);
+        if (result->tmp_buffer != NULL)
+            efree(result->tmp_buffer[i]);
 	}
 	efree_n(result->tmp_buffer);
 
@@ -1085,7 +1088,14 @@ static int php_sybase_finish_results(syb
 			case CS_ROW_RESULT:
 				/* Unexpected results, cancel them. */
 				php_error_docref(NULL TSRMLS_CC, 
E_NOTICE, "Sybase:  Unexpected results, cancelling current");
-				ct_cancel(NULL, result->sybase_ptr-
>cmd, CS_CANCEL_CURRENT);
+                // !!!:KLS:20090624 Do not cancel when there are 
additional
+                // rows. THe command will be cancelled upon next 
query if
+                // sybase_next_result() is not invoked.
+                // {
+                fail = 1;
+                retcode = CS_END_RESULTS;
+                // ct_cancel(NULL, result->sybase_ptr->cmd, 
CS_CANCEL_CURRENT);
+                // }
 				break;
 
 			case CS_STATUS_RESULT:
@@ -1167,7 +1177,6 @@ static int php_sybase_fetch_result_row (
 		}
 
 		for (j = 0; j < result->num_fields; j++) {
-
 			/* If we are in non-storing mode, free the 
previous result */
 			if (!result->store && result->num_rows > 1 && 
Z_TYPE(result->data[i][j]) == IS_STRING) {
 				efree(Z_STRVAL(result->data[i][j]));
@@ -1645,6 +1654,98 @@ PHP_FUNCTION(sybase_unbuffered_query)
 {
 	php_sybase_query(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
 }
+/* }}} */
+
+// MARK: sybase_next_result
+/* {{{ proto int sybase_next_result(int result)
+   Send Sybase query */
+PHP_FUNCTION(sybase_next_result)
+{
+	zval **db, **sybase_link_index;
+	int id;
+	char *cmdbuf;
+	sybase_link  *sybase_ptr;
+    sybase_result *result;
+    int retcode;
+    int restype;
+
+	switch(ZEND_NUM_ARGS()) {
+		case 1:
+			if (zend_get_parameters_ex(1, &db) == FAILURE) 
{
+				RETURN_FALSE;
+			}
+			id = 
php_sybase_get_default_link(INTERNAL_FUNCTION_PARAM_PASSTHRU);
+			CHECK_LINK(id);
+			break;
+		case 2:
+			if (zend_get_parameters_ex(2, &db, 
&sybase_link_index) == FAILURE) {
+				RETURN_FALSE;
+			}
+			id = -1;
+			break;
+		default:
+			WRONG_PARAM_COUNT;
+			break;
+	}
+
+	ZEND_FETCH_RESOURCE2(sybase_ptr, sybase_link *, 
sybase_link_index, id, "Sybase-Link", le_link, le_plink);
+
+	/* Check to see if a previous sybase_unbuffered_query has read 
all rows */
+	if (sybase_ptr->active_result_index) {
+		zval *tmp = NULL;
+		
+		php_error_docref(NULL TSRMLS_CC, E_NOTICE, "called 
without first fetching all rows from a previous unbuffered query");
+		if (sybase_ptr->cmd) {
+			ct_cancel(NULL, sybase_ptr->cmd, 
CS_CANCEL_ALL);
+		}
+		
+		/* Get the resultset and free it */
+		ALLOC_ZVAL(tmp);
+		Z_LVAL_P(tmp)= sybase_ptr->active_result_index;
+		Z_TYPE_P(tmp)= IS_RESOURCE;
+		INIT_PZVAL(tmp);
+		ZEND_FETCH_RESOURCE(result, sybase_result *, &tmp, -1, 
"Sybase result", le_result);
+		
+		if (result) {
+			php_sybase_finish_results(result TSRMLS_CC);
+		}
+		
+		zval_ptr_dtor(&tmp);
+		zend_list_delete(sybase_ptr->active_result_index);
+		sybase_ptr->active_result_index= 0;
+	}
+    
+    retcode = ct_results(sybase_ptr->cmd, &restype);
+    //printf("    ct_results(): retcode=%d, restype=%d\n", retcode, 
restype);
+    switch (retcode) {
+        case CS_SUCCEED:
+            result = php_sybase_fetch_result_set(sybase_ptr, 0, 1);
+            if (result == NULL) {
+                ct_cancel(NULL, sybase_ptr->cmd, CS_CANCEL_ALL);
+                sybase_ptr->dead = 1;
+                RETURN_FALSE;
+            }
+
+            /* Indicate we have data in case of buffered queries */
+            id= ZEND_REGISTER_RESOURCE(return_value, result, 
le_result);
+            sybase_ptr->active_result_index= 0 ? id : 0;
+            break;
+    
+        case CS_END_RESULTS:
+            /* No more result sets */
+            RETURN_FALSE;
+        
+        case CS_FAIL:
+            ct_cancel(NULL, sybase_ptr->cmd, CS_CANCEL_ALL);
+			sybase_ptr->dead = 1;
+            /* Fall through */
+            
+        case CS_CANCELED:
+        default:
+            RETURN_FALSE;
+    }
+}
+/* }}} */
 
 /* {{{ proto bool sybase_free_result(int result)
    Free result memory */
diff -rupN ../orig/php-5.2.9/ext/sybase_ct/php_sybase_ct.h 
ext/sybase_ct/php_sybase_ct.h
--- ../orig/php-5.2.9/ext/sybase_ct/php_sybase_ct.h	2008-12-31 
05:17:46.000000000 -0600
+++ ext/sybase_ct/php_sybase_ct.h	2009-06-23 11:44:01.000000000 
-0500
@@ -42,6 +42,7 @@ PHP_FUNCTION(sybase_select_db);
 PHP_FUNCTION(sybase_query);
 PHP_FUNCTION(sybase_unbuffered_query);
 PHP_FUNCTION(sybase_free_result);
+PHP_FUNCTION(sybase_next_result);
 PHP_FUNCTION(sybase_get_last_message);
 PHP_FUNCTION(sybase_num_rows);
 PHP_FUNCTION(sybase_num_fields);
 [2009-09-25 03:26 UTC] murali_dharan_2000 at yahoo dot com
The proposed solution did not work for me on PHP 5.3.0 on Linux x86-64. This functionality is really useful to have in PHP as the power of stored procedures in Sybase is the ability to return multiple result sets and PHP needs to be enhanced to handle the same.
 [2009-09-25 17:48 UTC] lo at readyon dot com
I haven't looked at 5.3.0. However, the changes to php_sybase_ct.c are 
relatively straightforward:

1. Disable cancelling/closing after successful result
   php_sybase_finish_results()

	case CS_COMPUTE_RESULT:
	case CS_CURSOR_RESULT:
	case CS_PARAM_RESULT:
	case CS_ROW_RESULT:
		/* Unexpected results, cancel them. */
		php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Sybase:  
Unexpected results, cancelling current");
		// !!!:KLS:20090624 Do not cancel when there are 
additional
		// rows. THe command will be cancelled upon next query 
if
		// sybase_next_result() is not invoked.
		// {
		fail = 1;
		retcode = CS_END_RESULTS;
		// ct_cancel(NULL, result->sybase_ptr->cmd, 
CS_CANCEL_CURRENT);
		// }
		break;


2. Add a sybase_next_result() function and register these functions.

    /* {{{ proto int sybase_next_result(int conn)
       Fetch the next result set */
    PHP_FUNCTION(sybase_next_result)
    {
        zval **db, **sybase_link_index;
        int id;
        char *cmdbuf;
        sybase_link  *sybase_ptr;
        sybase_result *result;
        int retcode;
        int restype;

        switch(ZEND_NUM_ARGS()) {
            case 1:
                if (zend_get_parameters_ex(1, &db) == FAILURE) {
                    RETURN_FALSE;
                }
                id = 
php_sybase_get_default_link(INTERNAL_FUNCTION_PARAM_PASSTHRU);
                CHECK_LINK(id);
                break;
            case 2:
                if (zend_get_parameters_ex(2, &db, &sybase_link_index) 
== FAILURE) {
                    RETURN_FALSE;
                }
                id = -1;
                break;
            default:
                WRONG_PARAM_COUNT;
                break;
        }

        ZEND_FETCH_RESOURCE2(sybase_ptr, sybase_link *, 
sybase_link_index, id, "Sybase-Link", le_link, le_plink);

        /* Check to see if a previous sybase_unbuffered_query has read 
all rows */
        if (sybase_ptr->active_result_index) {
            zval *tmp = NULL;
            
            php_error_docref(NULL TSRMLS_CC, E_NOTICE, "called without 
first fetching all rows from a previous 
unbuffered query");
            if (sybase_ptr->cmd) {
                ct_cancel(NULL, sybase_ptr->cmd, CS_CANCEL_ALL);
            }
            
            /* Get the resultset and free it */
            ALLOC_ZVAL(tmp);
            Z_LVAL_P(tmp)= sybase_ptr->active_result_index;
            Z_TYPE_P(tmp)= IS_RESOURCE;
            INIT_PZVAL(tmp);
            ZEND_FETCH_RESOURCE(result, sybase_result *, &tmp, -1, 
"Sybase result", le_result);
            
            if (result) {
                php_sybase_finish_results(result TSRMLS_CC);
            }
            
            zval_ptr_dtor(&tmp);
            zend_list_delete(sybase_ptr->active_result_index);
            sybase_ptr->active_result_index= 0;
        }
        
        retcode = ct_results(sybase_ptr->cmd, &restype);
        switch (retcode) {
            case CS_SUCCEED:
                result = php_sybase_fetch_result_set(sybase_ptr, 0, 
1);
                if (result == NULL) {
                    ct_cancel(NULL, sybase_ptr->cmd, CS_CANCEL_ALL);
                    sybase_ptr->dead = 1;
                    RETURN_FALSE;
                }

                /* Indicate we have data in case of buffered queries 
*/
                id= ZEND_REGISTER_RESOURCE(return_value, result, 
le_result);
                sybase_ptr->active_result_index= 0 ? id : 0;
                break;
        
            case CS_END_RESULTS:
                /* No more result sets */
                RETURN_FALSE;
            
            case CS_FAIL:
                ct_cancel(NULL, sybase_ptr->cmd, CS_CANCEL_ALL);
                sybase_ptr->dead = 1;
                /* Fall through */
                
            case CS_CANCELED:
            default:
                RETURN_FALSE;
        }
    }
    /* }}} */
 [2011-06-09 06:56 UTC] hexes at mail dot ru
Gentlemen developers!
When??? There is a patch, i'm not so cleaver as you, and cant use it. Can you 
apply it to main branch?
 [2012-04-13 12:24 UTC] jonas at bollden dot se
When will this patch find its way into the main branch?
 [2012-04-17 09:49 UTC] hexes at mail dot ru
PLZ!!!! Add this patch to main branch!!!!
 [2015-02-18 07:44 UTC] krakjoe@php.net
-Status: Open +Status: Wont fix
 [2015-02-18 07:44 UTC] krakjoe@php.net
The sybase maintainer has backed away from the project, since nobody new has come forward it has been removed in version 7 of PHP.

For this reason, I'm marking the bug as won't fix, it can still be found by any maintainer that might come along and revive sybase as a PECL project.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sat Dec 21 14:01:32 2024 UTC