xref: /PHP-5.6/ext/pdo_dblib/dblib_stmt.c (revision 478c8071)
1 /*
2   +----------------------------------------------------------------------+
3   | PHP Version 5                                                        |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1997-2016 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 	return 1;
107 }
108 
pdo_dblib_stmt_dtor(pdo_stmt_t * stmt TSRMLS_DC)109 static int pdo_dblib_stmt_dtor(pdo_stmt_t *stmt TSRMLS_DC)
110 {
111 	pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data;
112 
113 	efree(S);
114 
115 	return 1;
116 }
117 
pdo_dblib_stmt_next_rowset(pdo_stmt_t * stmt TSRMLS_DC)118 static int pdo_dblib_stmt_next_rowset(pdo_stmt_t *stmt TSRMLS_DC)
119 {
120 	pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data;
121 	pdo_dblib_db_handle *H = S->H;
122 	RETCODE ret;
123 
124 	ret = dbresults(H->link);
125 
126 	if (FAIL == ret) {
127 		pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO_DBLIB: dbresults() returned FAIL" TSRMLS_CC);
128 		return 0;
129 	}
130 
131 	if(NO_MORE_RESULTS == ret) {
132 		return 0;
133 	}
134 
135 	stmt->row_count = DBCOUNT(H->link);
136 	stmt->column_count = dbnumcols(H->link);
137 
138 	return 1;
139 }
140 
pdo_dblib_stmt_execute(pdo_stmt_t * stmt TSRMLS_DC)141 static int pdo_dblib_stmt_execute(pdo_stmt_t *stmt TSRMLS_DC)
142 {
143 	pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data;
144 	pdo_dblib_db_handle *H = S->H;
145 	RETCODE ret;
146 
147 	dbsetuserdata(H->link, (BYTE*) &S->err);
148 
149 	pdo_dblib_stmt_cursor_closer(stmt TSRMLS_CC);
150 
151 	if (FAIL == dbcmd(H->link, stmt->active_query_string)) {
152 		return 0;
153 	}
154 
155 	if (FAIL == dbsqlexec(H->link)) {
156 		return 0;
157 	}
158 
159 	ret = pdo_dblib_stmt_next_rowset(stmt TSRMLS_CC);
160 
161 	stmt->row_count = DBCOUNT(H->link);
162 	stmt->column_count = dbnumcols(H->link);
163 
164 	return 1;
165 }
166 
pdo_dblib_stmt_fetch(pdo_stmt_t * stmt,enum pdo_fetch_orientation ori,long offset TSRMLS_DC)167 static int pdo_dblib_stmt_fetch(pdo_stmt_t *stmt,
168 	enum pdo_fetch_orientation ori, long offset TSRMLS_DC)
169 {
170 
171 	RETCODE ret;
172 
173 	pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data;
174 	pdo_dblib_db_handle *H = S->H;
175 
176 	ret = dbnextrow(H->link);
177 
178 	if (FAIL == ret) {
179 		pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO_DBLIB: dbnextrow() returned FAIL" TSRMLS_CC);
180 		return 0;
181 	}
182 
183 	if(NO_MORE_ROWS == ret) {
184 		return 0;
185 	}
186 
187 	return 1;
188 }
189 
pdo_dblib_stmt_describe(pdo_stmt_t * stmt,int colno TSRMLS_DC)190 static int pdo_dblib_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC)
191 {
192 	pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data;
193 	pdo_dblib_db_handle *H = S->H;
194 	struct pdo_column_data *col;
195 	char *fname;
196 
197 	if(colno >= stmt->column_count || colno < 0)  {
198 		return FAILURE;
199 	}
200 
201 	col = &stmt->columns[colno];
202 	fname = (char*)dbcolname(H->link, colno+1);
203 
204 	if (fname && *fname) {
205 		col->name = estrdup(fname);
206 		col->namelen = strlen(col->name);
207 	} else {
208 		col->namelen = spprintf(&col->name, 0, "computed%d", colno);
209 	}
210 	col->maxlen = dbcollen(H->link, colno+1);
211 	col->param_type = PDO_PARAM_STR;
212 
213 	return 1;
214 }
215 
pdo_dblib_stmt_get_col(pdo_stmt_t * stmt,int colno,char ** ptr,unsigned long * len,int * caller_frees TSRMLS_DC)216 static int pdo_dblib_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr,
217 	 unsigned long *len, int *caller_frees TSRMLS_DC)
218 {
219 
220 	pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data;
221 	pdo_dblib_db_handle *H = S->H;
222 
223 	int coltype;
224 	unsigned int tmp_len;
225 	char *tmp_ptr = NULL;
226 
227 	coltype = dbcoltype(H->link, colno+1);
228 
229 	*len = dbdatlen(H->link, colno+1);
230 	*ptr = dbdata(H->link, colno+1);
231 
232 	if (*len == 0 && *ptr == NULL) {
233 		return 1;
234 	}
235 
236 	switch (coltype) {
237 		case SQLVARBINARY:
238 		case SQLBINARY:
239 		case SQLIMAGE:
240 		case SQLTEXT:
241 			/* FIXME: Above types should be returned as a stream as they can be VERY large */
242 		case SQLCHAR:
243 		case SQLVARCHAR:
244 			tmp_ptr = emalloc(*len + 1);
245 			memcpy(tmp_ptr, *ptr, *len);
246 			tmp_ptr[*len] = '\0';
247 			*ptr = tmp_ptr;
248 			break;
249 		case SQLMONEY:
250 		case SQLMONEY4:
251 		case SQLMONEYN: {
252 			DBFLT8 money_value;
253 			dbconvert(NULL, coltype, *ptr, *len, SQLFLT8, (LPBYTE)&money_value, 8);
254 			*len = spprintf(&tmp_ptr, 0, "%.4f", money_value);
255 			*ptr = tmp_ptr;
256 			break;
257 		}
258 		case SQLUNIQUE: {
259 			*len = 36+1;
260 			tmp_ptr = emalloc(*len + 1);
261 
262 			/* uniqueidentifier is a 16-byte binary number, convert to 32 char hex string */
263 			*len = dbconvert(NULL, SQLUNIQUE, *ptr, *len, SQLCHAR, tmp_ptr, *len);
264 			php_strtoupper(tmp_ptr, *len);
265 			*ptr = tmp_ptr;
266 			break;
267 		}
268 		case SQLDATETIM4:
269 		case SQLDATETIME: {
270 			DBDATETIME dt;
271 			DBDATEREC di;
272 
273 			dbconvert(H->link, coltype, (BYTE*) *ptr, -1, SQLDATETIME, (LPBYTE) &dt, -1);
274 			dbdatecrack(H->link, &di, &dt);
275 
276 			*len = spprintf((char**) &tmp_ptr, 20, "%d-%02d-%02d %02d:%02d:%02d",
277 #if defined(PHP_DBLIB_IS_MSSQL) || defined(MSDBLIB)
278 					di.year,     di.month,       di.day,        di.hour,     di.minute,     di.second
279 #else
280 					di.dateyear, di.datemonth+1, di.datedmonth, di.datehour, di.dateminute, di.datesecond
281 #endif
282 				);
283 
284 			*ptr = (char*) tmp_ptr;
285 			break;
286 		}
287 		default:
288 			if (dbwillconvert(coltype, SQLCHAR)) {
289 				tmp_len = 32 + (2 * (*len)); /* FIXME: We allocate more than we need here */
290 				tmp_ptr = emalloc(tmp_len);
291 				*len = dbconvert(NULL, coltype, *ptr, *len, SQLCHAR, tmp_ptr, -1);
292 				*ptr = tmp_ptr;
293 			} else {
294 				*len = 0; /* FIXME: Silently fails and returns null on conversion errors */
295 				*ptr = NULL;
296 			}
297 	}
298 
299 	*caller_frees = 1;
300 
301 	return 1;
302 }
303 
pdo_dblib_stmt_param_hook(pdo_stmt_t * stmt,struct pdo_bound_param_data * param,enum pdo_param_event event_type TSRMLS_DC)304 static int pdo_dblib_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *param,
305 		enum pdo_param_event event_type TSRMLS_DC)
306 {
307 	return 1;
308 }
309 
pdo_dblib_stmt_get_column_meta(pdo_stmt_t * stmt,long colno,zval * return_value TSRMLS_DC)310 static int pdo_dblib_stmt_get_column_meta(pdo_stmt_t *stmt, long colno, zval *return_value TSRMLS_DC)
311 {
312 	pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data;
313 	pdo_dblib_db_handle *H = S->H;
314 	DBTYPEINFO* dbtypeinfo;
315 
316 	if(colno >= stmt->column_count || colno < 0)  {
317 		return FAILURE;
318 	}
319 
320 	array_init(return_value);
321 
322 	dbtypeinfo = dbcoltypeinfo(H->link, colno+1);
323 
324 	if(!dbtypeinfo) return FAILURE;
325 
326 	add_assoc_long(return_value, "max_length", dbcollen(H->link, colno+1) );
327 	add_assoc_long(return_value, "precision", (int) dbtypeinfo->precision );
328 	add_assoc_long(return_value, "scale", (int) dbtypeinfo->scale );
329 	add_assoc_string(return_value, "column_source", dbcolsource(H->link, colno+1), 1);
330 	add_assoc_string(return_value, "native_type", pdo_dblib_get_field_name(dbcoltype(H->link, colno+1)), 1);
331 	add_assoc_long(return_value, "native_type_id", dbcoltype(H->link, colno+1));
332 	add_assoc_long(return_value, "native_usertype_id", dbcolutype(H->link, colno+1));
333 
334 	return 1;
335 }
336 
337 
338 struct pdo_stmt_methods dblib_stmt_methods = {
339 	pdo_dblib_stmt_dtor,
340 	pdo_dblib_stmt_execute,
341 	pdo_dblib_stmt_fetch,
342 	pdo_dblib_stmt_describe,
343 	pdo_dblib_stmt_get_col,
344 	pdo_dblib_stmt_param_hook,
345 	NULL, /* set attr */
346 	NULL, /* get attr */
347 	pdo_dblib_stmt_get_column_meta, /* meta */
348 	pdo_dblib_stmt_next_rowset, /* nextrow */
349 	pdo_dblib_stmt_cursor_closer
350 };
351 
352