php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
dblib_stmt.c
Go to the documentation of this file.
1/*
2 +----------------------------------------------------------------------+
3 | Copyright (c) The PHP Group |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | https://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Author: Wez Furlong <wez@php.net> |
14 | Frank M. Kromann <frank@kromann.info> |
15 +----------------------------------------------------------------------+
16*/
17
18#ifdef HAVE_CONFIG_H
19# include "config.h"
20#endif
21
22#include "php.h"
23#include "php_ini.h"
24#include "ext/standard/info.h"
25#include "ext/pdo/php_pdo.h"
27#include "php_pdo_dblib.h"
28#include "php_pdo_dblib_int.h"
29#include "zend_exceptions.h"
30
31
32/* {{{ pdo_dblib_get_field_name
33 *
34 * Return the data type name for a given TDS number
35 *
36 */
37static char *pdo_dblib_get_field_name(int type)
38{
39 /*
40 * I don't return dbprtype(type) because it does not fully describe the type
41 * (example: varchar is reported as char by dbprtype)
42 *
43 * FIX ME: Cache datatypes from server systypes table in pdo_dblib_handle_factory()
44 * to make this future-proof.
45 */
46
47 switch (type) {
48 case 31: return "nvarchar";
49 case 34: return "image";
50 case 35: return "text";
51 case 36: return "uniqueidentifier";
52 case 37: return "varbinary"; /* & timestamp - Sybase AS12 */
53 case 38: return "bigint"; /* & bigintn - Sybase AS12 */
54 case 39: return "varchar"; /* & sysname & nvarchar - Sybase AS12 */
55 case 40: return "date";
56 case 41: return "time";
57 case 42: return "datetime2";
58 case 43: return "datetimeoffset";
59 case 45: return "binary"; /* Sybase AS12 */
60 case 47: return "char"; /* & nchar & uniqueidentifierstr Sybase AS12 */
61 case 48: return "tinyint";
62 case 50: return "bit"; /* Sybase AS12 */
63 case 52: return "smallint";
64 case 55: return "decimal"; /* Sybase AS12 */
65 case 56: return "int";
66 case 58: return "smalldatetime";
67 case 59: return "real";
68 case 60: return "money";
69 case 61: return "datetime";
70 case 62: return "float";
71 case 63: return "numeric"; /* or uint, ubigint, usmallint Sybase AS12 */
72 case 98: return "sql_variant";
73 case 99: return "ntext";
74 case 104: return "bit";
75 case 106: return "decimal"; /* decimal n on sybase */
76 case 108: return "numeric"; /* numeric n on sybase */
77 case 122: return "smallmoney";
78 case 127: return "bigint";
79 case 165: return "varbinary";
80 case 167: return "varchar";
81 case 173: return "binary";
82 case 175: return "char";
83 case 189: return "timestamp";
84 case 231: return "nvarchar";
85 case 239: return "nchar";
86 case 240: return "geometry";
87 case 241: return "xml";
88 default: return "unknown";
89 }
90}
91/* }}} */
92
93static int pdo_dblib_stmt_cursor_closer(pdo_stmt_t *stmt)
94{
97
98 /* Cancel any pending results */
99 dbcancel(H->link);
100
101 pdo_dblib_err_dtor(&H->err);
102
103 return 1;
104}
105
106static int pdo_dblib_stmt_dtor(pdo_stmt_t *stmt)
107{
109
110 pdo_dblib_err_dtor(&S->err);
111
112 efree(S);
113
114 return 1;
115}
116
117static int pdo_dblib_stmt_next_rowset_no_cancel(pdo_stmt_t *stmt)
118{
120 pdo_dblib_db_handle *H = S->H;
121 RETCODE ret;
122 int num_fields;
123
124 do {
125 ret = dbresults(H->link);
126 num_fields = dbnumcols(H->link);
127 } while (H->skip_empty_rowsets && num_fields <= 0 && ret == SUCCEED);
128
129
130 if (FAIL == ret) {
131 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO_DBLIB: dbresults() returned FAIL");
132 return 0;
133 }
134
135 if (NO_MORE_RESULTS == ret) {
136 return 0;
137 }
138
139 if (H->skip_empty_rowsets && num_fields <= 0) {
140 return 0;
141 }
142
143 stmt->row_count = DBCOUNT(H->link);
144 stmt->column_count = num_fields;
145
146 return 1;
147}
148
149static int pdo_dblib_stmt_next_rowset(pdo_stmt_t *stmt)
150{
152 pdo_dblib_db_handle *H = S->H;
153 RETCODE ret = SUCCESS;
154
155 /* Ideally use dbcanquery here, but there is a bug in FreeTDS's implementation of dbcanquery
156 * It has been resolved but is currently only available in nightly builds
157 */
158 while (NO_MORE_ROWS != ret) {
159 ret = dbnextrow(H->link);
160
161 if (FAIL == ret) {
162 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO_DBLIB: dbnextrow() returned FAIL");
163 return 0;
164 }
165 }
166
167 return pdo_dblib_stmt_next_rowset_no_cancel(stmt);
168}
169
170static int pdo_dblib_stmt_execute(pdo_stmt_t *stmt)
171{
173 pdo_dblib_db_handle *H = S->H;
174
175 dbsetuserdata(H->link, (BYTE*) &S->err);
176
177 pdo_dblib_stmt_cursor_closer(stmt);
178
179 if (FAIL == dbcmd(H->link, ZSTR_VAL(stmt->active_query_string))) {
180 return 0;
181 }
182
183 if (FAIL == dbsqlexec(H->link)) {
184 return 0;
185 }
186
187 pdo_dblib_stmt_next_rowset_no_cancel(stmt);
188
189 stmt->row_count = DBCOUNT(H->link);
190 stmt->column_count = dbnumcols(H->link);
191
192 return 1;
193}
194
195static int pdo_dblib_stmt_fetch(pdo_stmt_t *stmt,
197{
198
199 RETCODE ret;
200
202 pdo_dblib_db_handle *H = S->H;
203
204 ret = dbnextrow(H->link);
205
206 if (FAIL == ret) {
207 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO_DBLIB: dbnextrow() returned FAIL");
208 return 0;
209 }
210
211 if(NO_MORE_ROWS == ret) {
212 return 0;
213 }
214
215 return 1;
216}
217
218static int pdo_dblib_stmt_describe(pdo_stmt_t *stmt, int colno)
219{
221 pdo_dblib_db_handle *H = S->H;
222 struct pdo_column_data *col;
223 char *fname;
224
225 if(colno >= stmt->column_count || colno < 0) {
226 return FAILURE;
227 }
228
229 if (colno == 0) {
230 S->computed_column_name_count = 0;
231 }
232
233 col = &stmt->columns[colno];
234 fname = (char*)dbcolname(H->link, colno+1);
235
236 if (fname && *fname) {
237 col->name = zend_string_init(fname, strlen(fname), 0);
238 } else {
239 if (S->computed_column_name_count > 0) {
240 char buf[16];
241 int len;
242
243 len = snprintf(buf, sizeof(buf), "computed%d", S->computed_column_name_count);
244 col->name = zend_string_init(buf, len, 0);
245 } else {
246 col->name = ZSTR_INIT_LITERAL("computed", 0);
247 }
248
249 S->computed_column_name_count++;
250 }
251
252 col->maxlen = dbcollen(H->link, colno+1);
253
254 return 1;
255}
256
257static int pdo_dblib_stmt_should_stringify_col(pdo_stmt_t *stmt, int coltype)
258{
260 pdo_dblib_db_handle *H = S->H;
261
262 switch (coltype) {
263 case SQLDECIMAL:
264 case SQLNUMERIC:
265 case SQLMONEY:
266 case SQLMONEY4:
267 case SQLMONEYN:
268 case SQLFLT4:
269 case SQLFLT8:
270 case SQLINT4:
271 case SQLINT2:
272 case SQLINT1:
273 case SQLBIT:
274 if (stmt->dbh->stringify) {
275 return 1;
276 }
277 break;
278
279 case SQLINT8:
280 if (stmt->dbh->stringify) {
281 return 1;
282 }
283
284 /* force stringify if DBBIGINT won't fit in zend_long */
285 /* this should only be an issue for 32-bit machines */
286 if (sizeof(zend_long) < sizeof(DBBIGINT)) {
287 return 1;
288 }
289 break;
290
291#ifdef SQLMSDATETIME2
292 case SQLMSDATETIME2:
293#endif
294 case SQLDATETIME:
295 case SQLDATETIM4:
296 if (H->datetime_convert) {
297 return 1;
298 }
299 break;
300 }
301
302 return 0;
303}
304
305static void pdo_dblib_stmt_stringify_col(int coltype, LPBYTE data, DBINT data_len, zval *zv)
306{
307 DBCHAR *tmp_data;
308
309 /* FIXME: We allocate more than we need here */
310 DBINT tmp_data_len = 32 + (2 * (data_len));
311
312 switch (coltype) {
313 case SQLDATETIME:
314 case SQLDATETIM4: {
315 if (tmp_data_len < DATETIME_MAX_LEN) {
316 tmp_data_len = DATETIME_MAX_LEN;
317 }
318 break;
319 }
320 }
321
322 tmp_data = emalloc(tmp_data_len);
323 data_len = dbconvert(NULL, coltype, data, data_len, SQLCHAR, (LPBYTE) tmp_data, tmp_data_len);
324
325 if (data_len > 0) {
326 /* to prevent overflows, tmp_data_len is provided as a dest len for dbconvert()
327 * this code previously passed a dest len of -1
328 * the FreeTDS impl of dbconvert() does an rtrim with that value, so replicate that behavior
329 */
330 while (data_len > 0 && tmp_data[data_len - 1] == ' ') {
331 data_len--;
332 }
333
334 ZVAL_STRINGL(zv, tmp_data, data_len);
335 } else {
337 }
338
339 efree(tmp_data);
340}
341
342static int pdo_dblib_stmt_get_col(pdo_stmt_t *stmt, int colno, zval *zv, enum pdo_param_type *type)
343{
344
346 pdo_dblib_db_handle *H = S->H;
347
348 int coltype;
349 LPBYTE data;
350 DBCHAR *tmp_data;
351 DBINT data_len, tmp_data_len;
352
353 coltype = dbcoltype(H->link, colno+1);
354 data = dbdata(H->link, colno+1);
355 data_len = dbdatlen(H->link, colno+1);
356
357 if (data_len != 0 || data != NULL) {
358 if (pdo_dblib_stmt_should_stringify_col(stmt, coltype) && dbwillconvert(coltype, SQLCHAR)) {
359 pdo_dblib_stmt_stringify_col(coltype, data, data_len, zv);
360 } else {
361 switch (coltype) {
362 case SQLCHAR:
363 case SQLVARCHAR:
364 case SQLTEXT: {
365#ifdef ilia_0
366 while (data_len>0 && data[data_len-1] == ' ') { /* nuke trailing whitespace */
367 data_len--;
368 }
369#endif
370 }
371 case SQLVARBINARY:
372 case SQLBINARY:
373 case SQLIMAGE: {
374 ZVAL_STRINGL(zv, (DBCHAR *) data, data_len);
375
376 break;
377 }
378#ifdef SQLMSDATETIME2
379 case SQLMSDATETIME2:
380#endif
381 case SQLDATETIME:
382 case SQLDATETIM4: {
383 size_t dl;
384 DBDATEREC di;
385 DBDATEREC dt;
386
387 dbconvert(H->link, coltype, data, -1, SQLDATETIME, (LPBYTE) &dt, -1);
388 dbdatecrack(H->link, &di, (DBDATETIME *) &dt);
389
390 dl = spprintf(&tmp_data, 20, "%04d-%02d-%02d %02d:%02d:%02d",
391#if defined(PHP_DBLIB_IS_MSSQL) || defined(MSDBLIB)
392 di.year, di.month, di.day, di.hour, di.minute, di.second
393#else
394 di.dateyear, di.datemonth+1, di.datedmonth, di.datehour, di.dateminute, di.datesecond
395#endif
396 );
397
398 ZVAL_STRINGL(zv, tmp_data, dl);
399
400 efree(tmp_data);
401
402 break;
403 }
404 case SQLFLT4:
405 ZVAL_DOUBLE(zv, *(DBFLT4 *) data);
406 break;
407 case SQLFLT8:
408 ZVAL_DOUBLE(zv, *(DBFLT8 *) data);
409 break;
410 case SQLINT8:
411 ZVAL_LONG(zv, *(DBBIGINT *) data);
412 break;
413 case SQLINT4:
414 ZVAL_LONG(zv, *(DBINT *) data);
415 break;
416 case SQLINT2:
417 ZVAL_LONG(zv, *(DBSMALLINT *) data);
418 break;
419 case SQLINT1:
420 case SQLBIT:
421 ZVAL_LONG(zv, *(DBTINYINT *) data);
422 break;
423 case SQLDECIMAL:
424 case SQLNUMERIC:
425 case SQLMONEY:
426 case SQLMONEY4:
427 case SQLMONEYN: {
428 DBFLT8 float_value;
429 dbconvert(NULL, coltype, data, 8, SQLFLT8, (LPBYTE) &float_value, -1);
430 ZVAL_DOUBLE(zv, float_value);
431 break;
432 }
433
434 case SQLUNIQUE: {
435 if (H->stringify_uniqueidentifier) {
436 /* 36-char hex string representation */
437 tmp_data_len = 36;
438 tmp_data = safe_emalloc(tmp_data_len, sizeof(char), 1);
439 data_len = dbconvert(NULL, SQLUNIQUE, data, data_len, SQLCHAR, (LPBYTE) tmp_data, tmp_data_len);
440 zend_str_toupper(tmp_data, data_len);
441 ZVAL_STRINGL(zv, tmp_data, data_len);
442 efree(tmp_data);
443 } else {
444 /* 16-byte binary representation */
445 ZVAL_STRINGL(zv, (DBCHAR *) data, 16);
446 }
447 break;
448 }
449
450 default: {
451 if (dbwillconvert(coltype, SQLCHAR)) {
452 pdo_dblib_stmt_stringify_col(coltype, data, data_len, zv);
453 }
454
455 break;
456 }
457 }
458 }
459 }
460
461 return 1;
462}
463
464static int pdo_dblib_stmt_get_column_meta(pdo_stmt_t *stmt, zend_long colno, zval *return_value)
465{
467 pdo_dblib_db_handle *H = S->H;
468 DBTYPEINFO* dbtypeinfo;
469 int coltype;
470
471 if(colno >= stmt->column_count || colno < 0) {
472 return FAILURE;
473 }
474
476
477 dbtypeinfo = dbcoltypeinfo(H->link, colno+1);
478
479 if(!dbtypeinfo) return FAILURE;
480
481 coltype = dbcoltype(H->link, colno+1);
482
483 add_assoc_long(return_value, "max_length", dbcollen(H->link, colno+1) );
484 add_assoc_long(return_value, "precision", (int) dbtypeinfo->precision );
485 add_assoc_long(return_value, "scale", (int) dbtypeinfo->scale );
486 add_assoc_string(return_value, "column_source", dbcolsource(H->link, colno+1));
487 add_assoc_string(return_value, "native_type", pdo_dblib_get_field_name(coltype));
488 add_assoc_long(return_value, "native_type_id", coltype);
489 add_assoc_long(return_value, "native_usertype_id", dbcolutype(H->link, colno+1));
490
491 switch (coltype) {
492 case SQLBIT:
493 case SQLINT1:
494 case SQLINT2:
495 case SQLINT4:
496 add_assoc_long(return_value, "pdo_type", PDO_PARAM_INT);
497 break;
498 default:
499 add_assoc_long(return_value, "pdo_type", PDO_PARAM_STR);
500 break;
501 }
502
503 return 1;
504}
505
506
508 pdo_dblib_stmt_dtor,
509 pdo_dblib_stmt_execute,
510 pdo_dblib_stmt_fetch,
511 pdo_dblib_stmt_describe,
512 pdo_dblib_stmt_get_col,
513 NULL, /* param hook */
514 NULL, /* set attr */
515 NULL, /* get attr */
516 pdo_dblib_stmt_get_column_meta, /* meta */
517 pdo_dblib_stmt_next_rowset, /* nextrow */
518 pdo_dblib_stmt_cursor_closer
519};
size_t len
Definition apprentice.c:174
const struct pdo_stmt_methods dblib_stmt_methods
Definition dblib_stmt.c:507
dl(string $extension_filename)
Definition dl.stub.php:3
zend_ffi_type * type
Definition ffi.c:3812
zval * zv
Definition ffi.c:3975
zend_ffi_ctype_name_buf buf
Definition ffi.c:4685
zend_long offset
#define NULL
Definition gdcache.h:45
#define S(s, l, r)
Definition hash_gost.c:121
#define SUCCESS
Definition hash_sha3.c:261
#define H(x, y, z)
Definition md5.c:146
void pdo_raise_impl_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, pdo_error_type sqlstate, const char *supp)
Definition pdo_dbh.c:68
void pdo_dblib_err_dtor(pdo_dblib_err *err)
Definition pdo_dblib.c:147
#define SQLINT8
#define SQLINT1
#define SQLUNIQUE
#define SQLMONEYN
#define SQLFLT8
#define DATETIME_MAX_LEN
#define SQLBIT
#define SQLINT4
#define SQLVARCHAR
#define SQLMONEY4
#define SQLCHAR
#define SQLFLT4
#define SQLMONEY
unsigned char * LPBYTE
#define SQLNUMERIC
#define SQLDATETIME
#define SQLTEXT
#define SQLDECIMAL
#define SQLBINARY
float DBFLT4
#define SQLVARBINARY
#define SQLIMAGE
#define SQLINT2
#define SQLDATETIM4
struct _pdo_stmt_t pdo_stmt_t
pdo_param_type
@ PDO_PARAM_INT
@ PDO_PARAM_STR
pdo_fetch_orientation
zend_constant * data
#define spprintf
Definition spprintf.h:29
#define FAIL(...)
zend_string * name
#define ZVAL_STRINGL(z, s, l)
Definition zend_API.h:952
#define array_init(arg)
Definition zend_API.h:537
#define ZVAL_EMPTY_STRING(z)
Definition zend_API.h:961
#define efree(ptr)
Definition zend_alloc.h:155
#define safe_emalloc(nmemb, size, offset)
Definition zend_alloc.h:154
#define emalloc(size)
Definition zend_alloc.h:151
struct _zval_struct zval
strlen(string $string)
defined(string $constant_name)
#define snprintf
int32_t zend_long
Definition zend_long.h:42
ZEND_API void ZEND_FASTCALL zend_str_toupper(char *str, size_t length)
#define ZSTR_VAL(zstr)
Definition zend_string.h:68
#define ZSTR_INIT_LITERAL(s, persistent)
#define ZVAL_LONG(z, l)
@ FAILURE
Definition zend_types.h:61
#define ZVAL_DOUBLE(z, d)
zval * return_value
zval * ret