30
30
#include "php_pdo_odbc.h"
31
31
#include "php_pdo_odbc_int.h"
32
32
33
- void _odbc_error (pdo_dbh_t * dbh , char * what , PDO_ODBC_HSTMT stmt , const char * file , int line TSRMLS_DC ) /* {{{ */
33
+ static struct {
34
+ char state [6 ];
35
+ enum pdo_error err ;
36
+ } odbc_to_pdo_err_map [] = {
37
+ /* this table maps ODBC V3 SQLSTATE codes to PDO_ERR codes */
38
+ { "42S01" , PDO_ERR_ALREADY_EXISTS },
39
+ { "42S11" , PDO_ERR_ALREADY_EXISTS },
40
+ { "42S21" , PDO_ERR_ALREADY_EXISTS },
41
+ { "IM001" , PDO_ERR_NOT_IMPLEMENTED },
42
+ { "42S22" , PDO_ERR_NOT_FOUND },
43
+ { "42S12" , PDO_ERR_NOT_FOUND },
44
+ { "42S02" , PDO_ERR_NOT_FOUND },
45
+ { "42000" , PDO_ERR_SYNTAX },
46
+ { "23000" , PDO_ERR_CONSTRAINT },
47
+ { "22025" , PDO_ERR_SYNTAX },
48
+ { "22019" , PDO_ERR_SYNTAX },
49
+ { "22018" , PDO_ERR_SYNTAX },
50
+ { "08S01" , PDO_ERR_DISCONNECTED },
51
+ { "01S07" , PDO_ERR_TRUNCATED },
52
+
53
+ };
54
+
55
+ static HashTable err_hash ;
56
+
57
+ void pdo_odbc_fini_error_table (void )
58
+ {
59
+ zend_hash_destroy (& err_hash );
60
+ }
61
+
62
+ void pdo_odbc_init_error_table (void )
63
+ {
64
+ int i ;
65
+
66
+ zend_hash_init (& err_hash , 0 , NULL , NULL , 1 );
67
+
68
+ for (i = 0 ; i < sizeof (odbc_to_pdo_err_map )/sizeof (odbc_to_pdo_err_map [0 ]); i ++ ) {
69
+ zend_hash_add (& err_hash , odbc_to_pdo_err_map [i ].state , sizeof (odbc_to_pdo_err_map [i ].state ),
70
+ & odbc_to_pdo_err_map [i ].err , sizeof (odbc_to_pdo_err_map [i ].err ), NULL );
71
+ }
72
+ }
73
+
74
+ static enum pdo_error pdo_odbc_map_error (char * state )
75
+ {
76
+ enum pdo_error * p_err ;
77
+ if (SUCCESS == zend_hash_find (& err_hash , state , sizeof (odbc_to_pdo_err_map [0 ].state ), (void * * )& p_err )) {
78
+ return * p_err ;
79
+ }
80
+ return PDO_ERR_CANT_MAP ;
81
+ }
82
+
83
+ static int pdo_odbc_fetch_error_func (pdo_dbh_t * dbh , pdo_stmt_t * stmt , zval * info TSRMLS_DC )
84
+ {
85
+ pdo_odbc_db_handle * H = (pdo_odbc_db_handle * )dbh -> driver_data ;
86
+ pdo_odbc_errinfo * einfo = & H -> einfo ;
87
+ pdo_odbc_stmt * S = NULL ;
88
+ char * message = NULL ;
89
+
90
+ if (stmt ) {
91
+ S = (pdo_odbc_stmt * )stmt -> driver_data ;
92
+ einfo = & S -> einfo ;
93
+ }
94
+
95
+ spprintf (& message , 0 , "%s: %d %s [SQL State %s] (%s:%d)" ,
96
+ einfo -> what , einfo -> last_error , einfo -> last_err_msg , einfo -> last_state , einfo -> file , einfo -> line );
97
+
98
+ add_next_index_long (info , einfo -> last_error );
99
+ add_next_index_string (info , message , 0 );
100
+ add_next_index_string (info , einfo -> last_state , 1 );
101
+
102
+ return 1 ;
103
+ }
104
+
105
+
106
+ 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 ) /* {{{ */
34
107
{
35
108
RETCODE rc ;
36
109
SWORD errmsgsize ;
37
110
pdo_odbc_db_handle * H = (pdo_odbc_db_handle * )dbh -> driver_data ;
111
+ pdo_odbc_errinfo * einfo = & H -> einfo ;
112
+ pdo_odbc_stmt * S = NULL ;
113
+ enum pdo_error * pdo_err = & dbh -> error_code ;
114
+
115
+ if (stmt ) {
116
+ S = (pdo_odbc_stmt * )stmt -> driver_data ;
38
117
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 );
118
+ einfo = & S -> einfo ;
119
+ pdo_err = & stmt -> error_code ;
120
+ }
41
121
42
- H -> last_err_msg [errmsgsize ] = '\0' ;
122
+ if (statement == SQL_NULL_HSTMT && S ) {
123
+ statement = S -> stmt ;
124
+ }
43
125
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 );
126
+ rc = SQLError (H -> env , H -> dbc , statement , einfo -> last_state , & einfo -> last_error ,
127
+ einfo -> last_err_msg , sizeof (einfo -> last_err_msg )- 1 , & errmsgsize );
128
+
129
+ einfo -> last_err_msg [errmsgsize ] = '\0' ;
130
+ einfo -> file = file ;
131
+ einfo -> line = line ;
132
+ einfo -> what = what ;
133
+
134
+ * pdo_err = pdo_odbc_map_error (einfo -> last_state );
135
+
136
+ if (!dbh -> methods ) {
137
+ zend_throw_exception_ex (php_pdo_get_exception (), * pdo_err TSRMLS_CC , "%s: %d %s [SQL State %s]" ,
138
+ what , einfo -> last_error , einfo -> last_err_msg , einfo -> last_state );
139
+ }
46
140
}
47
141
/* }}} */
48
142
@@ -54,7 +148,7 @@ static int odbc_handle_closer(pdo_dbh_t *dbh TSRMLS_DC)
54
148
SQLEndTran (SQL_HANDLE_DBC , H -> dbc , SQL_ROLLBACK );
55
149
}
56
150
57
- SQLFreeHandle (SQL_HANDLE_STMT , H -> dbc );
151
+ SQLFreeHandle (SQL_HANDLE_DBC , H -> dbc );
58
152
SQLFreeHandle (SQL_HANDLE_ENV , H -> env );
59
153
pefree (H , dbh -> is_persistent );
60
154
@@ -73,14 +167,14 @@ static int odbc_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_len, p
73
167
74
168
if (rc == SQL_INVALID_HANDLE || rc == SQL_ERROR ) {
75
169
efree (S );
76
- odbc_error ( dbh , "SQLAllocStmt" , SQL_NULL_HSTMT );
170
+ pdo_odbc_drv_error ( "SQLAllocStmt" );
77
171
return 0 ;
78
172
}
79
173
80
174
rc = SQLPrepare (S -> stmt , (char * )sql , SQL_NTS );
81
175
82
176
if (rc != SQL_SUCCESS ) {
83
- odbc_error ( dbh , "SQLPrepare" , S -> stmt );
177
+ pdo_odbc_stmt_error ( "SQLPrepare" );
84
178
}
85
179
86
180
if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO ) {
@@ -98,20 +192,29 @@ static long odbc_handle_doer(pdo_dbh_t *dbh, const char *sql, long sql_len TSRML
98
192
{
99
193
pdo_odbc_db_handle * H = (pdo_odbc_db_handle * )dbh -> driver_data ;
100
194
RETCODE rc ;
101
- long row_count ;
195
+ long row_count = -1 ;
196
+ PDO_ODBC_HSTMT stmt ;
197
+
198
+ rc = SQLAllocHandle (SQL_HANDLE_STMT , H -> dbc , & stmt );
199
+ if (rc != SQL_SUCCESS ) {
200
+ pdo_odbc_drv_error ("SQLAllocHandle: STMT" );
201
+ return -1 ;
202
+ }
203
+
204
+ rc = SQLExecDirect (stmt , (char * )sql , sql_len );
102
205
103
- rc = SQLExecDirect (H -> dbc , (char * )sql , sql_len );
104
206
if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO ) {
105
- /* XXX error reporting needed */
106
- return 0 ;
207
+ pdo_odbc_doer_error ( "SQLExecDirect" );
208
+ goto out ;
107
209
}
108
210
109
- rc = SQLRowCount (H -> dbc , & row_count );
211
+ rc = SQLRowCount (stmt , & row_count );
110
212
if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO ) {
111
- /* XXX error reporting needed */
112
- return 0 ;
213
+ pdo_odbc_doer_error ( "SQLRowCount" );
214
+ goto out ;
113
215
}
114
-
216
+ out :
217
+ SQLFreeHandle (SQL_HANDLE_STMT , stmt );
115
218
return row_count ;
116
219
}
117
220
@@ -136,7 +239,7 @@ static int odbc_handle_commit(pdo_dbh_t *dbh TSRMLS_DC)
136
239
rc = SQLEndTran (SQL_HANDLE_DBC , H -> dbc , SQL_COMMIT );
137
240
138
241
if (rc != SQL_SUCCESS ) {
139
- odbc_error ( dbh , "SQLEndTran: Commit" , SQL_NULL_HSTMT );
242
+ pdo_odbc_drv_error ( "SQLEndTran: Commit" );
140
243
141
244
if (rc != SQL_SUCCESS_WITH_INFO ) {
142
245
return 0 ;
@@ -153,7 +256,7 @@ static int odbc_handle_rollback(pdo_dbh_t *dbh TSRMLS_DC)
153
256
rc = SQLEndTran (SQL_HANDLE_DBC , H -> dbc , SQL_ROLLBACK );
154
257
155
258
if (rc != SQL_SUCCESS ) {
156
- odbc_error ( dbh , "SQLEndTran: Rollback" , SQL_NULL_HSTMT );
259
+ pdo_odbc_drv_error ( "SQLEndTran: Rollback" );
157
260
158
261
if (rc != SQL_SUCCESS_WITH_INFO ) {
159
262
return 0 ;
@@ -173,6 +276,10 @@ static struct pdo_dbh_methods odbc_methods = {
173
276
odbc_handle_begin ,
174
277
odbc_handle_commit ,
175
278
odbc_handle_rollback ,
279
+ NULL , /* set attr */
280
+ NULL , /* last id */
281
+ pdo_odbc_fetch_error_func ,
282
+ NULL , /* get attr */
176
283
};
177
284
178
285
static int pdo_odbc_handle_factory (pdo_dbh_t * dbh , zval * driver_options TSRMLS_DC ) /* {{{ */
@@ -189,22 +296,22 @@ static int pdo_odbc_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_D
189
296
rc = SQLSetEnvAttr (H -> env , SQL_ATTR_ODBC_VERSION , (void * )SQL_OV_ODBC3 , 0 );
190
297
191
298
if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO ) {
192
- odbc_error ( dbh , "SQLSetEnvAttr: ODBC3" , SQL_NULL_HSTMT );
299
+ pdo_odbc_drv_error ( "SQLSetEnvAttr: ODBC3" );
193
300
odbc_handle_closer (dbh TSRMLS_CC );
194
301
return 0 ;
195
302
}
196
303
197
304
rc = SQLAllocHandle (SQL_HANDLE_DBC , H -> env , & H -> dbc );
198
305
if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO ) {
199
- odbc_error ( dbh , "SQLAllocHandle (DBC)" , SQL_NULL_HSTMT );
306
+ pdo_odbc_drv_error ( "SQLAllocHandle (DBC)" );
200
307
odbc_handle_closer (dbh TSRMLS_CC );
201
308
return 0 ;
202
309
}
203
310
204
311
if (!dbh -> auto_commit ) {
205
312
rc = SQLSetConnectAttr (H -> dbc , SQL_ATTR_AUTOCOMMIT , SQL_AUTOCOMMIT_OFF , SQL_IS_UINTEGER );
206
313
if (rc != SQL_SUCCESS ) {
207
- odbc_error ( dbh , "SQLSetConnectAttr AUTOCOMMIT = OFF" , SQL_NULL_HSTMT );
314
+ pdo_odbc_drv_error ( "SQLSetConnectAttr AUTOCOMMIT = OFF" );
208
315
odbc_handle_closer (dbh TSRMLS_CC );
209
316
return 0 ;
210
317
}
@@ -232,7 +339,7 @@ static int pdo_odbc_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_D
232
339
}
233
340
234
341
if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO ) {
235
- odbc_error ( dbh , use_direct ? "SQLDriverConnect" : "SQLConnect" , SQL_NULL_HSTMT );
342
+ pdo_odbc_drv_error ( use_direct ? "SQLDriverConnect" : "SQLConnect" );
236
343
odbc_handle_closer (dbh TSRMLS_CC );
237
344
return 0 ;
238
345
}
0 commit comments