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 36static 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 54static 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 69static 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 236static 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 252static 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 269static 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 280static 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 286static 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 298struct 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