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