Merge branch 'PHP-7.0'

* PHP-7.0:
  return zvals instead of strings, cast or not based on stringify attribute
This commit is contained in:
Anatol Belski 2016-04-06 12:23:14 +02:00
commit 2267812cd2
5 changed files with 242 additions and 78 deletions

View 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);
data = dbdata(H->link, colno+1);
data_len = dbdatlen(H->link, colno+1);
*len = dbdatlen(H->link, colno+1);
*ptr = dbdata(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);
if (*len == 0 && *ptr == NULL) {
return 1;
zv = emalloc(sizeof(zval));
ZVAL_STRING(zv, tmp_data);
efree(tmp_data);
}
break;
}
}
}
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
#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
case 36: { /* FreeTDS hack */
#endif
zv = emalloc(sizeof(zval));
ZVAL_STRINGL(zv, data, 16); /* uniqueidentifier is a 16-byte binary number */
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;
}
}
}
}
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;
}
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 defined(PHP_DBLIB_IS_MSSQL) || defined(MSDBLIB)
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
);
*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;
}
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;
}

View 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)
}
}

View 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)
}

View 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"
}

View File

@ -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)