cvs: php-src(PHP_5_3) /ext/pdo_odbc odbc_driver.c odbc_stmt.c pdo_odbc.c php_pdo_odbc_int.h

From: Date: Thu, 13 Mar 2008 16:55:09 +0000
Subject: cvs: php-src(PHP_5_3) /ext/pdo_odbc odbc_driver.c odbc_stmt.c pdo_odbc.c php_pdo_odbc_int.h
Groups: php.cvs php.doc 
Request: Send a blank email to php-cvs+get-49098@lists.php.net to get a copy of this message
auroraeosrose Thu Mar 13 16:55:09 2008 UTC Modified files: (Branch: PHP_5_3) /php-src/ext/pdo_odbc odbc_driver.c odbc_stmt.c pdo_odbc.c php_pdo_odbc_int.h Log: [DOC] adds new odbc driver specific ODBC_ATTR_ASSUME_UTF8 to deal with unicode coming out of Microsoft SQL Server and is only relevant on windows, use it if unicode output from the server is garbled and it will autoconvert text - original patch by wez

http://cvs.php.net/viewvc.cgi/php-src/ext/pdo_odbc/odbc_driver.c?r1=1.27.2.4.2.3.2.1&r2=1.27.2.4.2.3.2.2&diff_format=u Index: php-src/ext/pdo_odbc/odbc_driver.c diff -u php-src/ext/pdo_odbc/odbc_driver.c:1.27.2.4.2.3.2.1 php-src/ext/pdo_odbc/odbc_driver.c:1.27.2.4.2.3.2.2 --- php-src/ext/pdo_odbc/odbc_driver.c:1.27.2.4.2.3.2.1 Mon Dec 31 07:17:12 2007 +++ php-src/ext/pdo_odbc/odbc_driver.c Thu Mar 13 16:55:09 2008 @@ -1,473 +1,493 @@ -/* - +----------------------------------------------------------------------+ - | PHP Version 5 | - +----------------------------------------------------------------------+ - | Copyright (c) 1997-2008 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 | - | available through the world-wide-web at the following url: | - | http://www.php.net/license/3_0.txt. | - | If you did not receive a copy of the PHP license and are unable to | - | obtain it through the world-wide-web, please send a note to | - | license@php.net so we can mail you a copy immediately. | - +----------------------------------------------------------------------+ - | Author: Wez Furlong <wez@php.net> | - +----------------------------------------------------------------------+ -*/ - -/* $Id: odbc_driver.c,v 1.27.2.4.2.3.2.1 2007/12/31 07:17:12 sebastian Exp $ */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "php.h" -#include "php_ini.h" -#include "ext/standard/info.h" -#include "pdo/php_pdo.h" -#include "pdo/php_pdo_driver.h" -#include "php_pdo_odbc.h" -#include "php_pdo_odbc_int.h" -#include "zend_exceptions.h" - -static int pdo_odbc_fetch_error_func(pdo_dbh_t *dbh, pdo_stmt_t *stmt, zval *info TSRMLS_DC) -{ - pdo_odbc_db_handle *H = (pdo_odbc_db_handle *)dbh->driver_data; - pdo_odbc_errinfo *einfo = &H->einfo; - pdo_odbc_stmt *S = NULL; - char *message = NULL; - - if (stmt) { - S = (pdo_odbc_stmt*)stmt->driver_data; - einfo = &S->einfo; - } - - spprintf(&message, 0, "%s (%s[%ld] at %s:%d)", - einfo->last_err_msg, - einfo->what, einfo->last_error, - einfo->file, einfo->line); - - add_next_index_long(info, einfo->last_error); - add_next_index_string(info, message, 0); - add_next_index_string(info, einfo->last_state, 1); - - return 1; -} - - -void pdo_odbc_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, PDO_ODBC_HSTMT statement, char *what, const char *file, int line TSRMLS_DC) /* {{{ */ -{ - SQLRETURN rc; - SQLSMALLINT errmsgsize = 0; - SQLHANDLE eh; - SQLSMALLINT htype, recno = 1; - pdo_odbc_db_handle *H = (pdo_odbc_db_handle*)dbh->driver_data; - pdo_odbc_errinfo *einfo = &H->einfo; - pdo_odbc_stmt *S = NULL; - pdo_error_type *pdo_err = &dbh->error_code; - - if (stmt) { - S = (pdo_odbc_stmt*)stmt->driver_data; - - einfo = &S->einfo; - pdo_err = &stmt->error_code; - } - - if (statement == SQL_NULL_HSTMT && S) { - statement = S->stmt; - } - - if (statement) { - htype = SQL_HANDLE_STMT; - eh = statement; - } else if (H->dbc) { - htype = SQL_HANDLE_DBC; - eh = H->dbc; - } else { - htype = SQL_HANDLE_ENV; - eh = H->env; - } - - rc = SQLGetDiagRec(htype, eh, recno++, einfo->last_state, &einfo->last_error, - einfo->last_err_msg, sizeof(einfo->last_err_msg)-1, &errmsgsize); - - if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { - errmsgsize = 0; - } - - einfo->last_err_msg[errmsgsize] = '\0'; - einfo->file = file; - einfo->line = line; - 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); - } - - /* just like a cursor, once you start pulling, you need to keep - * going until the end; SQL Server (at least) will mess with the - * actual cursor state if you don't finish retrieving all the - * diagnostic records (which can be generated by PRINT statements - * in the query, for instance). */ - while (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) { - char discard_state[5]; - char discard_buf[1024]; - SQLINTEGER code; - rc = SQLGetDiagRec(htype, eh, recno++, discard_state, &code, - discard_buf, sizeof(discard_buf)-1, &errmsgsize); - } - -} -/* }}} */ - -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); - SQLDisconnect(H->dbc); - 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; -} - -static int odbc_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_len, pdo_stmt_t *stmt, zval *driver_options TSRMLS_DC) -{ - RETCODE rc; - pdo_odbc_db_handle *H = (pdo_odbc_db_handle *)dbh->driver_data; - pdo_odbc_stmt *S = ecalloc(1, sizeof(*S)); - enum pdo_cursor_type cursor_type = PDO_CURSOR_FWDONLY; - int ret; - char *nsql = NULL; - int nsql_len = 0; - - S->H = H; - - /* before we prepare, we need to peek at the query; if it uses named parameters, - * we want PDO to rewrite them for us */ - stmt->supports_placeholders = PDO_PLACEHOLDER_POSITIONAL; - ret = pdo_parse_params(stmt, (char*)sql, sql_len, &nsql, &nsql_len TSRMLS_CC); - - if (ret == 1) { - /* query was re-written */ - sql = nsql; - } else if (ret == -1) { - /* couldn't grok it */ - strcpy(dbh->error_code, stmt->error_code); - efree(S); - return 0; - } - - rc = SQLAllocHandle(SQL_HANDLE_STMT, H->dbc, &S->stmt); - - if (rc == SQL_INVALID_HANDLE || rc == SQL_ERROR) { - efree(S); - if (nsql) { - efree(nsql); - } - pdo_odbc_drv_error("SQLAllocStmt"); - return 0; - } - - cursor_type = pdo_attr_lval(driver_options, PDO_ATTR_CURSOR, PDO_CURSOR_FWDONLY TSRMLS_CC); - if (cursor_type != PDO_CURSOR_FWDONLY) { - rc = SQLSetStmtAttr(S->stmt, SQL_ATTR_CURSOR_SCROLLABLE, (void*)SQL_SCROLLABLE, 0); - if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { - pdo_odbc_stmt_error("SQLSetStmtAttr: SQL_ATTR_CURSOR_SCROLLABLE"); - SQLFreeHandle(SQL_HANDLE_STMT, S->stmt); - if (nsql) { - efree(nsql); - } - return 0; - } - } - - rc = SQLPrepare(S->stmt, (char*)sql, SQL_NTS); - if (nsql) { - efree(nsql); - } - - stmt->driver_data = S; - stmt->methods = &odbc_stmt_methods; - - if (rc != SQL_SUCCESS) { - pdo_odbc_stmt_error("SQLPrepare"); - if (rc != SQL_SUCCESS_WITH_INFO) { - /* clone error information into the db handle */ - strcpy(H->einfo.last_err_msg, S->einfo.last_err_msg); - H->einfo.file = S->einfo.file; - H->einfo.line = S->einfo.line; - H->einfo.what = S->einfo.what; - strcpy(dbh->error_code, stmt->error_code); - } - } - - if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { - return 0; - } - return 1; -} - -static long odbc_handle_doer(pdo_dbh_t *dbh, const char *sql, long sql_len TSRMLS_DC) -{ - pdo_odbc_db_handle *H = (pdo_odbc_db_handle *)dbh->driver_data; - RETCODE rc; - long row_count = -1; - PDO_ODBC_HSTMT stmt; - - rc = SQLAllocHandle(SQL_HANDLE_STMT, H->dbc, &stmt); - if (rc != SQL_SUCCESS) { - pdo_odbc_drv_error("SQLAllocHandle: STMT"); - return -1; - } - - rc = SQLExecDirect(stmt, (char *)sql, sql_len); - - if (rc == SQL_NO_DATA) { - /* If SQLExecDirect executes a searched update or delete statement that - * does not affect any rows at the data source, the call to - * SQLExecDirect returns SQL_NO_DATA. */ - row_count = 0; - goto out; - } - - if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { - pdo_odbc_doer_error("SQLExecDirect"); - goto out; - } - - rc = SQLRowCount(stmt, &row_count); - if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { - pdo_odbc_doer_error("SQLRowCount"); - goto out; - } - if (row_count == -1) { - row_count = 0; - } -out: - SQLFreeHandle(SQL_HANDLE_STMT, stmt); - return row_count; -} - -static int odbc_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, int unquotedlen, char **quoted, int *quotedlen, enum pdo_param_type param_type TSRMLS_DC) -{ - pdo_odbc_db_handle *H = (pdo_odbc_db_handle *)dbh->driver_data; - /* TODO: figure it out */ - return 0; -} - -static int odbc_handle_begin(pdo_dbh_t *dbh TSRMLS_DC) -{ - if (dbh->auto_commit) { - /* we need to disable auto-commit now, to be able to initiate a transaction */ - RETCODE rc; - pdo_odbc_db_handle *H = (pdo_odbc_db_handle *)dbh->driver_data; - - rc = SQLSetConnectAttr(H->dbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)SQL_AUTOCOMMIT_OFF, SQL_IS_INTEGER); - if (rc != SQL_SUCCESS) { - pdo_odbc_drv_error("SQLSetConnectAttr AUTOCOMMIT = OFF"); - return 0; - } - } - return 1; -} - -static int odbc_handle_commit(pdo_dbh_t *dbh TSRMLS_DC) -{ - pdo_odbc_db_handle *H = (pdo_odbc_db_handle *)dbh->driver_data; - RETCODE rc; - - rc = SQLEndTran(SQL_HANDLE_DBC, H->dbc, SQL_COMMIT); - - if (rc != SQL_SUCCESS) { - pdo_odbc_drv_error("SQLEndTran: Commit"); - - if (rc != SQL_SUCCESS_WITH_INFO) { - return 0; - } - } - - if (dbh->auto_commit) { - /* turn auto-commit back on again */ - rc = SQLSetConnectAttr(H->dbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)SQL_AUTOCOMMIT_ON, SQL_IS_INTEGER); - if (rc != SQL_SUCCESS) { - pdo_odbc_drv_error("SQLSetConnectAttr AUTOCOMMIT = ON"); - return 0; - } - } - return 1; -} - -static int odbc_handle_rollback(pdo_dbh_t *dbh TSRMLS_DC) -{ - pdo_odbc_db_handle *H = (pdo_odbc_db_handle *)dbh->driver_data; - RETCODE rc; - - rc = SQLEndTran(SQL_HANDLE_DBC, H->dbc, SQL_ROLLBACK); - - if (rc != SQL_SUCCESS) { - pdo_odbc_drv_error("SQLEndTran: Rollback"); - - if (rc != SQL_SUCCESS_WITH_INFO) { - return 0; - } - } - if (dbh->auto_commit && H->dbc) { - /* turn auto-commit back on again */ - rc = SQLSetConnectAttr(H->dbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)SQL_AUTOCOMMIT_ON, SQL_IS_INTEGER); - if (rc != SQL_SUCCESS) { - pdo_odbc_drv_error("SQLSetConnectAttr AUTOCOMMIT = ON"); - return 0; - } - } - - return 1; -} - -static int odbc_handle_get_attr(pdo_dbh_t *dbh, long attr, zval *val TSRMLS_DC) -{ - switch (attr) { - case PDO_ATTR_CLIENT_VERSION: - ZVAL_STRING(val, "ODBC-" PDO_ODBC_TYPE, 1); - return 1; - - case PDO_ATTR_SERVER_VERSION: - case PDO_ATTR_PREFETCH: - case PDO_ATTR_TIMEOUT: - case PDO_ATTR_SERVER_INFO: - case PDO_ATTR_CONNECTION_STATUS: - break; - - } - return 0; -} - -static struct pdo_dbh_methods odbc_methods = { - odbc_handle_closer, - odbc_handle_preparer, - odbc_handle_doer, - odbc_handle_quoter, - odbc_handle_begin, - odbc_handle_commit, - odbc_handle_rollback, - NULL, /* set attr */ - NULL, /* last id */ - pdo_odbc_fetch_error_func, - odbc_handle_get_attr, /* get attr */ - NULL, /* check_liveness */ -}; - -static int pdo_odbc_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_DC) /* {{{ */ -{ - pdo_odbc_db_handle *H; - RETCODE rc; - int use_direct = 0; - SQLUINTEGER cursor_lib; - - H = pecalloc(1, sizeof(*H), dbh->is_persistent); - - dbh->driver_data = H; - - SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &H->env); - rc = SQLSetEnvAttr(H->env, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0); - - if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { - pdo_odbc_drv_error("SQLSetEnvAttr: ODBC3"); - goto fail; - } - -#ifdef 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"); - goto fail; - } - } -#endif - - rc = SQLAllocHandle(SQL_HANDLE_DBC, H->env, &H->dbc); - if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { - pdo_odbc_drv_error("SQLAllocHandle (DBC)"); - goto fail; - } - - rc = SQLSetConnectAttr(H->dbc, SQL_ATTR_AUTOCOMMIT, - (SQLPOINTER)(dbh->auto_commit ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF), SQL_IS_INTEGER); - if (rc != SQL_SUCCESS) { - pdo_odbc_drv_error("SQLSetConnectAttr AUTOCOMMIT"); - goto fail; - } - - /* set up the cursor library, if needed, or if configured explicitly */ - cursor_lib = pdo_attr_lval(driver_options, PDO_ODBC_ATTR_USE_CURSOR_LIBRARY, SQL_CUR_USE_IF_NEEDED TSRMLS_CC); - rc = SQLSetConnectAttr(H->dbc, SQL_ODBC_CURSORS, (void*)cursor_lib, SQL_IS_INTEGER); - if (rc != SQL_SUCCESS && cursor_lib != SQL_CUR_USE_IF_NEEDED) { - pdo_odbc_drv_error("SQLSetConnectAttr SQL_ODBC_CURSORS"); - goto fail; - } - - if (strchr(dbh->data_source, ';')) { - char dsnbuf[1024]; - short dsnbuflen; - - use_direct = 1; - - /* Force UID and PWD to be set in the DSN */ - if (dbh->username && *dbh->username && !strstr(dbh->data_source, "uid") - && !strstr(dbh->data_source, "UID")) { - char *dsn; - spprintf(&dsn, 0, "%s;UID=%s;PWD=%s", dbh->data_source, dbh->username, dbh->password); - pefree((char*)dbh->data_source, dbh->is_persistent); - dbh->data_source = dsn; - } - - rc = SQLDriverConnect(H->dbc, NULL, (char*)dbh->data_source, strlen(dbh->data_source), - dsnbuf, sizeof(dsnbuf)-1, &dsnbuflen, SQL_DRIVER_NOPROMPT); - } - if (!use_direct) { - rc = SQLConnect(H->dbc, (char*)dbh->data_source, SQL_NTS, dbh->username, SQL_NTS, dbh->password, SQL_NTS); - } - - if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { - pdo_odbc_drv_error(use_direct ? "SQLDriverConnect" : "SQLConnect"); - goto fail; - } - - /* TODO: if we want to play nicely, we should check to see if the driver really supports ODBC v3 or not */ - - dbh->methods = &odbc_methods; - dbh->alloc_own_columns = 1; - - return 1; - -fail: - dbh->methods = &odbc_methods; - return 0; -} -/* }}} */ - -pdo_driver_t pdo_odbc_driver = { - PDO_DRIVER_HEADER(odbc), - pdo_odbc_handle_factory -}; - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2008 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 | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_0.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Wez Furlong <wez@php.net> | + +----------------------------------------------------------------------+ +*/ + +/* $Id: odbc_driver.c,v 1.27.2.4.2.3.2.2 2008/03/13 16:55:09 auroraeosrose Exp $ */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php.h" +#include "php_ini.h" +#include "ext/standard/info.h" +#include "pdo/php_pdo.h" +#include "pdo/php_pdo_driver.h" +#include "php_pdo_odbc.h" +#include "php_pdo_odbc_int.h" +#include "zend_exceptions.h" + +static int pdo_odbc_fetch_error_func(pdo_dbh_t *dbh, pdo_stmt_t *stmt, zval *info TSRMLS_DC) +{ + pdo_odbc_db_handle *H = (pdo_odbc_db_handle *)dbh->driver_data; + pdo_odbc_errinfo *einfo = &H->einfo; + pdo_odbc_stmt *S = NULL; + char *message = NULL; + + if (stmt) { + S = (pdo_odbc_stmt*)stmt->driver_data; + einfo = &S->einfo; + } + + spprintf(&message, 0, "%s (%s[%ld] at %s:%d)", + einfo->last_err_msg, + einfo->what, einfo->last_error, + einfo->file, einfo->line); + + add_next_index_long(info, einfo->last_error); + add_next_index_string(info, message, 0); + add_next_index_string(info, einfo->last_state, 1); + + return 1; +} + + +void pdo_odbc_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, PDO_ODBC_HSTMT statement, char *what, const char *file, int line TSRMLS_DC) /* {{{ */ +{ + SQLRETURN rc; + SQLSMALLINT errmsgsize = 0; + SQLHANDLE eh; + SQLSMALLINT htype, recno = 1; + pdo_odbc_db_handle *H = (pdo_odbc_db_handle*)dbh->driver_data; + pdo_odbc_errinfo *einfo = &H->einfo; + pdo_odbc_stmt *S = NULL; + pdo_error_type *pdo_err = &dbh->error_code; + + if (stmt) { + S = (pdo_odbc_stmt*)stmt->driver_data; + + einfo = &S->einfo; + pdo_err = &stmt->error_code; + } + + if (statement == SQL_NULL_HSTMT && S) { + statement = S->stmt; + } + + if (statement) { + htype = SQL_HANDLE_STMT; + eh = statement; + } else if (H->dbc) { + htype = SQL_HANDLE_DBC; + eh = H->dbc; + } else { + htype = SQL_HANDLE_ENV; + eh = H->env; + } + + rc = SQLGetDiagRec(htype, eh, recno++, einfo->last_state, &einfo->last_error, + einfo->last_err_msg, sizeof(einfo->last_err_msg)-1, &errmsgsize); + + if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { + errmsgsize = 0; + } + + einfo->last_err_msg[errmsgsize] = '\0'; + einfo->file = file; + einfo->line = line; + 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); + } + + /* just like a cursor, once you start pulling, you need to keep + * going until the end; SQL Server (at least) will mess with the + * actual cursor state if you don't finish retrieving all the + * diagnostic records (which can be generated by PRINT statements + * in the query, for instance). */ + while (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) { + char discard_state[5]; + char discard_buf[1024]; + SQLINTEGER code; + rc = SQLGetDiagRec(htype, eh, recno++, discard_state, &code, + discard_buf, sizeof(discard_buf)-1, &errmsgsize); + } + +} +/* }}} */ + +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); + SQLDisconnect(H->dbc); + 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; +} + +static int odbc_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_len, pdo_stmt_t *stmt, zval *driver_options TSRMLS_DC) +{ + RETCODE rc; + pdo_odbc_db_handle *H = (pdo_odbc_db_handle *)dbh->driver_data; + pdo_odbc_stmt *S = ecalloc(1, sizeof(*S)); + enum pdo_cursor_type cursor_type = PDO_CURSOR_FWDONLY; + int ret; + char *nsql = NULL; + int nsql_len = 0; + + S->H = H; + S->assume_utf8 = H->assume_utf8; + + /* before we prepare, we need to peek at the query; if it uses named parameters, + * we want PDO to rewrite them for us */ + stmt->supports_placeholders = PDO_PLACEHOLDER_POSITIONAL; + ret = pdo_parse_params(stmt, (char*)sql, sql_len, &nsql, &nsql_len TSRMLS_CC); + + if (ret == 1) { + /* query was re-written */ + sql = nsql; + } else if (ret == -1) { + /* couldn't grok it */ + strcpy(dbh->error_code, stmt->error_code); + efree(S); + return 0; + } + + rc = SQLAllocHandle(SQL_HANDLE_STMT, H->dbc, &S->stmt); + + if (rc == SQL_INVALID_HANDLE || rc == SQL_ERROR) { + efree(S); + if (nsql) { + efree(nsql); + } + pdo_odbc_drv_error("SQLAllocStmt"); + return 0; + } + + cursor_type = pdo_attr_lval(driver_options, PDO_ATTR_CURSOR, PDO_CURSOR_FWDONLY TSRMLS_CC); + if (cursor_type != PDO_CURSOR_FWDONLY) { + rc = SQLSetStmtAttr(S->stmt, SQL_ATTR_CURSOR_SCROLLABLE, (void*)SQL_SCROLLABLE, 0); + if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { + pdo_odbc_stmt_error("SQLSetStmtAttr: SQL_ATTR_CURSOR_SCROLLABLE"); + SQLFreeHandle(SQL_HANDLE_STMT, S->stmt); + if (nsql) { + efree(nsql); + } + return 0; + } + } + + rc = SQLPrepare(S->stmt, (char*)sql, SQL_NTS); + if (nsql) { + efree(nsql); + } + + stmt->driver_data = S; + stmt->methods = &odbc_stmt_methods; + + if (rc != SQL_SUCCESS) { + pdo_odbc_stmt_error("SQLPrepare"); + if (rc != SQL_SUCCESS_WITH_INFO) { + /* clone error information into the db handle */ + strcpy(H->einfo.last_err_msg, S->einfo.last_err_msg); + H->einfo.file = S->einfo.file; + H->einfo.line = S->einfo.line; + H->einfo.what = S->einfo.what; + strcpy(dbh->error_code, stmt->error_code); + } + } + + if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { + return 0; + } + return 1; +} + +static long odbc_handle_doer(pdo_dbh_t *dbh, const char *sql, long sql_len TSRMLS_DC) +{ + pdo_odbc_db_handle *H = (pdo_odbc_db_handle *)dbh->driver_data; + RETCODE rc; + long row_count = -1; + PDO_ODBC_HSTMT stmt; + + rc = SQLAllocHandle(SQL_HANDLE_STMT, H->dbc, &stmt); + if (rc != SQL_SUCCESS) { + pdo_odbc_drv_error("SQLAllocHandle: STMT"); + return -1; + } + + rc = SQLExecDirect(stmt, (char *)sql, sql_len); + + if (rc == SQL_NO_DATA) { + /* If SQLExecDirect executes a searched update or delete statement that + * does not affect any rows at the data source, the call to + * SQLExecDirect returns SQL_NO_DATA. */ + row_count = 0; + goto out; + } + + if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { + pdo_odbc_doer_error("SQLExecDirect"); + goto out; + } + + rc = SQLRowCount(stmt, &row_count); + if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { + pdo_odbc_doer_error("SQLRowCount"); + goto out; + } + if (row_count == -1) { + row_count = 0; + } +out: + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + return row_count; +} + +static int odbc_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, int unquotedlen, char **quoted, int *quotedlen, enum pdo_param_type param_type TSRMLS_DC) +{ + pdo_odbc_db_handle *H = (pdo_odbc_db_handle *)dbh->driver_data; + /* TODO: figure it out */ + return 0; +} + +static int odbc_handle_begin(pdo_dbh_t *dbh TSRMLS_DC) +{ + if (dbh->auto_commit) { + /* we need to disable auto-commit now, to be able to initiate a transaction */ + RETCODE rc; + pdo_odbc_db_handle *H = (pdo_odbc_db_handle *)dbh->driver_data; + + rc = SQLSetConnectAttr(H->dbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)SQL_AUTOCOMMIT_OFF, SQL_IS_INTEGER); + if (rc != SQL_SUCCESS) { + pdo_odbc_drv_error("SQLSetConnectAttr AUTOCOMMIT = OFF"); + return 0; + } + } + return 1; +} + +static int odbc_handle_commit(pdo_dbh_t *dbh TSRMLS_DC) +{ + pdo_odbc_db_handle *H = (pdo_odbc_db_handle *)dbh->driver_data; + RETCODE rc; + + rc = SQLEndTran(SQL_HANDLE_DBC, H->dbc, SQL_COMMIT); + + if (rc != SQL_SUCCESS) { + pdo_odbc_drv_error("SQLEndTran: Commit"); + + if (rc != SQL_SUCCESS_WITH_INFO) { + return 0; + } + } + + if (dbh->auto_commit) { + /* turn auto-commit back on again */ + rc = SQLSetConnectAttr(H->dbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)SQL_AUTOCOMMIT_ON, SQL_IS_INTEGER); + if (rc != SQL_SUCCESS) { + pdo_odbc_drv_error("SQLSetConnectAttr AUTOCOMMIT = ON"); + return 0; + } + } + return 1; +} + +static int odbc_handle_rollback(pdo_dbh_t *dbh TSRMLS_DC) +{ + pdo_odbc_db_handle *H = (pdo_odbc_db_handle *)dbh->driver_data; + RETCODE rc; + + rc = SQLEndTran(SQL_HANDLE_DBC, H->dbc, SQL_ROLLBACK); + + if (rc != SQL_SUCCESS) { + pdo_odbc_drv_error("SQLEndTran: Rollback"); + + if (rc != SQL_SUCCESS_WITH_INFO) { + return 0; + } + } + if (dbh->auto_commit && H->dbc) { + /* turn auto-commit back on again */ + rc = SQLSetConnectAttr(H->dbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)SQL_AUTOCOMMIT_ON, SQL_IS_INTEGER); + if (rc != SQL_SUCCESS) { + pdo_odbc_drv_error("SQLSetConnectAttr AUTOCOMMIT = ON"); + return 0; + } + } + + return 1; +} + +static int odbc_handle_set_attr(pdo_dbh_t *dbh, long attr, zval *val TSRMLS_DC) +{ + pdo_odbc_db_handle *H = (pdo_odbc_db_handle *)dbh->driver_data; + switch (attr) { + case PDO_ODBC_ATTR_ASSUME_UTF8: + H->assume_utf8 = zval_is_true(val); + return 1; + default: + strcpy(H->einfo.last_err_msg, "Unknown Attribute"); + H->einfo.what = "setAttribute"; + strcpy(H->einfo.last_state, "IM0001"); + return -1; + } +} + +static int odbc_handle_get_attr(pdo_dbh_t *dbh, long attr, zval *val TSRMLS_DC) +{ + pdo_odbc_db_handle *H = (pdo_odbc_db_handle *)dbh->driver_data; + switch (attr) { + case PDO_ATTR_CLIENT_VERSION: + ZVAL_STRING(val, "ODBC-" PDO_ODBC_TYPE, 1); + return 1; + + case PDO_ATTR_SERVER_VERSION: + case PDO_ATTR_PREFETCH: + case PDO_ATTR_TIMEOUT: + case PDO_ATTR_SERVER_INFO: + case PDO_ATTR_CONNECTION_STATUS: + break; + case PDO_ODBC_ATTR_ASSUME_UTF8: + ZVAL_BOOL(val, H->assume_utf8 ? 1 : 0); + return 1; + + } + return 0; +} + +static struct pdo_dbh_methods odbc_methods = { + odbc_handle_closer, + odbc_handle_preparer, + odbc_handle_doer, + odbc_handle_quoter, + odbc_handle_begin, + odbc_handle_commit, + odbc_handle_rollback, + odbc_handle_set_attr, + NULL, /* last id */ + pdo_odbc_fetch_error_func, + odbc_handle_get_attr, /* get attr */ + NULL, /* check_liveness */ +}; + +static int pdo_odbc_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_DC) /* {{{ */ +{ + pdo_odbc_db_handle *H; + RETCODE rc; + int use_direct = 0; + SQLUINTEGER cursor_lib; + + H = pecalloc(1, sizeof(*H), dbh->is_persistent); + + dbh->driver_data = H; + + SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &H->env); + rc = SQLSetEnvAttr(H->env, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0); + + if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { + pdo_odbc_drv_error("SQLSetEnvAttr: ODBC3"); + goto fail; + } + +#ifdef 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"); + goto fail; + } + } +#endif + + rc = SQLAllocHandle(SQL_HANDLE_DBC, H->env, &H->dbc); + if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { + pdo_odbc_drv_error("SQLAllocHandle (DBC)"); + goto fail; + } + + rc = SQLSetConnectAttr(H->dbc, SQL_ATTR_AUTOCOMMIT, + (SQLPOINTER)(dbh->auto_commit ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF), SQL_IS_INTEGER); + if (rc != SQL_SUCCESS) { + pdo_odbc_drv_error("SQLSetConnectAttr AUTOCOMMIT"); + goto fail; + } + + /* set up the cursor library, if needed, or if configured explicitly */ + cursor_lib = pdo_attr_lval(driver_options, PDO_ODBC_ATTR_USE_CURSOR_LIBRARY, SQL_CUR_USE_IF_NEEDED TSRMLS_CC); + rc = SQLSetConnectAttr(H->dbc, SQL_ODBC_CURSORS, (void*)cursor_lib, SQL_IS_INTEGER); + if (rc != SQL_SUCCESS && cursor_lib != SQL_CUR_USE_IF_NEEDED) { + pdo_odbc_drv_error("SQLSetConnectAttr SQL_ODBC_CURSORS"); + goto fail; + } + + if (strchr(dbh->data_source, ';')) { + char dsnbuf[1024]; + short dsnbuflen; + + use_direct = 1; + + /* Force UID and PWD to be set in the DSN */ + if (dbh->username && *dbh->username && !strstr(dbh->data_source, "uid") + && !strstr(dbh->data_source, "UID")) { + char *dsn; + spprintf(&dsn, 0, "%s;UID=%s;PWD=%s", dbh->data_source, dbh->username, dbh->password); + pefree((char*)dbh->data_source, dbh->is_persistent); + dbh->data_source = dsn; + } + + rc = SQLDriverConnect(H->dbc, NULL, (char*)dbh->data_source, strlen(dbh->data_source), + dsnbuf, sizeof(dsnbuf)-1, &dsnbuflen, SQL_DRIVER_NOPROMPT); + } + if (!use_direct) { + rc = SQLConnect(H->dbc, (char*)dbh->data_source, SQL_NTS, dbh->username, SQL_NTS, dbh->password, SQL_NTS); + } + + if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { + pdo_odbc_drv_error(use_direct ? "SQLDriverConnect" : "SQLConnect"); + goto fail; + } + + /* TODO: if we want to play nicely, we should check to see if the driver really supports ODBC v3 or not */ + + dbh->methods = &odbc_methods; + dbh->alloc_own_columns = 1; + + return 1; + +fail: + dbh->methods = &odbc_methods; + return 0; +} +/* }}} */ + +pdo_driver_t pdo_odbc_driver = { + PDO_DRIVER_HEADER(odbc), + pdo_odbc_handle_factory +}; + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ http://cvs.php.net/viewvc.cgi/php-src/ext/pdo_odbc/odbc_stmt.c?r1=1.26.2.2.2.3.2.1&r2=1.26.2.2.2.3.2.2&diff_format=u Index: php-src/ext/pdo_odbc/odbc_stmt.c diff -u php-src/ext/pdo_odbc/odbc_stmt.c:1.26.2.2.2.3.2.1 php-src/ext/pdo_odbc/odbc_stmt.c:1.26.2.2.2.3.2.2 --- php-src/ext/pdo_odbc/odbc_stmt.c:1.26.2.2.2.3.2.1 Mon Dec 31 07:17:12 2007 +++ php-src/ext/pdo_odbc/odbc_stmt.c Thu Mar 13 16:55:09 2008 @@ -1,649 +1,848 @@ -/* - +----------------------------------------------------------------------+ - | PHP Version 5 | - +----------------------------------------------------------------------+ - | Copyright (c) 1997-2008 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 | - | available through the world-wide-web at the following url: | - | http://www.php.net/license/3_0.txt. | - | If you did not receive a copy of the PHP license and are unable to | - | obtain it through the world-wide-web, please send a note to | - | license@php.net so we can mail you a copy immediately. | - +----------------------------------------------------------------------+ - | Author: Wez Furlong <wez@php.net> | - +----------------------------------------------------------------------+ -*/ - -/* $Id: odbc_stmt.c,v 1.26.2.2.2.3.2.1 2007/12/31 07:17:12 sebastian Exp $ */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "php.h" -#include "php_ini.h" -#include "ext/standard/info.h" -#include "pdo/php_pdo.h" -#include "pdo/php_pdo_driver.h" -#include "php_pdo_odbc.h" -#include "php_pdo_odbc_int.h" - -static void free_cols(pdo_stmt_t *stmt, pdo_odbc_stmt *S TSRMLS_DC) -{ - if (S->cols) { - int i; - - for (i = 0; i < stmt->column_count; i++) { - if (S->cols[i].data) { - efree(S->cols[i].data); - } - } - efree(S->cols); - S->cols = NULL; - } -} - -static int odbc_stmt_dtor(pdo_stmt_t *stmt TSRMLS_DC) -{ - pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data; - - if (S->stmt != SQL_NULL_HANDLE) { - if (stmt->executed) { - SQLCloseCursor(S->stmt); - } - SQLFreeHandle(SQL_HANDLE_STMT, S->stmt); - S->stmt = SQL_NULL_HANDLE; - } - - free_cols(stmt, S TSRMLS_CC); - - efree(S); - - return 1; -} - -static int odbc_stmt_execute(pdo_stmt_t *stmt TSRMLS_DC) -{ - RETCODE rc; - pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data; - char *buf = NULL; - long row_count = -1; - - if (stmt->executed) { - SQLCloseCursor(S->stmt); - } - - rc = SQLExecute(S->stmt); - - while (rc == SQL_NEED_DATA) { - struct pdo_bound_param_data *param; - rc = SQLParamData(S->stmt, (SQLPOINTER*)&param); - if (rc == SQL_NEED_DATA) { - php_stream *stm; - int len; - - if (Z_TYPE_P(param->parameter) != IS_RESOURCE) { - /* they passed in a string */ - convert_to_string(param->parameter); - SQLPutData(S->stmt, Z_STRVAL_P(param->parameter), Z_STRLEN_P(param->parameter)); - continue; - } - - php_stream_from_zval_no_verify(stm, &param->parameter); - if (!stm) { - /* shouldn't happen either */ - pdo_odbc_stmt_error("input LOB is no longer a stream"); - SQLCloseCursor(S->stmt); - if (buf) { - efree(buf); - } - return 0; - } - - /* now suck data from the stream and stick it into the database */ - if (buf == NULL) { - buf = emalloc(8192); - } - - do { - len = php_stream_read(stm, buf, 8192); - if (len == 0) { - break; - } - SQLPutData(S->stmt, buf, len); - } while (1); - } - } - - if (buf) { - efree(buf); - } - - switch (rc) { - case SQL_SUCCESS: - break; - case SQL_NO_DATA_FOUND: - case SQL_SUCCESS_WITH_INFO: - pdo_odbc_stmt_error("SQLExecute"); - break; - - default: - pdo_odbc_stmt_error("SQLExecute"); - return 0; - } - - SQLRowCount(S->stmt, &row_count); - stmt->row_count = row_count; - - if (!stmt->executed) { - /* do first-time-only definition of bind/mapping stuff */ - SQLSMALLINT colcount; - - /* how many columns do we have ? */ - SQLNumResultCols(S->stmt, &colcount); - - stmt->column_count = (int)colcount; - S->cols = ecalloc(colcount, sizeof(pdo_odbc_column)); - S->going_long = 0; - } - - return 1; -} - -static int odbc_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *param, - enum pdo_param_event event_type TSRMLS_DC) -{ - pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data; - RETCODE rc; - 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 */ - if (param->is_param) { - - switch (event_type) { - case PDO_PARAM_EVT_FREE: - P = param->driver_data; - if (P) { - efree(P); - } - break; - - case PDO_PARAM_EVT_ALLOC: - { - /* figure out what we're doing */ - switch (PDO_PARAM_TYPE(param->param_type)) { - case PDO_PARAM_LOB: - break; - - case PDO_PARAM_STMT: - return 0; - - default: - break; - } - - 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 { - ctype = SQL_C_CHAR; - } - - P = emalloc(sizeof(*P)); - 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; - } else if (param->max_value_len <= 0) { - P->paramtype = SQL_PARAM_INPUT; - } else { - P->paramtype = SQL_PARAM_OUTPUT; - } - - 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; - } - - rc = SQLBindParameter(S->stmt, param->paramno+1, - P->paramtype, ctype, sqltype, precision, scale, - P->paramtype == SQL_PARAM_INPUT ? - (SQLPOINTER)param : - P->outbuf, - P->len, - &P->len - ); - - if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) { - return 1; - } - pdo_odbc_stmt_error("SQLBindParameter"); - return 0; - } - - case PDO_PARAM_EVT_EXEC_PRE: - P = param->driver_data; - if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB) { - if (Z_TYPE_P(param->parameter) == IS_RESOURCE) { - php_stream *stm; - php_stream_statbuf sb; - - php_stream_from_zval_no_verify(stm, &param->parameter); - - if (!stm) { - return 0; - } - - if (0 == php_stream_stat(stm, &sb)) { - 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 { - if (P->outbuf) { - P->len = 0; - } else { - P->len = SQL_LEN_DATA_AT_EXEC(0); - } - } - } else { - 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)); - } - } - } else if (Z_TYPE_P(param->parameter) == IS_NULL || PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_NULL) { - P->len = SQL_NULL_DATA; - } else { - 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: - 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; - } - } - return 1; -} - -static int odbc_stmt_fetch(pdo_stmt_t *stmt, - enum pdo_fetch_orientation ori, long offset TSRMLS_DC) -{ - pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data; - RETCODE rc; - SQLSMALLINT odbcori; - - switch (ori) { - case PDO_FETCH_ORI_NEXT: odbcori = SQL_FETCH_NEXT; break; - case PDO_FETCH_ORI_PRIOR: odbcori = SQL_FETCH_PRIOR; break; - case PDO_FETCH_ORI_FIRST: odbcori = SQL_FETCH_FIRST; break; - case PDO_FETCH_ORI_LAST: odbcori = SQL_FETCH_LAST; break; - case PDO_FETCH_ORI_ABS: odbcori = SQL_FETCH_ABSOLUTE; break; - case PDO_FETCH_ORI_REL: odbcori = SQL_FETCH_RELATIVE; break; - default: - strcpy(stmt->error_code, "HY106"); - return 0; - } - rc = SQLFetchScroll(S->stmt, odbcori, offset); - - if (rc == SQL_SUCCESS) { - return 1; - } - if (rc == SQL_SUCCESS_WITH_INFO) { - pdo_odbc_stmt_error("SQLFetchScroll"); - return 1; - } - - if (rc == SQL_NO_DATA) { - /* pdo_odbc_stmt_error("SQLFetchScroll"); */ - return 0; - } - - pdo_odbc_stmt_error("SQLFetchScroll"); - - return 0; -} - -static int odbc_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC) -{ - pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data; - struct pdo_column_data *col = &stmt->columns[colno]; - zend_bool dyn = FALSE; - RETCODE rc; - SWORD colnamelen; - SDWORD colsize, displaysize; - - rc = SQLDescribeCol(S->stmt, colno+1, S->cols[colno].colname, - sizeof(S->cols[colno].colname)-1, &colnamelen, - &S->cols[colno].coltype, &colsize, NULL, NULL); - - if (rc != SQL_SUCCESS) { - pdo_odbc_stmt_error("SQLDescribeCol"); - if (rc != SQL_SUCCESS_WITH_INFO) { - return 0; - } - } - - rc = SQLColAttribute(S->stmt, colno+1, - SQL_DESC_DISPLAY_SIZE, - NULL, 0, NULL, &displaysize); - - if (rc != SQL_SUCCESS) { - pdo_odbc_stmt_error("SQLColAttribute"); - if (rc != SQL_SUCCESS_WITH_INFO) { - return 0; - } - } - colsize = displaysize; - - col->maxlen = S->cols[colno].datalen = colsize; - col->namelen = colnamelen; - col->name = estrdup(S->cols[colno].colname); - - /* returning data as a string */ - col->param_type = PDO_PARAM_STR; - - /* tell ODBC to put it straight into our buffer, but only if it - * isn't "long" data, and only if we haven't already bound a long - * column. */ - if (colsize < 256 && !S->going_long) { - S->cols[colno].data = emalloc(colsize+1); - S->cols[colno].is_long = 0; - - 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; - } - } else { - /* allocate a smaller buffer to keep around for smaller - * "long" columns */ - S->cols[colno].data = emalloc(256); - S->going_long = 1; - S->cols[colno].is_long = 1; - } - - return 1; -} - -static int odbc_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, unsigned long *len, int *caller_frees TSRMLS_DC) -{ - pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data; - pdo_odbc_column *C = &S->cols[colno]; - - /* if it is a column containing "long" data, perform late binding now */ - if (C->is_long) { - unsigned long alloced = 4096; - unsigned long used = 0; - char *buf; - RETCODE rc; - - /* fetch it into C->data, which is allocated with a length - * of 256 bytes; if there is more to be had, we then allocate - * bigger buffer for the caller to free */ - - rc = SQLGetData(S->stmt, colno+1, SQL_C_CHAR, C->data, - 256, &C->fetched_len); - - if (rc == SQL_SUCCESS) { - /* all the data fit into our little buffer; - * jump down to the generic bound data case */ - goto in_data; - } - - if (rc == SQL_SUCCESS_WITH_INFO) { - /* promote up to a bigger buffer */ - - if (C->fetched_len != SQL_NO_TOTAL) { - /* use size suggested by the driver, if it knows it */ - alloced = C->fetched_len + 1; - } - - buf = emalloc(alloced); - memcpy(buf, C->data, 256); - used = 255; /* not 256; the driver NUL terminated the buffer */ - - do { - C->fetched_len = 0; - rc = SQLGetData(S->stmt, colno+1, SQL_C_CHAR, - buf + used, alloced - used, - &C->fetched_len); - - if (rc == SQL_NO_DATA) { - /* we got the lot */ - break; - } else if (rc != SQL_SUCCESS) { - pdo_odbc_stmt_error("SQLGetData"); - if (rc != SQL_SUCCESS_WITH_INFO) { - break; - } - } - - if (C->fetched_len == SQL_NO_TOTAL) { - used += alloced - used; - } else { - used += C->fetched_len; - } - - if (rc == SQL_SUCCESS) { - /* this was the final fetch */ - break; - } - - /* we need to fetch another chunk; resize the - * buffer */ - alloced *= 2; - buf = erealloc(buf, alloced); - } while (1); - - /* size down */ - if (used < alloced - 1024) { - alloced = used+1; - buf = erealloc(buf, used+1); - } - buf[used] = '\0'; - *ptr = buf; - *caller_frees = 1; - *len = used; - return 1; - } - - /* something went caca */ - *ptr = NULL; - *len = 0; - return 1; - } - -in_data: - /* check the indicator to ensure that the data is intact */ - if (C->fetched_len == SQL_NULL_DATA) { - /* A NULL value */ - *ptr = NULL; - *len = 0; - return 1; - } else if (C->fetched_len >= 0) { - /* it was stored perfectly */ - *ptr = C->data; - *len = C->fetched_len; - return 1; - } else { - /* no data? */ - *ptr = NULL; - *len = 0; - return 1; - } -} - -static int odbc_stmt_set_param(pdo_stmt_t *stmt, long attr, zval *val TSRMLS_DC) -{ - SQLRETURN rc; - pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data; - - switch (attr) { - case PDO_ATTR_CURSOR_NAME: - convert_to_string(val); - rc = SQLSetCursorName(S->stmt, Z_STRVAL_P(val), Z_STRLEN_P(val)); - - if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) { - return 1; - } - pdo_odbc_stmt_error("SQLSetCursorName"); - return 0; - - default: - strcpy(S->einfo.last_err_msg, "Unknown Attribute"); - S->einfo.what = "setAttribute"; - strcpy(S->einfo.last_state, "IM0001"); - return -1; - } -} - -static int odbc_stmt_get_attr(pdo_stmt_t *stmt, long attr, zval *val TSRMLS_DC) -{ - SQLRETURN rc; - pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data; - - switch (attr) { - case PDO_ATTR_CURSOR_NAME: - { - char buf[256]; - SQLSMALLINT len = 0; - rc = SQLGetCursorName(S->stmt, buf, sizeof(buf), &len); - - if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) { - ZVAL_STRINGL(val, buf, len, 1); - return 1; - } - pdo_odbc_stmt_error("SQLGetCursorName"); - return 0; - } - - default: - strcpy(S->einfo.last_err_msg, "Unknown Attribute"); - S->einfo.what = "getAttribute"; - strcpy(S->einfo.last_state, "IM0001"); - return -1; - } -} - -static int odbc_stmt_next_rowset(pdo_stmt_t *stmt TSRMLS_DC) -{ - SQLRETURN rc; - SQLSMALLINT colcount; - pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data; - - /* 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) { - return 0; - } - - free_cols(stmt, S TSRMLS_CC); - /* how many columns do we have ? */ - SQLNumResultCols(S->stmt, &colcount); - stmt->column_count = (int)colcount; - S->cols = ecalloc(colcount, sizeof(pdo_odbc_column)); - S->going_long = 0; - - return 1; -} - -struct pdo_stmt_methods odbc_stmt_methods = { - odbc_stmt_dtor, - odbc_stmt_execute, - odbc_stmt_fetch, - odbc_stmt_describe, - odbc_stmt_get_col, - odbc_stmt_param_hook, - odbc_stmt_set_param, - odbc_stmt_get_attr, /* get attr */ - NULL, /* get column meta */ - odbc_stmt_next_rowset -}; - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2008 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 | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_0.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Wez Furlong <wez@php.net> | + +----------------------------------------------------------------------+ +*/ + +/* $Id: odbc_stmt.c,v 1.26.2.2.2.3.2.2 2008/03/13 16:55:09 auroraeosrose Exp $ */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php.h" +#include "php_ini.h" +#include "ext/standard/info.h" +#include "pdo/php_pdo.h" +#include "pdo/php_pdo_driver.h" +#include "php_pdo_odbc.h" +#include "php_pdo_odbc_int.h" + +enum pdo_odbc_conv_result { + PDO_ODBC_CONV_NOT_REQUIRED, + PDO_ODBC_CONV_OK, + PDO_ODBC_CONV_FAIL +}; + +static int pdo_odbc_sqltype_is_unicode(pdo_odbc_stmt *S, SWORD sqltype) +{ + if (!S->assume_utf8) return 0; + switch (sqltype) { +#ifdef SQL_WCHAR + case SQL_WCHAR: + return 1; +#endif +#ifdef SQL_WLONGVARCHAR + case SQL_WLONGVARCHAR: + return 1; +#endif +#ifdef SQL_WVARCHAR + case SQL_WVARCHAR: + return 1; +#endif + default: + return 0; + } +} + +static int pdo_odbc_utf82ucs2(pdo_stmt_t *stmt, int is_unicode, const char *buf, + unsigned long buflen, unsigned long *outlen) +{ +#ifdef PHP_WIN32 + if (is_unicode && buflen) { + pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data; + DWORD ret; + + ret = MultiByteToWideChar(CP_UTF8, 0, buf, buflen, NULL, 0); + if (ret == 0) { + //printf("%s:%d %d [%d] %.*s\n", __FILE__, __LINE__, GetLastError(), buflen, buflen, buf); + return PDO_ODBC_CONV_FAIL; + } + + ret *= sizeof(WCHAR); + + if (S->convbufsize <= ret) { + S->convbufsize = ret + sizeof(WCHAR); + S->convbuf = erealloc(S->convbuf, S->convbufsize); + } + + ret = MultiByteToWideChar(CP_UTF8, 0, buf, buflen, (LPWSTR)S->convbuf, S->convbufsize / sizeof(WCHAR)); + if (ret == 0) { + //printf("%s:%d %d [%d] %.*s\n", __FILE__, __LINE__, GetLastError(), buflen, buflen, buf); + return PDO_ODBC_CONV_FAIL; + } + + ret *= sizeof(WCHAR); + *outlen = ret; + return PDO_ODBC_CONV_OK; + } +#endif + return PDO_ODBC_CONV_NOT_REQUIRED; +} + +static int pdo_odbc_ucs22utf8(pdo_stmt_t *stmt, int is_unicode, const char *buf, + unsigned long buflen, unsigned long *outlen) +{ +#ifdef PHP_WIN32 + if (is_unicode && buflen) { + pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data; + DWORD ret; + + ret = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)buf, buflen/sizeof(WCHAR), NULL, 0, NULL, NULL); + if (ret == 0) { + return PDO_ODBC_CONV_FAIL; + } + + if (S->convbufsize <= ret) { + S->convbufsize = ret + 1; + S->convbuf = erealloc(S->convbuf, S->convbufsize); + } + + ret = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)buf, buflen/sizeof(WCHAR), S->convbuf, S->convbufsize, NULL, NULL); + if (ret == 0) { + return PDO_ODBC_CONV_FAIL; + } + + *outlen = ret; + S->convbuf[*outlen] = '\0'; + return PDO_ODBC_CONV_OK; + } +#endif + return PDO_ODBC_CONV_NOT_REQUIRED; +} + +static void free_cols(pdo_stmt_t *stmt, pdo_odbc_stmt *S TSRMLS_DC) +{ + if (S->cols) { + int i; + + for (i = 0; i < stmt->column_count; i++) { + if (S->cols[i].data) { + efree(S->cols[i].data); + } + } + efree(S->cols); + S->cols = NULL; + } +} + +static int odbc_stmt_dtor(pdo_stmt_t *stmt TSRMLS_DC) +{ + pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data; + + if (S->stmt != SQL_NULL_HANDLE) { + if (stmt->executed) { + SQLCloseCursor(S->stmt); + } + SQLFreeHandle(SQL_HANDLE_STMT, S->stmt); + S->stmt = SQL_NULL_HANDLE; + } + + free_cols(stmt, S TSRMLS_CC); + if (S->convbuf) { + efree(S->convbuf); + } + efree(S); + + return 1; +} + +static int odbc_stmt_execute(pdo_stmt_t *stmt TSRMLS_DC) +{ + RETCODE rc; + pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data; + char *buf = NULL; + long row_count = -1; + + if (stmt->executed) { + SQLCloseCursor(S->stmt); + } + + rc = SQLExecute(S->stmt); + + while (rc == SQL_NEED_DATA) { + struct pdo_bound_param_data *param; + + rc = SQLParamData(S->stmt, (SQLPOINTER*)&param); + if (rc == SQL_NEED_DATA) { + php_stream *stm; + int len; + pdo_odbc_param *P; + + P = (pdo_odbc_param*)param->driver_data; + if (Z_TYPE_P(param->parameter) != IS_RESOURCE) { + /* they passed in a string */ + unsigned long ulen; + convert_to_string(param->parameter); + + switch (pdo_odbc_utf82ucs2(stmt, P->is_unicode, + Z_STRVAL_P(param->parameter), + Z_STRLEN_P(param->parameter), + &ulen)) { + case PDO_ODBC_CONV_NOT_REQUIRED: + SQLPutData(S->stmt, Z_STRVAL_P(param->parameter), + Z_STRLEN_P(param->parameter)); + break; + case PDO_ODBC_CONV_OK: + SQLPutData(S->stmt, S->convbuf, ulen); + break; + case PDO_ODBC_CONV_FAIL: + pdo_odbc_stmt_error("error converting input string"); + SQLCloseCursor(S->stmt); + if (buf) { + efree(buf); + } + return 0; + } + continue; + } + + /* we assume that LOBs are binary and don't need charset + * conversion */ + + php_stream_from_zval_no_verify(stm, &param->parameter); + if (!stm) { + /* shouldn't happen either */ + pdo_odbc_stmt_error("input LOB is no longer a stream"); + SQLCloseCursor(S->stmt); + if (buf) { + efree(buf); + } + return 0; + } + + /* now suck data from the stream and stick it into the database */ + if (buf == NULL) { + buf = emalloc(8192); + } + + do { + len = php_stream_read(stm, buf, 8192); + if (len == 0) { + break; + } + SQLPutData(S->stmt, buf, len); + } while (1); + } + } + + if (buf) { + efree(buf); + } + + switch (rc) { + case SQL_SUCCESS: + break; + case SQL_NO_DATA_FOUND: + case SQL_SUCCESS_WITH_INFO: + pdo_odbc_stmt_error("SQLExecute"); + break; + + default: + pdo_odbc_stmt_error("SQLExecute"); + return 0; + } + + SQLRowCount(S->stmt, &row_count); + stmt->row_count = row_count; + + if (!stmt->executed) { + /* do first-time-only definition of bind/mapping stuff */ + SQLSMALLINT colcount; + + /* how many columns do we have ? */ + SQLNumResultCols(S->stmt, &colcount); + + stmt->column_count = (int)colcount; + S->cols = ecalloc(colcount, sizeof(pdo_odbc_column)); + S->going_long = 0; + } + + return 1; +} + +static int odbc_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *param, + enum pdo_param_event event_type TSRMLS_DC) +{ + pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data; + RETCODE rc; + 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 */ + if (param->is_param) { + + switch (event_type) { + case PDO_PARAM_EVT_FREE: + P = param->driver_data; + if (P) { + efree(P); + } + break; + + case PDO_PARAM_EVT_ALLOC: + { + /* figure out what we're doing */ + switch (PDO_PARAM_TYPE(param->param_type)) { + case PDO_PARAM_LOB: + break; + + case PDO_PARAM_STMT: + return 0; + + default: + break; + } + + 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 { + ctype = SQL_C_CHAR; + } + + P = emalloc(sizeof(*P)); + param->driver_data = P; + + P->len = 0; /* is re-populated each EXEC_PRE */ + P->outbuf = NULL; + + P->is_unicode = pdo_odbc_sqltype_is_unicode(S, sqltype); + if (P->is_unicode) { + /* avoid driver auto-translation: we'll do it ourselves */ + ctype = SQL_C_BINARY; + } + + if ((param->param_type & PDO_PARAM_INPUT_OUTPUT) == PDO_PARAM_INPUT_OUTPUT) { + P->paramtype = SQL_PARAM_INPUT_OUTPUT; + } else if (param->max_value_len <= 0) { + P->paramtype = SQL_PARAM_INPUT; + } else { + P->paramtype = SQL_PARAM_OUTPUT; + } + + 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; + if (P->is_unicode) { + P->len *= 2; + } + P->outbuf = emalloc(P->len + (P->is_unicode ? 2: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; + } + + rc = SQLBindParameter(S->stmt, param->paramno+1, + P->paramtype, ctype, sqltype, precision, scale, + P->paramtype == SQL_PARAM_INPUT ? + (SQLPOINTER)param : + P->outbuf, + P->len, + &P->len + ); + + if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) { + return 1; + } + pdo_odbc_stmt_error("SQLBindParameter"); + return 0; + } + + case PDO_PARAM_EVT_EXEC_PRE: + P = param->driver_data; + if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB) { + if (Z_TYPE_P(param->parameter) == IS_RESOURCE) { + php_stream *stm; + php_stream_statbuf sb; + + php_stream_from_zval_no_verify(stm, &param->parameter); + + if (!stm) { + return 0; + } + + if (0 == php_stream_stat(stm, &sb)) { + 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 { + if (P->outbuf) { + P->len = 0; + } else { + P->len = SQL_LEN_DATA_AT_EXEC(0); + } + } + } else { + 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)); + } + } + } else if (Z_TYPE_P(param->parameter) == IS_NULL || PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_NULL) { + P->len = SQL_NULL_DATA; + } else { + convert_to_string(param->parameter); + if (P->outbuf) { + unsigned long ulen; + switch (pdo_odbc_utf82ucs2(stmt, P->is_unicode, + Z_STRVAL_P(param->parameter), + Z_STRLEN_P(param->parameter), + &ulen)) { + case PDO_ODBC_CONV_FAIL: + case PDO_ODBC_CONV_NOT_REQUIRED: + P->len = Z_STRLEN_P(param->parameter); + memcpy(P->outbuf, Z_STRVAL_P(param->parameter), P->len); + break; + case PDO_ODBC_CONV_OK: + P->len = ulen; + memcpy(P->outbuf, S->convbuf, P->len); + break; + } + } else { + P->len = SQL_LEN_DATA_AT_EXEC(Z_STRLEN_P(param->parameter)); + } + } + return 1; + + case PDO_PARAM_EVT_EXEC_POST: + P = param->driver_data; + if (P->outbuf) { + if (P->outbuf) { + unsigned long ulen; + char *srcbuf; + unsigned long srclen; + + switch (P->len) { + case SQL_NULL_DATA: + zval_dtor(param->parameter); + ZVAL_NULL(param->parameter); + break; + default: + convert_to_string(param->parameter); + switch (pdo_odbc_ucs22utf8(stmt, P->is_unicode, P->outbuf, P->len, &ulen)) { + case PDO_ODBC_CONV_FAIL: + /* something fishy, but allow it to come back as binary */ + case PDO_ODBC_CONV_NOT_REQUIRED: + srcbuf = P->outbuf; + srclen = P->len; + break; + case PDO_ODBC_CONV_OK: + srcbuf = S->convbuf; + srclen = ulen; + break; + } + + Z_STRVAL_P(param->parameter) = erealloc(Z_STRVAL_P(param->parameter), srclen+1); + memcpy(Z_STRVAL_P(param->parameter), srcbuf, srclen); + Z_STRLEN_P(param->parameter) = srclen; + Z_STRVAL_P(param->parameter)[srclen] = '\0'; + } + } + } + return 1; + } + } + return 1; +} + +static int odbc_stmt_fetch(pdo_stmt_t *stmt, + enum pdo_fetch_orientation ori, long offset TSRMLS_DC) +{ + RETCODE rc; + SQLSMALLINT odbcori; + pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data; + + switch (ori) { + case PDO_FETCH_ORI_NEXT: odbcori = SQL_FETCH_NEXT; break; + case PDO_FETCH_ORI_PRIOR: odbcori = SQL_FETCH_PRIOR; break; + case PDO_FETCH_ORI_FIRST: odbcori = SQL_FETCH_FIRST; break; + case PDO_FETCH_ORI_LAST: odbcori = SQL_FETCH_LAST; break; + case PDO_FETCH_ORI_ABS: odbcori = SQL_FETCH_ABSOLUTE; break; + case PDO_FETCH_ORI_REL: odbcori = SQL_FETCH_RELATIVE; break; + default: + strcpy(stmt->error_code, "HY106"); + return 0; + } + rc = SQLFetchScroll(S->stmt, odbcori, offset); + + if (rc == SQL_SUCCESS) { + return 1; + } + if (rc == SQL_SUCCESS_WITH_INFO) { + pdo_odbc_stmt_error("SQLFetchScroll"); + return 1; + } + + if (rc == SQL_NO_DATA) { + /* pdo_odbc_stmt_error("SQLFetchScroll"); */ + return 0; + } + + pdo_odbc_stmt_error("SQLFetchScroll"); + + return 0; +} + +static int odbc_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC) +{ + pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data; + struct pdo_column_data *col = &stmt->columns[colno]; + zend_bool dyn = FALSE; + RETCODE rc; + SWORD colnamelen; + SDWORD colsize, displaysize; + + rc = SQLDescribeCol(S->stmt, colno+1, S->cols[colno].colname, + sizeof(S->cols[colno].colname)-1, &colnamelen, + &S->cols[colno].coltype, &colsize, NULL, NULL); + + if (rc != SQL_SUCCESS) { + pdo_odbc_stmt_error("SQLDescribeCol"); + if (rc != SQL_SUCCESS_WITH_INFO) { + return 0; + } + } + + rc = SQLColAttribute(S->stmt, colno+1, + SQL_DESC_DISPLAY_SIZE, + NULL, 0, NULL, &displaysize); + + if (rc != SQL_SUCCESS) { + pdo_odbc_stmt_error("SQLColAttribute"); + if (rc != SQL_SUCCESS_WITH_INFO) { + return 0; + } + } + colsize = displaysize; + + col->maxlen = S->cols[colno].datalen = colsize; + col->namelen = colnamelen; + col->name = estrdup(S->cols[colno].colname); + S->cols[colno].is_unicode = pdo_odbc_sqltype_is_unicode(S, S->cols[colno].coltype); + + /* returning data as a string */ + col->param_type = PDO_PARAM_STR; + + /* tell ODBC to put it straight into our buffer, but only if it + * isn't "long" data, and only if we haven't already bound a long + * column. */ + if (colsize < 256 && !S->going_long) { + S->cols[colno].data = emalloc(colsize+1); + S->cols[colno].is_long = 0; + + rc = SQLBindCol(S->stmt, colno+1, + S->cols[colno].is_unicode ? SQL_C_BINARY : 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; + } + } else { + /* allocate a smaller buffer to keep around for smaller + * "long" columns */ + S->cols[colno].data = emalloc(256); + S->going_long = 1; + S->cols[colno].is_long = 1; + } + + return 1; +} + +static int odbc_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, unsigned long *len, int *caller_frees TSRMLS_DC) +{ + pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data; + pdo_odbc_column *C = &S->cols[colno]; + unsigned long ulen; + + /* if it is a column containing "long" data, perform late binding now */ + if (C->is_long) { + unsigned long alloced = 4096; + unsigned long used = 0; + char *buf; + RETCODE rc; + + /* fetch it into C->data, which is allocated with a length + * of 256 bytes; if there is more to be had, we then allocate + * bigger buffer for the caller to free */ + + rc = SQLGetData(S->stmt, colno+1, C->is_unicode ? SQL_C_BINARY : SQL_C_CHAR, C->data, + 256, &C->fetched_len); + + if (rc == SQL_SUCCESS) { + /* all the data fit into our little buffer; + * jump down to the generic bound data case */ + goto in_data; + } + + if (rc == SQL_SUCCESS_WITH_INFO) { + /* promote up to a bigger buffer */ + + if (C->fetched_len != SQL_NO_TOTAL) { + /* use size suggested by the driver, if it knows it */ + alloced = C->fetched_len + 1; + } + + buf = emalloc(alloced); + memcpy(buf, C->data, 256); + used = 255; /* not 256; the driver NUL terminated the buffer */ + + do { + C->fetched_len = 0; + rc = SQLGetData(S->stmt, colno+1, SQL_C_CHAR, + buf + used, alloced - used, + &C->fetched_len); + + if (rc == SQL_NO_DATA) { + /* we got the lot */ + break; + } else if (rc != SQL_SUCCESS) { + pdo_odbc_stmt_error("SQLGetData"); + if (rc != SQL_SUCCESS_WITH_INFO) { + break; + } + } + + if (C->fetched_len == SQL_NO_TOTAL) { + used += alloced - used; + } else { + used += C->fetched_len; + } + + if (rc == SQL_SUCCESS) { + /* this was the final fetch */ + break; + } + + /* we need to fetch another chunk; resize the + * buffer */ + alloced *= 2; + buf = erealloc(buf, alloced); + } while (1); + + /* size down */ + if (used < alloced - 1024) { + alloced = used+1; + buf = erealloc(buf, used+1); + } + buf[used] = '\0'; + *ptr = buf; + *caller_frees = 1; + *len = used; + if (C->is_unicode) { + goto unicode_conv; + } + return 1; + } + + /* something went caca */ + *ptr = NULL; + *len = 0; + return 1; + } + +in_data: + /* check the indicator to ensure that the data is intact */ + if (C->fetched_len == SQL_NULL_DATA) { + /* A NULL value */ + *ptr = NULL; + *len = 0; + return 1; + } else if (C->fetched_len >= 0) { + /* it was stored perfectly */ + *ptr = C->data; + *len = C->fetched_len; + if (C->is_unicode) { + goto unicode_conv; + } + return 1; + } else { + /* no data? */ + *ptr = NULL; + *len = 0; + return 1; + } + + unicode_conv: + switch (pdo_odbc_ucs22utf8(stmt, C->is_unicode, *ptr, *len, &ulen)) { + case PDO_ODBC_CONV_FAIL: + /* oh well. They can have the binary version of it */ + case PDO_ODBC_CONV_NOT_REQUIRED: + /* shouldn't happen... */ + return 1; + + case PDO_ODBC_CONV_OK: + if (*caller_frees) { + efree(*ptr); + } + *ptr = emalloc(ulen + 1); + *len = ulen; + memcpy(*ptr, S->convbuf, ulen+1); + *caller_frees = 1; + return 1; + } + return 1; +} + +static int odbc_stmt_set_param(pdo_stmt_t *stmt, long attr, zval *val TSRMLS_DC) +{ + SQLRETURN rc; + pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data; + + switch (attr) { + case PDO_ATTR_CURSOR_NAME: + convert_to_string(val); + rc = SQLSetCursorName(S->stmt, Z_STRVAL_P(val), Z_STRLEN_P(val)); + + if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) { + return 1; + } + pdo_odbc_stmt_error("SQLSetCursorName"); + return 0; + + case PDO_ODBC_ATTR_ASSUME_UTF8: + S->assume_utf8 = zval_is_true(val); + return 0; + default: + strcpy(S->einfo.last_err_msg, "Unknown Attribute"); + S->einfo.what = "setAttribute"; + strcpy(S->einfo.last_state, "IM0001"); + return -1; + } +} + +static int odbc_stmt_get_attr(pdo_stmt_t *stmt, long attr, zval *val TSRMLS_DC) +{ + SQLRETURN rc; + pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data; + + switch (attr) { + case PDO_ATTR_CURSOR_NAME: + { + char buf[256]; + SQLSMALLINT len = 0; + rc = SQLGetCursorName(S->stmt, buf, sizeof(buf), &len); + + if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) { + ZVAL_STRINGL(val, buf, len, 1); + return 1; + } + pdo_odbc_stmt_error("SQLGetCursorName"); + return 0; + } + + case PDO_ODBC_ATTR_ASSUME_UTF8: + ZVAL_BOOL(val, S->assume_utf8 ? 1 : 0); + return 0; + + default: + strcpy(S->einfo.last_err_msg, "Unknown Attribute"); + S->einfo.what = "getAttribute"; + strcpy(S->einfo.last_state, "IM0001"); + return -1; + } +} + +static int odbc_stmt_next_rowset(pdo_stmt_t *stmt TSRMLS_DC) +{ + SQLRETURN rc; + SQLSMALLINT colcount; + pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data; + + /* 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) { + return 0; + } + + free_cols(stmt, S TSRMLS_CC); + /* how many columns do we have ? */ + SQLNumResultCols(S->stmt, &colcount); + stmt->column_count = (int)colcount; + S->cols = ecalloc(colcount, sizeof(pdo_odbc_column)); + S->going_long = 0; + + return 1; +} + +struct pdo_stmt_methods odbc_stmt_methods = { + odbc_stmt_dtor, + odbc_stmt_execute, + odbc_stmt_fetch, + odbc_stmt_describe, + odbc_stmt_get_col, + odbc_stmt_param_hook, + odbc_stmt_set_param, + odbc_stmt_get_attr, /* get attr */ + NULL, /* get column meta */ + odbc_stmt_next_rowset +}; + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ http://cvs.php.net/viewvc.cgi/php-src/ext/pdo_odbc/pdo_odbc.c?r1=1.14.2.7.2.2.2.2&r2=1.14.2.7.2.2.2.3&diff_format=u Index: php-src/ext/pdo_odbc/pdo_odbc.c diff -u php-src/ext/pdo_odbc/pdo_odbc.c:1.14.2.7.2.2.2.2 php-src/ext/pdo_odbc/pdo_odbc.c:1.14.2.7.2.2.2.3 --- php-src/ext/pdo_odbc/pdo_odbc.c:1.14.2.7.2.2.2.2 Mon Dec 31 07:17:12 2007 +++ php-src/ext/pdo_odbc/pdo_odbc.c Thu Mar 13 16:55:09 2008 @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: pdo_odbc.c,v 1.14.2.7.2.2.2.2 2007/12/31 07:17:12 sebastian Exp $ */ +/* $Id: pdo_odbc.c,v 1.14.2.7.2.2.2.3 2008/03/13 16:55:09 auroraeosrose Exp $ */ #ifdef HAVE_CONFIG_H #include "config.h" @@ -134,6 +134,7 @@ #endif REGISTER_PDO_CLASS_CONST_LONG("ODBC_ATTR_USE_CURSOR_LIBRARY", PDO_ODBC_ATTR_USE_CURSOR_LIBRARY); + REGISTER_PDO_CLASS_CONST_LONG("ODBC_ATTR_ASSUME_UTF8", PDO_ODBC_ATTR_ASSUME_UTF8); REGISTER_PDO_CLASS_CONST_LONG("ODBC_SQL_USE_IF_NEEDED", SQL_CUR_USE_IF_NEEDED); REGISTER_PDO_CLASS_CONST_LONG("ODBC_SQL_USE_DRIVER", SQL_CUR_USE_DRIVER); REGISTER_PDO_CLASS_CONST_LONG("ODBC_SQL_USE_ODBC", SQL_CUR_USE_ODBC); http://cvs.php.net/viewvc.cgi/php-src/ext/pdo_odbc/php_pdo_odbc_int.h?r1=1.9.2.1.2.2.2.1&r2=1.9.2.1.2.2.2.2&diff_format=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.9.2.1.2.2.2.1 php-src/ext/pdo_odbc/php_pdo_odbc_int.h:1.9.2.1.2.2.2.2 --- php-src/ext/pdo_odbc/php_pdo_odbc_int.h:1.9.2.1.2.2.2.1 Mon Dec 31 07:17:12 2007 +++ php-src/ext/pdo_odbc/php_pdo_odbc_int.h Thu Mar 13 16:55:09 2008 @@ -1,185 +1,195 @@ -/* - +----------------------------------------------------------------------+ - | PHP Version 5 | - +----------------------------------------------------------------------+ - | Copyright (c) 1997-2008 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 | - | available through the world-wide-web at the following url: | - | http://www.php.net/license/3_0.txt. | - | If you did not receive a copy of the PHP license and are unable to | - | obtain it through the world-wide-web, please send a note to | - | license@php.net so we can mail you a copy immediately. | - +----------------------------------------------------------------------+ - | Author: Wez Furlong <wez@php.net> | - +----------------------------------------------------------------------+ -*/ - -/* $Id: php_pdo_odbc_int.h,v 1.9.2.1.2.2.2.1 2007/12/31 07:17:12 sebastian Exp $ */ - -#ifdef PHP_WIN32 -# define PDO_ODBC_TYPE "Win32" -#endif - -#ifndef PDO_ODBC_TYPE -# warning Please fix configure to give your ODBC libraries a name -# define PDO_ODBC_TYPE "Unknown" -#endif - -/* {{{ Roll a dice, pick a header at random... */ -#if HAVE_SQLCLI1_H -# include <sqlcli1.h> -# if defined(DB268K) && HAVE_LIBRARYMANAGER_H -# include <LibraryManager.h> -# endif -#endif - -#if HAVE_ODBC_H -# include <odbc.h> -#endif - -#if HAVE_IODBC_H -# include <iodbc.h> -#endif - -#if HAVE_SQLUNIX_H && !defined(PHP_WIN32) -# include <sqlunix.h> -#endif - -#if HAVE_SQLTYPES_H -# include <sqltypes.h> -#endif - -#if HAVE_SQLUCODE_H -# include <sqlucode.h> -#endif - -#if HAVE_SQL_H -# include <sql.h> -#endif - -#if HAVE_ISQL_H -# include <isql.h> -#endif - -#if HAVE_SQLEXT_H -# include <sqlext.h> -#endif - -#if HAVE_ISQLEXT_H -# include <isqlext.h> -#endif - -#if HAVE_UDBCEXT_H -# include <udbcext.h> -#endif - -#if HAVE_CLI0CORE_H -# include <cli0core.h> -#endif - -#if HAVE_CLI0EXT1_H -# include <cli0ext.h> -#endif - -#if HAVE_CLI0CLI_H -# include <cli0cli.h> -#endif - -#if HAVE_CLI0DEFS_H -# include <cli0defs.h> -#endif - -#if HAVE_CLI0ENV_H -# include <cli0env.h> -#endif - -#if HAVE_ODBCSDK_H -# include <odbcsdk.h> -#endif - -/* }}} */ - -/* {{{ Figure out the type for handles */ -#if !defined(HENV) && !defined(SQLHENV) && defined(SQLHANDLE) -# define PDO_ODBC_HENV SQLHANDLE -# define PDO_ODBC_HDBC SQLHANDLE -# define PDO_ODBC_HSTMT SQLHANDLE -#elif !defined(HENV) && (defined(SQLHENV) || defined(DB2CLI_VER)) -# define PDO_ODBC_HENV SQLHENV -# define PDO_ODBC_HDBC SQLHDBC -# define PDO_ODBC_HSTMT SQLHSTMT -#else -# define PDO_ODBC_HENV HENV -# define PDO_ODBC_HDBC HDBC -# define PDO_ODBC_HSTMT HSTMT -#endif -/* }}} */ - -typedef struct { - char last_state[6]; - char last_err_msg[SQL_MAX_MESSAGE_LENGTH]; - SDWORD last_error; - const char *file, *what; - int line; -} pdo_odbc_errinfo; - -typedef struct { - PDO_ODBC_HENV env; - PDO_ODBC_HDBC dbc; - pdo_odbc_errinfo einfo; -} pdo_odbc_db_handle; - -typedef struct { - char *data; - unsigned long datalen; - long fetched_len; - SWORD coltype; - char colname[128]; - unsigned is_long; -} pdo_odbc_column; - -typedef struct { - PDO_ODBC_HSTMT stmt; - pdo_odbc_column *cols; - pdo_odbc_db_handle *H; - pdo_odbc_errinfo einfo; - unsigned going_long:1; - unsigned _spare:31; -} pdo_odbc_stmt; - -typedef struct { - SQLINTEGER len; - SQLSMALLINT paramtype; - char *outbuf; -} pdo_odbc_param; - -extern pdo_driver_t pdo_odbc_driver; -extern struct pdo_stmt_methods odbc_stmt_methods; - -void pdo_odbc_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, PDO_ODBC_HSTMT statement, char *what, const char *file, int line TSRMLS_DC); -#define pdo_odbc_drv_error(what) pdo_odbc_error(dbh, NULL, SQL_NULL_HSTMT, what, __FILE__, __LINE__ TSRMLS_CC) -#define pdo_odbc_stmt_error(what) pdo_odbc_error(stmt->dbh, stmt, SQL_NULL_HSTMT, what, __FILE__, __LINE__ TSRMLS_CC) -#define pdo_odbc_doer_error(what) pdo_odbc_error(dbh, NULL, stmt, what, __FILE__, __LINE__ TSRMLS_CC) - -void pdo_odbc_init_error_table(void); -void pdo_odbc_fini_error_table(void); - -#ifdef SQL_ATTR_CONNECTION_POOLING -extern SQLUINTEGER pdo_odbc_pool_on; -extern SQLUINTEGER pdo_odbc_pool_mode; -#endif - -enum { - PDO_ODBC_ATTR_USE_CURSOR_LIBRARY = PDO_ATTR_DRIVER_SPECIFIC, -}; - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2008 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 | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_0.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Wez Furlong <wez@php.net> | + +----------------------------------------------------------------------+ +*/ + +/* $Id: php_pdo_odbc_int.h,v 1.9.2.1.2.2.2.2 2008/03/13 16:55:09 auroraeosrose Exp $ */ + +#ifdef PHP_WIN32 +# define PDO_ODBC_TYPE "Win32" +#endif + +#ifndef PDO_ODBC_TYPE +# warning Please fix configure to give your ODBC libraries a name +# define PDO_ODBC_TYPE "Unknown" +#endif + +/* {{{ Roll a dice, pick a header at random... */ +#if HAVE_SQLCLI1_H +# include <sqlcli1.h> +# if defined(DB268K) && HAVE_LIBRARYMANAGER_H +# include <LibraryManager.h> +# endif +#endif + +#if HAVE_ODBC_H +# include <odbc.h> +#endif + +#if HAVE_IODBC_H +# include <iodbc.h> +#endif + +#if HAVE_SQLUNIX_H && !defined(PHP_WIN32) +# include <sqlunix.h> +#endif + +#if HAVE_SQLTYPES_H +# include <sqltypes.h> +#endif + +#if HAVE_SQLUCODE_H +# include <sqlucode.h> +#endif + +#if HAVE_SQL_H +# include <sql.h> +#endif + +#if HAVE_ISQL_H +# include <isql.h> +#endif + +#if HAVE_SQLEXT_H +# include <sqlext.h> +#endif + +#if HAVE_ISQLEXT_H +# include <isqlext.h> +#endif + +#if HAVE_UDBCEXT_H +# include <udbcext.h> +#endif + +#if HAVE_CLI0CORE_H +# include <cli0core.h> +#endif + +#if HAVE_CLI0EXT1_H +# include <cli0ext.h> +#endif + +#if HAVE_CLI0CLI_H +# include <cli0cli.h> +#endif + +#if HAVE_CLI0DEFS_H +# include <cli0defs.h> +#endif + +#if HAVE_CLI0ENV_H +# include <cli0env.h> +#endif + +#if HAVE_ODBCSDK_H +# include <odbcsdk.h> +#endif + +/* }}} */ + +/* {{{ Figure out the type for handles */ +#if !defined(HENV) && !defined(SQLHENV) && defined(SQLHANDLE) +# define PDO_ODBC_HENV SQLHANDLE +# define PDO_ODBC_HDBC SQLHANDLE +# define PDO_ODBC_HSTMT SQLHANDLE +#elif !defined(HENV) && (defined(SQLHENV) || defined(DB2CLI_VER)) +# define PDO_ODBC_HENV SQLHENV +# define PDO_ODBC_HDBC SQLHDBC +# define PDO_ODBC_HSTMT SQLHSTMT +#else +# define PDO_ODBC_HENV HENV +# define PDO_ODBC_HDBC HDBC +# define PDO_ODBC_HSTMT HSTMT +#endif +/* }}} */ + +typedef struct { + char last_state[6]; + char last_err_msg[SQL_MAX_MESSAGE_LENGTH]; + SDWORD last_error; + const char *file, *what; + int line; +} pdo_odbc_errinfo; + +typedef struct { + PDO_ODBC_HENV env; + PDO_ODBC_HDBC dbc; + pdo_odbc_errinfo einfo; + unsigned assume_utf8:1; + unsigned _spare:31; +} pdo_odbc_db_handle; + +typedef struct { + char *data; + unsigned long datalen; + long fetched_len; + SWORD coltype; + char colname[128]; + unsigned is_long; + unsigned is_unicode:1; + unsigned _spare:31; +} pdo_odbc_column; + +typedef struct { + PDO_ODBC_HSTMT stmt; + pdo_odbc_column *cols; + pdo_odbc_db_handle *H; + pdo_odbc_errinfo einfo; + char *convbuf; + unsigned long convbufsize; + unsigned going_long:1; + unsigned assume_utf8:1; + unsigned _spare:30; +} pdo_odbc_stmt; + +typedef struct { + SQLINTEGER len; + SQLSMALLINT paramtype; + char *outbuf; + unsigned is_unicode:1; + unsigned _spare:31; +} pdo_odbc_param; + +extern pdo_driver_t pdo_odbc_driver; +extern struct pdo_stmt_methods odbc_stmt_methods; + +void pdo_odbc_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, PDO_ODBC_HSTMT statement, char *what, const char *file, int line TSRMLS_DC); +#define pdo_odbc_drv_error(what) pdo_odbc_error(dbh, NULL, SQL_NULL_HSTMT, what, __FILE__, __LINE__ TSRMLS_CC) +#define pdo_odbc_stmt_error(what) pdo_odbc_error(stmt->dbh, stmt, SQL_NULL_HSTMT, what, __FILE__, __LINE__ TSRMLS_CC) +#define pdo_odbc_doer_error(what) pdo_odbc_error(dbh, NULL, stmt, what, __FILE__, __LINE__ TSRMLS_CC) + +void pdo_odbc_init_error_table(void); +void pdo_odbc_fini_error_table(void); + +#ifdef SQL_ATTR_CONNECTION_POOLING +extern SQLUINTEGER pdo_odbc_pool_on; +extern SQLUINTEGER pdo_odbc_pool_mode; +#endif + +enum { + PDO_ODBC_ATTR_USE_CURSOR_LIBRARY = PDO_ATTR_DRIVER_SPECIFIC, + PDO_ODBC_ATTR_ASSUME_UTF8 /* assume that input strings are UTF-8 when feeding data to unicode columns */ +}; + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */
« previous php.cvs (#49098) next »