1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 5 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2015 The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 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_01.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 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Author: Wez Furlong <wez@php.net> |
16 | Frank M. Kromann <frank@kromann.info> |
17 +----------------------------------------------------------------------+
18 */
19
20 /* $Id$ */
21
22 #ifdef HAVE_CONFIG_H
23 # include "config.h"
24 #endif
25
26 #include "php.h"
27 #include "php_ini.h"
28 #include "ext/standard/php_string.h"
29 #include "ext/standard/info.h"
30 #include "pdo/php_pdo.h"
31 #include "pdo/php_pdo_driver.h"
32 #include "php_pdo_dblib.h"
33 #include "php_pdo_dblib_int.h"
34 #include "zend_exceptions.h"
35
36
37 /* {{{ pdo_dblib_get_field_name
38 *
39 * Return the data type name for a given TDS number
40 *
41 */
pdo_dblib_get_field_name(int type)42 static char *pdo_dblib_get_field_name(int type)
43 {
44 /*
45 * I don't return dbprtype(type) because it does not fully describe the type
46 * (example: varchar is reported as char by dbprtype)
47 *
48 * FIX ME: Cache datatypes from server systypes table in pdo_dblib_handle_factory()
49 * to make this future proof.
50 */
51
52 switch (type) {
53 case 31: return "nvarchar";
54 case 34: return "image";
55 case 35: return "text";
56 case 36: return "uniqueidentifier";
57 case 37: return "varbinary"; /* & timestamp - Sybase AS12 */
58 case 38: return "bigint"; /* & bigintn - Sybase AS12 */
59 case 39: return "varchar"; /* & sysname & nvarchar - Sybase AS12 */
60 case 40: return "date";
61 case 41: return "time";
62 case 42: return "datetime2";
63 case 43: return "datetimeoffset";
64 case 45: return "binary"; /* Sybase AS12 */
65 case 47: return "char"; /* & nchar & uniqueidentifierstr Sybase AS12 */
66 case 48: return "tinyint";
67 case 50: return "bit"; /* Sybase AS12 */
68 case 52: return "smallint";
69 case 55: return "decimal"; /* Sybase AS12 */
70 case 56: return "int";
71 case 58: return "smalldatetime";
72 case 59: return "real";
73 case 60: return "money";
74 case 61: return "datetime";
75 case 62: return "float";
76 case 63: return "numeric"; /* or uint, ubigint, usmallint Sybase AS12 */
77 case 98: return "sql_variant";
78 case 99: return "ntext";
79 case 104: return "bit";
80 case 106: return "decimal"; /* decimal n on sybase */
81 case 108: return "numeric"; /* numeric n on sybase */
82 case 122: return "smallmoney";
83 case 127: return "bigint";
84 case 165: return "varbinary";
85 case 167: return "varchar";
86 case 173: return "binary";
87 case 175: return "char";
88 case 189: return "timestamp";
89 case 231: return "nvarchar";
90 case 239: return "nchar";
91 case 240: return "geometry";
92 case 241: return "xml";
93 default: return "unknown";
94 }
95 }
96 /* }}} */
97
pdo_dblib_stmt_cursor_closer(pdo_stmt_t * stmt TSRMLS_DC)98 static int pdo_dblib_stmt_cursor_closer(pdo_stmt_t *stmt TSRMLS_DC)
99 {
100 pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data;
101 pdo_dblib_db_handle *H = S->H;
102
103 /* Cancel any pending results */
104 dbcancel(H->link);
105
106 efree(stmt->columns);
107 stmt->columns = NULL;
108
109 return 1;
110 }
111
pdo_dblib_stmt_dtor(pdo_stmt_t * stmt TSRMLS_DC)112 static int pdo_dblib_stmt_dtor(pdo_stmt_t *stmt TSRMLS_DC)
113 {
114 pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data;
115
116 efree(stmt->columns);
117 stmt->columns = NULL;
118
119 efree(S);
120
121 return 1;
122 }
123
pdo_dblib_stmt_next_rowset(pdo_stmt_t * stmt TSRMLS_DC)124 static int pdo_dblib_stmt_next_rowset(pdo_stmt_t *stmt TSRMLS_DC)
125 {
126 pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data;
127 pdo_dblib_db_handle *H = S->H;
128 RETCODE ret;
129
130 ret = dbresults(H->link);
131
132 if (FAIL == ret) {
133 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO_DBLIB: dbresults() returned FAIL" TSRMLS_CC);
134 return 0;
135 }
136
137 if(NO_MORE_RESULTS == ret) {
138 return 0;
139 }
140
141 stmt->row_count = DBCOUNT(H->link);
142 stmt->column_count = dbnumcols(H->link);
143
144 return 1;
145 }
146
pdo_dblib_stmt_execute(pdo_stmt_t * stmt TSRMLS_DC)147 static int pdo_dblib_stmt_execute(pdo_stmt_t *stmt TSRMLS_DC)
148 {
149 pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data;
150 pdo_dblib_db_handle *H = S->H;
151 RETCODE ret;
152
153 dbsetuserdata(H->link, (BYTE*) &S->err);
154
155 pdo_dblib_stmt_cursor_closer(stmt TSRMLS_CC);
156
157 if (FAIL == dbcmd(H->link, stmt->active_query_string)) {
158 return 0;
159 }
160
161 if (FAIL == dbsqlexec(H->link)) {
162 return 0;
163 }
164
165 ret = pdo_dblib_stmt_next_rowset(stmt TSRMLS_CC);
166
167 stmt->row_count = DBCOUNT(H->link);
168 stmt->column_count = dbnumcols(H->link);
169
170 return 1;
171 }
172
pdo_dblib_stmt_fetch(pdo_stmt_t * stmt,enum pdo_fetch_orientation ori,long offset TSRMLS_DC)173 static int pdo_dblib_stmt_fetch(pdo_stmt_t *stmt,
174 enum pdo_fetch_orientation ori, long offset TSRMLS_DC)
175 {
176
177 RETCODE ret;
178
179 pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data;
180 pdo_dblib_db_handle *H = S->H;
181
182 ret = dbnextrow(H->link);
183
184 if (FAIL == ret) {
185 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO_DBLIB: dbnextrow() returned FAIL" TSRMLS_CC);
186 return 0;
187 }
188
189 if(NO_MORE_ROWS == ret) {
190 return 0;
191 }
192
193 return 1;
194 }
195
pdo_dblib_stmt_describe(pdo_stmt_t * stmt,int colno TSRMLS_DC)196 static int pdo_dblib_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC)
197 {
198 pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data;
199 pdo_dblib_db_handle *H = S->H;
200
201 if(colno >= stmt->column_count || colno < 0) {
202 return FAILURE;
203 }
204
205 struct pdo_column_data *col = &stmt->columns[colno];
206
207 col->name = (char*)dbcolname(H->link, colno+1);
208 col->maxlen = dbcollen(H->link, colno+1);
209 col->namelen = strlen(col->name);
210 col->param_type = PDO_PARAM_STR;
211
212 return 1;
213 }
214
pdo_dblib_stmt_get_col(pdo_stmt_t * stmt,int colno,char ** ptr,unsigned long * len,int * caller_frees TSRMLS_DC)215 static int pdo_dblib_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr,
216 unsigned long *len, int *caller_frees TSRMLS_DC)
217 {
218
219 pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data;
220 pdo_dblib_db_handle *H = S->H;
221
222 int coltype;
223 unsigned int tmp_len;
224 char *tmp_ptr = NULL;
225
226 coltype = dbcoltype(H->link, colno+1);
227
228 *len = dbdatlen(H->link, colno+1);
229 *ptr = dbdata(H->link, colno+1);
230
231 if (*len == 0 && *ptr == NULL) {
232 return 1;
233 }
234
235 switch (coltype) {
236 case SQLVARBINARY:
237 case SQLBINARY:
238 case SQLIMAGE:
239 case SQLTEXT:
240 /* FIXME: Above types should be returned as a stream as they can be VERY large */
241 case SQLCHAR:
242 case SQLVARCHAR:
243 tmp_ptr = emalloc(*len + 1);
244 memcpy(tmp_ptr, *ptr, *len);
245 tmp_ptr[*len] = '\0';
246 *ptr = tmp_ptr;
247 break;
248 case SQLMONEY:
249 case SQLMONEY4:
250 case SQLMONEYN: {
251 DBFLT8 money_value;
252 dbconvert(NULL, coltype, *ptr, *len, SQLFLT8, (LPBYTE)&money_value, 8);
253 *len = spprintf(&tmp_ptr, 0, "%.4f", money_value);
254 *ptr = tmp_ptr;
255 break;
256 }
257 case SQLUNIQUE: {
258 *len = 36+1;
259 tmp_ptr = emalloc(*len + 1);
260
261 /* uniqueidentifier is a 16-byte binary number, convert to 32 char hex string */
262 *len = dbconvert(NULL, SQLUNIQUE, *ptr, *len, SQLCHAR, tmp_ptr, *len);
263 php_strtoupper(tmp_ptr, *len);
264 *ptr = tmp_ptr;
265 break;
266 }
267 default:
268 if (dbwillconvert(coltype, SQLCHAR)) {
269 tmp_len = 32 + (2 * (*len)); /* FIXME: We allocate more than we need here */
270 tmp_ptr = emalloc(tmp_len);
271 *len = dbconvert(NULL, coltype, *ptr, *len, SQLCHAR, tmp_ptr, -1);
272 *ptr = tmp_ptr;
273 } else {
274 *len = 0; /* FIXME: Silently fails and returns null on conversion errors */
275 *ptr = NULL;
276 }
277 }
278
279 *caller_frees = 1;
280
281 return 1;
282 }
283
pdo_dblib_stmt_param_hook(pdo_stmt_t * stmt,struct pdo_bound_param_data * param,enum pdo_param_event event_type TSRMLS_DC)284 static int pdo_dblib_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *param,
285 enum pdo_param_event event_type TSRMLS_DC)
286 {
287 return 1;
288 }
289
pdo_dblib_stmt_get_column_meta(pdo_stmt_t * stmt,long colno,zval * return_value TSRMLS_DC)290 static int pdo_dblib_stmt_get_column_meta(pdo_stmt_t *stmt, long colno, zval *return_value TSRMLS_DC)
291 {
292 pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data;
293 pdo_dblib_db_handle *H = S->H;
294 DBTYPEINFO* dbtypeinfo;
295
296 if(colno >= stmt->column_count || colno < 0) {
297 return FAILURE;
298 }
299
300 array_init(return_value);
301
302 dbtypeinfo = dbcoltypeinfo(H->link, colno+1);
303
304 if(!dbtypeinfo) return FAILURE;
305
306 add_assoc_long(return_value, "max_length", dbcollen(H->link, colno+1) );
307 add_assoc_long(return_value, "precision", (int) dbtypeinfo->precision );
308 add_assoc_long(return_value, "scale", (int) dbtypeinfo->scale );
309 add_assoc_string(return_value, "column_source", dbcolsource(H->link, colno+1), 1);
310 add_assoc_string(return_value, "native_type", pdo_dblib_get_field_name(dbcoltype(H->link, colno+1)), 1);
311 add_assoc_long(return_value, "native_type_id", dbcoltype(H->link, colno+1));
312 add_assoc_long(return_value, "native_usertype_id", dbcolutype(H->link, colno+1));
313
314 return 1;
315 }
316
317
318 struct pdo_stmt_methods dblib_stmt_methods = {
319 pdo_dblib_stmt_dtor,
320 pdo_dblib_stmt_execute,
321 pdo_dblib_stmt_fetch,
322 pdo_dblib_stmt_describe,
323 pdo_dblib_stmt_get_col,
324 pdo_dblib_stmt_param_hook,
325 NULL, /* set attr */
326 NULL, /* get attr */
327 pdo_dblib_stmt_get_column_meta, /* meta */
328 pdo_dblib_stmt_next_rowset, /* nextrow */
329 pdo_dblib_stmt_cursor_closer
330 };
331
332