]> granicus.if.org Git - php/commitdiff
return zvals instead of strings, cast or not based on stringify attribute
authorAdam Baratz <abaratz@wayfair.com>
Wed, 6 Apr 2016 10:18:53 +0000 (12:18 +0200)
committerAnatol Belski <ab@php.net>
Wed, 6 Apr 2016 10:18:53 +0000 (12:18 +0200)
ext/pdo_dblib/dblib_stmt.c
ext/pdo_dblib/tests/bug_38955.phpt
ext/pdo_dblib/tests/bug_45876.phpt
ext/pdo_dblib/tests/bug_47588.phpt
ext/pdo_dblib/tests/types.phpt [new file with mode: 0644]

index 49b75ee2bb4826cca726c54c2e8bbf4353aa60b4..6098ae515ddd4676f1ab145d77214ff64bbc373d 100644 (file)
@@ -232,7 +232,7 @@ static int pdo_dblib_stmt_describe(pdo_stmt_t *stmt, int colno)
        }
 
        col->maxlen = dbcollen(H->link, colno+1);
-       col->param_type = PDO_PARAM_STR;
+       col->param_type = PDO_PARAM_ZVAL;
 
        return 1;
 }
@@ -245,78 +245,161 @@ static int pdo_dblib_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr,
        pdo_dblib_db_handle *H = S->H;
 
        int coltype;
-       unsigned int tmp_len;
-       char *tmp_ptr = NULL;
+       char *data, *tmp_data;
+       unsigned int data_len, tmp_data_len;
+       zval *zv = NULL;
 
        coltype = dbcoltype(H->link, colno+1);
