wez Thu Jul 7 08:49:23 2005 EDT
Modified files:
/php-src/ext/pdo_odbc odbc_driver.c odbc_stmt.c pdo_odbc.c
php_pdo_odbc.h php_pdo_odbc_int.h
Log:
Fix handling of parameter binding.
We need to guess at parameter sizing in some cases (eg: MS Access) as the
SQLDescribeParam() API is an optional feature.
Tidy up error handling.
Add workaround for a shutdown bug that I see with MS ODBC implementation.
(working to determine the precise cause of this).
PDO core test suite now passes all tests.
http://cvs.php.net/diff.php/php-src/ext/pdo_odbc/odbc_driver.c?r1=1.23&r2=1.24&ty=u
Index: php-src/ext/pdo_odbc/odbc_driver.c
diff -u php-src/ext/pdo_odbc/odbc_driver.c:1.23
php-src/ext/pdo_odbc/odbc_driver.c:1.24
--- php-src/ext/pdo_odbc/odbc_driver.c:1.23 Sat Jun 11 10:48:06 2005
+++ php-src/ext/pdo_odbc/odbc_driver.c Thu Jul 7 08:49:21 2005
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2004 The PHP Group |
+ | Copyright (c) 1997-2005 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.0 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -16,7 +16,7 @@
+----------------------------------------------------------------------+
*/
-/* $Id: odbc_driver.c,v 1.23 2005/06/11 14:48:06 wez Exp $ */
+/* $Id: odbc_driver.c,v 1.24 2005/07/07 12:49:21 wez Exp $ */
#ifdef HAVE_CONFIG_H
#include "config.h"
@@ -85,7 +85,7 @@
einfo->what = what;
strcpy(*pdo_err, einfo->last_state);
-
+/* printf("@@ SQLSTATE[%s] %s\n", *pdo_err, einfo->last_err_msg); */
if (!dbh->methods) {
zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC,
"SQLSTATE[%s] %s: %d %s",
*pdo_err, what, einfo->last_error,
einfo->last_err_msg);
@@ -96,16 +96,18 @@
static int odbc_handle_closer(pdo_dbh_t *dbh TSRMLS_DC)
{
pdo_odbc_db_handle *H = (pdo_odbc_db_handle*)dbh->driver_data;
-
if (H->dbc != SQL_NULL_HANDLE) {
SQLEndTran(SQL_HANDLE_DBC, H->dbc, SQL_ROLLBACK);
+#ifndef PHP_WIN32 /* avoiding a bug I've found on my XP box */
SQLDisconnect(H->dbc);
+#endif
SQLFreeHandle(SQL_HANDLE_DBC, H->dbc);
H->dbc = NULL;
}
SQLFreeHandle(SQL_HANDLE_ENV, H->env);
H->env = NULL;
pefree(H, dbh->is_persistent);
+ dbh->driver_data = NULL;
return 0;
}
@@ -174,7 +176,7 @@
SQLFreeHandle(SQL_HANDLE_STMT, S->stmt);
return 0;
}
-
+
stmt->driver_data = S;
stmt->methods = &odbc_stmt_methods;
@@ -335,17 +337,15 @@
if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
pdo_odbc_drv_error("SQLSetEnvAttr: ODBC3");
- odbc_handle_closer(dbh TSRMLS_CC);
- return 0;
+ goto fail;
}
-#ifdef SQL_ATTR_CONNECTION_POOLING
+#if 0 /*&& def SQL_ATTR_CONNECTION_POOLING */
if (pdo_odbc_pool_on != SQL_CP_OFF) {
rc = SQLSetEnvAttr(H->env, SQL_ATTR_CP_MATCH,
(void*)pdo_odbc_pool_mode, 0);
if (rc != SQL_SUCCESS) {
pdo_odbc_drv_error("SQLSetEnvAttr: SQL_ATTR_CP_MATCH");
- odbc_handle_closer(dbh TSRMLS_CC);
- return 0;
+ goto fail;
}
}
#endif
@@ -353,16 +353,14 @@
rc = SQLAllocHandle(SQL_HANDLE_DBC, H->env, &H->dbc);
if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
pdo_odbc_drv_error("SQLAllocHandle (DBC)");
- odbc_handle_closer(dbh TSRMLS_CC);
- return 0;
+ goto fail;
}
rc = SQLSetConnectAttr(H->dbc, SQL_ATTR_AUTOCOMMIT,
(SQLPOINTER)(dbh->auto_commit ? SQL_AUTOCOMMIT_ON :
SQL_AUTOCOMMIT_OFF), SQL_NTS);
if (rc != SQL_SUCCESS) {
pdo_odbc_drv_error("SQLSetConnectAttr AUTOCOMMIT");
- odbc_handle_closer(dbh TSRMLS_CC);
- return 0;
+ goto fail;
}
/* set up the cursor library, if needed, or if configured explicitly */
@@ -370,8 +368,7 @@
rc = SQLSetConnectAttr(H->dbc, SQL_ODBC_CURSORS, (void*)cursor_lib, 0);
if (rc != SQL_SUCCESS && cursor_lib != SQL_CUR_USE_IF_NEEDED) {
pdo_odbc_drv_error("SQLSetConnectAttr SQL_ODBC_CURSORS");
- odbc_handle_closer(dbh TSRMLS_CC);
- return 0;
+ goto fail;
}
@@ -399,8 +396,7 @@
if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
pdo_odbc_drv_error(use_direct ? "SQLDriverConnect" :
"SQLConnect");
- odbc_handle_closer(dbh TSRMLS_CC);
- return 0;
+ goto fail;
}
/* TODO: if we want to play nicely, we should check to see if the
driver really supports ODBC v3 or not */
@@ -409,6 +405,10 @@
dbh->alloc_own_columns = 1;
return 1;
+
+fail:
+ dbh->methods = &odbc_methods;
+ return 0;
}
/* }}} */
http://cvs.php.net/diff.php/php-src/ext/pdo_odbc/odbc_stmt.c?r1=1.20&r2=1.21&ty=u
Index: php-src/ext/pdo_odbc/odbc_stmt.c
diff -u php-src/ext/pdo_odbc/odbc_stmt.c:1.20
php-src/ext/pdo_odbc/odbc_stmt.c:1.21
--- php-src/ext/pdo_odbc/odbc_stmt.c:1.20 Tue Apr 19 16:55:02 2005
+++ php-src/ext/pdo_odbc/odbc_stmt.c Thu Jul 7 08:49:21 2005
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2004 The PHP Group |
+ | Copyright (c) 1997-2005 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.0 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -16,7 +16,7 @@
+----------------------------------------------------------------------+
*/
-/* $Id: odbc_stmt.c,v 1.20 2005/04/19 20:55:02 iliaa Exp $ */
+/* $Id: odbc_stmt.c,v 1.21 2005/07/07 12:49:21 wez Exp $ */
#ifdef HAVE_CONFIG_H
#include "config.h"
@@ -140,7 +140,6 @@
SQLNumResultCols(S->stmt, &colcount);
stmt->column_count = (int)colcount;
-
S->cols = ecalloc(colcount, sizeof(pdo_odbc_column));
}
@@ -152,8 +151,8 @@
{
pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
RETCODE rc;
- SWORD sqltype, ctype, scale, nullable;
- UDWORD precision;
+ SWORD sqltype = 0, ctype = 0, scale = 0, nullable = 0;
+ UDWORD precision = 0;
pdo_odbc_param *P;
/* we're only interested in parameters for prepared SQL right now */
@@ -176,13 +175,26 @@
case PDO_PARAM_STMT:
return 0;
-
- case PDO_PARAM_STR:
+
default:
-
convert_to_string(param->parameter);
+ break;
}
- SQLDescribeParam(S->stmt, param->paramno+1,
&sqltype, &precision, &scale, &nullable);
+ rc = SQLDescribeParam(S->stmt,
param->paramno+1, &sqltype, &precision, &scale, &nullable);
+ if (rc != SQL_SUCCESS && rc !=
SQL_SUCCESS_WITH_INFO) {
+ /* MS Access, for instance, doesn't
support SQLDescribeParam,
+ * so we need to guess */
+ sqltype =
PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB ?
+
SQL_LONGVARBINARY :
+
SQL_LONGVARCHAR;
+ precision = 4000;
+ scale = 5;
+ nullable = 1;
+
+ if (param->max_value_len > 0) {
+ precision =
param->max_value_len;
+ }
+ }
if (sqltype == SQL_BINARY || sqltype ==
SQL_VARBINARY || sqltype == SQL_LONGVARBINARY) {
ctype = SQL_C_BINARY;
} else {
@@ -193,6 +205,7 @@
param->driver_data = P;
P->len = 0; /* is re-populated each EXEC_PRE */
+ P->outbuf = NULL;
if ((param->param_type &
PDO_PARAM_INPUT_OUTPUT) == PDO_PARAM_INPUT_OUTPUT) {
P->paramtype = SQL_PARAM_INPUT_OUTPUT;
@@ -201,10 +214,15 @@
} else {
P->paramtype = SQL_PARAM_OUTPUT;
}
- if (P->paramtype != SQL_PARAM_INPUT &&
PDO_PARAM_TYPE(param->param_type) != PDO_PARAM_LOB && param->max_value_len >
Z_STRLEN_P(param->parameter)) {
- Z_STRVAL_P(param->parameter) =
erealloc(Z_STRVAL_P(param->parameter), param->max_value_len + 1);
+
+ if (P->paramtype != SQL_PARAM_INPUT) {
+ if (PDO_PARAM_TYPE(param->param_type)
!= PDO_PARAM_NULL) {
+ /* need an explicit buffer to
hold result */
+ P->len = param->max_value_len >
0 ? param->max_value_len : precision;
+ P->outbuf = emalloc(P->len + 1);
+ }
}
-
+
if (PDO_PARAM_TYPE(param->param_type) ==
PDO_PARAM_LOB && P->paramtype != SQL_PARAM_INPUT) {
pdo_odbc_stmt_error("Can't bind a lob
for output");
return 0;
@@ -212,11 +230,10 @@
rc = SQLBindParameter(S->stmt, param->paramno+1,
P->paramtype, ctype, sqltype,
precision, scale,
- P->paramtype == SQL_PARAM_INPUT
&&
-
PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB ?
-
(SQLPOINTER)param :
-
Z_STRVAL_P(param->parameter),
- param->max_value_len <= 0 ? 0 :
param->max_value_len,
+ P->paramtype == SQL_PARAM_INPUT
?
+ (SQLPOINTER)param :
+ P->outbuf,
+ P->len,
&P->len
);
@@ -241,24 +258,74 @@
}
if (0 == php_stream_stat(stm,
&sb)) {
- P->len =
SQL_LEN_DATA_AT_EXEC(sb.sb.st_size);
+ if (P->outbuf) {
+ int len, amount;
+ char *ptr =
P->outbuf;
+ char *end =
P->outbuf + P->len;
+
+ P->len = 0;
+ do {
+ amount
= end - ptr;
+ if
(amount == 0) {
+
break;
+ }
+ if
(amount > 8192)
+
amount = 8192;
+ len =
php_stream_read(stm, ptr, amount);
+ if (len
== 0) {
+
break;
+ }
+ ptr +=
len;
+ P->len
+= len;
+ } while (1);
+
+ } else {
+ P->len =
SQL_LEN_DATA_AT_EXEC(sb.sb.st_size);
+ }
} else {
- P->len =
SQL_LEN_DATA_AT_EXEC(0);
+ if (P->outbuf) {
+ P->len = 0;
+ } else {
+ P->len =
SQL_LEN_DATA_AT_EXEC(0);
+ }
}
} else {
convert_to_string(param->parameter);
- P->len =
SQL_LEN_DATA_AT_EXEC(Z_STRLEN_P(param->parameter));
+ if (P->outbuf) {
+ P->len =
Z_STRLEN_P(param->parameter);
+ memcpy(P->outbuf,
Z_STRVAL_P(param->parameter), P->len);
+ } else {
+ P->len =
SQL_LEN_DATA_AT_EXEC(Z_STRLEN_P(param->parameter));
+ }
}
+ } else if (Z_TYPE_P(param->parameter) ==
IS_NULL || PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_NULL) {
+ P->len = SQL_NULL_DATA;
} else {
- P->len = Z_STRLEN_P(param->parameter);
+ convert_to_string(param->parameter);
+ if (P->outbuf) {
+ P->len =
Z_STRLEN_P(param->parameter);
+ memcpy(P->outbuf,
Z_STRVAL_P(param->parameter), P->len);
+ } else {
+ P->len =
SQL_LEN_DATA_AT_EXEC(Z_STRLEN_P(param->parameter));
+ }
}
return 1;
case PDO_PARAM_EVT_EXEC_POST:
- if (Z_TYPE_P(param->parameter) == IS_STRING) {
- P = param->driver_data;
- Z_STRLEN_P(param->parameter) = P->len;
- Z_STRVAL_P(param->parameter)[P->len] =
'\0';
+ P = param->driver_data;
+ if (P->outbuf) {
+ switch (P->len) {
+ case SQL_NULL_DATA:
+
zval_dtor(param->parameter);
+
ZVAL_NULL(param->parameter);
+ break;
+ default:
+
convert_to_string(param->parameter);
+
Z_STRVAL_P(param->parameter) = erealloc(Z_STRVAL_P(param->parameter), P->len+1);
+
memcpy(Z_STRVAL_P(param->parameter), P->outbuf, P->len);
+
Z_STRLEN_P(param->parameter) = P->len;
+
Z_STRVAL_P(param->parameter)[P->len] = '\0';
+ }
}
return 1;
}
@@ -287,10 +354,12 @@
rc = SQLFetchScroll(S->stmt, odbcori, offset);
if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) {
+ pdo_odbc_stmt_error("SQLFetchScroll");
return 1;
}
if (rc == SQL_NO_DATA) {
+ pdo_odbc_stmt_error("SQLFetchScroll");
return 0;
}
@@ -312,6 +381,11 @@
sizeof(S->cols[colno].colname)-1, &colnamelen,
&S->cols[colno].coltype, &colsize, NULL, NULL);
+ if (rc != SQL_SUCCESS) {
+ pdo_odbc_stmt_error("SQLBindCol");
+ return 0;
+ }
+
col->maxlen = S->cols[colno].datalen = colsize;
col->namelen = colnamelen;
col->name = estrdup(S->cols[colno].colname);
@@ -324,7 +398,12 @@
/* tell ODBC to put it straight into our buffer */
rc = SQLBindCol(S->stmt, colno+1, SQL_C_CHAR, S->cols[colno].data,
S->cols[colno].datalen+1, &S->cols[colno].fetched_len);
-
+
+ if (rc != SQL_SUCCESS) {
+ pdo_odbc_stmt_error("SQLBindCol");
+ return 0;
+ }
+
return 1;
}
@@ -412,6 +491,9 @@
free_cols(stmt, S TSRMLS_CC);
+ /* NOTE: can't guarantee that output or input/output parameters
+ * are set until this fella returns SQL_NO_DATA, according to
+ * MSDN ODBC docs */
rc = SQLMoreResults(S->stmt);
if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
http://cvs.php.net/diff.php/php-src/ext/pdo_odbc/pdo_odbc.c?r1=1.12&r2=1.13&ty=u
Index: php-src/ext/pdo_odbc/pdo_odbc.c
diff -u php-src/ext/pdo_odbc/pdo_odbc.c:1.12
php-src/ext/pdo_odbc/pdo_odbc.c:1.13
--- php-src/ext/pdo_odbc/pdo_odbc.c:1.12 Wed Jun 22 04:45:22 2005
+++ php-src/ext/pdo_odbc/pdo_odbc.c Thu Jul 7 08:49:21 2005
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2004 The PHP Group |
+ | Copyright (c) 1997-2005 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.0 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -16,7 +16,7 @@
+----------------------------------------------------------------------+
*/
-/* $Id: pdo_odbc.c,v 1.12 2005/06/22 08:45:22 wez Exp $ */
+/* $Id: pdo_odbc.c,v 1.13 2005/07/07 12:49:21 wez Exp $ */
#ifdef HAVE_CONFIG_H
#include "config.h"
@@ -80,7 +80,7 @@
}
#ifdef SQL_ATTR_CONNECTION_POOLING
- /* ugh, we don't really .ini stuff in PDO, but since ODBC connection
+ /* ugh, we don't really like .ini stuff in PDO, but since ODBC
connection
* pooling is process wide, we can't set it from within the scope of a
* request without affecting others, which goes against our isolated
request
* policy. So, we use cfg_get_string here to check it this once.
http://cvs.php.net/diff.php/php-src/ext/pdo_odbc/php_pdo_odbc.h?r1=1.1&r2=1.2&ty=u
Index: php-src/ext/pdo_odbc/php_pdo_odbc.h
diff -u php-src/ext/pdo_odbc/php_pdo_odbc.h:1.1
php-src/ext/pdo_odbc/php_pdo_odbc.h:1.2
--- php-src/ext/pdo_odbc/php_pdo_odbc.h:1.1 Mon May 17 11:43:01 2004
+++ php-src/ext/pdo_odbc/php_pdo_odbc.h Thu Jul 7 08:49:21 2005
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2004 The PHP Group |
+ | Copyright (c) 1997-2005 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.0 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -12,11 +12,11 @@
| obtain it through the world-wide-web, please send a note to |
| [EMAIL PROTECTED] so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
- | Author: |
+ | Author: Wez Furlong <[EMAIL PROTECTED]>
|
+----------------------------------------------------------------------+
*/
-/* $Id: php_pdo_odbc.h,v 1.1 2004/05/17 15:43:01 wez Exp $ */
+/* $Id: php_pdo_odbc.h,v 1.2 2005/07/07 12:49:21 wez Exp $ */
#ifndef PHP_PDO_ODBC_H
#define PHP_PDO_ODBC_H
http://cvs.php.net/diff.php/php-src/ext/pdo_odbc/php_pdo_odbc_int.h?r1=1.8&r2=1.9&ty=u
Index: php-src/ext/pdo_odbc/php_pdo_odbc_int.h
diff -u php-src/ext/pdo_odbc/php_pdo_odbc_int.h:1.8
php-src/ext/pdo_odbc/php_pdo_odbc_int.h:1.9
--- php-src/ext/pdo_odbc/php_pdo_odbc_int.h:1.8 Sun Feb 6 22:27:54 2005
+++ php-src/ext/pdo_odbc/php_pdo_odbc_int.h Thu Jul 7 08:49:21 2005
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2004 The PHP Group |
+ | Copyright (c) 1997-2005 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.0 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -16,7 +16,7 @@
+----------------------------------------------------------------------+
*/
-/* $Id: php_pdo_odbc_int.h,v 1.8 2005/02/07 03:27:54 wez Exp $ */
+/* $Id: php_pdo_odbc_int.h,v 1.9 2005/07/07 12:49:21 wez Exp $ */
#ifdef PHP_WIN32
# define PDO_ODBC_TYPE "Win32"
@@ -149,6 +149,7 @@
typedef struct {
SQLINTEGER len;
SQLSMALLINT paramtype;
+ char *outbuf;
} pdo_odbc_param;
extern pdo_driver_t pdo_odbc_driver;
--
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php