--- embedaddon/php/ext/pdo_dblib/dblib_stmt.c 2012/05/29 12:34:41 1.1.1.2 +++ embedaddon/php/ext/pdo_dblib/dblib_stmt.c 2013/07/22 01:31:58 1.1.1.3 @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2012 The PHP Group | + | Copyright (c) 1997-2013 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -17,7 +17,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: dblib_stmt.c,v 1.1.1.2 2012/05/29 12:34:41 misho Exp $ */ +/* $Id: dblib_stmt.c,v 1.1.1.3 2013/07/22 01:31:58 misho Exp $ */ #ifdef HAVE_CONFIG_H # include "config.h" @@ -36,35 +36,51 @@ /* {{{ pdo_dblib_get_field_name * - * Updated for MSSQL 2008 SR2 extended types + * Return the data type name for a given TDS number * */ static char *pdo_dblib_get_field_name(int type) { + /* + * I don't return dbprtype(type) because it does not fully describe the type + * (example: varchar is reported as char by dbprtype) + * + * FIX ME: Cache datatypes from server systypes table in pdo_dblib_handle_factory() + * to make this future proof. + */ + switch (type) { + case 31: return "nvarchar"; case 34: return "image"; case 35: return "text"; case 36: return "uniqueidentifier"; + case 37: return "varbinary"; /* & timestamp - Sybase AS12 */ + case 38: return "bigint"; /* & bigintn - Sybase AS12 */ + case 39: return "varchar"; /* & sysname & nvarchar - Sybase AS12 */ case 40: return "date"; case 41: return "time"; case 42: return "datetime2"; case 43: return "datetimeoffset"; + case 45: return "binary"; /* Sybase AS12 */ + case 47: return "char"; /* & nchar & uniqueidentifierstr Sybase AS12 */ case 48: return "tinyint"; + case 50: return "bit"; /* Sybase AS12 */ case 52: return "smallint"; + case 55: return "decimal"; /* Sybase AS12 */ case 56: return "int"; case 58: return "smalldatetime"; case 59: return "real"; case 60: return "money"; case 61: return "datetime"; case 62: return "float"; + case 63: return "numeric"; /* or uint, ubigint, usmallint Sybase AS12 */ case 98: return "sql_variant"; case 99: return "ntext"; case 104: return "bit"; - case 106: return "decimal"; - case 108: return "numeric"; + case 106: return "decimal"; /* decimal n on sybase */ + case 108: return "numeric"; /* numeric n on sybase */ case 122: return "smallmoney"; case 127: return "bigint"; - case 240: return "geometry"; case 165: return "varbinary"; case 167: return "varchar"; case 173: return "binary"; @@ -72,23 +88,22 @@ static char *pdo_dblib_get_field_name(int type) case 189: return "timestamp"; case 231: return "nvarchar"; case 239: return "nchar"; + case 240: return "geometry"; case 241: return "xml"; - default: - return "unknown"; - break; + default: return "unknown"; } } /* }}} */ -static int dblib_dblib_stmt_cursor_closer(pdo_stmt_t *stmt TSRMLS_DC) +static int pdo_dblib_stmt_cursor_closer(pdo_stmt_t *stmt TSRMLS_DC) { pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data; pdo_dblib_db_handle *H = S->H; /* Cancel any pending results */ dbcancel(H->link); - - efree(stmt->columns); + + efree(stmt->columns); stmt->columns = NULL; return 1; @@ -98,7 +113,8 @@ static int pdo_dblib_stmt_dtor(pdo_stmt_t *stmt TSRMLS { pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data; - dblib_dblib_stmt_cursor_closer(stmt TSRMLS_CC); + efree(stmt->columns); + stmt->columns = NULL; efree(S); @@ -113,9 +129,14 @@ static int pdo_dblib_stmt_next_rowset(pdo_stmt_t *stmt ret = dbresults(H->link); - if (ret == FAIL || ret == NO_MORE_RESULTS) { + if (FAIL == ret) { + pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO_DBLIB: dbresults() returned FAIL" TSRMLS_CC); return 0; } + + if(NO_MORE_RESULTS == ret) { + return 0; + } stmt->row_count = DBCOUNT(H->link); stmt->column_count = dbnumcols(H->link); @@ -131,6 +152,8 @@ static int pdo_dblib_stmt_execute(pdo_stmt_t *stmt TSR dbsetuserdata(H->link, (BYTE*) &S->err); + pdo_dblib_stmt_cursor_closer(stmt TSRMLS_CC); + if (FAIL == dbcmd(H->link, stmt->active_query_string)) { return 0; } @@ -141,10 +164,6 @@ static int pdo_dblib_stmt_execute(pdo_stmt_t *stmt TSR ret = pdo_dblib_stmt_next_rowset(stmt TSRMLS_CC); - if (ret == 0) { - return 0; - } - stmt->row_count = DBCOUNT(H->link); stmt->column_count = dbnumcols(H->link); @@ -162,9 +181,14 @@ static int pdo_dblib_stmt_fetch(pdo_stmt_t *stmt, ret = dbnextrow(H->link); - if (ret == FAIL || ret == NO_MORE_ROWS) { + if (FAIL == ret) { + pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO_DBLIB: dbnextrow() returned FAIL" TSRMLS_CC); return 0; } + + if(NO_MORE_ROWS == ret) { + return 0; + } return 1; } @@ -174,6 +198,10 @@ static int pdo_dblib_stmt_describe(pdo_stmt_t *stmt, i pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data; pdo_dblib_db_handle *H = S->H; + if(colno >= stmt->column_count || colno < 0) { + return FAILURE; + } + struct pdo_column_data *col = &stmt->columns[colno]; col->name = (char*)dbcolname(H->link, colno+1); @@ -205,11 +233,12 @@ static int pdo_dblib_stmt_get_col(pdo_stmt_t *stmt, in } switch (coltype) { - case SQLCHAR: - case SQLTEXT: 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); @@ -225,34 +254,26 @@ static int pdo_dblib_stmt_get_col(pdo_stmt_t *stmt, in *ptr = tmp_ptr; break; } -#ifdef SQLUNIQUE case SQLUNIQUE: { -#else - case 36: { /* FreeTDS hack, also used by ext/mssql */ -#endif *len = 36+1; tmp_ptr = emalloc(*len + 1); /* uniqueidentifier is a 16-byte binary number, convert to 32 char hex string */ -#ifdef SQLUNIQUE *len = dbconvert(NULL, SQLUNIQUE, *ptr, *len, SQLCHAR, tmp_ptr, *len); -#else - *len = dbconvert(NULL, 36, *ptr, *len, SQLCHAR, tmp_ptr, *len); -#endif php_strtoupper(tmp_ptr, *len); *ptr = tmp_ptr; break; } default: if (dbwillconvert(coltype, SQLCHAR)) { - tmp_len = 32 + (2 * (*len)); + 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; - *ptr = NULL; - } + } else { + *len = 0; /* FIXME: Silently fails and returns null on conversion errors */ + *ptr = NULL; + } } *caller_frees = 1; @@ -270,17 +291,25 @@ static int pdo_dblib_stmt_get_column_meta(pdo_stmt_t * { pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data; pdo_dblib_db_handle *H = S->H; - + DBTYPEINFO* dbtypeinfo; + + if(colno >= stmt->column_count || colno < 0) { + return FAILURE; + } + array_init(return_value); - DBTYPEINFO* dbtypeinfo; dbtypeinfo = dbcoltypeinfo(H->link, colno+1); + + if(!dbtypeinfo) return FAILURE; 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), 1); add_assoc_string(return_value, "native_type", pdo_dblib_get_field_name(dbcoltype(H->link, colno+1)), 1); + add_assoc_long(return_value, "native_type_id", dbcoltype(H->link, colno+1)); + add_assoc_long(return_value, "native_usertype_id", dbcolutype(H->link, colno+1)); return 1; } @@ -297,6 +326,6 @@ struct pdo_stmt_methods dblib_stmt_methods = { NULL, /* get attr */ pdo_dblib_stmt_get_column_meta, /* meta */ pdo_dblib_stmt_next_rowset, /* nextrow */ - dblib_dblib_stmt_cursor_closer + pdo_dblib_stmt_cursor_closer };