]> granicus.if.org Git - php/commitdiff
- MFH:
authorTimm Friebe <thekid@php.net>
Thu, 29 Jul 2004 20:05:46 +0000 (20:05 +0000)
committerTimm Friebe <thekid@php.net>
Thu, 29 Jul 2004 20:05:46 +0000 (20:05 +0000)
  . Fixed bug #29064 (Exact numeric/decimal/money datatypes lose precision)
  . Fixed bug #27843 (sybase_query() triggers (spurious?) notices when
    query is a stored procedure)
  . Fixed multiple memory leaks with sybase_unbuffered_query()
  . Changed sybase_query() to ignore store_results = false in  buffering
    mode, it would yield unpredictable results
  . Fixed sybase_unbuffered_query() when used with store_results = false
  . Changed sybase_fetch_object() to ignore second argument when passed
    as NULL
  . Made sybase_data_seek() error message more verbose
  . Fixed memory leak in shutdown when not all rows where selected in an
    unbuffered query
# sort of, empty_string -> STR_EMPTY_ALLOC patch ommitted

ext/sybase_ct/php_sybase_ct.c

index 43dca5df2a5cf8b60c87ea54a7b38bf1a6794737..f1cf9f1257927b5857c4fc7329e437bacbc120d6 100644 (file)
@@ -118,13 +118,12 @@ static int _clean_invalid_results(list_entry *le TSRMLS_DC)
        return 0;
 }
 
