summaryrefslogtreecommitdiff
path: root/ext/pdo_dblib
diff options
context:
space:
mode:
authorStanley Sufficool <ssufficool@php.net>2013-06-03 20:02:08 -0700
committerStanley Sufficool <ssufficool@php.net>2013-06-03 20:02:08 -0700
commit5a04ab9a54f529f4197bed6f17599604266cdb35 (patch)
treef8ecd80c92159255e84616b56d0399b0da4dd6c7 /ext/pdo_dblib
parent7360f0f1e6c4b49e89bd3c2cf1f524e9cf7f9dcc (diff)
downloadphp-git-5a04ab9a54f529f4197bed6f17599604266cdb35.tar.gz
Fix PDO_DBLIB bugs: #64338, #64808, #63638
Synchronize with master
Diffstat (limited to 'ext/pdo_dblib')
-rw-r--r--ext/pdo_dblib/dblib_driver.c103
-rw-r--r--ext/pdo_dblib/dblib_stmt.c99
-rw-r--r--ext/pdo_dblib/pdo_dblib.c8
-rw-r--r--ext/pdo_dblib/php_pdo_dblib_int.h8
4 files changed, 160 insertions, 58 deletions
diff --git a/ext/pdo_dblib/dblib_driver.c b/ext/pdo_dblib/dblib_driver.c
index ffc910177f..9ed5087369 100644
--- a/ext/pdo_dblib/dblib_driver.c
+++ b/ext/pdo_dblib/dblib_driver.c
@@ -32,6 +32,9 @@
#include "php_pdo_dblib_int.h"
#include "zend_exceptions.h"
+/* Cache of the server supported datatypes, initialized in handle_factory */
+zval* pdo_dblib_datatypes;
+
static int dblib_fetch_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, zval *info TSRMLS_DC)
{
pdo_dblib_db_handle *H = (pdo_dblib_db_handle *)dbh->driver_data;
@@ -262,17 +265,37 @@ static struct pdo_dbh_methods dblib_methods = {
static int pdo_dblib_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_DC)
{
pdo_dblib_db_handle *H;
- int i, ret = 0;
+ int i, nvars, nvers, ret = 0;
+ int *val;
+
+ const pdo_dblib_keyval tdsver[] = {
+ {"4.2",DBVERSION_42}
+ ,{"4.6",DBVERSION_46}
+ ,{"5.0",DBVERSION_70} /* FIXME: This does not work with Sybase, but environ will */
+ ,{"6.0",DBVERSION_70}
+ ,{"7.0",DBVERSION_70}
+ ,{"7.1",DBVERSION_71}
+ ,{"7.2",DBVERSION_72}
+ ,{"8.0",DBVERSION_72}
+ ,{"10.0",DBVERSION_100}
+ ,{"auto",0} /* Only works with FreeTDS. Other drivers will bork */
+
+ };
+
+ nvers = sizeof(tdsver)/sizeof(tdsver[0]);
+
struct pdo_data_src_parser vars[] = {
- { "charset", NULL, 0 },
- { "appname", "PHP " PDO_DBLIB_FLAVOUR, 0 },
- { "host", "127.0.0.1", 0 },
- { "dbname", NULL, 0 },
- { "secure", NULL, 0 }, /* DBSETLSECURE */
- /* TODO: DBSETLVERSION ? */
+ { "charset", NULL, 0 }
+ ,{ "appname", "PHP " PDO_DBLIB_FLAVOUR, 0 }
+ ,{ "host", "127.0.0.1", 0 }
+ ,{ "dbname", NULL, 0 }
+ ,{ "secure", NULL, 0 } /* DBSETLSECURE */
+ ,{ "version", NULL, 0 } /* DBSETLVERSION */
};
-
- php_pdo_parse_data_source(dbh->data_source, dbh->data_source_len, vars, 5);
+
+ nvars = sizeof(vars)/sizeof(vars[0]);
+
+ php_pdo_parse_data_source(dbh->data_source, dbh->data_source_len, vars, nvars);
H = pecalloc(1, sizeof(*H), dbh->is_persistent);
H->login = dblogin();
@@ -282,11 +305,37 @@ static int pdo_dblib_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_
goto cleanup;
}
+ DBERRHANDLE(H->login, (EHANDLEFUNC) error_handler);
+ DBMSGHANDLE(H->login, (MHANDLEFUNC) msg_handler);
+
+ if(vars[5].optval) {
+ for(i=0;i<nvers;i++) {
+ if(strcmp(vars[5].optval,tdsver[i].key) == 0) {
+ if(FAIL==dbsetlversion(H->login, tdsver[i].value)) {
+ pdo_raise_impl_error(dbh, NULL, "HY000", "PDO_DBLIB: Failed to set version specified in connection string." TSRMLS_CC);
+ goto cleanup;
+ }
+ break;
+ }
+ }
+
+ if (i==nvers) {
+ printf("Invalid version '%s'\n", vars[5].optval);
+ pdo_raise_impl_error(dbh, NULL, "HY000", "PDO_DBLIB: Invalid version specified in connection string." TSRMLS_CC);
+ goto cleanup; /* unknown version specified */
+ }
+ }
+
if (dbh->username) {
- DBSETLUSER(H->login, dbh->username);
+ if(FAIL == DBSETLUSER(H->login, dbh->username)) {
+ goto cleanup;
+ }
}
+
if (dbh->password) {
- DBSETLPWD(H->login, dbh->password);
+ if(FAIL == DBSETLPWD(H->login, dbh->password)) {
+ goto cleanup;
+ }
}
#if !PHP_DBLIB_IS_MSSQL
@@ -297,14 +346,9 @@ static int pdo_dblib_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_
DBSETLAPP(H->login, vars[1].optval);
-#if PHP_DBLIB_IS_MSSQL
- dbprocerrhandle(H->login, (EHANDLEFUNC) error_handler);
- dbprocmsghandle(H->login, (MHANDLEFUNC) msg_handler);
-#endif
-
H->link = dbopen(H->login, vars[2].optval);
- if (H->link == NULL) {
+ if (!H->link) {
goto cleanup;
}
@@ -315,18 +359,35 @@ static int pdo_dblib_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_
DBSETOPT(H->link, DBTEXTSIZE, "2147483647");
/* allow double quoted indentifiers */
- DBSETOPT(H->link, DBQUOTEDIDENT, NULL);
+ DBSETOPT(H->link, DBQUOTEDIDENT, "1");
- if (vars[3].optval && FAIL == dbuse(H->link, vars[3].optval)) {
- goto cleanup;
+ if (vars[3].optval) {
+ DBSETLDBNAME(H->login, vars[3].optval);
}
ret = 1;
dbh->max_escaped_char_length = 2;
dbh->alloc_own_columns = 1;
+#if 0
+ /* Cache the supported data types from the servers systypes table */
+ if(dbcmd(H->link, "select usertype, name from systypes order by usertype") != FAIL) {
+ if(dbsqlexec(H->link) != FAIL) {
+ dbresults(H->link);
+ while (dbnextrow(H->link) == SUCCESS) {
+ val = dbdata(H->link, 1);
+ add_index_string(pdo_dblib_datatypes, *val, dbdata(H->link, 2), 1);
+ }
+ }
+ /* Throw out any remaining resultsets */
+ dbcancel(H-link);
+ }
+#endif
+
+
+
cleanup:
- for (i = 0; i < sizeof(vars)/sizeof(vars[0]); i++) {
+ for (i = 0; i < nvars; i++) {
if (vars[i].freeme) {
efree(vars[i].optval);
}
diff --git a/ext/pdo_dblib/dblib_stmt.c b/ext/pdo_dblib/dblib_stmt.c
index 1a2fefd47a..51cebc48b0 100644
--- a/ext/pdo_dblib/dblib_stmt.c
+++ b/ext/pdo_dblib/dblib_stmt.c
@@ -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_DC)
{
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,7 +129,12 @@ static int pdo_dblib_stmt_next_rowset(pdo_stmt_t *stmt TSRMLS_DC)
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;
}
@@ -131,6 +152,8 @@ static int pdo_dblib_stmt_execute(pdo_stmt_t *stmt TSRMLS_DC)
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 TSRMLS_DC)
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,7 +181,12 @@ 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;
}
@@ -174,6 +198,10 @@ static int pdo_dblib_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC)
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, int colno, char **ptr,
}
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, int colno, char **ptr,
*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 *stmt, long colno, zval *re
{
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
};
diff --git a/ext/pdo_dblib/pdo_dblib.c b/ext/pdo_dblib/pdo_dblib.c
index ed79aea20d..bc5d364ed3 100644
--- a/ext/pdo_dblib/pdo_dblib.c
+++ b/ext/pdo_dblib/pdo_dblib.c
@@ -93,8 +93,12 @@ int error_handler(DBPROCESS *dbproc, int severity, int dberr,
char *state = "HY000";
TSRMLS_FETCH();
- einfo = (pdo_dblib_err*)dbgetuserdata(dbproc);
- if (!einfo) einfo = &DBLIB_G(err);
+ if(dbproc) {
+ einfo = (pdo_dblib_err*)dbgetuserdata(dbproc);
+ if (!einfo) einfo = &DBLIB_G(err);
+ } else {
+ einfo = &DBLIB_G(err);
+ }
einfo->severity = severity;
einfo->oserr = oserr;
diff --git a/ext/pdo_dblib/php_pdo_dblib_int.h b/ext/pdo_dblib/php_pdo_dblib_int.h
index dd06a1d94f..2bdb83c326 100644
--- a/ext/pdo_dblib/php_pdo_dblib_int.h
+++ b/ext/pdo_dblib/php_pdo_dblib_int.h
@@ -71,6 +71,8 @@
# define SQLVARBINARY SYBVARBINARY
# ifdef SYBUNIQUE
# define SQLUNIQUE SYBUNIQUE
+#else
+# define SQLUNIQUE 36 /* FreeTDS Hack */
# endif
# define DBERRHANDLE(a, b) dberrhandle(b)
@@ -118,6 +120,12 @@ typedef struct {
pdo_dblib_err err;
} pdo_dblib_stmt;
+typedef struct {
+ const char* key;
+ int value;
+} pdo_dblib_keyval;
+
+
ZEND_BEGIN_MODULE_GLOBALS(dblib)
pdo_dblib_err err;
char sqlstate[6];