File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / pdo_odbc / odbc_stmt.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:34:41 2012 UTC (12 years, 1 month ago) by misho
Branches: php, MAIN
CVS tags: v5_4_3elwix, v5_4_17p0, HEAD
php 5.4.3+patches

    1: /*
    2:   +----------------------------------------------------------------------+
    3:   | PHP Version 5                                                        |
    4:   +----------------------------------------------------------------------+
    5:   | Copyright (c) 1997-2012 The PHP Group                                |
    6:   +----------------------------------------------------------------------+
    7:   | This source file is subject to version 3.0 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_0.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:   +----------------------------------------------------------------------+
   17: */
   18: 
   19: /* $Id: odbc_stmt.c,v 1.1.1.2 2012/05/29 12:34:41 misho Exp $ */
   20: 
   21: #ifdef HAVE_CONFIG_H
   22: #include "config.h"
   23: #endif
   24: 
   25: #include "php.h"
   26: #include "php_ini.h"
   27: #include "ext/standard/info.h"
   28: #include "pdo/php_pdo.h"
   29: #include "pdo/php_pdo_driver.h"
   30: #include "php_pdo_odbc.h"
   31: #include "php_pdo_odbc_int.h"
   32: 
   33: enum pdo_odbc_conv_result {
   34: 	PDO_ODBC_CONV_NOT_REQUIRED,
   35: 	PDO_ODBC_CONV_OK,
   36: 	PDO_ODBC_CONV_FAIL
   37: };
   38: 
   39: static int pdo_odbc_sqltype_is_unicode(pdo_odbc_stmt *S, SWORD sqltype)
   40: {
   41: 	if (!S->assume_utf8) return 0;
   42: 	switch (sqltype) {
   43: #ifdef SQL_WCHAR
   44: 		case SQL_WCHAR:
   45: 			return 1;
   46: #endif
   47: #ifdef SQL_WLONGVARCHAR
   48: 		case SQL_WLONGVARCHAR:
   49: 			return 1;
   50: #endif
   51: #ifdef SQL_WVARCHAR
   52: 		case SQL_WVARCHAR:
   53: 			return 1;
   54: #endif
   55: 		default:
   56: 			return 0;
   57: 	}
   58: }
   59: 
   60: static int pdo_odbc_utf82ucs2(pdo_stmt_t *stmt, int is_unicode, const char *buf, 
   61: 	unsigned long buflen, unsigned long *outlen)
   62: {
   63: #ifdef PHP_WIN32
   64: 	if (is_unicode && buflen) {
   65: 		pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
   66: 		DWORD ret;
   67: 
   68: 		ret = MultiByteToWideChar(CP_UTF8, 0, buf, buflen, NULL, 0);
   69: 		if (ret == 0) {
   70: 			/*printf("%s:%d %d [%d] %.*s\n", __FILE__, __LINE__, GetLastError(), buflen, buflen, buf);*/
   71: 			return PDO_ODBC_CONV_FAIL;
   72: 		}
   73: 
   74: 		ret *= sizeof(WCHAR);
   75: 
   76: 		if (S->convbufsize <= ret) {
   77: 			S->convbufsize = ret + sizeof(WCHAR);
   78: 			S->convbuf = erealloc(S->convbuf, S->convbufsize);
   79: 		}
   80: 		
   81: 		ret = MultiByteToWideChar(CP_UTF8, 0, buf, buflen, (LPWSTR)S->convbuf, S->convbufsize / sizeof(WCHAR));
   82: 		if (ret == 0) {
   83: 			/*printf("%s:%d %d [%d] %.*s\n", __FILE__, __LINE__, GetLastError(), buflen, buflen, buf);*/
   84: 			return PDO_ODBC_CONV_FAIL;
   85: 		}
   86: 
   87: 		ret *= sizeof(WCHAR);
   88: 		*outlen = ret;
   89: 		return PDO_ODBC_CONV_OK;
   90: 	}
   91: #endif
   92: 	return PDO_ODBC_CONV_NOT_REQUIRED;
   93: }
   94: 
   95: static int pdo_odbc_ucs22utf8(pdo_stmt_t *stmt, int is_unicode, const char *buf, 
   96: 	unsigned long buflen, unsigned long *outlen)
   97: {
   98: #ifdef PHP_WIN32
   99: 	if (is_unicode && buflen) {
  100: 		pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
  101: 		DWORD ret;
  102: 
  103: 		ret = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)buf, buflen/sizeof(WCHAR), NULL, 0, NULL, NULL);
  104: 		if (ret == 0) {
  105: 			return PDO_ODBC_CONV_FAIL;
  106: 		}
  107: 
  108: 		if (S->convbufsize <= ret) {
  109: 			S->convbufsize = ret + 1;
  110: 			S->convbuf = erealloc(S->convbuf, S->convbufsize);
  111: 		}
  112: 		
  113: 		ret = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)buf, buflen/sizeof(WCHAR), S->convbuf, S->convbufsize, NULL, NULL);
  114: 		if (ret == 0) {
  115: 			return PDO_ODBC_CONV_FAIL;
  116: 		}
  117: 
  118: 		*outlen = ret;
  119: 		S->convbuf[*outlen] = '\0';
  120: 		return PDO_ODBC_CONV_OK;
  121: 	}
  122: #endif
  123: 	return PDO_ODBC_CONV_NOT_REQUIRED;
  124: }
  125: 
  126: static void free_cols(pdo_stmt_t *stmt, pdo_odbc_stmt *S TSRMLS_DC)
  127: {
  128: 	if (S->cols) {
  129: 		int i;
  130: 
  131: 		for (i = 0; i < stmt->column_count; i++) {
  132: 			if (S->cols[i].data) {
  133: 				efree(S->cols[i].data);
  134: 			}
  135: 		}
  136: 		efree(S->cols);
  137: 		S->cols = NULL;
  138: 	}
  139: }
  140: 
  141: static int odbc_stmt_dtor(pdo_stmt_t *stmt TSRMLS_DC)
  142: {
  143: 	pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
  144: 
  145: 	if (S->stmt != SQL_NULL_HANDLE) {
  146: 		if (stmt->executed) {
  147: 			SQLCloseCursor(S->stmt);
  148: 		}
  149: 		SQLFreeHandle(SQL_HANDLE_STMT, S->stmt);
  150: 		S->stmt = SQL_NULL_HANDLE;
  151: 	}
  152: 
  153: 	free_cols(stmt, S TSRMLS_CC);
  154: 	if (S->convbuf) {
  155: 		efree(S->convbuf);
  156: 	}
  157: 	efree(S);
  158: 
  159: 	return 1;
  160: }
  161: 
  162: static int odbc_stmt_execute(pdo_stmt_t *stmt TSRMLS_DC)
  163: {
  164: 	RETCODE rc;
  165: 	pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
  166: 	char *buf = NULL;
  167: 	SQLLEN row_count = -1;
  168: 
  169: 	if (stmt->executed) {
  170: 		SQLCloseCursor(S->stmt);
  171: 	}
  172: 	
  173: 	rc = SQLExecute(S->stmt);	
  174: 
  175: 	while (rc == SQL_NEED_DATA) {
  176: 		struct pdo_bound_param_data *param;
  177: 
  178: 		rc = SQLParamData(S->stmt, (SQLPOINTER*)&param);
  179: 		if (rc == SQL_NEED_DATA) {
  180: 			php_stream *stm;
  181: 			int len;
  182: 			pdo_odbc_param *P;
  183: 	
  184: 			P = (pdo_odbc_param*)param->driver_data;
  185: 			if (Z_TYPE_P(param->parameter) != IS_RESOURCE) {
  186: 				/* they passed in a string */
  187: 				unsigned long ulen;
  188: 				convert_to_string(param->parameter);
  189: 
  190: 				switch (pdo_odbc_utf82ucs2(stmt, P->is_unicode, 
  191: 							Z_STRVAL_P(param->parameter),
  192: 							Z_STRLEN_P(param->parameter),
  193: 							&ulen)) {
  194: 					case PDO_ODBC_CONV_NOT_REQUIRED:
  195: 						SQLPutData(S->stmt, Z_STRVAL_P(param->parameter),
  196: 							Z_STRLEN_P(param->parameter));
  197: 						break;
  198: 					case PDO_ODBC_CONV_OK:
  199: 						SQLPutData(S->stmt, S->convbuf, ulen);
  200: 						break;
  201: 					case PDO_ODBC_CONV_FAIL:
  202: 						pdo_odbc_stmt_error("error converting input string");
  203: 						SQLCloseCursor(S->stmt);
  204: 						if (buf) {
  205: 							efree(buf);
  206: 						}
  207: 						return 0;
  208: 				}
  209: 				continue;
  210: 			}
  211: 
  212: 			/* we assume that LOBs are binary and don't need charset
  213: 			 * conversion */
  214: 
  215: 			php_stream_from_zval_no_verify(stm, &param->parameter);
  216: 			if (!stm) {
  217: 				/* shouldn't happen either */
  218: 				pdo_odbc_stmt_error("input LOB is no longer a stream");
  219: 				SQLCloseCursor(S->stmt);
  220: 				if (buf) {
  221: 					efree(buf);
  222: 				}
  223: 				return 0;
  224: 			}
  225: 
  226: 			/* now suck data from the stream and stick it into the database */
  227: 			if (buf == NULL) {
  228: 				buf = emalloc(8192);
  229: 			}
  230: 
  231: 			do {
  232: 				len = php_stream_read(stm, buf, 8192);
  233: 				if (len == 0) {
  234: 					break;
  235: 				}
  236: 				SQLPutData(S->stmt, buf, len);
  237: 			} while (1);
  238: 		}
  239: 	}
  240: 
  241: 	if (buf) {
  242: 		efree(buf);
  243: 	}
  244: 
  245: 	switch (rc) {
  246: 		case SQL_SUCCESS:
  247: 			break;
  248: 		case SQL_NO_DATA_FOUND:
  249: 		case SQL_SUCCESS_WITH_INFO:
  250: 			pdo_odbc_stmt_error("SQLExecute");
  251: 			break;
  252: 
  253: 		default:
  254: 			pdo_odbc_stmt_error("SQLExecute");
  255: 			return 0;
  256: 	}
  257: 
  258: 	SQLRowCount(S->stmt, &row_count);
  259: 	stmt->row_count = row_count;
  260: 
  261: 	if (!stmt->executed) {
  262: 		/* do first-time-only definition of bind/mapping stuff */
  263: 		SQLSMALLINT colcount;
  264: 
  265: 		/* how many columns do we have ? */
  266: 		SQLNumResultCols(S->stmt, &colcount);
  267: 
  268: 		stmt->column_count = (int)colcount;
  269: 		S->cols = ecalloc(colcount, sizeof(pdo_odbc_column));
  270: 		S->going_long = 0;
  271: 	}
  272: 
  273: 	return 1;
  274: }
  275: 
  276: static int odbc_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *param,
  277: 		enum pdo_param_event event_type TSRMLS_DC)
  278: {
  279: 	pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
  280: 	RETCODE rc;
  281: 	SWORD sqltype = 0, ctype = 0, scale = 0, nullable = 0;
  282: 	UDWORD precision = 0;
  283: 	pdo_odbc_param *P;
  284: 	
  285: 	/* we're only interested in parameters for prepared SQL right now */
  286: 	if (param->is_param) {
  287: 
  288: 		switch (event_type) {
  289: 			case PDO_PARAM_EVT_FREE:
  290: 				P = param->driver_data;
  291: 				if (P) {
  292: 					efree(P);
  293: 				}
  294: 				break;
  295: 
  296: 			case PDO_PARAM_EVT_ALLOC:
  297: 			{
  298: 				/* figure out what we're doing */
  299: 				switch (PDO_PARAM_TYPE(param->param_type)) {
  300: 					case PDO_PARAM_LOB:
  301: 						break;
  302: 
  303: 					case PDO_PARAM_STMT:
  304: 						return 0;
  305: 					
  306: 					default:
  307: 						break;
  308: 				}
  309: 
  310: 				rc = SQLDescribeParam(S->stmt, (SQLUSMALLINT) param->paramno+1, &sqltype, &precision, &scale, &nullable);
  311: 				if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
  312: 					/* MS Access, for instance, doesn't support SQLDescribeParam,
  313: 					 * so we need to guess */
  314: 					sqltype = PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB ?
  315: 									SQL_LONGVARBINARY :
  316: 									SQL_LONGVARCHAR;
  317: 					precision = 4000;
  318: 					scale = 5;
  319: 					nullable = 1;
  320: 
  321: 					if (param->max_value_len > 0) {
  322: 						precision = param->max_value_len;
  323: 					}
  324: 				}
  325: 				if (sqltype == SQL_BINARY || sqltype == SQL_VARBINARY || sqltype == SQL_LONGVARBINARY) {
  326: 					ctype = SQL_C_BINARY;
  327: 				} else {
  328: 					ctype = SQL_C_CHAR;
  329: 				}
  330: 
  331: 				P = emalloc(sizeof(*P));
  332: 				param->driver_data = P;
  333: 
  334: 				P->len = 0; /* is re-populated each EXEC_PRE */
  335: 				P->outbuf = NULL;
  336: 
  337: 				P->is_unicode = pdo_odbc_sqltype_is_unicode(S, sqltype);
  338: 				if (P->is_unicode) {
  339: 					/* avoid driver auto-translation: we'll do it ourselves */
  340: 					ctype = SQL_C_BINARY;
  341: 				}
  342: 
  343: 				if ((param->param_type & PDO_PARAM_INPUT_OUTPUT) == PDO_PARAM_INPUT_OUTPUT) {
  344: 					P->paramtype = SQL_PARAM_INPUT_OUTPUT;
  345: 				} else if (param->max_value_len <= 0) {
  346: 					P->paramtype = SQL_PARAM_INPUT;
  347: 				} else {
  348: 					P->paramtype = SQL_PARAM_OUTPUT;
  349: 				}
  350: 				
  351: 				if (P->paramtype != SQL_PARAM_INPUT) {
  352: 					if (PDO_PARAM_TYPE(param->param_type) != PDO_PARAM_NULL) {
  353: 						/* need an explicit buffer to hold result */
  354: 						P->len = param->max_value_len > 0 ? param->max_value_len : precision;
  355: 						if (P->is_unicode) {
  356: 							P->len *= 2;
  357: 						}
  358: 						P->outbuf = emalloc(P->len + (P->is_unicode ? 2:1));
  359: 					}
  360: 				}
  361: 				
  362: 				if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB && P->paramtype != SQL_PARAM_INPUT) {
  363: 					pdo_odbc_stmt_error("Can't bind a lob for output");
  364: 					return 0;
  365: 				}
  366: 
  367: 				rc = SQLBindParameter(S->stmt, (SQLUSMALLINT) param->paramno+1,
  368: 						P->paramtype, ctype, sqltype, precision, scale,
  369: 						P->paramtype == SQL_PARAM_INPUT ? 
  370: 							(SQLPOINTER)param :
  371: 							P->outbuf,
  372: 						P->len,
  373: 						&P->len
  374: 						);
  375: 	
  376: 				if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) {
  377: 					return 1;
  378: 				}
  379: 				pdo_odbc_stmt_error("SQLBindParameter");
  380: 				return 0;
  381: 			}
  382: 
  383: 			case PDO_PARAM_EVT_EXEC_PRE:
  384: 				P = param->driver_data;
  385: 				if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB) {
  386: 					if (Z_TYPE_P(param->parameter) == IS_RESOURCE) {
  387: 						php_stream *stm;
  388: 						php_stream_statbuf sb;
  389: 
  390: 						php_stream_from_zval_no_verify(stm, &param->parameter);
  391: 
  392: 						if (!stm) {
  393: 							return 0;
  394: 						}
  395: 
  396: 						if (0 == php_stream_stat(stm, &sb)) {
  397: 							if (P->outbuf) {
  398: 								int len, amount;
  399: 								char *ptr = P->outbuf;
  400: 								char *end = P->outbuf + P->len;
  401: 
  402: 								P->len = 0;
  403: 								do {
  404: 									amount = end - ptr;
  405: 									if (amount == 0) {
  406: 										break;
  407: 									}
  408: 									if (amount > 8192)
  409: 										amount = 8192;
  410: 									len = php_stream_read(stm, ptr, amount);
  411: 									if (len == 0) {
  412: 										break;
  413: 									}
  414: 									ptr += len;
  415: 									P->len += len;
  416: 								} while (1);
  417: 
  418: 							} else {
  419: 								P->len = SQL_LEN_DATA_AT_EXEC(sb.sb.st_size);
  420: 							}
  421: 						} else {
  422: 							if (P->outbuf) {
  423: 								P->len = 0;
  424: 							} else {
  425: 								P->len = SQL_LEN_DATA_AT_EXEC(0);
  426: 							}
  427: 						}
  428: 					} else {
  429: 						convert_to_string(param->parameter);
  430: 						if (P->outbuf) {
  431: 							P->len = Z_STRLEN_P(param->parameter);
  432: 							memcpy(P->outbuf, Z_STRVAL_P(param->parameter), P->len);
  433: 						} else {
  434: 							P->len = SQL_LEN_DATA_AT_EXEC(Z_STRLEN_P(param->parameter));
  435: 						}
  436: 					}
  437: 				} else if (Z_TYPE_P(param->parameter) == IS_NULL || PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_NULL) {
  438: 					P->len = SQL_NULL_DATA;
  439: 				} else {
  440: 					convert_to_string(param->parameter);
  441: 					if (P->outbuf) {
  442: 						unsigned long ulen;
  443: 						switch (pdo_odbc_utf82ucs2(stmt, P->is_unicode,
  444: 								Z_STRVAL_P(param->parameter),
  445: 								Z_STRLEN_P(param->parameter),
  446: 								&ulen)) {
  447: 							case PDO_ODBC_CONV_FAIL:
  448: 							case PDO_ODBC_CONV_NOT_REQUIRED:
  449: 								P->len = Z_STRLEN_P(param->parameter);
  450: 								memcpy(P->outbuf, Z_STRVAL_P(param->parameter), P->len);
  451: 								break;
  452: 							case PDO_ODBC_CONV_OK:
  453: 								P->len = ulen;
  454: 								memcpy(P->outbuf, S->convbuf, P->len);
  455: 								break;
  456: 						}
  457: 					} else {
  458: 						P->len = SQL_LEN_DATA_AT_EXEC(Z_STRLEN_P(param->parameter));
  459: 					}
  460: 				}
  461: 				return 1;
  462: 			
  463: 			case PDO_PARAM_EVT_EXEC_POST:
  464: 				P = param->driver_data;
  465: 				if (P->outbuf) {
  466: 					if (P->outbuf) {
  467: 						unsigned long ulen;
  468: 						char *srcbuf;
  469: 						unsigned long srclen;
  470: 
  471: 						switch (P->len) {
  472: 							case SQL_NULL_DATA:
  473: 								zval_dtor(param->parameter);
  474: 								ZVAL_NULL(param->parameter);
  475: 								break;
  476: 							default:
  477: 								convert_to_string(param->parameter);
  478: 								switch (pdo_odbc_ucs22utf8(stmt, P->is_unicode, P->outbuf, P->len, &ulen)) {
  479: 									case PDO_ODBC_CONV_FAIL:
  480: 										/* something fishy, but allow it to come back as binary */
  481: 									case PDO_ODBC_CONV_NOT_REQUIRED:
  482: 										srcbuf = P->outbuf;
  483: 										srclen = P->len;
  484: 										break;
  485: 									case PDO_ODBC_CONV_OK:
  486: 										srcbuf = S->convbuf;
  487: 										srclen = ulen;
  488: 										break;
  489: 								}
  490: 										
  491: 								Z_STRVAL_P(param->parameter) = erealloc(Z_STRVAL_P(param->parameter), srclen+1);
  492: 								memcpy(Z_STRVAL_P(param->parameter), srcbuf, srclen);
  493: 								Z_STRLEN_P(param->parameter) = srclen;
  494: 								Z_STRVAL_P(param->parameter)[srclen] = '\0';
  495: 						}
  496: 					}
  497: 				}
  498: 				return 1;
  499: 		}
  500: 	}
  501: 	return 1;
  502: }
  503: 
  504: static int odbc_stmt_fetch(pdo_stmt_t *stmt,
  505: 	enum pdo_fetch_orientation ori, long offset TSRMLS_DC)
  506: {
  507: 	RETCODE rc;
  508: 	SQLSMALLINT odbcori;
  509: 	pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
  510: 
  511: 	switch (ori) {
  512: 		case PDO_FETCH_ORI_NEXT:	odbcori = SQL_FETCH_NEXT; break;
  513: 		case PDO_FETCH_ORI_PRIOR:	odbcori = SQL_FETCH_PRIOR; break;
  514: 		case PDO_FETCH_ORI_FIRST:	odbcori = SQL_FETCH_FIRST; break;
  515: 		case PDO_FETCH_ORI_LAST:	odbcori = SQL_FETCH_LAST; break;
  516: 		case PDO_FETCH_ORI_ABS:		odbcori = SQL_FETCH_ABSOLUTE; break;
  517: 		case PDO_FETCH_ORI_REL:		odbcori = SQL_FETCH_RELATIVE; break;
  518: 		default: 
  519: 			strcpy(stmt->error_code, "HY106");
  520: 			return 0;
  521: 	}
  522: 	rc = SQLFetchScroll(S->stmt, odbcori, offset);
  523: 
  524: 	if (rc == SQL_SUCCESS) {
  525: 		return 1;
  526: 	}
  527: 	if (rc == SQL_SUCCESS_WITH_INFO) {
  528: 		pdo_odbc_stmt_error("SQLFetchScroll");
  529: 		return 1;
  530: 	}
  531: 
  532: 	if (rc == SQL_NO_DATA) {
  533: 		/* pdo_odbc_stmt_error("SQLFetchScroll"); */
  534: 		return 0;
  535: 	}
  536: 
  537: 	pdo_odbc_stmt_error("SQLFetchScroll");
  538: 
  539: 	return 0;
  540: }
  541: 
  542: static int odbc_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC)
  543: {
  544: 	pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
  545: 	struct pdo_column_data *col = &stmt->columns[colno];
  546: 	zend_bool dyn = FALSE;
  547: 	RETCODE rc;
  548: 	SWORD	colnamelen;
  549: 	SDWORD	colsize, displaysize;
  550: 
  551: 	rc = SQLDescribeCol(S->stmt, colno+1, S->cols[colno].colname,
  552: 			sizeof(S->cols[colno].colname)-1, &colnamelen,
  553: 			&S->cols[colno].coltype, &colsize, NULL, NULL);
  554: 
  555: 	if (rc != SQL_SUCCESS) {
  556: 		pdo_odbc_stmt_error("SQLDescribeCol");
  557: 		if (rc != SQL_SUCCESS_WITH_INFO) {
  558: 			return 0;
  559: 		}
  560: 	}
  561: 
  562: 	rc = SQLColAttribute(S->stmt, colno+1,
  563: 			SQL_DESC_DISPLAY_SIZE,
  564: 			NULL, 0, NULL, &displaysize);
  565: 
  566: 	if (rc != SQL_SUCCESS) {
  567: 		pdo_odbc_stmt_error("SQLColAttribute");
  568: 		if (rc != SQL_SUCCESS_WITH_INFO) {
  569: 			return 0;
  570: 		}
  571: 	}
  572: 	colsize = displaysize;
  573: 
  574: 	col->maxlen = S->cols[colno].datalen = colsize;
  575: 	col->namelen = colnamelen;
  576: 	col->name = estrdup(S->cols[colno].colname);
  577: 	S->cols[colno].is_unicode = pdo_odbc_sqltype_is_unicode(S, S->cols[colno].coltype);
  578: 
  579: 	/* returning data as a string */
  580: 	col->param_type = PDO_PARAM_STR;
  581: 
  582: 	/* tell ODBC to put it straight into our buffer, but only if it
  583: 	 * isn't "long" data, and only if we haven't already bound a long
  584: 	 * column. */
  585: 	if (colsize < 256 && !S->going_long) {
  586: 		S->cols[colno].data = emalloc(colsize+1);
  587: 		S->cols[colno].is_long = 0;
  588: 
  589: 		rc = SQLBindCol(S->stmt, colno+1,
  590: 			S->cols[colno].is_unicode ? SQL_C_BINARY : SQL_C_CHAR,
  591: 			S->cols[colno].data,
  592:  			S->cols[colno].datalen+1, &S->cols[colno].fetched_len);
  593: 
  594: 		if (rc != SQL_SUCCESS) {
  595: 			pdo_odbc_stmt_error("SQLBindCol");
  596: 			return 0;
  597: 		}
  598: 	} else {
  599: 		/* allocate a smaller buffer to keep around for smaller
  600: 		 * "long" columns */
  601: 		S->cols[colno].data = emalloc(256);
  602: 		S->going_long = 1;
  603: 		S->cols[colno].is_long = 1;
  604: 	}
  605: 
  606: 	return 1;
  607: }
  608: 
  609: static int odbc_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, unsigned long *len, int *caller_frees TSRMLS_DC)
  610: {
  611: 	pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
  612: 	pdo_odbc_column *C = &S->cols[colno];
  613: 	unsigned long ulen;
  614: 
  615: 	/* if it is a column containing "long" data, perform late binding now */
  616: 	if (C->is_long) {
  617: 		unsigned long alloced = 4096;
  618: 		unsigned long used = 0;
  619: 		char *buf;
  620: 		RETCODE rc;
  621: 
  622: 		/* fetch it into C->data, which is allocated with a length
  623: 		 * of 256 bytes; if there is more to be had, we then allocate
  624: 		 * bigger buffer for the caller to free */
  625: 
  626: 		rc = SQLGetData(S->stmt, colno+1, C->is_unicode ? SQL_C_BINARY : SQL_C_CHAR, C->data,
  627:  			256, &C->fetched_len);
  628: 
  629: 		if (rc == SQL_SUCCESS) {
  630: 			/* all the data fit into our little buffer;
  631: 			 * jump down to the generic bound data case */
  632: 			goto in_data;
  633: 		}
  634: 
  635: 		if (rc == SQL_SUCCESS_WITH_INFO) {
  636: 			/* promote up to a bigger buffer */
  637: 
  638: 			if (C->fetched_len != SQL_NO_TOTAL) {
  639: 				/* use size suggested by the driver, if it knows it */
  640: 				buf = emalloc(C->fetched_len + 1);
  641: 				memcpy(buf, C->data, C->fetched_len);
  642: 				buf[C->fetched_len] = 0;
  643: 				used = C->fetched_len;
  644: 			} else {
  645: 				buf = estrndup(C->data, 256);
  646: 				used = 255; /* not 256; the driver NUL terminated the buffer */
  647: 			}
  648: 
  649: 			do {
  650: 				C->fetched_len = 0;
  651: 				rc = SQLGetData(S->stmt, colno+1, SQL_C_CHAR,
  652: 					buf + used, alloced - used,
  653: 					&C->fetched_len);
  654: 
  655: 				if (rc == SQL_NO_DATA) {
  656: 					/* we got the lot */
  657: 					break;
  658: 				} else if (rc != SQL_SUCCESS) {
  659: 					pdo_odbc_stmt_error("SQLGetData");
  660: 					if (rc != SQL_SUCCESS_WITH_INFO) {
  661: 						break;
  662: 					}
  663: 				}
  664: 
  665: 				if (C->fetched_len == SQL_NO_TOTAL) {
  666: 					used += alloced - used;
  667: 				} else {
  668: 					used += C->fetched_len;
  669: 				}
  670: 
  671: 				if (rc == SQL_SUCCESS) {
  672: 					/* this was the final fetch */
  673: 					break;
  674: 				}
  675: 
  676: 				/* we need to fetch another chunk; resize the
  677: 				 * buffer */
  678: 				alloced *= 2;
  679: 				buf = erealloc(buf, alloced);
  680: 			} while (1);
  681: 
  682: 			/* size down */
  683: 			if (used < alloced - 1024) {
  684: 				alloced = used+1;
  685: 				buf = erealloc(buf, used+1);
  686: 			}
  687: 			buf[used] = '\0';
  688: 			*ptr = buf;
  689: 			*caller_frees = 1;
  690: 			*len = used;
  691: 			if (C->is_unicode) {
  692: 				goto unicode_conv;
  693: 			}
  694: 			return 1;
  695: 		}
  696: 
  697: 		/* something went caca */
  698: 		*ptr = NULL;
  699: 		*len = 0;
  700: 		return 1;
  701: 	}
  702: 
  703: in_data:
  704: 	/* check the indicator to ensure that the data is intact */
  705: 	if (C->fetched_len == SQL_NULL_DATA) {
  706: 		/* A NULL value */
  707: 		*ptr = NULL;
  708: 		*len = 0;
  709: 		return 1;
  710: 	} else if (C->fetched_len >= 0) {
  711: 		/* it was stored perfectly */
  712: 		*ptr = C->data;
  713: 		*len = C->fetched_len;
  714: 		if (C->is_unicode) {
  715: 			goto unicode_conv;
  716: 		}
  717: 		return 1;
  718: 	} else {
  719: 		/* no data? */
  720: 		*ptr = NULL;
  721: 		*len = 0;
  722: 		return 1;
  723: 	}
  724: 
  725: 	unicode_conv:
  726: 	switch (pdo_odbc_ucs22utf8(stmt, C->is_unicode, *ptr, *len, &ulen)) {
  727: 		case PDO_ODBC_CONV_FAIL:
  728: 			/* oh well.  They can have the binary version of it */
  729: 		case PDO_ODBC_CONV_NOT_REQUIRED:
  730: 			/* shouldn't happen... */
  731: 			return 1;
  732: 
  733: 		case PDO_ODBC_CONV_OK:
  734: 			if (*caller_frees) {
  735: 				efree(*ptr);
  736: 			}
  737: 			*ptr = emalloc(ulen + 1);
  738: 			*len = ulen;
  739: 			memcpy(*ptr, S->convbuf, ulen+1);
  740: 			*caller_frees = 1;
  741: 			return 1;
  742: 	}
  743: 	return 1;
  744: }
  745: 
  746: static int odbc_stmt_set_param(pdo_stmt_t *stmt, long attr, zval *val TSRMLS_DC)
  747: {
  748: 	SQLRETURN rc;
  749: 	pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
  750: 
  751: 	switch (attr) {
  752: 		case PDO_ATTR_CURSOR_NAME:
  753: 			convert_to_string(val);
  754: 			rc = SQLSetCursorName(S->stmt, Z_STRVAL_P(val), Z_STRLEN_P(val));
  755: 
  756: 			if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) {
  757: 				return 1;
  758: 			}
  759: 			pdo_odbc_stmt_error("SQLSetCursorName");
  760: 			return 0;
  761: 
  762: 		case PDO_ODBC_ATTR_ASSUME_UTF8:
  763: 			S->assume_utf8 = zval_is_true(val);
  764: 			return 0;
  765: 		default:
  766: 			strcpy(S->einfo.last_err_msg, "Unknown Attribute");
  767: 			S->einfo.what = "setAttribute";
  768: 			strcpy(S->einfo.last_state, "IM001");
  769: 			return -1;
  770: 	}
  771: }
  772: 
  773: static int odbc_stmt_get_attr(pdo_stmt_t *stmt, long attr, zval *val TSRMLS_DC)
  774: {
  775: 	SQLRETURN rc;
  776: 	pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
  777: 
  778: 	switch (attr) {
  779: 		case PDO_ATTR_CURSOR_NAME:
  780: 		{
  781: 			char buf[256];
  782: 			SQLSMALLINT len = 0;
  783: 			rc = SQLGetCursorName(S->stmt, buf, sizeof(buf), &len);
  784: 
  785: 			if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) {
  786: 				ZVAL_STRINGL(val, buf, len, 1);
  787: 				return 1;
  788: 			}
  789: 			pdo_odbc_stmt_error("SQLGetCursorName");
  790: 			return 0;
  791: 		}
  792: 
  793: 		case PDO_ODBC_ATTR_ASSUME_UTF8:
  794: 			ZVAL_BOOL(val, S->assume_utf8 ? 1 : 0);
  795: 			return 0;
  796: 
  797: 		default:
  798: 			strcpy(S->einfo.last_err_msg, "Unknown Attribute");
  799: 			S->einfo.what = "getAttribute";
  800: 			strcpy(S->einfo.last_state, "IM001");
  801: 			return -1;
  802: 	}
  803: }
  804: 
  805: static int odbc_stmt_next_rowset(pdo_stmt_t *stmt TSRMLS_DC)
  806: {
  807: 	SQLRETURN rc;
  808: 	SQLSMALLINT colcount;
  809: 	pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
  810: 
  811: 	/* NOTE: can't guarantee that output or input/output parameters
  812: 	 * are set until this fella returns SQL_NO_DATA, according to
  813: 	 * MSDN ODBC docs */
  814: 	rc = SQLMoreResults(S->stmt);
  815: 
  816: 	if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
  817: 		return 0;
  818: 	}
  819: 
  820: 	free_cols(stmt, S TSRMLS_CC);
  821: 	/* how many columns do we have ? */
  822: 	SQLNumResultCols(S->stmt, &colcount);
  823: 	stmt->column_count = (int)colcount;
  824: 	S->cols = ecalloc(colcount, sizeof(pdo_odbc_column));
  825: 	S->going_long = 0;
  826: 
  827: 	return 1;
  828: }
  829: 
  830: struct pdo_stmt_methods odbc_stmt_methods = {
  831: 	odbc_stmt_dtor,
  832: 	odbc_stmt_execute,
  833: 	odbc_stmt_fetch,
  834: 	odbc_stmt_describe,
  835: 	odbc_stmt_get_col,
  836: 	odbc_stmt_param_hook,
  837: 	odbc_stmt_set_param,
  838: 	odbc_stmt_get_attr, /* get attr */
  839: 	NULL, /* get column meta */
  840: 	odbc_stmt_next_rowset
  841: };
  842: 
  843: /*
  844:  * Local variables:
  845:  * tab-width: 4
  846:  * c-basic-offset: 4
  847:  * End:
  848:  * vim600: noet sw=4 ts=4 fdm=marker
  849:  * vim<600: noet sw=4 ts=4
  850:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>