xref: /PHP-5.4/ext/mssql/php_mssql.c (revision c0d060f5)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 5                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1997-2014 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: Frank M. Kromann <frank@kromann.info>                        |
16    +----------------------------------------------------------------------+
17  */
18 
19 /* $Id$ */
20 
21 #ifdef COMPILE_DL_MSSQL
22 #define HAVE_MSSQL 1
23 #endif
24 
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28 
29 #include "php.h"
30 #include "php_globals.h"
31 #include "ext/standard/php_standard.h"
32 #include "ext/standard/info.h"
33 #include "php_mssql.h"
34 #include "php_ini.h"
35 
36 #if HAVE_MSSQL
37 #define SAFE_STRING(s) ((s)?(s):"")
38 
39 #define MSSQL_ASSOC		1<<0
40 #define MSSQL_NUM		1<<1
41 #define MSSQL_BOTH		(MSSQL_ASSOC|MSSQL_NUM)
42 
43 static int le_result, le_link, le_plink, le_statement;
44 
45 static void php_mssql_get_column_content_with_type(mssql_link *mssql_ptr,int offset,zval *result, int column_type TSRMLS_DC);
46 static void php_mssql_get_column_content_without_type(mssql_link *mssql_ptr,int offset,zval *result, int column_type TSRMLS_DC);
47 
48 static void _mssql_bind_hash_dtor(void *data);
49 
50 /* {{{ arginfo */
51 ZEND_BEGIN_ARG_INFO_EX(arginfo_mssql_connect, 0, 0, 0)
52 	ZEND_ARG_INFO(0, servername)
53 	ZEND_ARG_INFO(0, username)
54 	ZEND_ARG_INFO(0, password)
55 	ZEND_ARG_INFO(0, newlink)
56 ZEND_END_ARG_INFO()
57 
58 ZEND_BEGIN_ARG_INFO_EX(arginfo_mssql_close, 0, 0, 0)
59 	ZEND_ARG_INFO(0, link_identifier)
60 ZEND_END_ARG_INFO()
61 
62 ZEND_BEGIN_ARG_INFO_EX(arginfo_mssql_select_db, 0, 0, 1)
63 	ZEND_ARG_INFO(0, database_name)
64 	ZEND_ARG_INFO(0, link_identifier)
65 ZEND_END_ARG_INFO()
66 
67 ZEND_BEGIN_ARG_INFO_EX(arginfo_mssql_query, 0, 0, 1)
68 	ZEND_ARG_INFO(0, query)
69 	ZEND_ARG_INFO(0, link_identifier)
70 	ZEND_ARG_INFO(0, batch_size)
71 ZEND_END_ARG_INFO()
72 
73 ZEND_BEGIN_ARG_INFO_EX(arginfo_mssql_fetch_batch, 0, 0, 1)
74 	ZEND_ARG_INFO(0, result)
75 ZEND_END_ARG_INFO()
76 
77 ZEND_BEGIN_ARG_INFO_EX(arginfo_mssql_rows_affected, 0, 0, 1)
78 	ZEND_ARG_INFO(0, link_identifier)
79 ZEND_END_ARG_INFO()
80 
81 ZEND_BEGIN_ARG_INFO(arginfo_mssql_get_last_message, 0)
82 ZEND_END_ARG_INFO()
83 
84 ZEND_BEGIN_ARG_INFO_EX(arginfo_mssql_fetch_field, 0, 0, 1)
85 	ZEND_ARG_INFO(0, result)
86 	ZEND_ARG_INFO(0, field_offset)
87 ZEND_END_ARG_INFO()
88 
89 ZEND_BEGIN_ARG_INFO_EX(arginfo_mssql_fetch_array, 0, 0, 1)
90 	ZEND_ARG_INFO(0, result)
91 	ZEND_ARG_INFO(0, result_type)
92 ZEND_END_ARG_INFO()
93 
94 ZEND_BEGIN_ARG_INFO_EX(arginfo_mssql_fetch_assoc, 0, 0, 1)
95 	ZEND_ARG_INFO(0, result_id)
96 ZEND_END_ARG_INFO()
97 
98 ZEND_BEGIN_ARG_INFO_EX(arginfo_mssql_field_length, 0, 0, 1)
99 	ZEND_ARG_INFO(0, result)
100 	ZEND_ARG_INFO(0, offset)
101 ZEND_END_ARG_INFO()
102 
103 ZEND_BEGIN_ARG_INFO_EX(arginfo_mssql_data_seek, 0, 0, 2)
104 	ZEND_ARG_INFO(0, result_identifier)
105 	ZEND_ARG_INFO(0, row_number)
106 ZEND_END_ARG_INFO()
107 
108 ZEND_BEGIN_ARG_INFO_EX(arginfo_mssql_result, 0, 0, 3)
109 	ZEND_ARG_INFO(0, result)
110 	ZEND_ARG_INFO(0, row)
111 	ZEND_ARG_INFO(0, field)
112 ZEND_END_ARG_INFO()
113 
114 ZEND_BEGIN_ARG_INFO_EX(arginfo_mssql_min_error_severity, 0, 0, 1)
115 	ZEND_ARG_INFO(0, severity)
116 ZEND_END_ARG_INFO()
117 
118 ZEND_BEGIN_ARG_INFO_EX(arginfo_mssql_init, 0, 0, 1)
119 	ZEND_ARG_INFO(0, sp_name)
120 	ZEND_ARG_INFO(0, link_identifier)
121 ZEND_END_ARG_INFO()
122 
123 ZEND_BEGIN_ARG_INFO_EX(arginfo_mssql_bind, 0, 0, 4)
124 	ZEND_ARG_INFO(0, stmt)
125 	ZEND_ARG_INFO(0, param_name)
126 	ZEND_ARG_INFO(1, var)
127 	ZEND_ARG_INFO(0, type)
128 	ZEND_ARG_INFO(0, is_output)
129 	ZEND_ARG_INFO(0, is_null)
130 	ZEND_ARG_INFO(0, maxlen)
131 ZEND_END_ARG_INFO()
132 
133 ZEND_BEGIN_ARG_INFO_EX(arginfo_mssql_execute, 0, 0, 1)
134 	ZEND_ARG_INFO(0, stmt)
135 	ZEND_ARG_INFO(0, skip_results)
136 ZEND_END_ARG_INFO()
137 
138 ZEND_BEGIN_ARG_INFO_EX(arginfo_mssql_free_statement, 0, 0, 1)
139 	ZEND_ARG_INFO(0, stmt)
140 ZEND_END_ARG_INFO()
141 
142 ZEND_BEGIN_ARG_INFO_EX(arginfo_mssql_guid_string, 0, 0, 1)
143 	ZEND_ARG_INFO(0, binary)
144 	ZEND_ARG_INFO(0, short_format)
145 ZEND_END_ARG_INFO()
146 /* }}} */
147 
148 /* {{{ mssql_functions
149 */
150 const zend_function_entry mssql_functions[] = {
151 	PHP_FE(mssql_connect,				arginfo_mssql_connect)
152 	PHP_FE(mssql_pconnect,				arginfo_mssql_connect)
153 	PHP_FE(mssql_close,					arginfo_mssql_close)
154 	PHP_FE(mssql_select_db,				arginfo_mssql_select_db)
155 	PHP_FE(mssql_query,					arginfo_mssql_query)
156 	PHP_FE(mssql_fetch_batch,			arginfo_mssql_fetch_batch)
157 	PHP_FE(mssql_rows_affected,			arginfo_mssql_rows_affected)
158 	PHP_FE(mssql_free_result,			arginfo_mssql_fetch_batch)
159 	PHP_FE(mssql_get_last_message,		arginfo_mssql_get_last_message)
160 	PHP_FE(mssql_num_rows,				arginfo_mssql_fetch_batch)
161 	PHP_FE(mssql_num_fields,			arginfo_mssql_fetch_batch)
162 	PHP_FE(mssql_fetch_field,			arginfo_mssql_fetch_field)
163 	PHP_FE(mssql_fetch_row,				arginfo_mssql_fetch_batch)
164 	PHP_FE(mssql_fetch_array,			arginfo_mssql_fetch_array)
165 	PHP_FE(mssql_fetch_assoc,			arginfo_mssql_fetch_assoc)
166 	PHP_FE(mssql_fetch_object,			arginfo_mssql_fetch_batch)
167 	PHP_FE(mssql_field_length,			arginfo_mssql_field_length)
168 	PHP_FE(mssql_field_name,			arginfo_mssql_field_length)
169 	PHP_FE(mssql_field_type,			arginfo_mssql_field_length)
170 	PHP_FE(mssql_data_seek,				arginfo_mssql_data_seek)
171 	PHP_FE(mssql_field_seek,			arginfo_mssql_fetch_field)
172 	PHP_FE(mssql_result,				arginfo_mssql_result)
173 	PHP_FE(mssql_next_result,			arginfo_mssql_fetch_assoc)
174 	PHP_FE(mssql_min_error_severity,	arginfo_mssql_min_error_severity)
175 	PHP_FE(mssql_min_message_severity,	arginfo_mssql_min_error_severity)
176  	PHP_FE(mssql_init,					arginfo_mssql_init)
177  	PHP_FE(mssql_bind,					arginfo_mssql_bind)
178  	PHP_FE(mssql_execute,				arginfo_mssql_execute)
179 	PHP_FE(mssql_free_statement,		arginfo_mssql_free_statement)
180  	PHP_FE(mssql_guid_string,			arginfo_mssql_guid_string)
181 	PHP_FE_END
182 };
183 /* }}} */
184 
185 ZEND_DECLARE_MODULE_GLOBALS(mssql)
186 static PHP_GINIT_FUNCTION(mssql);
187 
188 /* {{{ mssql_module_entry
189 */
190 zend_module_entry mssql_module_entry =
191 {
192 	STANDARD_MODULE_HEADER,
193 	"mssql",
194 	mssql_functions,
195 	PHP_MINIT(mssql),
196 	PHP_MSHUTDOWN(mssql),
197 	PHP_RINIT(mssql),
198 	PHP_RSHUTDOWN(mssql),
199 	PHP_MINFO(mssql),
200 	NO_VERSION_YET,
201 	PHP_MODULE_GLOBALS(mssql),
202 	PHP_GINIT(mssql),
203 	NULL,
204 	NULL,
205 	STANDARD_MODULE_PROPERTIES_EX
206 };
207 /* }}} */
208 
209 #ifdef COMPILE_DL_MSSQL
210 ZEND_GET_MODULE(mssql)
211 #endif
212 
213 #define CHECK_LINK(link) { if (link==-1) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "A link to the server could not be established"); RETURN_FALSE; } }
214 
215 /* {{{ PHP_INI_DISP
216 */
PHP_INI_DISP(display_text_size)217 static PHP_INI_DISP(display_text_size)
218 {
219 	char *value;
220 	TSRMLS_FETCH();
221 
222     if (type == PHP_INI_DISPLAY_ORIG && ini_entry->modified) {
223 		value = ini_entry->orig_value;
224 	} else if (ini_entry->value) {
225 		value = ini_entry->value;
226 	} else {
227 		value = NULL;
228 	}
229 
230 	if (atoi(value) == -1) {
231 		PUTS("Server default");
232 	} else {
233 		php_printf("%s", value);
234 	}
235 }
236 /* }}} */
237 
238 /* {{{ PHP_INI
239 */
240 PHP_INI_BEGIN()
241 	STD_PHP_INI_BOOLEAN("mssql.allow_persistent",		"1",	PHP_INI_SYSTEM,	OnUpdateBool,	allow_persistent,			zend_mssql_globals,		mssql_globals)
242 	STD_PHP_INI_ENTRY_EX("mssql.max_persistent",		"-1",	PHP_INI_SYSTEM,	OnUpdateLong,	max_persistent,				zend_mssql_globals,		mssql_globals,	display_link_numbers)
243 	STD_PHP_INI_ENTRY_EX("mssql.max_links",				"-1",	PHP_INI_SYSTEM,	OnUpdateLong,	max_links,					zend_mssql_globals,		mssql_globals,	display_link_numbers)
244 	STD_PHP_INI_ENTRY_EX("mssql.min_error_severity",	"10",	PHP_INI_ALL,	OnUpdateLong,	cfg_min_error_severity,		zend_mssql_globals,		mssql_globals,	display_link_numbers)
245 	STD_PHP_INI_ENTRY_EX("mssql.min_message_severity",	"10",	PHP_INI_ALL,	OnUpdateLong,	cfg_min_message_severity,	zend_mssql_globals,		mssql_globals,	display_link_numbers)
246 	STD_PHP_INI_BOOLEAN("mssql.compatability_mode",		"0",	PHP_INI_ALL,	OnUpdateBool,	compatability_mode,			zend_mssql_globals,		mssql_globals)
247 	STD_PHP_INI_ENTRY_EX("mssql.connect_timeout",    	"5",	PHP_INI_ALL,	OnUpdateLong,	connect_timeout,			zend_mssql_globals,		mssql_globals,	display_link_numbers)
248 	STD_PHP_INI_ENTRY_EX("mssql.timeout",      			"60",	PHP_INI_ALL,	OnUpdateLong,	timeout,					zend_mssql_globals,		mssql_globals,	display_link_numbers)
249 	STD_PHP_INI_ENTRY_EX("mssql.textsize",   			"-1",	PHP_INI_ALL,	OnUpdateLong,	textsize,					zend_mssql_globals,		mssql_globals,	display_text_size)
250 	STD_PHP_INI_ENTRY_EX("mssql.textlimit",   			"-1",	PHP_INI_ALL,	OnUpdateLong,	textlimit,					zend_mssql_globals,		mssql_globals,	display_text_size)
251 	STD_PHP_INI_ENTRY_EX("mssql.batchsize",   			"0",	PHP_INI_ALL,	OnUpdateLong,	batchsize,					zend_mssql_globals,		mssql_globals,	display_link_numbers)
252 	STD_PHP_INI_BOOLEAN("mssql.datetimeconvert",  		"1",	PHP_INI_ALL,	OnUpdateBool,	datetimeconvert,			zend_mssql_globals,		mssql_globals)
253 	STD_PHP_INI_BOOLEAN("mssql.secure_connection",		"0",	PHP_INI_SYSTEM, OnUpdateBool,	secure_connection,			zend_mssql_globals,		mssql_globals)
254 	STD_PHP_INI_ENTRY_EX("mssql.max_procs",				"-1",	PHP_INI_ALL,	OnUpdateLong,	max_procs,					zend_mssql_globals,		mssql_globals,	display_link_numbers)
255 #ifdef HAVE_FREETDS
256 	STD_PHP_INI_ENTRY("mssql.charset",					"",		PHP_INI_ALL,	OnUpdateString,	charset,					zend_mssql_globals,		mssql_globals)
257 #endif
PHP_INI_END()258 PHP_INI_END()
259 /* }}} */
260 
261 /* error handler */
262 static int php_mssql_error_handler(DBPROCESS *dbproc, int severity, int dberr, int oserr, char *dberrstr, char *oserrstr)
263 {
264 	TSRMLS_FETCH();
265 
266 	if (severity >= MS_SQL_G(min_error_severity)) {
267 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s (severity %d)", dberrstr, severity);
268 	}
269 	return INT_CANCEL;
270 }
271 
272 /* {{{ php_mssql_message_handler
273 */
274 /* message handler */
php_mssql_message_handler(DBPROCESS * dbproc,DBINT msgno,int msgstate,int severity,char * msgtext,char * srvname,char * procname,DBUSMALLINT line)275 static int php_mssql_message_handler(DBPROCESS *dbproc, DBINT msgno,int msgstate, int severity,char *msgtext,char *srvname, char *procname,DBUSMALLINT line)
276 {
277 	TSRMLS_FETCH();
278 
279 	if (severity >= MS_SQL_G(min_message_severity)) {
280 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "message: %s (severity %d)", msgtext, severity);
281 	}
282 	if (MS_SQL_G(server_message)) {
283 		STR_FREE(MS_SQL_G(server_message));
284 		MS_SQL_G(server_message) = NULL;
285 	}
286 	MS_SQL_G(server_message) = estrdup(msgtext);
287 	return 0;
288 }
289 /* }}} */
290 
291 /* {{{ _clean_invalid_results
292 */
_clean_invalid_results(zend_rsrc_list_entry * le TSRMLS_DC)293 static int _clean_invalid_results(zend_rsrc_list_entry *le TSRMLS_DC)
294 {
295 	if (Z_TYPE_P(le) == le_result) {
296 		mssql_link *mssql_ptr = ((mssql_result *) le->ptr)->mssql_ptr;
297 
298 		if (!mssql_ptr->valid) {
299 			return 1;
300 		}
301 	}
302 	return 0;
303 }
304 /* }}} */
305 
306 /* {{{ _free_result
307 */
_free_result(mssql_result * result,int free_fields)308 static void _free_result(mssql_result *result, int free_fields)
309 {
310 	int i,j;
311 
312 	if (result->data) {
313 		for (i=0; i<result->num_rows; i++) {
314 			if (result->data[i]) {
315 				for (j=0; j<result->num_fields; j++) {
316 					zval_dtor(&result->data[i][j]);
317 				}
318 				efree(result->data[i]);
319 			}
320 		}
321 		efree(result->data);
322 		result->data = NULL;
323 		result->blocks_initialized = 0;
324 	}
325 
326 	if (free_fields && result->fields) {
327 		for (i=0; i<result->num_fields; i++) {
328 			STR_FREE(result->fields[i].name);
329 			STR_FREE(result->fields[i].column_source);
330 		}
331 		efree(result->fields);
332 	}
333 }
334 /* }}} */
335 
336 /* {{{ _free_mssql_statement
337 */
_free_mssql_statement(zend_rsrc_list_entry * rsrc TSRMLS_DC)338 static void _free_mssql_statement(zend_rsrc_list_entry *rsrc TSRMLS_DC)
339 {
340 	mssql_statement *statement = (mssql_statement *)rsrc->ptr;
341 
342 	if (statement->binds) {
343 		zend_hash_destroy(statement->binds);
344 		efree(statement->binds);
345 	}
346 
347 	efree(statement);
348 }
349 /* }}} */
350 
351 /* {{{ _free_mssql_result
352 */
_free_mssql_result(zend_rsrc_list_entry * rsrc TSRMLS_DC)353 static void _free_mssql_result(zend_rsrc_list_entry *rsrc TSRMLS_DC)
354 {
355 	mssql_result *result = (mssql_result *)rsrc->ptr;
356 
357 	_free_result(result, 1);
358 	dbcancel(result->mssql_ptr->link);
359 	efree(result);
360 }
361 /* }}} */
362 
363 /* {{{ php_mssql_set_defaullt_link
364 */
php_mssql_set_default_link(int id TSRMLS_DC)365 static void php_mssql_set_default_link(int id TSRMLS_DC)
366 {
367 	if (MS_SQL_G(default_link)!=-1) {
368 		zend_list_delete(MS_SQL_G(default_link));
369 	}
370 	MS_SQL_G(default_link) = id;
371 	zend_list_addref(id);
372 }
373 /* }}} */
374 
375 /* {{{ _close_mssql_link
376 */
_close_mssql_link(zend_rsrc_list_entry * rsrc TSRMLS_DC)377 static void _close_mssql_link(zend_rsrc_list_entry *rsrc TSRMLS_DC)
378 {
379 	mssql_link *mssql_ptr = (mssql_link *)rsrc->ptr;
380 
381 	mssql_ptr->valid = 0;
382 	zend_hash_apply(&EG(regular_list),(apply_func_t) _clean_invalid_results TSRMLS_CC);
383 	dbclose(mssql_ptr->link);
384 	dbfreelogin(mssql_ptr->login);
385 	efree(mssql_ptr);
386 	MS_SQL_G(num_links)--;
387 }
388 /* }}} */
389 
390 /* {{{ _close_mssql_plink
391 */
_close_mssql_plink(zend_rsrc_list_entry * rsrc TSRMLS_DC)392 static void _close_mssql_plink(zend_rsrc_list_entry *rsrc TSRMLS_DC)
393 {
394 	mssql_link *mssql_ptr = (mssql_link *)rsrc->ptr;
395 
396 	dbclose(mssql_ptr->link);
397 	dbfreelogin(mssql_ptr->login);
398 	free(mssql_ptr);
399 	MS_SQL_G(num_persistent)--;
400 	MS_SQL_G(num_links)--;
401 }
402 /* }}} */
403 
404 /* {{{ _mssql_bind_hash_dtor
405 */
_mssql_bind_hash_dtor(void * data)406 static void _mssql_bind_hash_dtor(void *data)
407 {
408 	mssql_bind *bind= (mssql_bind *) data;
409 
410    	zval_ptr_dtor(&(bind->zval));
411 }
412 /* }}} */
413 
414 /* {{{ PHP_GINIT_FUNCTION
415 */
PHP_GINIT_FUNCTION(mssql)416 static PHP_GINIT_FUNCTION(mssql)
417 {
418 	long compatability_mode;
419 
420 	mssql_globals->num_persistent = 0;
421 	mssql_globals->get_column_content = php_mssql_get_column_content_with_type;
422 	if (cfg_get_long("mssql.compatability_mode", &compatability_mode) == SUCCESS) {
423 		if (compatability_mode) {
424 			mssql_globals->get_column_content = php_mssql_get_column_content_without_type;
425 		}
426 	}
427 }
428 /* }}} */
429 
430 /* {{{ PHP_MINIT_FUNCTION
431 */
PHP_MINIT_FUNCTION(mssql)432 PHP_MINIT_FUNCTION(mssql)
433 {
434 	REGISTER_INI_ENTRIES();
435 
436 	le_statement = zend_register_list_destructors_ex(_free_mssql_statement, NULL, "mssql statement", module_number);
437 	le_result = zend_register_list_destructors_ex(_free_mssql_result, NULL, "mssql result", module_number);
438 	le_link = zend_register_list_destructors_ex(_close_mssql_link, NULL, "mssql link", module_number);
439 	le_plink = zend_register_list_destructors_ex(NULL, _close_mssql_plink, "mssql link persistent", module_number);
440 	Z_TYPE(mssql_module_entry) = type;
441 
442 	if (dbinit()==FAIL) {
443 		return FAILURE;
444 	}
445 
446 	/* BEGIN MSSQL data types for mssql_bind */
447 	REGISTER_LONG_CONSTANT("MSSQL_ASSOC", MSSQL_ASSOC, CONST_CS | CONST_PERSISTENT);
448 	REGISTER_LONG_CONSTANT("MSSQL_NUM", MSSQL_NUM, CONST_CS | CONST_PERSISTENT);
449 	REGISTER_LONG_CONSTANT("MSSQL_BOTH", MSSQL_BOTH, CONST_CS | CONST_PERSISTENT);
450 
451 	REGISTER_LONG_CONSTANT("SQLTEXT",SQLTEXT, CONST_CS | CONST_PERSISTENT);
452 	REGISTER_LONG_CONSTANT("SQLVARCHAR",SQLVARCHAR, CONST_CS | CONST_PERSISTENT);
453 	REGISTER_LONG_CONSTANT("SQLCHAR",SQLCHAR, CONST_CS | CONST_PERSISTENT);
454 	REGISTER_LONG_CONSTANT("SQLINT1",SQLINT1, CONST_CS | CONST_PERSISTENT);
455 	REGISTER_LONG_CONSTANT("SQLINT2",SQLINT2, CONST_CS | CONST_PERSISTENT);
456 	REGISTER_LONG_CONSTANT("SQLINT4",SQLINT4, CONST_CS | CONST_PERSISTENT);
457 	REGISTER_LONG_CONSTANT("SQLBIT",SQLBIT, CONST_CS | CONST_PERSISTENT);
458 	REGISTER_LONG_CONSTANT("SQLFLT4",SQLFLT4, CONST_CS | CONST_PERSISTENT);
459 	REGISTER_LONG_CONSTANT("SQLFLT8",SQLFLT8, CONST_CS | CONST_PERSISTENT);
460 	REGISTER_LONG_CONSTANT("SQLFLTN",SQLFLTN, CONST_CS | CONST_PERSISTENT);
461 	/* END MSSQL data types for mssql_bind */
462 
463 	return SUCCESS;
464 }
465 /* }}} */
466 
467 /* {{{ PHP_MSHUTDOWN_FUNCTION
468 */
PHP_MSHUTDOWN_FUNCTION(mssql)469 PHP_MSHUTDOWN_FUNCTION(mssql)
470 {
471 	UNREGISTER_INI_ENTRIES();
472 #ifndef HAVE_FREETDS
473 	dbwinexit();
474 #else
475 	dbexit();
476 #endif
477 	return SUCCESS;
478 }
479 /* }}} */
480 
481 /* {{{ PHP_RINIT_FUNCTION
482 */
PHP_RINIT_FUNCTION(mssql)483 PHP_RINIT_FUNCTION(mssql)
484 {
485 	MS_SQL_G(default_link) = -1;
486 	MS_SQL_G(num_links) = MS_SQL_G(num_persistent);
487 	MS_SQL_G(appname) = estrndup("PHP 5", 5);
488 	MS_SQL_G(server_message) = NULL;
489 	MS_SQL_G(min_error_severity) = MS_SQL_G(cfg_min_error_severity);
490 	MS_SQL_G(min_message_severity) = MS_SQL_G(cfg_min_message_severity);
491 	if (MS_SQL_G(connect_timeout) < 1) MS_SQL_G(connect_timeout) = 1;
492 	if (MS_SQL_G(timeout) < 0) MS_SQL_G(timeout) = 60;
493 	if (MS_SQL_G(max_procs) != -1) {
494 		dbsetmaxprocs((TDS_SHORT)MS_SQL_G(max_procs));
495 	}
496 
497 	return SUCCESS;
498 }
499 /* }}} */
500 
501 /* {{{ PHP_RSHUTDOWN_FUNCTION
502 */
PHP_RSHUTDOWN_FUNCTION(mssql)503 PHP_RSHUTDOWN_FUNCTION(mssql)
504 {
505 	STR_FREE(MS_SQL_G(appname));
506 	MS_SQL_G(appname) = NULL;
507 	if (MS_SQL_G(server_message)) {
508 		STR_FREE(MS_SQL_G(server_message));
509 		MS_SQL_G(server_message) = NULL;
510 	}
511 	return SUCCESS;
512 }
513 /* }}} */
514 
515 /* {{{ PHP_MINFO_FUNCTION
516 */
PHP_MINFO_FUNCTION(mssql)517 PHP_MINFO_FUNCTION(mssql)
518 {
519 	char buf[32];
520 
521 	php_info_print_table_start();
522 	php_info_print_table_header(2, "MSSQL Support", "enabled");
523 
524 	snprintf(buf, sizeof(buf), "%ld", MS_SQL_G(num_persistent));
525 	php_info_print_table_row(2, "Active Persistent Links", buf);
526 	snprintf(buf, sizeof(buf), "%ld", MS_SQL_G(num_links));
527 	php_info_print_table_row(2, "Active Links", buf);
528 
529 	php_info_print_table_row(2, "Library version", MSSQL_VERSION);
530 	php_info_print_table_end();
531 
532 	DISPLAY_INI_ENTRIES();
533 
534 }
535 /* }}} */
536 
537 /* {{{ php_mssql_do_connect
538 */
php_mssql_do_connect(INTERNAL_FUNCTION_PARAMETERS,int persistent)539 static void php_mssql_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent)
540 {
541 	char *host = NULL, *user = NULL, *passwd = NULL;
542 	int host_len = 0, user_len = 0, passwd_len = 0;
543 	zend_bool new_link = 0;
544 	char *hashed_details;
545 	int hashed_details_length;
546 	mssql_link mssql, *mssql_ptr;
547 	char buffer[40];
548 
549 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sssb", &host, &host_len, &user, &user_len, &passwd, &passwd_len, &new_link) == FAILURE) {
550 		return;
551 	}
552 
553 	/* Limit strings to 255 chars to prevent overflow issues in underlying libraries */
554 	if(host_len>255) {
555 		host[255] = '\0';
556 	}
557 	if(user_len>255) {
558 		user[255] = '\0';
559 	}
560 	if(passwd_len>255) {
561 		passwd[255] = '\0';
562 	}
563 
564 	switch(ZEND_NUM_ARGS())
565 	{
566 		case 0:
567 			/* defaults */
568 			hashed_details_length=5+3;
569 			hashed_details = (char *) emalloc(hashed_details_length+1);
570 			strcpy(hashed_details, "mssql___");
571 			break;
572 		case 1:
573 			hashed_details_length = spprintf(&hashed_details, 0, "mssql_%s__", host);
574 			break;
575 		case 2:
576 			hashed_details_length = spprintf(&hashed_details, 0, "mssql_%s_%s_", host, user);
577 			break;
578 		case 3:
579 		case 4:
580 			hashed_details_length = spprintf(&hashed_details, 0, "mssql_%s_%s_%s", host, user, passwd);
581 			break;
582 	}
583 
584 	if (hashed_details == NULL) {
585 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Out of memory");
586 		RETURN_FALSE;
587 	}
588 
589 	dbsetlogintime(MS_SQL_G(connect_timeout));
590 	dbsettime(MS_SQL_G(timeout));
591 
592 	/* set a DBLOGIN record */
593 	if ((mssql.login = dblogin()) == NULL) {
594 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to allocate login record");
595 		RETURN_FALSE;
596 	}
597 
598 	DBERRHANDLE(mssql.login, (EHANDLEFUNC) php_mssql_error_handler);
599 	DBMSGHANDLE(mssql.login, (MHANDLEFUNC) php_mssql_message_handler);
600 
601 #ifndef HAVE_FREETDS
602 	if (MS_SQL_G(secure_connection)){
603 		DBSETLSECURE(mssql.login);
604 	}
605 	else {
606 #endif
607 		if (user) {
608 			DBSETLUSER(mssql.login,user);
609 		}
610 		if (passwd) {
611 			DBSETLPWD(mssql.login,passwd);
612 		}
613 #ifndef HAVE_FREETDS
614 	}
615 #endif
616 
617 #ifdef HAVE_FREETDS
618 		if (MS_SQL_G(charset) && strlen(MS_SQL_G(charset))) {
619 			DBSETLCHARSET(mssql.login, MS_SQL_G(charset));
620 		}
621 #endif
622 
623 	DBSETLAPP(mssql.login,MS_SQL_G(appname));
624 	mssql.valid = 1;
625 
626 #ifndef HAVE_FREETDS
627 	DBSETLVERSION(mssql.login, DBVER60);
628 #endif
629 /*	DBSETLTIME(mssql.login, TIMEOUT_INFINITE); */
630 
631 	if (!MS_SQL_G(allow_persistent)) {
632 		persistent=0;
633 	}
634 	if (persistent) {
635 		zend_rsrc_list_entry *le;
636 
637 		/* try to find if we already have this link in our persistent list */
638 		if (new_link || zend_hash_find(&EG(persistent_list), hashed_details, hashed_details_length + 1, (void **) &le)==FAILURE) {  /* we don't */
639 			zend_rsrc_list_entry new_le;
640 
641 			if (MS_SQL_G(max_links) != -1 && MS_SQL_G(num_links) >= MS_SQL_G(max_links)) {
642 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Too many open links (%ld)", MS_SQL_G(num_links));
643 				efree(hashed_details);
644 				dbfreelogin(mssql.login);
645 				RETURN_FALSE;
646 			}
647 			if (MS_SQL_G(max_persistent) != -1 && MS_SQL_G(num_persistent) >= MS_SQL_G(max_persistent)) {
648 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Too many open persistent links (%ld)", MS_SQL_G(num_persistent));
649 				efree(hashed_details);
650 				dbfreelogin(mssql.login);
651 				RETURN_FALSE;
652 			}
653 			/* create the link */
654 			if ((mssql.link = dbopen(mssql.login, host)) == FAIL) {
655 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to connect to server: %s", (host == NULL ? "" : host));
656 				efree(hashed_details);
657 				dbfreelogin(mssql.login);
658 				RETURN_FALSE;
659 			}
660 
661 			if (DBSETOPT(mssql.link, DBBUFFER, "2")==FAIL) {
662 				efree(hashed_details);
663 				dbfreelogin(mssql.login);
664 				dbclose(mssql.link);
665 				RETURN_FALSE;
666 			}
667 
668 #ifndef HAVE_FREETDS
669 			if (MS_SQL_G(textlimit) != -1) {
670 				snprintf(buffer, sizeof(buffer), "%li", MS_SQL_G(textlimit));
671 				if (DBSETOPT(mssql.link, DBTEXTLIMIT, buffer)==FAIL) {
672 					efree(hashed_details);
673 					dbfreelogin(mssql.login);
674 					dbclose(mssql.link);
675 					RETURN_FALSE;
676 				}
677 			}
678 #endif
679 			if (MS_SQL_G(textsize) != -1) {
680 				snprintf(buffer, sizeof(buffer), "SET TEXTSIZE %li", MS_SQL_G(textsize));
681 				dbcmd(mssql.link, buffer);
682 				dbsqlexec(mssql.link);
683 				dbresults(mssql.link);
684 			}
685 
686 			/* hash it up */
687 			mssql_ptr = (mssql_link *) malloc(sizeof(mssql_link));
688 			if (!mssql_ptr) {
689 				efree(hashed_details);
690 				dbfreelogin(mssql.login);
691 				dbclose(mssql.link);
692 				RETURN_FALSE;
693 			}
694 
695 			memcpy(mssql_ptr, &mssql, sizeof(mssql_link));
696 			Z_TYPE(new_le) = le_plink;
697 			new_le.ptr = mssql_ptr;
698 			if (zend_hash_update(&EG(persistent_list), hashed_details, hashed_details_length + 1, &new_le, sizeof(zend_rsrc_list_entry), NULL)==FAILURE) {
699 				free(mssql_ptr);
700 				efree(hashed_details);
701 				dbfreelogin(mssql.login);
702 				dbclose(mssql.link);
703 				RETURN_FALSE;
704 			}
705 			MS_SQL_G(num_persistent)++;
706 			MS_SQL_G(num_links)++;
707 		} else {  /* we do */
708 			if (Z_TYPE_P(le) != le_plink) {
709 #if BROKEN_MSSQL_PCONNECTS
710 				log_error("PHP/MS SQL: Hashed persistent link is not a MS SQL link!",php_rqst->server);
711 #endif
712 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Hashed persistent link is not a MS SQL link!");
713 				efree(hashed_details);
714 				RETURN_FALSE;
715 			}
716 
717 			mssql_ptr = (mssql_link *) le->ptr;
718 			/* test that the link hasn't died */
719 			if (DBDEAD(mssql_ptr->link) == TRUE) {
720 				dbclose(mssql_ptr->link);
721 #if BROKEN_MSSQL_PCONNECTS
722 				log_error("PHP/MS SQL: Persistent link died, trying to reconnect...",php_rqst->server);
723 #endif
724 				if ((mssql_ptr->link=dbopen(mssql_ptr->login,host))==NULL) {
725 #if BROKEN_MSSQL_PCONNECTS
726 					log_error("PHP/MS SQL: Unable to reconnect!",php_rqst->server);
727 #endif
728 					php_error_docref(NULL TSRMLS_CC, E_WARNING, "Link to server lost, unable to reconnect");
729 					zend_hash_del(&EG(persistent_list), hashed_details, hashed_details_length+1);
730 					efree(hashed_details);
731 					dbfreelogin(mssql_ptr->login);
732 					RETURN_FALSE;
733 				}
734 #if BROKEN_MSSQL_PCONNECTS
735 				log_error("PHP/MS SQL: Reconnect successful!",php_rqst->server);
736 #endif
737 				if (DBSETOPT(mssql_ptr->link, DBBUFFER, "2")==FAIL) {
738 #if BROKEN_MSSQL_PCONNECTS
739 					log_error("PHP/MS SQL: Unable to set required options",php_rqst->server);
740 #endif
741 					zend_hash_del(&EG(persistent_list), hashed_details, hashed_details_length + 1);
742 					efree(hashed_details);
743 					dbfreelogin(mssql_ptr->login);
744 					dbclose(mssql_ptr->link);
745 					RETURN_FALSE;
746 				}
747 			}
748 		}
749 		ZEND_REGISTER_RESOURCE(return_value, mssql_ptr, le_plink);
750 	} else { /* non persistent */
751 		zend_rsrc_list_entry *index_ptr, new_index_ptr;
752 
753 		/* first we check the hash for the hashed_details key.  if it exists,
754 		 * it should point us to the right offset where the actual mssql link sits.
755 		 * if it doesn't, open a new mssql link, add it to the resource list,
756 		 * and add a pointer to it with hashed_details as the key.
757 		 */
758 		if (!new_link && zend_hash_find(&EG(regular_list), hashed_details, hashed_details_length + 1,(void **) &index_ptr)==SUCCESS) {
759 			int type,link;
760 			void *ptr;
761 
762 			if (Z_TYPE_P(index_ptr) != le_index_ptr) {
763 				efree(hashed_details);
764 				dbfreelogin(mssql.login);
765 				RETURN_FALSE;
766 			}
767 			link = (int) index_ptr->ptr;
768 			ptr = zend_list_find(link,&type);   /* check if the link is still there */
769 			if (ptr && (type==le_link || type==le_plink)) {
770 				zend_list_addref(link);
771 				Z_LVAL_P(return_value) = link;
772 				php_mssql_set_default_link(link TSRMLS_CC);
773 				Z_TYPE_P(return_value) = IS_RESOURCE;
774 				dbfreelogin(mssql.login);
775 				efree(hashed_details);
776 				return;
777 			} else {
778 				zend_hash_del(&EG(regular_list), hashed_details, hashed_details_length + 1);
779 			}
780 		}
781 		if (MS_SQL_G(max_links) != -1 && MS_SQL_G(num_links) >= MS_SQL_G(max_links)) {
782 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Too many open links (%ld)", MS_SQL_G(num_links));
783 			efree(hashed_details);
784 			dbfreelogin(mssql.login);
785 			RETURN_FALSE;
786 		}
787 
788 		if ((mssql.link=dbopen(mssql.login, host))==NULL) {
789 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to connect to server: %s", (host == NULL ? "" : host));
790 			efree(hashed_details);
791 			dbfreelogin(mssql.login);
792 			RETURN_FALSE;
793 		}
794 
795 		if (DBSETOPT(mssql.link, DBBUFFER,"2")==FAIL) {
796 			efree(hashed_details);
797 			dbfreelogin(mssql.login);
798 			dbclose(mssql.link);
799 			RETURN_FALSE;
800 		}
801 
802 #ifndef HAVE_FREETDS
803 		if (MS_SQL_G(textlimit) != -1) {
804 			snprintf(buffer, sizeof(buffer), "%li", MS_SQL_G(textlimit));
805 			if (DBSETOPT(mssql.link, DBTEXTLIMIT, buffer)==FAIL) {
806 				efree(hashed_details);
807 				dbfreelogin(mssql.login);
808 				dbclose(mssql.link);
809 				RETURN_FALSE;
810 			}
811 		}
812 #endif
813 		if (MS_SQL_G(textsize) != -1) {
814 			snprintf(buffer, sizeof(buffer), "SET TEXTSIZE %li", MS_SQL_G(textsize));
815 			dbcmd(mssql.link, buffer);
816 			dbsqlexec(mssql.link);
817 			dbresults(mssql.link);
818 		}
819 
820 		/* add it to the list */
821 		mssql_ptr = (mssql_link *) emalloc(sizeof(mssql_link));
822 		memcpy(mssql_ptr, &mssql, sizeof(mssql_link));
823 		ZEND_REGISTER_RESOURCE(return_value, mssql_ptr, le_link);
824 
825 		/* add it to the hash */
826 		new_index_ptr.ptr = (void *) Z_LVAL_P(return_value);
827 		Z_TYPE(new_index_ptr) = le_index_ptr;
828 		if (zend_hash_update(&EG(regular_list), hashed_details, hashed_details_length + 1,(void *) &new_index_ptr, sizeof(zend_rsrc_list_entry),NULL)==FAILURE) {
829 			efree(hashed_details);
830 			RETURN_FALSE;
831 		}
832 		MS_SQL_G(num_links)++;
833 	}
834 	efree(hashed_details);
835 	php_mssql_set_default_link(Z_LVAL_P(return_value) TSRMLS_CC);
836 }
837 /* }}} */
838 
839 /* {{{ php_mssql_get_default_link
840 */
php_mssql_get_default_link(INTERNAL_FUNCTION_PARAMETERS)841 static int php_mssql_get_default_link(INTERNAL_FUNCTION_PARAMETERS)
842 {
843 	if (MS_SQL_G(default_link)==-1) { /* no link opened yet, implicitly open one */
844 		ht = 0;
845 		php_mssql_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU,0);
846 	}
847 	return MS_SQL_G(default_link);
848 }
849 /* }}} */
850 
851 /* {{{ proto int mssql_connect([string servername [, string username [, string password [, bool new_link]]]])
852    Establishes a connection to a MS-SQL server */
PHP_FUNCTION(mssql_connect)853 PHP_FUNCTION(mssql_connect)
854 {
855 	php_mssql_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU,0);
856 }
857 /* }}} */
858 
859 /* {{{ proto int mssql_pconnect([string servername [, string username [, string password [, bool new_link]]]])
860    Establishes a persistent connection to a MS-SQL server */
PHP_FUNCTION(mssql_pconnect)861 PHP_FUNCTION(mssql_pconnect)
862 {
863 	php_mssql_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU,1);
864 }
865 /* }}} */
866 
867 /* {{{ proto bool mssql_close([resource conn_id])
868    Closes a connection to a MS-SQL server */
PHP_FUNCTION(mssql_close)869 PHP_FUNCTION(mssql_close)
870 {
871 	zval *mssql_link_index = NULL;
872 	int id = -1;
873 	mssql_link *mssql_ptr;
874 
875 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|r", &mssql_link_index) == FAILURE) {
876 		return;
877 	}
878 
879 	if (mssql_link_index == NULL) {
880 		id = php_mssql_get_default_link(INTERNAL_FUNCTION_PARAM_PASSTHRU);
881 		CHECK_LINK(id);
882 	}
883 
884 	ZEND_FETCH_RESOURCE2(mssql_ptr, mssql_link *, &mssql_link_index, id, "MS SQL-Link", le_link, le_plink);
885 
886 	if (mssql_link_index) {
887 		zend_list_delete(Z_RESVAL_P(mssql_link_index));
888 	} else {
889 		zend_list_delete(id);
890 	}
891 
892 	RETURN_TRUE;
893 }
894 /* }}} */
895 
896 /* {{{ proto bool mssql_select_db(string database_name [, resource conn_id])
897    Select a MS-SQL database */
PHP_FUNCTION(mssql_select_db)898 PHP_FUNCTION(mssql_select_db)
899 {
900 	char *db;
901 	zval *mssql_link_index = NULL;
902 	int db_len;
903 	int id = -1;
904 	mssql_link  *mssql_ptr;
905 
906 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|r", &db, &db_len, &mssql_link_index) == FAILURE) {
907 		return;
908 	}
909 
910 	if (mssql_link_index == NULL) {
911 		id = php_mssql_get_default_link(INTERNAL_FUNCTION_PARAM_PASSTHRU);
912 		CHECK_LINK(id);
913 	}
914 
915 	ZEND_FETCH_RESOURCE2(mssql_ptr, mssql_link *, &mssql_link_index, id, "MS SQL-Link", le_link, le_plink);
916 
917 	if (dbuse(mssql_ptr->link, db)==FAIL) {
918 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to select database:  %s", db);
919 		RETURN_FALSE;
920 	} else {
921 		RETURN_TRUE;
922 	}
923 }
924 /* }}} */
925 
926 /* {{{ php_mssql_get_column_content_with_type
927 */
php_mssql_get_column_content_with_type(mssql_link * mssql_ptr,int offset,zval * result,int column_type TSRMLS_DC)928 static void php_mssql_get_column_content_with_type(mssql_link *mssql_ptr,int offset,zval *result, int column_type  TSRMLS_DC)
929 {
930 	if (dbdata(mssql_ptr->link,offset) == NULL && dbdatlen(mssql_ptr->link,offset) == 0) {
931 		ZVAL_NULL(result);
932 		return;
933 	}
934 
935 	switch (column_type)
936 	{
937 		case SQLBIT:
938 		case SQLINT1:
939 		case SQLINT2:
940 		case SQLINT4:
941 		case SQLINTN: {
942 			ZVAL_LONG(result, (long) anyintcol(offset));
943 			break;
944 		}
945 		case SQLCHAR:
946 		case SQLVARCHAR:
947 		case SQLTEXT: {
948 			int length;
949 			char *data = charcol(offset);
950 
951 			length=dbdatlen(mssql_ptr->link,offset);
952 #if ilia_0
953 			while (length>0 && data[length-1] == ' ') { /* nuke trailing whitespace */
954 				length--;
955 			}
956 #endif
957 			ZVAL_STRINGL(result, data, length, 1);
958 			break;
959 		}
960 		case SQLFLT4:
961 			ZVAL_DOUBLE(result, (double) floatcol4(offset));
962 			break;
963 		case SQLMONEY:
964 		case SQLMONEY4:
965 		case SQLMONEYN: {
966 			DBFLT8 res_buf;
967 			dbconvert(NULL, column_type, dbdata(mssql_ptr->link,offset), 8, SQLFLT8, (LPBYTE)&res_buf, -1);
968 			ZVAL_DOUBLE(result, res_buf);
969 			}
970 			break;
971 		case SQLFLT8:
972 			ZVAL_DOUBLE(result, (double) floatcol8(offset));
973 			break;
974 #ifdef SQLUNIQUE
975 		case SQLUNIQUE: {
976 #else
977 		case 36: {			/* FreeTDS hack */
978 #endif
979 			char *data = charcol(offset);
980 
981 			/* uniqueidentifier is a 16-byte binary number */
982 			ZVAL_STRINGL(result, data, 16, 1);
983 			}
984 			break;
985 		case SQLVARBINARY:
986 		case SQLBINARY:
987 		case SQLIMAGE: {
988 			int res_length = dbdatlen(mssql_ptr->link, offset);
989 
990 			if (!res_length) {
991 				ZVAL_NULL(result);
992 			} else {
993 				ZVAL_STRINGL(result, (char *)dbdata(mssql_ptr->link, offset), res_length, 1);
994 			}
995 		}
996 			break;
997 		case SQLNUMERIC:
998 		default: {
999 			if (dbwillconvert(column_type,SQLCHAR)) {
1000 				char *res_buf;
1001 				DBDATEREC dateinfo;
1002 				int res_length = dbdatlen(mssql_ptr->link,offset);
1003 
1004 				if (res_length == -1) {
1005 					res_length = 255;
1006 				}
1007 
1008 				if ((column_type != SQLDATETIME && column_type != SQLDATETIM4) || MS_SQL_G(datetimeconvert)) {
1009 
1010 					switch (column_type) {
1011 						case SQLDATETIME :
1012 						case SQLDATETIM4 :
1013 							res_length += 20;
1014 							break;
1015 						case SQLMONEY :
1016 						case SQLMONEY4 :
1017 						case SQLMONEYN :
1018 						case SQLDECIMAL :
1019 						case SQLNUMERIC :
1020 							res_length += 5;
1021 						case 127 :
1022 							res_length += 20;
1023 							break;
1024 					}
1025 
1026 					res_buf = (unsigned char *) emalloc(res_length+1);
1027 					res_length = dbconvert(NULL,coltype(offset),dbdata(mssql_ptr->link,offset), res_length, SQLCHAR,res_buf,-1);
1028 					res_buf[res_length] = '\0';
1029 				} else {
1030 					if (column_type == SQLDATETIM4) {
1031 						DBDATETIME temp;
1032 
1033 						dbconvert(NULL, SQLDATETIM4, dbdata(mssql_ptr->link,offset), -1, SQLDATETIME, (LPBYTE) &temp, -1);
1034 						dbdatecrack(mssql_ptr->link, &dateinfo, &temp);
1035 					} else {
1036 						dbdatecrack(mssql_ptr->link, &dateinfo, (DBDATETIME *) dbdata(mssql_ptr->link,offset));
1037 					}
1038 
1039 					res_length = 19;
1040 					spprintf(&res_buf, 0, "%d-%02d-%02d %02d:%02d:%02d" , dateinfo.year, dateinfo.month, dateinfo.day, dateinfo.hour, dateinfo.minute, dateinfo.second);
1041 				}
1042 
1043 				ZVAL_STRINGL(result, res_buf, res_length, 0);
1044 			} else {
1045 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "column %d has unknown data type (%d)", offset, coltype(offset));
1046 				ZVAL_FALSE(result);
1047 			}
1048 		}
1049 	}
1050 }
1051 /* }}} */
1052 
1053 /* {{{ php_mssql_get_column_content_without_type
1054 */
1055 static void php_mssql_get_column_content_without_type(mssql_link *mssql_ptr,int offset,zval *result, int column_type TSRMLS_DC)
1056 {
1057 	if (dbdatlen(mssql_ptr->link,offset) == 0) {
1058 		ZVAL_NULL(result);
1059 		return;
1060 	}
1061 
1062 	if (column_type == SQLVARBINARY ||
1063 		column_type == SQLBINARY ||
1064 		column_type == SQLIMAGE) {
1065 		DBBINARY *bin;
1066 		unsigned char *res_buf;
1067 		int res_length = dbdatlen(mssql_ptr->link, offset);
1068 
1069 		if (res_length == 0) {
1070 			ZVAL_NULL(result);
1071 			return;
1072 		} else if (res_length < 0) {
1073 			ZVAL_FALSE(result);
1074 			return;
1075 		}
1076 
1077 		res_buf = (unsigned char *) emalloc(res_length+1);
1078 		bin = ((DBBINARY *)dbdata(mssql_ptr->link, offset));
1079 		res_buf[res_length] = '\0';
1080 		memcpy(res_buf, bin, res_length);
1081 		ZVAL_STRINGL(result, res_buf, res_length, 0);
1082 	}
1083 	else if  (dbwillconvert(coltype(offset),SQLCHAR)) {
1084 		unsigned char *res_buf;
1085 		DBDATEREC dateinfo;
1086 		int res_length = dbdatlen(mssql_ptr->link,offset);
1087 
1088 		if ((column_type != SQLDATETIME && column_type != SQLDATETIM4) || MS_SQL_G(datetimeconvert)) {
1089 
1090 			switch (column_type) {
1091 				case SQLDATETIME :
1092 				case SQLDATETIM4 :
1093 					res_length += 20;
1094 					break;
1095 				case SQLMONEY :
1096 				case SQLMONEY4 :
1097 				case SQLMONEYN :
1098 				case SQLDECIMAL :
1099 				case SQLNUMERIC :
1100 					res_length += 5;
1101 				case 127 :
1102 					res_length += 20;
1103 					break;
1104 			}
1105 
1106 			res_buf = (unsigned char *) emalloc(res_length+1);
1107 			res_length = dbconvert(NULL,coltype(offset),dbdata(mssql_ptr->link,offset), res_length, SQLCHAR, res_buf, -1);
1108 			res_buf[res_length] = '\0';
1109 		} else {
1110 			if (column_type == SQLDATETIM4) {
1111 				DBDATETIME temp;
1112 
1113 				dbconvert(NULL, SQLDATETIM4, dbdata(mssql_ptr->link,offset), -1, SQLDATETIME, (LPBYTE) &temp, -1);
1114 				dbdatecrack(mssql_ptr->link, &dateinfo, &temp);
1115 			} else {
1116 				dbdatecrack(mssql_ptr->link, &dateinfo, (DBDATETIME *) dbdata(mssql_ptr->link,offset));
1117 			}
1118 
1119 			res_length = 19;
1120 			spprintf(&res_buf, 0, "%d-%02d-%02d %02d:%02d:%02d" , dateinfo.year, dateinfo.month, dateinfo.day, dateinfo.hour, dateinfo.minute, dateinfo.second);
1121 		}
1122 
1123 		ZVAL_STRINGL(result, res_buf, res_length, 0);
1124 	} else {
1125 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "column %d has unknown data type (%d)", offset, coltype(offset));
1126 		ZVAL_FALSE(result);
1127 	}
1128 }
1129 /* }}} */
1130 
1131 /* {{{ _mssql_get_sp_result
1132 */
1133 static void _mssql_get_sp_result(mssql_link *mssql_ptr, mssql_statement *statement TSRMLS_DC)
1134 {
1135 	int i, num_rets, type;
1136 	char *parameter;
1137 	mssql_bind *bind;
1138 
1139 	/* Now to fetch RETVAL and OUTPUT values*/
1140 	num_rets = dbnumrets(mssql_ptr->link);
1141 
1142 	if (num_rets!=0) {
1143 		for (i = 1; i <= num_rets; i++) {
1144 			parameter = (char*)dbretname(mssql_ptr->link, i);
1145 			type = dbrettype(mssql_ptr->link, i);
1146 
1147 			if (statement->binds != NULL) {	/*	Maybe a non-parameter sp	*/
1148 				if (zend_hash_find(statement->binds, parameter, strlen(parameter), (void**)&bind)==SUCCESS) {
1149 					if (!dbretlen(mssql_ptr->link,i)) {
1150 						ZVAL_NULL(bind->zval);
1151 					}
1152 					else {
1153 						switch (type) {
1154 							case SQLBIT:
1155 							case SQLINT1:
1156 							case SQLINT2:
1157 							case SQLINT4:
1158 								convert_to_long_ex(&bind->zval);
1159 								/* FIXME this works only on little endian machine !!! */
1160 								Z_LVAL_P(bind->zval) = *((int *)(dbretdata(mssql_ptr->link,i)));
1161 								break;
1162 
1163 							case SQLFLT4:
1164 							case SQLFLT8:
1165 							case SQLFLTN:
1166 							case SQLMONEY4:
1167 							case SQLMONEY:
1168 							case SQLMONEYN:
1169 								convert_to_double_ex(&bind->zval);
1170 								Z_DVAL_P(bind->zval) = *((double *)(dbretdata(mssql_ptr->link,i)));
1171 								break;
1172 
1173 							case SQLCHAR:
1174 							case SQLVARCHAR:
1175 							case SQLTEXT:
1176 								convert_to_string_ex(&bind->zval);
1177 								Z_STRLEN_P(bind->zval) = dbretlen(mssql_ptr->link,i);
1178 								Z_STRVAL_P(bind->zval) = estrndup(dbretdata(mssql_ptr->link,i),Z_STRLEN_P(bind->zval));
1179 								break;
1180 							/* TODO binary */
1181 						}
1182 					}
1183 				}
1184 				else {
1185 					php_error_docref(NULL TSRMLS_CC, E_WARNING, "An output parameter variable was not provided");
1186 				}
1187 			}
1188 		}
1189 	}
1190 	if (statement->binds != NULL) {	/*	Maybe a non-parameter sp	*/
1191 		if (zend_hash_find(statement->binds, "RETVAL", 6, (void**)&bind)==SUCCESS) {
1192 			if (dbhasretstat(mssql_ptr->link)) {
1193 				convert_to_long_ex(&bind->zval);
1194 				Z_LVAL_P(bind->zval)=dbretstatus(mssql_ptr->link);
1195 			}
1196 			else {
1197 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "stored procedure has no return value. Nothing was returned into RETVAL");
1198 			}
1199 		}
1200 	}
1201 }
1202 /* }}} */
1203 
1204 /* {{{ _mssql_fetch_batch
1205 */
1206 static int _mssql_fetch_batch(mssql_link *mssql_ptr, mssql_result *result, int retvalue TSRMLS_DC)
1207 {
1208 	int i, j = 0;
1209 	char computed_buf[16];
1210 
1211 	if (!result->have_fields) {
1212 		for (i=0; i<result->num_fields; i++) {
1213 			char *source = NULL;
1214 			char *fname = (char *)dbcolname(mssql_ptr->link,i+1);
1215 
1216 			if (*fname) {
1217 				result->fields[i].name = estrdup(fname);
1218 			} else {
1219 				if (j>0) {
1220 					snprintf(computed_buf,16,"computed%d",j);
1221 				} else {
1222 					strcpy(computed_buf,"computed");
1223 				}
1224 				result->fields[i].name = estrdup(computed_buf);
1225 				j++;
1226 			}
1227 			result->fields[i].max_length = dbcollen(mssql_ptr->link,i+1);
1228 			source = (char *)dbcolsource(mssql_ptr->link,i+1);
1229 			if (source) {
1230 				result->fields[i].column_source = estrdup(source);
1231 			}
1232 			else {
1233 				result->fields[i].column_source = STR_EMPTY_ALLOC();
1234 			}
1235 
1236 			result->fields[i].type = coltype(i+1);
1237 			/* set numeric flag */
1238 			switch (result->fields[i].type) {
1239 				case SQLINT1:
1240 				case SQLINT2:
1241 				case SQLINT4:
1242 				case SQLINTN:
1243 				case SQLFLT4:
1244 				case SQLFLT8:
1245 				case SQLNUMERIC:
1246 				case SQLDECIMAL:
1247 					result->fields[i].numeric = 1;
1248 					break;
1249 				case SQLCHAR:
1250 				case SQLVARCHAR:
1251 				case SQLTEXT:
1252 				default:
1253 					result->fields[i].numeric = 0;
1254 					break;
1255 			}
1256 		}
1257 		result->have_fields = 1;
1258 	}
1259 
1260 	i=0;
1261 	if (!result->data) {
1262 		result->data = (zval **) safe_emalloc(sizeof(zval *), MSSQL_ROWS_BLOCK*(++result->blocks_initialized), 0);
1263 	}
1264 	while (retvalue!=FAIL && retvalue!=NO_MORE_ROWS) {
1265 		result->num_rows++;
1266 		if (result->num_rows > result->blocks_initialized*MSSQL_ROWS_BLOCK) {
1267 			result->data = (zval **) erealloc(result->data,sizeof(zval *)*MSSQL_ROWS_BLOCK*(++result->blocks_initialized));
1268 		}
1269 		result->data[i] = (zval *) safe_emalloc(sizeof(zval), result->num_fields, 0);
1270 		for (j=0; j<result->num_fields; j++) {
1271 			INIT_ZVAL(result->data[i][j]);
1272 			MS_SQL_G(get_column_content(mssql_ptr, j+1, &result->data[i][j], result->fields[j].type TSRMLS_CC));
1273 		}
1274 		if (i<result->batchsize || result->batchsize==0) {
1275 			i++;
1276 			dbclrbuf(mssql_ptr->link,DBLASTROW(mssql_ptr->link));
1277 			retvalue=dbnextrow(mssql_ptr->link);
1278 		}
1279 		else
1280 			break;
1281 		result->lastresult = retvalue;
1282 	}
1283 	if (result->statement && (retvalue == NO_MORE_RESULTS || retvalue == NO_MORE_RPC_RESULTS)) {
1284 		_mssql_get_sp_result(mssql_ptr, result->statement TSRMLS_CC);
1285 	}
1286 	return i;
1287 }
1288 /* }}} */
1289 
1290 /* {{{ proto int mssql_fetch_batch(resource result_index)
1291    Returns the next batch of records */
1292 PHP_FUNCTION(mssql_fetch_batch)
1293 {
1294 	zval *mssql_result_index;
1295 	mssql_result *result;
1296 	mssql_link *mssql_ptr;
1297 
1298 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &mssql_result_index) == FAILURE) {
1299 		return;
1300 	}
1301 
1302 	if (Z_RESVAL_P(mssql_result_index) == 0) {
1303 		RETURN_FALSE;
1304 	}
1305 
1306 	ZEND_FETCH_RESOURCE(result, mssql_result *, &mssql_result_index, -1, "MS SQL-result", le_result);
1307 
1308 	mssql_ptr = result->mssql_ptr;
1309 	_free_result(result, 0);
1310 	result->cur_row=result->num_rows=0;
1311 	result->num_rows = _mssql_fetch_batch(mssql_ptr, result, result->lastresult TSRMLS_CC);
1312 
1313 	RETURN_LONG(result->num_rows);
1314 }
1315 /* }}} */
1316 
1317 /* {{{ proto resource mssql_query(string query [, resource conn_id [, int batch_size]])
1318    Perform an SQL query on a MS-SQL server database */
1319 PHP_FUNCTION(mssql_query)
1320 {
1321 	char *query;
1322 	zval *mssql_link_index = NULL;
1323 	int query_len, retvalue, batchsize, num_fields;
1324 	long zbatchsize = 0;
1325 	mssql_link *mssql_ptr;
1326 	mssql_result *result;
1327 	int id = -1;
1328 
1329 	dbsettime(MS_SQL_G(timeout));
1330 	batchsize = MS_SQL_G(batchsize);
1331 
1332 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|rl", &query, &query_len, &mssql_link_index, &zbatchsize) == FAILURE) {
1333 		return;
1334 	}
1335 
1336 	switch(ZEND_NUM_ARGS()) {
1337 		case 1:
1338 			id = php_mssql_get_default_link(INTERNAL_FUNCTION_PARAM_PASSTHRU);
1339 			CHECK_LINK(id);
1340 			break;
1341 		case 3:
1342 			batchsize = (int) zbatchsize;
1343 			break;
1344 	}
1345 
1346 	ZEND_FETCH_RESOURCE2(mssql_ptr, mssql_link *, &mssql_link_index, id, "MS SQL-Link", le_link, le_plink);
1347 
1348 	if (dbcmd(mssql_ptr->link, query)==FAIL) {
1349 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to set query");
1350 		RETURN_FALSE;
1351 	}
1352 	if (dbsqlexec(mssql_ptr->link)==FAIL || (retvalue = dbresults(mssql_ptr->link))==FAIL) {
1353 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Query failed");
1354 		dbcancel(mssql_ptr->link);
1355 		RETURN_FALSE;
1356 	}
1357 
1358 	/* Skip results not returning any columns */
1359 	while ((num_fields = dbnumcols(mssql_ptr->link)) <= 0 && retvalue == SUCCEED) {
1360 		retvalue = dbresults(mssql_ptr->link);
1361 	}
1362 
1363 	if (num_fields <= 0) {
1364 		RETURN_TRUE;
1365 	}
1366 
1367 	retvalue=dbnextrow(mssql_ptr->link);
1368 	if (retvalue==FAIL) {
1369 		dbcancel(mssql_ptr->link);
1370 		RETURN_FALSE;
1371 	}
1372 
1373 	result = (mssql_result *) emalloc(sizeof(mssql_result));
1374 	result->statement = NULL;
1375 	result->num_fields = num_fields;
1376 	result->blocks_initialized = 1;
1377 
1378 	result->batchsize = batchsize;
1379 	result->data = NULL;
1380 	result->blocks_initialized = 0;
1381 	result->mssql_ptr = mssql_ptr;
1382 	result->cur_field=result->cur_row=result->num_rows=0;
1383 	result->have_fields = 0;
1384 
1385 	result->fields = (mssql_field *) safe_emalloc(sizeof(mssql_field), result->num_fields, 0);
1386 	result->num_rows = _mssql_fetch_batch(mssql_ptr, result, retvalue TSRMLS_CC);
1387 
1388 	ZEND_REGISTER_RESOURCE(return_value, result, le_result);
1389 }
1390 /* }}} */
1391 
1392 /* {{{ proto int mssql_rows_affected(resource conn_id)
1393    Returns the number of records affected by the query */
1394 PHP_FUNCTION(mssql_rows_affected)
1395 {
1396 	zval *mssql_link_index;
1397 	mssql_link *mssql_ptr;
1398 
1399 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &mssql_link_index) == FAILURE) {
1400 		return;
1401 	}
1402 
1403 	ZEND_FETCH_RESOURCE2(mssql_ptr, mssql_link *, &mssql_link_index, -1, "MS SQL-Link", le_link, le_plink);
1404 
1405 	RETURN_LONG(DBCOUNT(mssql_ptr->link));
1406 }
1407 /* }}} */
1408 
1409 /* {{{ proto bool mssql_free_result(resource result_index)
1410    Free a MS-SQL result index */
1411 PHP_FUNCTION(mssql_free_result)
1412 {
1413 	zval *mssql_result_index;
1414 	mssql_result *result;
1415 	int retvalue;
1416 
1417 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &mssql_result_index) == FAILURE) {
1418 		return;
1419 	}
1420 
1421 	if (Z_RESVAL_P(mssql_result_index) == 0) {
1422 		RETURN_FALSE;
1423 	}
1424 
1425 	ZEND_FETCH_RESOURCE(result, mssql_result *, &mssql_result_index, -1, "MS SQL-result", le_result);
1426 	/* Release remaining results */
1427 	do {
1428 		dbcanquery(result->mssql_ptr->link);
1429 		retvalue = dbresults(result->mssql_ptr->link);
1430 	} while (retvalue == SUCCEED);
1431 
1432 	zend_list_delete(Z_RESVAL_P(mssql_result_index));
1433 	RETURN_TRUE;
1434 }
1435 /* }}} */
1436 
1437 /* {{{ proto string mssql_get_last_message(void)
1438    Gets the last message from the MS-SQL server */
1439 PHP_FUNCTION(mssql_get_last_message)
1440 {
1441 	if (zend_parse_parameters_none() == FAILURE) {
1442 		return;
1443 	}
1444 
1445 	if (MS_SQL_G(server_message)) {
1446 		RETURN_STRING(MS_SQL_G(server_message),1);
1447 	} else {
1448 		RETURN_STRING("",1);
1449 	}
1450 }
1451 /* }}} */
1452 
1453 /* {{{ proto int mssql_num_rows(resource mssql_result_index)
1454    Returns the number of rows fetched in from the result id specified */
1455 PHP_FUNCTION(mssql_num_rows)
1456 {
1457 	zval *mssql_result_index;
1458 	mssql_result *result;
1459 
1460 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &mssql_result_index) == FAILURE) {
1461 		return;
1462 	}
1463 
1464 	ZEND_FETCH_RESOURCE(result, mssql_result *, &mssql_result_index, -1, "MS SQL-result", le_result);
1465 
1466 	RETURN_LONG(result->num_rows);
1467 }
1468 /* }}} */
1469 
1470 /* {{{ proto int mssql_num_fields(resource mssql_result_index)
1471    Returns the number of fields fetched in from the result id specified */
1472 PHP_FUNCTION(mssql_num_fields)
1473 {
1474 	zval *mssql_result_index;
1475 	mssql_result *result;
1476 
1477 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &mssql_result_index) == FAILURE) {
1478 		return;
1479 	}
1480 
1481 	ZEND_FETCH_RESOURCE(result, mssql_result *, &mssql_result_index, -1, "MS SQL-result", le_result);
1482 
1483 	RETURN_LONG(result->num_fields);
1484 }
1485 /* }}} */
1486 
1487 /* {{{ php_mssql_fetch_hash
1488 */
1489 static void php_mssql_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, int result_type)
1490 {
1491 	zval *mssql_result_index;
1492 	mssql_result *result;
1493 	int i;
1494 	long resulttype = 0;
1495 
1496 	switch (result_type) {
1497 		case MSSQL_NUM:
1498 		case MSSQL_ASSOC:
1499 			if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &mssql_result_index) == FAILURE) {
1500 				return;
1501 			}
1502 			break;
1503 		case MSSQL_BOTH:
1504 			if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &mssql_result_index, &resulttype) == FAILURE) {
1505 				return;
1506 			}
1507 			result_type = (resulttype > 0 && (resulttype & MSSQL_BOTH)) ? resulttype : result_type;
1508 			break;
1509 		default:
1510 			return;
1511 	}
1512 
1513 	ZEND_FETCH_RESOURCE(result, mssql_result *, &mssql_result_index, -1, "MS SQL-result", le_result);
1514 
1515 	if (MS_SQL_G(server_message)) {
1516 		STR_FREE(MS_SQL_G(server_message));
1517 		MS_SQL_G(server_message) = NULL;
1518 	}
1519 
1520 	if (result->cur_row >= result->num_rows) {
1521 		RETURN_FALSE;
1522 	}
1523 
1524 	array_init(return_value);
1525 
1526 	for (i=0; i<result->num_fields; i++) {
1527 		if (Z_TYPE(result->data[result->cur_row][i]) != IS_NULL) {
1528 			char *data;
1529 			int data_len;
1530 
1531 			if (Z_TYPE(result->data[result->cur_row][i]) == IS_STRING) {
1532 				data = Z_STRVAL(result->data[result->cur_row][i]);
1533 				data_len = Z_STRLEN(result->data[result->cur_row][i]);
1534 
1535 				if (result_type & MSSQL_NUM) {
1536 					add_index_stringl(return_value, i, data, data_len, 1);
1537 				}
1538 
1539 				if (result_type & MSSQL_ASSOC) {
1540 					add_assoc_stringl(return_value, result->fields[i].name, data, data_len, 1);
1541 				}
1542 			}
1543 			else if (Z_TYPE(result->data[result->cur_row][i]) == IS_LONG) {
1544 				if (result_type & MSSQL_NUM)
1545 					add_index_long(return_value, i, Z_LVAL(result->data[result->cur_row][i]));
1546 
1547 				if (result_type & MSSQL_ASSOC)
1548 					add_assoc_long(return_value, result->fields[i].name, Z_LVAL(result->data[result->cur_row][i]));
1549 			}
1550 			else if (Z_TYPE(result->data[result->cur_row][i]) == IS_DOUBLE) {
1551 				if (result_type & MSSQL_NUM)
1552 					add_index_double(return_value, i, Z_DVAL(result->data[result->cur_row][i]));
1553 
1554 				if (result_type & MSSQL_ASSOC)
1555 					add_assoc_double(return_value, result->fields[i].name, Z_DVAL(result->data[result->cur_row][i]));
1556 			}
1557 		}
1558 		else
1559 		{
1560 			if (result_type & MSSQL_NUM)
1561 				add_index_null(return_value, i);
1562 			if (result_type & MSSQL_ASSOC)
1563 				add_assoc_null(return_value, result->fields[i].name);
1564 		}
1565 	}
1566 	result->cur_row++;
1567 }
1568 /* }}} */
1569 
1570 /* {{{ proto array mssql_fetch_row(resource result_id)
1571    Returns an array of the current row in the result set specified by result_id */
1572 PHP_FUNCTION(mssql_fetch_row)
1573 {
1574 	php_mssql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, MSSQL_NUM);
1575 }
1576 /* }}} */
1577 
1578 /* {{{ proto object mssql_fetch_object(resource result_id)
1579    Returns a pseudo-object of the current row in the result set specified by result_id */
1580 PHP_FUNCTION(mssql_fetch_object)
1581 {
1582 	php_mssql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, MSSQL_ASSOC);
1583 	if (Z_TYPE_P(return_value)==IS_ARRAY) {
1584 		object_and_properties_init(return_value, ZEND_STANDARD_CLASS_DEF_PTR, Z_ARRVAL_P(return_value));
1585 	}
1586 }
1587 /* }}} */
1588 
1589 /* {{{ proto array mssql_fetch_array(resource result_id [, int result_type])
1590    Returns an associative array of the current row in the result set specified by result_id */
1591 PHP_FUNCTION(mssql_fetch_array)
1592 {
1593 	php_mssql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, MSSQL_BOTH);
1594 }
1595 /* }}} */
1596 
1597 /* {{{ proto array mssql_fetch_assoc(resource result_id)
1598    Returns an associative array of the current row in the result set specified by result_id */
1599 PHP_FUNCTION(mssql_fetch_assoc)
1600 {
1601 	php_mssql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, MSSQL_ASSOC);
1602 }
1603 /* }}} */
1604 
1605 /* {{{ proto bool mssql_data_seek(resource result_id, int offset)
1606    Moves the internal row pointer of the MS-SQL result associated with the specified result identifier to pointer to the specified row number */
1607 PHP_FUNCTION(mssql_data_seek)
1608 {
1609 	zval *mssql_result_index;
1610 	long offset;
1611 	mssql_result *result;
1612 
1613 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &mssql_result_index, &offset) == FAILURE) {
1614 		return;
1615 	}
1616 
1617 	ZEND_FETCH_RESOURCE(result, mssql_result *, &mssql_result_index, -1, "MS SQL-result", le_result);
1618 
1619 	if (offset < 0 || offset >= result->num_rows) {
1620 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad row offset");
1621 		RETURN_FALSE;
1622 	}
1623 
1624 	result->cur_row = offset;
1625 	RETURN_TRUE;
1626 }
1627 /* }}} */
1628 
1629 /* {{{ php_mssql_get_field_name
1630 */
1631 static char *php_mssql_get_field_name(int type)
1632 {
1633 	switch (type) {
1634 		case SQLBINARY:
1635 		case SQLVARBINARY:
1636 			return "blob";
1637 			break;
1638 		case SQLCHAR:
1639 		case SQLVARCHAR:
1640 			return "char";
1641 			break;
1642 		case SQLTEXT:
1643 			return "text";
1644 			break;
1645 		case SQLDATETIME:
1646 		case SQLDATETIM4:
1647 		case SQLDATETIMN:
1648 			return "datetime";
1649 			break;
1650 		case SQLDECIMAL:
1651 		case SQLFLT4:
1652 		case SQLFLT8:
1653 		case SQLFLTN:
1654 			return "real";
1655 			break;
1656 		case SQLINT1:
1657 		case SQLINT2:
1658 		case SQLINT4:
1659 		case SQLINTN:
1660 			return "int";
1661 			break;
1662 		case SQLNUMERIC:
1663 			return "numeric";
1664 			break;
1665 		case SQLMONEY:
1666 		case SQLMONEY4:
1667 		case SQLMONEYN:
1668 			return "money";
1669 			break;
1670 		case SQLBIT:
1671 			return "bit";
1672 			break;
1673 		case SQLIMAGE:
1674 			return "image";
1675 			break;
1676 #ifdef SQLUNIQUE
1677 		case SQLUNIQUE:
1678 			return "uniqueidentifier";
1679 			break;
1680 #endif
1681 		default:
1682 			return "unknown";
1683 			break;
1684 	}
1685 }
1686 /* }}} */
1687 
1688 /* {{{ proto object mssql_fetch_field(resource result_id [, int offset])
1689    Gets information about certain fields in a query result */
1690 PHP_FUNCTION(mssql_fetch_field)
1691 {
1692 	zval *mssql_result_index;
1693 	long field_offset = -1;
1694 	mssql_result *result;
1695 
1696 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &mssql_result_index, &field_offset) == FAILURE) {
1697 		return;
1698 	}
1699 
1700 	ZEND_FETCH_RESOURCE(result, mssql_result *, &mssql_result_index, -1, "MS SQL-result", le_result);
1701 
1702 	if (field_offset==-1) {
1703 		field_offset = result->cur_field;
1704 		result->cur_field++;
1705 	}
1706 
1707 	if (field_offset<0 || field_offset >= result->num_fields) {
1708 		if (ZEND_NUM_ARGS()==2) { /* field specified explicitly */
1709 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad column offset");
1710 		}
1711 		RETURN_FALSE;
1712 	}
1713 
1714 	object_init(return_value);
1715 
1716 	add_property_string(return_value, "name",result->fields[field_offset].name, 1);
1717 	add_property_long(return_value, "max_length",result->fields[field_offset].max_length);
1718 	add_property_string(return_value, "column_source",result->fields[field_offset].column_source, 1);
1719 	add_property_long(return_value, "numeric", result->fields[field_offset].numeric);
1720 	add_property_string(return_value, "type", php_mssql_get_field_name(Z_TYPE(result->fields[field_offset])), 1);
1721 }
1722 /* }}} */
1723 
1724 /* {{{ proto int mssql_field_length(resource result_id [, int offset])
1725    Get the length of a MS-SQL field */
1726 PHP_FUNCTION(mssql_field_length)
1727 {
1728 	zval *mssql_result_index;
1729 	long field_offset = -1;
1730 	mssql_result *result;
1731 
1732 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &mssql_result_index, &field_offset) == FAILURE) {
1733 		return;
1734 	}
1735 
1736 	ZEND_FETCH_RESOURCE(result, mssql_result *, &mssql_result_index, -1, "MS SQL-result", le_result);
1737 
1738 	if (field_offset==-1) {
1739 		field_offset = result->cur_field;
1740 		result->cur_field++;
1741 	}
1742 
1743 	if (field_offset<0 || field_offset >= result->num_fields) {
1744 		if (ZEND_NUM_ARGS()==2) { /* field specified explicitly */
1745 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad column offset");
1746 		}
1747 		RETURN_FALSE;
1748 	}
1749 
1750 	RETURN_LONG(result->fields[field_offset].max_length);
1751 }
1752 /* }}} */
1753 
1754 /* {{{ proto string mssql_field_name(resource result_id [, int offset])
1755    Returns the name of the field given by offset in the result set given by result_id */
1756 PHP_FUNCTION(mssql_field_name)
1757 {
1758 	zval *mssql_result_index;
1759 	long field_offset = -1;
1760 	mssql_result *result;
1761 
1762 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &mssql_result_index, &field_offset) == FAILURE) {
1763 		return;
1764 	}
1765 
1766 	ZEND_FETCH_RESOURCE(result, mssql_result *, &mssql_result_index, -1, "MS SQL-result", le_result);
1767 
1768 	if (field_offset==-1) {
1769 		field_offset = result->cur_field;
1770 		result->cur_field++;
1771 	}
1772 
1773 	if (field_offset<0 || field_offset >= result->num_fields) {
1774 		if (ZEND_NUM_ARGS()==2) { /* field specified explicitly */
1775 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad column offset");
1776 		}
1777 		RETURN_FALSE;
1778 	}
1779 
1780 	RETURN_STRINGL(result->fields[field_offset].name, strlen(result->fields[field_offset].name), 1);
1781 }
1782 /* }}} */
1783 
1784 /* {{{ proto string mssql_field_type(resource result_id [, int offset])
1785    Returns the type of a field */
1786 PHP_FUNCTION(mssql_field_type)
1787 {
1788 	zval *mssql_result_index;
1789 	long field_offset = -1;
1790 	mssql_result *result;
1791 
1792 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &mssql_result_index, &field_offset) == FAILURE) {
1793 		return;
1794 	}
1795 
1796 	ZEND_FETCH_RESOURCE(result, mssql_result *, &mssql_result_index, -1, "MS SQL-result", le_result);
1797 
1798 	if (field_offset==-1) {
1799 		field_offset = result->cur_field;
1800 		result->cur_field++;
1801 	}
1802 
1803 	if (field_offset<0 || field_offset >= result->num_fields) {
1804 		if (ZEND_NUM_ARGS()==2) { /* field specified explicitly */
1805 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad column offset");
1806 		}
1807 		RETURN_FALSE;
1808 	}
1809 
1810 	RETURN_STRINGL(php_mssql_get_field_name(Z_TYPE(result->fields[field_offset])), strlen(php_mssql_get_field_name(Z_TYPE(result->fields[field_offset]))), 1);
1811 }
1812 /* }}} */
1813 
1814 /* {{{ proto bool mssql_field_seek(resource result_id, int offset)
1815    Seeks to the specified field offset */
1816 PHP_FUNCTION(mssql_field_seek)
1817 {
1818 	zval *mssql_result_index;
1819 	long field_offset;
1820 	mssql_result *result;
1821 
1822 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &mssql_result_index, &field_offset) == FAILURE) {
1823 		return;
1824 	}
1825 
1826 	ZEND_FETCH_RESOURCE(result, mssql_result *, &mssql_result_index, -1, "MS SQL-result", le_result);
1827 
1828 	if (field_offset<0 || field_offset >= result->num_fields) {
1829 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad column offset");
1830 		RETURN_FALSE;
1831 	}
1832 
1833 	result->cur_field = field_offset;
1834 	RETURN_TRUE;
1835 }
1836 /* }}} */
1837 
1838 /* {{{ proto string mssql_result(resource result_id, int row, mixed field)
1839    Returns the contents of one cell from a MS-SQL result set */
1840 PHP_FUNCTION(mssql_result)
1841 {
1842 	zval **field, *mssql_result_index;
1843 	long row;
1844 	int field_offset=0;
1845 	mssql_result *result;
1846 
1847 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rlZ", &mssql_result_index, &row, &field) == FAILURE) {
1848 		return;
1849 	}
1850 
1851 	ZEND_FETCH_RESOURCE(result, mssql_result *, &mssql_result_index, -1, "MS SQL-result", le_result);
1852 
1853 	if (row < 0 || row >= result->num_rows) {
1854 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad row offset (%ld)", row);
1855 		RETURN_FALSE;
1856 	}
1857 
1858 	switch(Z_TYPE_PP(field)) {
1859 		case IS_STRING: {
1860 			int i;
1861 
1862 			for (i=0; i<result->num_fields; i++) {
1863 				if (!strcasecmp(result->fields[i].name, Z_STRVAL_PP(field))) {
1864 					field_offset = i;
1865 					break;
1866 				}
1867 			}
1868 			if (i>=result->num_fields) { /* no match found */
1869 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s field not found in result", Z_STRVAL_PP(field));
1870 				RETURN_FALSE;
1871 			}
1872 			break;
1873 		}
1874 		default:
1875 			convert_to_long_ex(field);
1876 			field_offset = Z_LVAL_PP(field);
1877 			if (field_offset<0 || field_offset>=result->num_fields) {
1878 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad column offset specified");
1879 				RETURN_FALSE;
1880 			}
1881 			break;
1882 	}
1883 
1884 	*return_value = result->data[row][field_offset];
1885 	zval_copy_ctor(return_value);
1886 }
1887 /* }}} */
1888 
1889 /* {{{ proto bool mssql_next_result(resource result_id)
1890    Move the internal result pointer to the next result */
1891 PHP_FUNCTION(mssql_next_result)
1892 {
1893 	zval *mssql_result_index;
1894 	int retvalue;
1895 	mssql_result *result;
1896 	mssql_link *mssql_ptr;
1897 
1898 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &mssql_result_index) == FAILURE) {
1899 		return;
1900 	}
1901 
1902 	ZEND_FETCH_RESOURCE(result, mssql_result *, &mssql_result_index, -1, "MS SQL-result", le_result);
1903 
1904 	mssql_ptr = result->mssql_ptr;
1905 	retvalue = dbresults(mssql_ptr->link);
1906 
1907 	while (dbnumcols(mssql_ptr->link) <= 0 && retvalue == SUCCEED) {
1908 		retvalue = dbresults(mssql_ptr->link);
1909 	}
1910 
1911 	if (retvalue == FAIL) {
1912 		RETURN_FALSE;
1913 	}
1914 	else if (retvalue == NO_MORE_RESULTS || retvalue == NO_MORE_RPC_RESULTS) {
1915 		if (result->statement) {
1916 			_mssql_get_sp_result(mssql_ptr, result->statement TSRMLS_CC);
1917 		}
1918 		RETURN_FALSE;
1919 	}
1920 	else {
1921 		_free_result(result, 1);
1922 		result->cur_row=result->num_fields=result->num_rows=0;
1923 		dbclrbuf(mssql_ptr->link,DBLASTROW(mssql_ptr->link));
1924 		retvalue = dbnextrow(mssql_ptr->link);
1925 
1926 		result->num_fields = dbnumcols(mssql_ptr->link);
1927 		result->fields = (mssql_field *) safe_emalloc(sizeof(mssql_field), result->num_fields, 0);
1928 		result->have_fields = 0;
1929 		result->num_rows = _mssql_fetch_batch(mssql_ptr, result, retvalue TSRMLS_CC);
1930 		RETURN_TRUE;
1931 	}
1932 
1933 }
1934 /* }}} */
1935 
1936 
1937 /* {{{ proto void mssql_min_error_severity(int severity)
1938    Sets the lower error severity */
1939 PHP_FUNCTION(mssql_min_error_severity)
1940 {
1941 	long severity;
1942 
1943 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &severity) == FAILURE) {
1944 		return;
1945 	}
1946 
1947 	MS_SQL_G(min_error_severity) = severity;
1948 }
1949 
1950 /* }}} */
1951 
1952 /* {{{ proto void mssql_min_message_severity(int severity)
1953    Sets the lower message severity */
1954 PHP_FUNCTION(mssql_min_message_severity)
1955 {
1956 	long severity;
1957 
1958 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &severity) == FAILURE) {
1959 		return;
1960 	}
1961 
1962 	MS_SQL_G(min_message_severity) = severity;
1963 }
1964 /* }}} */
1965 
1966 /* {{{ proto int mssql_init(string sp_name [, resource conn_id])
1967    Initializes a stored procedure or a remote stored procedure  */
1968 PHP_FUNCTION(mssql_init)
1969 {
1970 	char *sp_name;
1971 	int sp_name_len;
1972 	zval *mssql_link_index = NULL;
1973 	mssql_link *mssql_ptr;
1974 	mssql_statement *statement;
1975 	int id = -1;
1976 
1977 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|r", &sp_name, &sp_name_len, &mssql_link_index) == FAILURE) {
1978 		return;
1979 	}
1980 
1981 	if (mssql_link_index == NULL) {
1982 		id = php_mssql_get_default_link(INTERNAL_FUNCTION_PARAM_PASSTHRU);
1983 		CHECK_LINK(id);
1984 	}
1985 
1986 	ZEND_FETCH_RESOURCE2(mssql_ptr, mssql_link *, &mssql_link_index, id, "MS SQL-Link", le_link, le_plink);
1987 
1988 	if (dbrpcinit(mssql_ptr->link, sp_name,0)==FAIL) {
1989 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to init stored procedure");
1990 		RETURN_FALSE;
1991 	}
1992 
1993 	statement=NULL;
1994 	statement = ecalloc(1,sizeof(mssql_statement));
1995 	statement->link = mssql_ptr;
1996 	statement->executed=FALSE;
1997 
1998 	statement->id = zend_list_insert(statement,le_statement TSRMLS_CC);
1999 
2000 	RETURN_RESOURCE(statement->id);
2001 }
2002 /* }}} */
2003 
2004 /* {{{ proto bool mssql_bind(resource stmt, string param_name, mixed var, int type [, bool is_output [, bool is_null [, int maxlen]]])
2005    Adds a parameter to a stored procedure or a remote stored procedure  */
2006 PHP_FUNCTION(mssql_bind)
2007 {
2008 	char *param_name;
2009 	int param_name_len, datalen;
2010 	int status = 0;
2011 	long type = 0, maxlen = -1;
2012 	zval *stmt, **var;
2013 	zend_bool is_output = 0, is_null = 0;
2014 	mssql_link *mssql_ptr;
2015 	mssql_statement *statement;
2016 	mssql_bind bind,*bindp;
2017 	LPBYTE value = NULL;
2018 
2019 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsZl|bbl", &stmt, &param_name, &param_name_len, &var, &type, &is_output, &is_null, &maxlen) == FAILURE) {
2020 		return;
2021 	}
2022 
2023 	if (ZEND_NUM_ARGS() == 7 && !is_output) {
2024 		maxlen = -1;
2025 	}
2026 
2027 	ZEND_FETCH_RESOURCE(statement, mssql_statement *, &stmt, -1, "MS SQL-Statement", le_statement);
2028 
2029 	if (statement==NULL) {
2030 		RETURN_FALSE;
2031 	}
2032 	mssql_ptr=statement->link;
2033 
2034 	/* modify datalen and maxlen according to dbrpcparam documentation */
2035 	if ( (type==SQLVARCHAR) || (type==SQLCHAR) || (type==SQLTEXT) )	{	/* variable-length type */
2036 		if (is_null) {
2037 			maxlen=0;
2038 			datalen=0;
2039 		} else {
2040 			convert_to_string_ex(var);
2041 			datalen=Z_STRLEN_PP(var);
2042 			value=(LPBYTE)Z_STRVAL_PP(var);
2043 		}
2044 	} else {
2045 		/* fixed-length type */
2046 		if (is_null)	{
2047 			datalen=0;
2048 		} else {
2049 			datalen=-1;
2050 		}
2051 		maxlen=-1;
2052 
2053 		switch (type) {
2054 			case SQLFLT4:
2055 			case SQLFLT8:
2056 			case SQLFLTN:
2057 				convert_to_double_ex(var);
2058 				value=(LPBYTE)(&Z_DVAL_PP(var));
2059 				break;
2060 
2061 			case SQLBIT:
2062 			case SQLINT1:
2063 			case SQLINT2:
2064 			case SQLINT4:
2065 				convert_to_long_ex(var);
2066 				value=(LPBYTE)(&Z_LVAL_PP(var));
2067 				break;
2068 
2069 			default:
2070 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "unsupported type");
2071 				RETURN_FALSE;
2072 				break;
2073 		}
2074 	}
2075 
2076 	if (is_output) {
2077 		status=DBRPCRETURN;
2078 	}
2079 
2080 	/* hashtable of binds */
2081 	if (! statement->binds) {
2082 		ALLOC_HASHTABLE(statement->binds);
2083 		zend_hash_init(statement->binds, 13, NULL, _mssql_bind_hash_dtor, 0);
2084 	}
2085 
2086 	if (zend_hash_exists(statement->binds, param_name, param_name_len)) {
2087 		RETURN_FALSE;
2088 	}
2089 	else {
2090 		memset((void*)&bind,0,sizeof(mssql_bind));
2091 		zend_hash_add(statement->binds, param_name, param_name_len, &bind, sizeof(mssql_bind), (void **)&bindp);
2092 		if( NULL == bindp ) RETURN_FALSE;
2093 		bindp->zval=*var;
2094 		zval_add_ref(var);
2095 
2096 		/* no call to dbrpcparam if RETVAL */
2097 		if ( strcmp("RETVAL", param_name)!=0 ) {
2098 			if (dbrpcparam(mssql_ptr->link, param_name, (BYTE)status, type, maxlen, datalen, (LPBYTE)value)==FAIL) {
2099 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to set parameter");
2100 				RETURN_FALSE;
2101 			}
2102 		}
2103 	}
2104 
2105 	RETURN_TRUE;
2106 }
2107 /* }}} */
2108 
2109 /* {{{ proto mixed mssql_execute(resource stmt [, bool skip_results = false])
2110    Executes a stored procedure on a MS-SQL server database */
2111 PHP_FUNCTION(mssql_execute)
2112 {
2113 	zval *stmt;
2114 	zend_bool skip_results = 0;
2115 	int retvalue, retval_results;
2116 	mssql_link *mssql_ptr;
2117 	mssql_statement *statement;
2118 	mssql_result *result;
2119 	int num_fields;
2120 	int batchsize;
2121 	int exec_retval;
2122 
2123 	batchsize = MS_SQL_G(batchsize);
2124 
2125 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|b", &stmt, &skip_results) == FAILURE) {
2126 		return;
2127 	}
2128 
2129 	ZEND_FETCH_RESOURCE(statement, mssql_statement *, &stmt, -1, "MS SQL-Statement", le_statement);
2130 
2131 	mssql_ptr=statement->link;
2132 	exec_retval = dbrpcexec(mssql_ptr->link);
2133 
2134 	if (exec_retval == FAIL || dbsqlok(mssql_ptr->link) == FAIL) {
2135 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "stored procedure execution failed");
2136 
2137 		if (exec_retval == FAIL) {
2138 			dbcancel(mssql_ptr->link);
2139 		}
2140 
2141 		RETURN_FALSE;
2142 	}
2143 
2144 	retval_results=dbresults(mssql_ptr->link);
2145 
2146 	if (retval_results==FAIL) {
2147 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not retrieve results");
2148 		dbcancel(mssql_ptr->link);
2149 		RETURN_FALSE;
2150 	}
2151 
2152 	/* The following is just like mssql_query, fetch all rows from the first result
2153 	 *	set into the row buffer.
2154  	 */
2155 	result=NULL;
2156 	if (retval_results == SUCCEED) {
2157 		if (skip_results) {
2158 			do {
2159 				dbcanquery(mssql_ptr->link);
2160 				retval_results = dbresults(mssql_ptr->link);
2161 			} while (retval_results == SUCCEED);
2162 		}
2163 		else {
2164 			/* Skip results not returning any columns */
2165 			while ((num_fields = dbnumcols(mssql_ptr->link)) <= 0 && retval_results == SUCCEED) {
2166 				retval_results = dbresults(mssql_ptr->link);
2167 			}
2168 			if ((num_fields = dbnumcols(mssql_ptr->link)) > 0) {
2169 				retvalue = dbnextrow(mssql_ptr->link);
2170 				result = (mssql_result *) emalloc(sizeof(mssql_result));
2171 				result->batchsize = batchsize;
2172 				result->blocks_initialized = 1;
2173 				result->data = (zval **) safe_emalloc(sizeof(zval *), MSSQL_ROWS_BLOCK, 0);
2174 				result->mssql_ptr = mssql_ptr;
2175 				result->cur_field=result->cur_row=result->num_rows=0;
2176 				result->num_fields = num_fields;
2177 				result->have_fields = 0;
2178 
2179 				result->fields = (mssql_field *) safe_emalloc(sizeof(mssql_field), num_fields, 0);
2180 				result->statement = statement;
2181 				result->num_rows = _mssql_fetch_batch(mssql_ptr, result, retvalue TSRMLS_CC);
2182 			}
2183 		}
2184 	}
2185 	if (retval_results == NO_MORE_RESULTS || retval_results == NO_MORE_RPC_RESULTS) {
2186 		_mssql_get_sp_result(mssql_ptr, statement TSRMLS_CC);
2187 	}
2188 
2189 	if (result==NULL) {
2190 		RETURN_TRUE;	/* no recordset returned ...*/
2191 	}
2192 	else {
2193 		ZEND_REGISTER_RESOURCE(return_value, result, le_result);
2194 	}
2195 }
2196 /* }}} */
2197 
2198 /* {{{ proto bool mssql_free_statement(resource result_index)
2199    Free a MS-SQL statement index */
2200 PHP_FUNCTION(mssql_free_statement)
2201 {
2202 	zval *mssql_statement_index;
2203 	mssql_statement *statement;
2204 	int retvalue;
2205 
2206 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &mssql_statement_index) == FAILURE) {
2207 		return;
2208 	}
2209 
2210 	if (Z_RESVAL_P(mssql_statement_index) == 0) {
2211 		RETURN_FALSE;
2212 	}
2213 
2214 	ZEND_FETCH_RESOURCE(statement, mssql_statement *, &mssql_statement_index, -1, "MS SQL-statement", le_statement);
2215 	/* Release remaining results */
2216 	do {
2217 		dbcanquery(statement->link->link);
2218 		retvalue = dbresults(statement->link->link);
2219 	} while (retvalue == SUCCEED);
2220 
2221 	zend_list_delete(Z_RESVAL_P(mssql_statement_index));
2222 	RETURN_TRUE;
2223 }
2224 /* }}} */
2225 
2226 /* {{{ proto string mssql_guid_string(string binary [,bool short_format])
2227    Converts a 16 byte binary GUID to a string  */
2228 PHP_FUNCTION(mssql_guid_string)
2229 {
2230 	char *binary;
2231 	int binary_len;
2232 	zend_bool sf = 0;
2233 	char buffer[32+1];
2234 	char buffer2[36+1];
2235 
2236 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &binary, &binary_len, &sf) == FAILURE) {
2237 		return;
2238 	}
2239 
2240 	dbconvert(NULL, SQLBINARY, (BYTE*) binary, MIN(16, binary_len), SQLCHAR, buffer, -1);
2241 
2242 	if (sf) {
2243 		php_strtoupper(buffer, 32);
2244 		RETURN_STRING(buffer, 1);
2245 	}
2246 	else {
2247 		int i;
2248 		/* FIXME this works only on little endian machine */
2249 		for (i=0; i<4; i++) {
2250 			buffer2[2*i] = buffer[6-2*i];
2251 			buffer2[2*i+1] = buffer[7-2*i];
2252 		}
2253 		buffer2[8] = '-';
2254 		for (i=0; i<2; i++) {
2255 			buffer2[9+2*i] = buffer[10-2*i];
2256 			buffer2[10+2*i] = buffer[11-2*i];
2257 		}
2258 		buffer2[13] = '-';
2259 		for (i=0; i<2; i++) {
2260 			buffer2[14+2*i] = buffer[14-2*i];
2261 			buffer2[15+2*i] = buffer[15-2*i];
2262 		}
2263 		buffer2[18] = '-';
2264 		for (i=0; i<4; i++) {
2265 			buffer2[19+i] = buffer[16+i];
2266 		}
2267 		buffer2[23] = '-';
2268 		for (i=0; i<12; i++) {
2269 			buffer2[24+i] = buffer[20+i];
2270 		}
2271 		buffer2[36] = 0;
2272 
2273 		php_strtoupper(buffer2, 36);
2274 		RETURN_STRING(buffer2, 1);
2275 	}
2276 }
2277 /* }}} */
2278 
2279 #endif
2280