-
-       *len = dbdatlen(H->link, colno+1);
-       *ptr = dbdata(H->link, colno+1);
-
-       if (*len == 0 && *ptr == NULL) {
-               return 1;
-       }
-
-       switch (coltype) {
-               case SQLVARBINARY:
-               case SQLBINARY:
-               case SQLIMAGE:
-               case SQLTEXT:
-                       /* FIXME: Above types should be returned as a stream as they can be VERY large */
-               case SQLCHAR:
-               case SQLVARCHAR:
-                       tmp_ptr = emalloc(*len + 1);
-                       memcpy(tmp_ptr, *ptr, *len);
-                       tmp_ptr[*len] = '\0';
-                       *ptr = tmp_ptr;
-                       break;
-               case SQLMONEY:
-               case SQLMONEY4:
-               case SQLMONEYN: {
-                       DBFLT8 money_value;
-                       dbconvert(NULL, coltype, *ptr, *len, SQLFLT8, (LPBYTE)&money_value, 8);
-                       *len = spprintf(&tmp_ptr, 0, "%.4f", money_value);
-                       *ptr = tmp_ptr;
-                       break;
-               }
-               case SQLUNIQUE: {
-                       *len = 37;
-                       tmp_ptr = emalloc(*len + 1);
-                       *len = dbconvert(NULL, SQLUNIQUE, *ptr, *len, SQLCHAR, tmp_ptr, *len);
-                       php_strtoupper(tmp_ptr, *len);
-                       tmp_ptr[36] = '\0';
-                       *ptr = tmp_ptr;
-                       break;
+       data = dbdata(H->link, colno+1);
+       data_len = dbdatlen(H->link, colno+1);
+
+       if (data_len != 0 || data != NULL) {
+               if (stmt->dbh->stringify) {
+                       switch (coltype) {
+                               case SQLFLT4:
+                               case SQLFLT8:
+                               case SQLINT4:
+                               case SQLINT2:
+                               case SQLINT1:
+                               case SQLBIT: {
+                                       if (dbwillconvert(coltype, SQLCHAR)) {
+                                               tmp_data_len = 32 + (2 * (data_len)); /* FIXME: We allocate more than we need here */
+                                               tmp_data = emalloc(tmp_data_len);
+                                               data_len = dbconvert(NULL, coltype, data, data_len, SQLCHAR, tmp_data, -1);
+
+                                               zv = emalloc(sizeof(zval));
+                                               ZVAL_STRING(zv, tmp_data);
+
+                                               efree(tmp_data);
+                                       }
+                                       break;
+                               }
+                       }
                }
-               case SQLDATETIM4:
-               case SQLDATETIME: {
-                       DBDATETIME dt;
-                       DBDATEREC di;
-
-                       dbconvert(H->link, coltype, (BYTE*) *ptr, -1, SQLDATETIME, (LPBYTE) &dt, -1);
-                       dbdatecrack(H->link, &di, &dt);
 
-                       *len = spprintf((char**) &tmp_ptr, 20, "%d-%02d-%02d %02d:%02d:%02d",
+               if (!zv) {
+                       switch (coltype) {
+                               case SQLCHAR:
+                               case SQLVARCHAR:
+                               case SQLTEXT: {
+#if ilia_0
+                                       while (data_len>0 && data[data_len-1] == ' ') { /* nuke trailing whitespace */
+                                               data_len--;
+                                       }
+#endif
+                               }
+                               case SQLVARBINARY:
+                               case SQLBINARY:
+                               case SQLIMAGE: {
+                                       zv = emalloc(sizeof(zval));
+                                       ZVAL_STRINGL(zv, data, data_len);
+
+                                       break;
+                               }
+                               case SQLDATETIME:
+                               case SQLDATETIM4: {
+                                       int dl;
+                                       DBDATEREC di;
+                                       DBDATEREC dt;
+
+                                       dbconvert(H->link, coltype, data, -1, SQLDATETIME, (LPBYTE) &dt, -1);
+                                       dbdatecrack(H->link, &di, (DBDATETIME *) &dt);
+
+                                       dl = spprintf(&tmp_data, 20, "%d-%02d-%02d %02d:%02d:%02d",
 #if defined(PHP_DBLIB_IS_MSSQL) || defined(MSDBLIB)
-                                       di.year,     di.month,       di.day,        di.hour,     di.minute,     di.second
+                                                       di.year,     di.month,       di.day,        di.hour,     di.minute,     di.second
+#else
+                                                       di.dateyear, di.datemonth+1, di.datedmonth, di.datehour, di.dateminute, di.datesecond
+#endif
+                                       );
+
+                                       zv = emalloc(sizeof(zval));
+                                       ZVAL_STRINGL(zv, tmp_data, dl);
+
+                                       efree(tmp_data);
+
+                                       break;
+                               }
+                               case SQLFLT4: {
+                                       zv = emalloc(sizeof(zval));
+                                       ZVAL_DOUBLE(zv, (double) (*(DBFLT4 *) data));
+
+                                       break;
+                               }
+                               case SQLFLT8: {
+                                       zv = emalloc(sizeof(zval));
+                                       ZVAL_DOUBLE(zv, (double) (*(DBFLT8 *) data));
+
+                                       break;
+                               }
+                               case SQLINT4: {
+                                       zv = emalloc(sizeof(zval));
+                                       ZVAL_LONG(zv, (long) ((int) *(DBINT *) data));
+
+                                       break;
+                               }
+                               case SQLINT2: {
+                                       zv = emalloc(sizeof(zval));
+                                       ZVAL_LONG(zv, (long) ((int) *(DBSMALLINT *) data));
+
+                                       break;
+                               }
+                               case SQLINT1:
+                               case SQLBIT: {
+                                       zv = emalloc(sizeof(zval));
+                                       ZVAL_LONG(zv, (long) ((int) *(DBTINYINT *) data));
+
+                                       break;
+                               }
+                               case SQLMONEY:
+                               case SQLMONEY4:
+                               case SQLMONEYN: {
+                                       DBFLT8 money_value;
+                                       dbconvert(NULL, coltype, data, 8, SQLFLT8, (LPBYTE)&money_value, -1);
+
+                                       zv = emalloc(sizeof(zval));
+                                       ZVAL_DOUBLE(zv, money_value);
+
+                                       if (stmt->dbh->stringify) {
+                                               convert_to_string(zv);
+                                       }
+
+                                       break;
+                               }
+#ifdef SQLUNIQUE
+                               case SQLUNIQUE: {
 #else
-                                       di.dateyear, di.datemonth+1, di.datedmonth, di.datehour, di.dateminute, di.datesecond
+                               case 36: { /* FreeTDS hack */
 #endif
-                               );
+                                       zv = emalloc(sizeof(zval));
+                                       ZVAL_STRINGL(zv, data, 16); /* uniqueidentifier is a 16-byte binary number */
 
-                       *ptr = (char*) tmp_ptr;
-                       break;
-               }
-               default:
-                       if (dbwillconvert(coltype, SQLCHAR)) {
-                               tmp_len = 32 + (2 * (*len)); /* FIXME: We allocate more than we need here */
-                               tmp_ptr = emalloc(tmp_len);
-                               *len = dbconvert(NULL, coltype, *ptr, *len, SQLCHAR, tmp_ptr, -1);
-                               *ptr = tmp_ptr;
-                       } else {
-                               *len = 0; /* FIXME: Silently fails and returns null on conversion errors */
-                               *ptr = NULL;
+                                       break;
+                               }
+                               default: {
+                                       if (dbwillconvert(coltype, SQLCHAR)) {
+                                               tmp_data_len = 32 + (2 * (data_len)); /* FIXME: We allocate more than we need here */
+                                               tmp_data = emalloc(tmp_data_len);
+                                               data_len = dbconvert(NULL, coltype, data, data_len, SQLCHAR, tmp_data, -1);
+
+                                               zv = emalloc(sizeof(zval));
+                                               ZVAL_STRING(zv, tmp_data);
+
+                                               efree(tmp_data);
+                                       }
+
+                                       break;
+                               }
                        }
+               }
+       }
+
+       if (zv != NULL) {
+               *ptr = (char*)zv;
+               *len = sizeof(zval);
+       } else {
+               *ptr = NULL;
+               *len = 0;
        }
 
        *caller_frees = 1;
@@ -335,6 +418,7 @@ static int pdo_dblib_stmt_get_column_meta(pdo_stmt_t *stmt, zend_long colno, zva
        pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data;
        pdo_dblib_db_handle *H = S->H;
        DBTYPEINFO* dbtypeinfo;
+       int coltype;
 
        if(colno >= stmt->column_count || colno < 0)  {
                return FAILURE;
@@ -346,14 +430,28 @@ static int pdo_dblib_stmt_get_column_meta(pdo_stmt_t *stmt, zend_long colno, zva
 
        if(!dbtypeinfo) return FAILURE;
 
+       coltype = dbcoltype(H->link, colno+1);
+
        add_assoc_long(return_value, "max_length", dbcollen(H->link, colno+1) );
        add_assoc_long(return_value, "precision", (int) dbtypeinfo->precision );
        add_assoc_long(return_value, "scale", (int) dbtypeinfo->scale );
        add_assoc_string(return_value, "column_source", dbcolsource(H->link, colno+1));
-       add_assoc_string(return_value, "native_type", pdo_dblib_get_field_name(dbcoltype(H->link, colno+1)));
-       add_assoc_long(return_value, "native_type_id", dbcoltype(H->link, colno+1));
+       add_assoc_string(return_value, "native_type", pdo_dblib_get_field_name(coltype));
+       add_assoc_long(return_value, "native_type_id", coltype);
        add_assoc_long(return_value, "native_usertype_id", dbcolutype(H->link, colno+1));
 
+       switch (coltype) {
+               case SQLBIT:
+               case SQLINT1:
+               case SQLINT2:
+               case SQLINT4:
+                       add_assoc_long(return_value, "pdo_type", PDO_PARAM_INT);
+                       break;
+               default:
+                       add_assoc_long(return_value, "pdo_type", PDO_PARAM_STR);
+                       break;
+       }
+
        return 1;
 }
 
index 1954ed460b54f41ec338f5c075c0d5f74aa5d31f..57adbf6c4040bfc8ab50127f833f0d6a2887b36a 100644 (file)
@@ -37,21 +37,21 @@ array(4) {
   [0]=>
   array(1) {
     ["val"]=>
-    string(1) "1"
+    int(1)
   }
   [1]=>
   array(1) {
     ["val"]=>
-    string(1) "2"
+    int(2)
   }
   [2]=>
   array(1) {
     ["val"]=>
-    string(1) "3"
+    int(3)
   }
   [3]=>
   array(1) {
     ["val"]=>
-    string(1) "4"
+    int(4)
   }
 }
index 3d527e5ffecaff894a88f0dcb8982709ef515882..5f1026e623214ac76eb0552d81c4176548eb46de 100644 (file)
@@ -30,10 +30,10 @@ array(10) {
   int(%d)
   ["native_usertype_id"]=>
   int(%d)
+  ["pdo_type"]=>
+  int(2)
   ["name"]=>
   string(13) "TABLE_CATALOG"
   ["len"]=>
   int(255)
-  ["pdo_type"]=>
-  int(2)
 }
index d8f424e8728efd5cd08c012714c07dbb129db118..262720f632b5c2786c037243ce6ffae98f5cb218 100644 (file)
@@ -23,21 +23,21 @@ array(3) {
   [0]=>
   array(2) {
     ["My Field"]=>
-    string(1) "1"
+    int(1)
     ["Another Field"]=>
     string(11) "test_string"
   }
   [1]=>
   array(2) {
     ["My Field"]=>
-    string(1) "2"
+    int(2)
     ["Another Field"]=>
     string(11) "test_string"
   }
   [2]=>
   array(2) {
     ["My Field"]=>
-    string(1) "3"
+    int(3)
     ["Another Field"]=>
     string(11) "test_string"
   }
diff --git a/ext/pdo_dblib/tests/types.phpt b/ext/pdo_dblib/tests/types.phpt
new file mode 100644 (file)
index 0000000..dd849ad
--- /dev/null
@@ -0,0 +1,66 @@
+--TEST--
+PDO_DBLIB: Column data types, with or without stringifying
+--SKIPIF--
+<?php
+if (!extension_loaded('pdo_dblib')) die('skip not loaded');
+require __DIR__ . '/config.inc';
+?>
+--FILE--
+<?php
+require __DIR__ . '/config.inc';
+
+$sql = "
+       SELECT
+               'foo' AS [char],
+               CAST('2030-01-01 23:59:59' AS DATETIME) AS [datetime],
+               CAST(0 AS BIT) AS [false],
+               10.5 AS [float],
+               1000 AS [int],
+               CAST(10.5 AS MONEY) AS [money],
+               CAST('1950-01-18 23:00:00' AS SMALLDATETIME) as [smalldatetime],
+               CAST(1 AS BIT) AS [true]
+";
+
+$stmt = $db->query($sql);
+$row = $stmt->fetch(PDO::FETCH_ASSOC);
+
+var_dump($row['char'] === 'foo');
+var_dump($row['datetime'] === '2030-01-01 23:59:59');
+var_dump($row['false'] === 0);
+var_dump($row['float'] === 10.5);
+var_dump($row['int'] === 1000);
+var_dump($row['money'] === 10.5);
+var_dump($row['smalldatetime'] === '1950-01-18 23:00:00');
+var_dump($row['true'] === 1);
+
+$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
+$stmt = $db->query($sql);
+$row = $stmt->fetch(PDO::FETCH_ASSOC);
+
+var_dump($row['char'] === 'foo');
+var_dump($row['datetime'] === '2030-01-01 23:59:59');
+var_dump($row['false'] === '0');
+var_dump($row['float'] === '10.5');
+var_dump($row['int'] === '1000');
+var_dump($row['money'] === '10.5');
+var_dump($row['smalldatetime'] === '1950-01-18 23:00:00');
+var_dump($row['true'] === '1');
+
+?>
+--EXPECT--
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)