-
 static void _free_sybase_result(sybase_result *result)
 {
        int i, j;
 
        if (result->data) {
-               for (i=0; i<(result->store ? result->num_rows : 0); i++) {
+               for (i = 0; i < (result->store ? result->num_rows : MIN(1, result->num_rows)); i++) {
                        for (j=0; j<result->num_fields; j++) {
                                zval_dtor(&result->data[i][j]);
                        }
@@ -144,10 +143,21 @@ static void _free_sybase_result(sybase_result *result)
        efree(result);
 }
 
+/* Forward declaration */
+static int php_sybase_finish_results (sybase_result *result);
+
 static void php_free_sybase_result(zend_rsrc_list_entry *rsrc TSRMLS_DC)
 {
        sybase_result *result = (sybase_result *)rsrc->ptr;
 
+       /* Check to see if we've read all rows */
+       if (result->sybase_ptr && result->sybase_ptr->active_result_index) {
+               if (result->sybase_ptr->cmd) {
+                       ct_cancel(NULL, result->sybase_ptr->cmd, CS_CANCEL_ALL);
+               }
+               php_sybase_finish_results(result);
+       }
+
        _free_sybase_result(result);
 }
 
@@ -1042,11 +1052,15 @@ static int php_sybase_finish_results (sybase_result *result)
                        case CS_PARAM_RESULT:
                        case CS_ROW_RESULT:
                                /* Unexpected results, cancel them. */
-                       case CS_STATUS_RESULT:
                                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Sybase:  Unexpected results, cancelling current");
                                ct_cancel(NULL, result->sybase_ptr->cmd, CS_CANCEL_CURRENT);
                                break;
 
+                       case CS_STATUS_RESULT:
+                               /* Status result from a stored procedure, cancel it but do not tell user */
+                               ct_cancel(NULL, result->sybase_ptr->cmd, CS_CANCEL_CURRENT);
+                               break;
+
                        default:
                                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Sybase:  Unexpected results, cancelling all");
                                ct_cancel(NULL, result->sybase_ptr->cmd, CS_CANCEL_ALL);
@@ -1087,6 +1101,19 @@ static int php_sybase_finish_results (sybase_result *result)
        return retcode;
 }
 
+#define RETURN_DOUBLE_VAL(result, buf, length)          \
+       if ((length - 1) <= EG(precision)) {                \
+               errno = 0;                                      \
+               Z_DVAL(result) = strtod(buf, NULL);             \
+               if (errno != ERANGE) {                          \
+                       Z_TYPE(result) = IS_DOUBLE;                 \
+               } else {                                        \
+                       ZVAL_STRINGL(&result, buf, length- 1, 1);   \
+               }                                               \
+       } else {                                            \
+               ZVAL_STRINGL(&result, buf, length- 1, 1);       \
+       }
+
 static int php_sybase_fetch_result_row (sybase_result *result, int numrows)
 {
        int i, j;
@@ -1107,7 +1134,6 @@ static int php_sybase_fetch_result_row (sybase_result *result, int numrows)
                }
                */
                
-               /* i= result->num_rows++; */
                result->num_rows++;
                i= result->store ? result->num_rows- 1 : 0;
                if (i >= result->blocks_initialized*SYBASE_ROWS_BLOCK) {
@@ -1117,27 +1143,48 @@ static int php_sybase_fetch_result_row (sybase_result *result, int numrows)
                        result->data[i] = (zval *) safe_emalloc(sizeof(zval), result->num_fields, 0);
                }
 
-               for (j=0; j<result->num_fields; j++) {
+               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]));
+                       }
+
                        if (result->indicators[j] == -1) { /* null value */
                                ZVAL_NULL(&result->data[i][j]);
                        } else {
-                               Z_STRLEN(result->data[i][j]) = result->lengths[j]-1;  /* we don't need the NULL in the length */
-                               Z_STRVAL(result->data[i][j]) = estrndup(result->tmp_buffer[j], result->lengths[j]);
-                               Z_TYPE(result->data[i][j]) = IS_STRING;
-                               
                                switch (result->numerics[j]) {
-                                       case 1:
-                                               convert_to_long(&result->data[i][j]);
+                                       case 1: {
+                                               /* This indicates a long */
+                                               ZVAL_LONG(&result->data[i][j], strtol(result->tmp_buffer[j], NULL, 10));
                                                break;
-                                       case 2:
-                                               convert_to_double(&result->data[i][j]);
+                                       }
+                                       
+                                       case 2: {
+                                               /* This indicates a float */
+                                               RETURN_DOUBLE_VAL(result->data[i][j], result->tmp_buffer[j], result->lengths[j]); 
                                                break;
-                                       case 3:
-                                               /* This signals we have an integer datatype, but we need to convert to double if we 
-                                                * overflow. 
-                                                */
-                                               convert_scalar_to_number(&result->data[i][j] TSRMLS_CC);
+                                       }
+
+                                       case 3: {
+                                               /* This indicates either a long or a float, which ever fits */
+                                               errno = 0;
+                                               Z_LVAL(result->data[i][j]) = strtol(result->tmp_buffer[j], NULL, 10);
+                                               if (errno == ERANGE) {
+                                               
+                                                       /* An overflow occurred, so try to fit it into a double */
+                                                       RETURN_DOUBLE_VAL(result->data[i][j], result->tmp_buffer[j], result->lengths[j]); 
+                                                       break;
+                                               }
+                                               Z_TYPE(result->data[i][j]) = IS_LONG;
+                                               break;
+                                       }
+                                       
+                                       default: {
+                                               /* This indicates anything else, return it as string */
+                                               ZVAL_STRINGL(&result->data[i][j], result->tmp_buffer[j], result->lengths[j]- 1, 1);
                                                break;
+                                       }          
                                }
                        }
                }
@@ -1280,9 +1327,12 @@ static sybase_result * php_sybase_fetch_result_set (sybase_link *sybase_ptr, int
                Z_TYPE(result->fields[i]) = result->types[i];
        }
        
