xref: /PHP-5.5/ext/pdo_dblib/dblib_stmt.c (revision 73c1be26)
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