Skip to content

Commit d6c4dee

Browse files
committed
ODBC (v3 ish) driver for PDO.
Will not build under unix yet.
1 parent 1b1ced5 commit d6c4dee

File tree

9 files changed

+831
-0
lines changed

9 files changed

+831
-0
lines changed

ext/pdo_odbc/CREDITS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
ODBC driver for PDO
2+
Wez Furlong

ext/pdo_odbc/EXPERIMENTAL

Whitespace-only changes.

ext/pdo_odbc/config.m4

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
dnl $Id$
2+
dnl config.m4 for extension pdo_odbc
3+
4+
PHP_ARG_WITH(pdo_odbc, for pdo_odbc support,
5+
[ --with-pdo_odbc Include pdo_odbc support])
6+
7+
if test "$PHP_PDO_ODBC" != "no"; then
8+
PHP_NEW_EXTENSION(pdo_odbc, pdo_odbc.c odbc_driver.c odbc_stmt.c, $ext_shared)
9+
fi

ext/pdo_odbc/config.w32

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// $Id$
2+
// vim:ft=javascript
3+
4+
ARG_WITH("pdo-odbc", "ODBC support for PDO", "no");
5+
6+
if (PHP_PDO_ODBC != "no") {
7+
if (CHECK_LIB("odbc32.lib", "pdo_odbc") && CHECK_LIB("odbccp32.lib", "pdo_odbc")) {
8+
EXTENSION("pdo_odbc", "pdo_odbc.c odbc_driver.c odbc_stmt.c");
9+
CHECK_HEADER_ADD_INCLUDE('sql.h', 'CFLAGS_PDO_ODBC');
10+
CHECK_HEADER_ADD_INCLUDE('sqlext.h', 'CFLAGS_PDO_ODBC');
11+
ADD_FLAG('CFLAGS_PDO_ODBC', "/I ..\\pecl");
12+
}
13+
ADD_EXTENSION_DEP('pdo_odbc', 'pdo');
14+
}
15+