-       retcode= php_sybase_fetch_result_row(result, buffered ? 1 : -1);
-       if (retcode == CS_FAIL) {
-               return NULL;
+       if (buffered) {
+               retcode = CS_SUCCEED;
+       } else {
+               if ((retcode = php_sybase_fetch_result_row(result, -1)) == CS_FAIL) {
+                       return NULL;
+               }
        }
 
        result->last_retcode = retcode;
@@ -1322,9 +1372,14 @@ static void php_sybase_query (INTERNAL_FUNCTION_PARAMETERS, int buffered)
                        if (zend_get_parameters_ex(3, &query, &sybase_link_index, &store_mode)==FAILURE) {
                                RETURN_FALSE;
                        }
+                       if (!buffered) {
+                               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "cannot use non-storing mode with buffered queries");
+                               store = 1;
+                       } else {
+                               convert_to_long_ex(store_mode);
+                               store= (Z_LVAL_PP(store_mode) != 0);
+                       }
                        id = -1;
-                       convert_to_long_ex(store_mode);
-                       store= (Z_LVAL_PP(store_mode) != 0);
                        break;
                default:
                        WRONG_PARAM_COUNT;
@@ -1760,19 +1815,23 @@ PHP_FUNCTION(sybase_fetch_object)
                
                switch (Z_TYPE_PP(object)) {
                        case IS_OBJECT:
-                               ce= Z_OBJCE_PP(object);
+                               ce = Z_OBJCE_PP(object);
                                break;
-                       default:
-                               convert_to_string_ex(object);
-                               zend_str_tolower(Z_STRVAL_PP(object), Z_STRLEN_PP(object));
-                               zend_hash_find(EG(class_table), Z_STRVAL_PP(object), Z_STRLEN_PP(object)+1, (void **)&ce);
+                       case IS_NULL:
+                               break;
+                       default: {
+                               zend_class_entry **pce = NULL;
 
-                               if (!ce) {
+                               convert_to_string_ex(object);
+                               if (zend_lookup_class(Z_STRVAL_PP(object), Z_STRLEN_PP(object), &pce TSRMLS_CC) == FAILURE) {
                                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Sybase:  Class %s has not been declared", Z_STRVAL_PP(object));
-                                       ce= ZEND_STANDARD_CLASS_DEF_PTR;
+                               } else {
+                                       ce = *pce;
                                }
+                       }
                }
-               
+
+               /* Reset no. of arguments to 1 so that we can use INTERNAL_FUNCTION_PARAM_PASSTHRU */
                ht= 1;
        }
        
@@ -1780,7 +1839,7 @@ PHP_FUNCTION(sybase_fetch_object)
        if (Z_TYPE_P(return_value)==IS_ARRAY) {
                object_and_properties_init(
                        return_value, 
-                       object ? ce : ZEND_STANDARD_CLASS_DEF_PTR, 
+                       ce ? ce : ZEND_STANDARD_CLASS_DEF_PTR, 
                        Z_ARRVAL_P(return_value)
                );
        }
@@ -1821,11 +1880,11 @@ PHP_FUNCTION(sybase_data_seek)
 
        /* Unbuffered ? */
        if (result->last_retcode != CS_END_DATA && result->last_retcode != CS_END_RESULTS && Z_LVAL_PP(offset)>=result->num_rows) {
-               php_sybase_fetch_result_row(result, Z_LVAL_PP(offset));
+               php_sybase_fetch_result_row(result, Z_LVAL_PP(offset)+ 1);
        }
        
        if (Z_LVAL_PP(offset)<0 || Z_LVAL_PP(offset)>=result->num_rows) {
-               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Bad row offset");
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Bad row offset %ld, must be betweem 0 and %d", Z_LVAL_PP(offset), result->num_rows - 1);
                RETURN_FALSE;
        }
 
@@ -1947,11 +2006,6 @@ PHP_FUNCTION(sybase_field_seek)
        convert_to_long_ex(offset);
        field_offset = Z_LVAL_PP(offset);
        
-       /* Unbuffered ? */
-       if (result->last_retcode != CS_END_DATA && result->last_retcode != CS_END_RESULTS && field_offset>=result->num_rows) {
-               php_sybase_fetch_result_row(result, field_offset);
-       }
-
        if (field_offset<0 || field_offset >= result->num_fields) {
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Sybase:  Bad column offset");
                RETURN_FALSE;