xref: /PHP-5.3/ext/pdo_dblib/dblib_stmt.c (revision a2045ff3)
1 /*
2   +----------------------------------------------------------------------+
3   | PHP Version 5                                                        |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1997-2013 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 
free_rows(pdo_dblib_stmt * S TSRMLS_DC)36 static void free_rows(pdo_dblib_stmt *S TSRMLS_DC)
37 {
38 	int i, j;
39 
40 	for (i = 0; i < S->nrows; i++) {
41 		for (j = 0; j < S->ncols; j++) {
42 			pdo_dblib_colval *val = &S->rows[i*S->ncols] + j;
43 			if (val->data) {
44 				efree(val->data);
45 				val->data = NULL;
46 			}
47 		}
48 	}
49 	efree(S->rows);
50 	S->rows = NULL;
51 	S->nrows = 0;
52 }
53 
pdo_dblib_stmt_dtor(pdo_stmt_t * stmt TSRMLS_DC)54 static int pdo_dblib_stmt_dtor(pdo_stmt_t *stmt TSRMLS_DC)
55 {
56 	pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data;
57 
58 	if (S->rows) {
59 		free_rows(S TSRMLS_CC);
60 	}
61 	if (S->cols) {
62 		efree(S->cols);
63 	}
64 	efree(S);
65 
66 	return 1;
67 }
68 
pdo_dblib_stmt_execute(pdo_stmt_t * stmt TSRMLS_DC)69 static int pdo_dblib_stmt_execute(pdo_stmt_t *stmt TSRMLS_DC)
70 {
71 	pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data;
72 	pdo_dblib_db_handle *H = S->H;
73 	RETCODE resret, ret;
74 	int i, j;
75 	int arows;
76 	unsigned int size;
77 
78 	dbsetuserdata(H->link, &S->err);
79 
80 	if (S->rows) {
81 		/* clean them up */
82 		free_rows(S TSRMLS_CC);
83 	}
84 
85 	if (FAIL == dbcmd(H->link, stmt->active_query_string)) {
86 		return 0;
87 	}
88 	if (FAIL == dbsqlexec(H->link)) {
89 		return 0;
90 	}
91 
92 	resret = dbresults(H->link);
93 	if (resret == FAIL) {
94 		return 0;
95 	}
96 
97 	ret = dbnextrow(H->link);
98 
99 	stmt->row_count = DBCOUNT(H->link);
100 
101     if (ret == NO_MORE_ROWS) {
102        return 1;
103     }
104 
105 	if (!S->cols) {
106 		S->ncols = dbnumcols(H->link);
107 
108 		if (S->ncols <= 0) {
109 			return 1;
110 		}
111 
112 		S->cols = ecalloc(S->ncols, sizeof(pdo_dblib_col));
113 		stmt->column_count = S->ncols;
114 
115 		for (i = 0, j = 0; i < S->ncols; i++) {
116 			char *tmp = NULL;
117 
118 			S->cols[i].coltype = dbcoltype(H->link, i+1);
119 			S->cols[i].name = (char*)dbcolname(H->link, i+1);
120 
121 			if (!strlen(S->cols[i].name)) {
122 				if (j) {
123 					spprintf(&tmp, 0, "computed%d", j++);
124 					strlcpy(S->cols[i].name, tmp, strlen(tmp)+1);
125 					efree(tmp);
126 				} else {
127 					S->cols[i].name = "computed";
128 					j++;
129 				}
130 			}
131 
132 			S->cols[i].source = (char*)dbcolsource(H->link, i+1);
133 			tmp = estrdup(S->cols[i].source ? S->cols[i].source : "");
134 			S->cols[i].source = tmp;
135 			efree(tmp);
136 
137 			S->cols[i].maxlen = dbcollen(H->link, i+1);
138 		}
139 	}
140 
141 	arows = 100;
142 	size = S->ncols * sizeof(pdo_dblib_colval);
143 	S->rows = safe_emalloc(arows, size, 0);
144 
145 	/* let's fetch all the data */
146 	do {
147 		if (S->nrows >= arows) {
148 			arows *= 2;
149 			S->rows = erealloc(S->rows, arows * size);
150 		}
151 		for (i = 0; i < S->ncols; i++) {
152 			pdo_dblib_colval *val = &S->rows[S->nrows * S->ncols + i];
153 
154 			if (dbdatlen(H->link, i+1) == 0 && dbdata(H->link, i+1) == NULL) {
155 				val->len = 0;
156 				val->data = NULL;
157 			} else {
158 				switch (S->cols[i].coltype) {
159 					case SQLCHAR:
160 					case SQLTEXT:
161 					case SQLVARBINARY:
162 					case SQLBINARY:
163 					case SQLIMAGE:
164 						val->len = dbdatlen(H->link, i+1);
165 						val->data = emalloc(val->len + 1);
166 						memcpy(val->data, dbdata(H->link, i+1), val->len);
167 						val->data[val->len] = '\0';
168 						break;
169 					case SQLMONEY:
170 					case SQLMONEY4:
171 					case SQLMONEYN: {
172 						DBFLT8 money_value;
173 						dbconvert(NULL, S->cols[i].coltype, dbdata(H->link, i+1), dbdatlen(H->link, i+1), SQLFLT8, (LPBYTE)&money_value, 8);
174 						val->len = spprintf(&val->data, 0, "%.4f", money_value);
175 						}
176 						break;
177 #ifdef SQLUNIQUE
178 					case SQLUNIQUE: {
179 #else
180 					case 36: { /* FreeTDS hack, also used by ext/mssql */
181 #endif
182 						val->len = 36+1;
183 						val->data = emalloc(val->len + 1);
184 
185 						/* uniqueidentifier is a 16-byte binary number, convert to 32 char hex string */
186 #ifdef SQLUNIQUE
187 						val->len = dbconvert(NULL, SQLUNIQUE, dbdata(H->link, i+1), dbdatlen(H->link, i+1), SQLCHAR, val->data, val->len);
188 #else
189 						val->len = dbconvert(NULL, 36, dbdata(H->link, i+1), dbdatlen(H->link, i+1), SQLCHAR, val->data, val->len);
190 #endif
191 						php_strtoupper(val->data, val->len);
192 						break;
193 						}
194 					default:
195 						if (dbwillconvert(S->cols[i].coltype, SQLCHAR)) {
196 							val->len = 32 + (2 * dbdatlen(H->link, i+1));
197 							val->data = emalloc(val->len);
198 
199 							val->len = dbconvert(NULL, S->cols[i].coltype, dbdata(H->link, i+1),
200 									dbdatlen(H->link, i+1), SQLCHAR, val->data, val->len);
201 
202 							if (val->len >= 0) {
203 								val->data[val->len] = '\0';
204 							}
205 						} else {
206 							val->len = 0;
207 							val->data = NULL;
208 						}
209 				}
210 			}
211 		}
212 
213 		S->nrows++;
214 
215 		ret = dbnextrow(H->link);
216 
217 		if (ret == BUF_FULL) {
218 			dbclrbuf(H->link, DBLASTROW(H->link)-1);
219 		}
220 	} while (ret != FAIL && ret != NO_MORE_ROWS);
221 
222 	if (resret != NO_MORE_RESULTS) {
223 		/* there are additional result sets available */
224 		dbresults(H->link);
225 		/* cancel pending rows */
226 		dbcanquery(H->link);
227 
228 		/* TODO: figure out a sane solution */
229 	}
230 
231 	S->current = -1;
232 
233 	return 1;
234 }
235 
236 static int pdo_dblib_stmt_fetch(pdo_stmt_t *stmt,
237 	enum pdo_fetch_orientation ori, long offset TSRMLS_DC)
238 {
239 	pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data;
240 
241 	if (!S->rows) {
242 		return 0;
243 	}
244 
245 	if (++S->current < S->nrows) {
246 		return 1;
247 	}
248 
249 	return 0;
250 }
251 
252 static int pdo_dblib_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC)
253 {
254 	pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data;
255 	struct pdo_column_data *col = &stmt->columns[colno];
256 
257 	if (!S->rows) {
258 		return 0;
259 	}
260 
261 	col->maxlen = S->cols[colno].maxlen;
262 	col->namelen = strlen(S->cols[colno].name);
263 	col->name = estrdup(S->cols[colno].name);
264 	col->param_type = PDO_PARAM_STR;
265 
266 	return 1;
267 }
268 
269 static int pdo_dblib_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr,
270 	 unsigned long *len, int *caller_frees TSRMLS_DC)
271 {
272 	pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data;
273 	pdo_dblib_colval *val = &S->rows[S->current * S->ncols + colno];
274 
275 	*ptr = val->data;
276 	*len = val->len;
277 	return 1;
278 }
279 
280 static int pdo_dblib_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *param,
281 		enum pdo_param_event event_type TSRMLS_DC)
282 {
283 	return 1;
284 }
285 
286 static int dblib_dblib_stmt_cursor_closer(pdo_stmt_t *stmt TSRMLS_DC)
287 {
288 	pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data;
289 
290 	if (S->rows) {
291 		free_rows(S TSRMLS_CC);
292 		S->rows = NULL;
293 	}
294 
295 	return 1;
296 }
297 
298 struct pdo_stmt_methods dblib_stmt_methods = {
299 	pdo_dblib_stmt_dtor,
300 	pdo_dblib_stmt_execute,
301 	pdo_dblib_stmt_fetch,
302 	pdo_dblib_stmt_describe,
303 	pdo_dblib_stmt_get_col,
304 	pdo_dblib_stmt_param_hook,
305 	NULL, /* set attr */
306 	NULL, /* get attr */
307 	NULL, /* meta */
308 	NULL, /* nextrow */
309 	dblib_dblib_stmt_cursor_closer
310 };
311 
312