ext/pdo_odbc/odbc_driver.c

Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
/*
2+
+----------------------------------------------------------------------+
3+
| PHP Version 5 |
4+
+----------------------------------------------------------------------+
5+
| Copyright (c) 1997-2004 The PHP Group |
6+
+----------------------------------------------------------------------+
7+
| This source file is subject to version 3.0 of the PHP license, |
8+
| that is bundled with this package in the file LICENSE, and is |
9+
| available through the world-wide-web at the following url: |
10+
| http://www.php.net/license/3_0.txt. |
11+
| If you did not receive a copy of the PHP license and are unable to |
12+
| obtain it through the world-wide-web, please send a note to |
13+
| [email protected] so we can mail you a copy immediately. |
14+
+----------------------------------------------------------------------+
15+
| Author: Wez Furlong <[email protected]> |
16+
+----------------------------------------------------------------------+
17+
*/
18+
19+
/* $Id$ */
20+
21+
#ifdef HAVE_CONFIG_H
22+
#include "config.h"
23+
#endif
24+
25+
#include "php.h"
26+
#include "php_ini.h"
27+
#include "ext/standard/info.h"
28+
#include "pdo/php_pdo.h"
29+
#include "pdo/php_pdo_driver.h"
30+
#include "php_pdo_odbc.h"
31+
#include "php_pdo_odbc_int.h"
32+
33+
void _odbc_error(pdo_dbh_t *dbh, char *what, PDO_ODBC_HSTMT stmt, const char *file, int line TSRMLS_DC) /* {{{ */
34+
{
35+
RETCODE rc;
36+
SWORD errmsgsize;
37+
pdo_odbc_db_handle *H = (pdo_odbc_db_handle*)dbh->driver_data;
38+
39+
rc = SQLError(H->env, H->dbc, stmt, H->last_state, &H->last_error,
40+
H->last_err_msg, sizeof(H->last_err_msg)-1, &errmsgsize);
41+
42+
H->last_err_msg[errmsgsize] = '\0';
43+
44+
php_error_docref(NULL TSRMLS_CC, E_WARNING, "(%s:%d) %s: %d %s [SQL State %s]",
45+
file, line, what, H->last_error, H->last_err_msg, H->last_state);
46+
}
47+
/* }}} */
48+
49+
static int odbc_handle_closer(pdo_dbh_t *dbh TSRMLS_DC)
50+
{
51+
pdo_odbc_db_handle *H = (pdo_odbc_db_handle*)dbh->driver_data;
52+
53+
if (H->dbc != SQL_NULL_HANDLE) {
54+
SQLEndTran(SQL_HANDLE_DBC, H->dbc, SQL_ROLLBACK);
55+
}
56+
57+
SQLFreeHandle(SQL_HANDLE_STMT, H->dbc);
58+
SQLFreeHandle(SQL_HANDLE_ENV, H->env);
59+
pefree(H, dbh->is_persistent);
60+
61+
return 0;
62+
}
63+
64+
static int odbc_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_len, pdo_stmt_t *stmt TSRMLS_DC)
65+
{
66+
RETCODE rc;
67+
pdo_odbc_db_handle *H = (pdo_odbc_db_handle *)dbh->driver_data;
68+
pdo_odbc_stmt *S = ecalloc(1, sizeof(*S));
69+
70+
S->H = H;
71+
72+
rc = SQLAllocHandle(SQL_HANDLE_STMT, H->dbc, &S->stmt);
73+
74+
if (rc == SQL_INVALID_HANDLE || rc == SQL_ERROR) {
75+
efree(S);
76+
odbc_error(dbh, "SQLAllocStmt", SQL_NULL_HSTMT);
77+
return 0;
78+
}
79+
80+
rc = SQLPrepare(S->stmt, (char*)sql, SQL_NTS);
81+
82+
if (rc != SQL_SUCCESS) {
83+
odbc_error(dbh, "SQLPrepare", S->stmt);
84+
}
85+
86+
if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
87+
SQLFreeHandle(SQL_HANDLE_STMT, S->stmt);
88+
return 0;
89+
}
90+
91+
stmt->driver_data = S;
92+
stmt->methods = &odbc_stmt_methods;
93+
94+
return 1;
95+
}
96+
97+
static int odbc_handle_doer(pdo_dbh_t *dbh, const char *sql TSRMLS_DC)
98+
{
99+
pdo_odbc_db_handle *H = (pdo_odbc_db_handle *)dbh->driver_data;
100+
101+
return 0;
102+
}
103+
104+
static int odbc_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, char **quoted, int *quotedlen TSRMLS_DC)
105+
{
106+
pdo_odbc_db_handle *H = (pdo_odbc_db_handle *)dbh->driver_data;
107+
108+
return 0;
109+
}
110+
111+
static int odbc_handle_begin(pdo_dbh_t *dbh TSRMLS_DC)
112+
{
113+
/* with ODBC, there is nothing special to be done */
114+
return 1;
115+
}
116+
117+
static int odbc_handle_commit(pdo_dbh_t *dbh TSRMLS_DC)
118+
{
119+
pdo_odbc_db_handle *H = (pdo_odbc_db_handle *)dbh->driver_data;
120+
RETCODE rc;
121+
122+
rc = SQLEndTran(SQL_HANDLE_DBC, H->dbc, SQL_COMMIT);
123+
124+
if (rc != SQL_SUCCESS) {
125+
odbc_error(dbh, "SQLEndTran: Commit", SQL_NULL_HSTMT);
126+
127+
if (rc != SQL_SUCCESS_WITH_INFO) {
128+
return 0;
129+
}
130+
}
131+
return 1;
132+
}
133+
134+
static int odbc_handle_rollback(pdo_dbh_t *dbh TSRMLS_DC)
135+
{
136+
pdo_odbc_db_handle *H = (pdo_odbc_db_handle *)dbh->driver_data;
137+
RETCODE rc;
138+
139+
rc = SQLEndTran(SQL_HANDLE_DBC, H->dbc, SQL_ROLLBACK);
140+
141+
if (rc != SQL_SUCCESS) {
142+
odbc_error(dbh, "SQLEndTran: Rollback", SQL_NULL_HSTMT);
143+
144+
if (rc != SQL_SUCCESS_WITH_INFO) {
145+
return 0;
146+
}
147+
}
148+
return 1;
149+
150+
}
151+
152+
153+
154+
static struct pdo_dbh_methods odbc_methods = {
155+
odbc_handle_closer,
156+
odbc_handle_preparer,
157+
odbc_handle_doer,
158+
odbc_handle_quoter,
159+
odbc_handle_begin,
160+
odbc_handle_commit,
161+
odbc_handle_rollback,
162+
};
163+
164+
static int pdo_odbc_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_DC) /* {{{ */
165+
{
166+
pdo_odbc_db_handle *H;
167+
RETCODE rc;
168+
int use_direct = 0;
169+
170+
H = pecalloc(1, sizeof(*H), dbh->is_persistent);
171+
172+
dbh->driver_data = H;
173+
174+
SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &H->env);
175+
rc = SQLSetEnvAttr(H->env, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);
176+
177+
if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
178+
odbc_error(dbh, "SQLSetEnvAttr: ODBC3", SQL_NULL_HSTMT);
179+
odbc_handle_closer(dbh TSRMLS_CC);
180+
return 0;
181+
}
182+
183+
rc = SQLAllocHandle(SQL_HANDLE_DBC, H->env, &H->dbc);
184+
if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
185+
odbc_error(dbh, "SQLAllocHandle (DBC)", SQL_NULL_HSTMT);
186+
odbc_handle_closer(dbh TSRMLS_CC);
187+
return 0;
188+
}
189+
190+
if (!dbh->auto_commit) {
191+
rc = SQLSetConnectAttr(H->dbc, SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF, SQL_IS_UINTEGER);
192+
if (rc != SQL_SUCCESS) {
193+
odbc_error(dbh, "SQLSetConnectAttr AUTOCOMMIT = OFF", SQL_NULL_HSTMT);
194+
odbc_handle_closer(dbh TSRMLS_CC);
195+
return 0;
196+
}
197+
}
198+
199+
if (strchr(dbh->data_source, ';')) {
200+
char dsnbuf[1024];
201+
short dsnbuflen;
202+
203+
use_direct = 1;
204+
205+
/* Force UID and PWD to be set in the DSN */
206+
if (*dbh->username && !strstr(dbh->data_source, "uid") && !strstr(dbh->data_source, "UID")) {
207+
char *dsn = pemalloc(strlen(dbh->data_source) + strlen(dbh->username) + strlen(dbh->password) + sizeof(";UID=;PWD="), dbh->is_persistent);
208+
sprintf(dsn, "%s;UID=%s;PWD=%s", dbh->data_source, dbh->username, dbh->password);
209+
pefree((char*)dbh->data_source, dbh->is_persistent);
210+
dbh->data_source = dsn;
211+
}
212+
213+
rc = SQLDriverConnect(H->dbc, NULL, (char*)dbh->data_source, strlen(dbh->data_source),
214+
dsnbuf, sizeof(dsnbuf)-1, &dsnbuflen, SQL_DRIVER_NOPROMPT);
215+
}
216+
if (!use_direct) {
217+
rc = SQLConnect(H->dbc, (char*)dbh->data_source, SQL_NTS, dbh->username, SQL_NTS, dbh->password, SQL_NTS);
218+
}
219+
220+
if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
221+
odbc_error(dbh, use_direct ? "SQLDriverConnect" : "SQLConnect", SQL_NULL_HSTMT);
222+
odbc_handle_closer(dbh TSRMLS_CC);
223+
return 0;
224+
}
225+
226+
/* TODO: if we want to play nicely, we should check to see if the driver supports ODBC v3 or not */
227+
228+
dbh->methods = &odbc_methods;
229+
dbh->alloc_own_columns = 1;
230+
dbh->supports_placeholders = 1;
231+
232+
return 1;
233+
}
234+
/* }}} */
235+
236+
pdo_driver_t pdo_odbc_driver = {
237+
PDO_DRIVER_HEADER(odbc),
238+
pdo_odbc_handle_factory
239+
};
240+
241+
/*
242+
* Local variables:
243+
* tab-width: 4
244+
* c-basic-offset: 4
245+
* End:
246+
* vim600: noet sw=4 ts=4 fdm=marker
247+
* vim<600: noet sw=4 ts=4
248+
*/

0 commit comments

Comments
 (0)