xref: /PHP-5.3/ext/mssql/php_mssql.c (revision a2045ff3)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 5                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1997-2013 The PHP Group                                |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 3.01 of the PHP license,      |
8    | that is bundled with this package in the file LICENSE, and is        |
9    | available through the world-wide-web at the following url:           |
10    | http://www.php.net/license/3_01.txt                                  |
11    | If you did not receive a copy of the PHP license and are unable to   |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@php.net so we can mail you a copy immediately.               |
14    +----------------------------------------------------------------------+
15    | Author: 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 			int should_copy;
1531 
1532 			if (Z_TYPE(result->data[result->cur_row][i]) == IS_STRING) {
1533 				if (PG(magic_quotes_runtime)) {
1534 					data = php_addslashes(Z_STRVAL(result->data[result->cur_row][i]), Z_STRLEN(result->data[result->cur_row][i]), &data_len, 0 TSRMLS_CC);
1535 					should_copy = 0;
1536 				}
1537 				else
1538 				{
1539 					data = Z_STRVAL(result->data[result->cur_row][i]);
1540 					data_len = Z_STRLEN(result->data[result->cur_row][i]);
1541 					should_copy = 1;
1542 				}
1543 
1544 				if (result_type & MSSQL_NUM) {
1545 					add_index_stringl(return_value, i, data, data_len, should_copy);
1546 					should_copy = 1;
1547 				}
1548 
1549 				if (result_type & MSSQL_ASSOC) {
1550 					add_assoc_stringl(return_value, result->fields[i].name, data, data_len, should_copy);
1551 				}
1552 			}
1553 			else if (Z_TYPE(result->data[result->cur_row][i]) == IS_LONG) {
1554 				if (result_type & MSSQL_NUM)
1555 					add_index_long(return_value, i, Z_LVAL(result->data[result->cur_row][i]));
1556 
1557 				if (result_type & MSSQL_ASSOC)
1558 					add_assoc_long(return_value, result->fields[i].name, Z_LVAL(result->data[result->cur_row][i]));
1559 			}
1560 			else if (Z_TYPE(result->data[result->cur_row][i]) == IS_DOUBLE) {
1561 				if (result_type & MSSQL_NUM)
1562 					add_index_double(return_value, i, Z_DVAL(result->data[result->cur_row][i]));
1563 
1564 				if (result_type & MSSQL_ASSOC)
1565 					add_assoc_double(return_value, result->fields[i].name, Z_DVAL(result->data[result->cur_row][i]));
1566 			}
1567 		}
1568 		else
1569 		{
1570 			if (result_type & MSSQL_NUM)
1571 				add_index_null(return_value, i);
1572 			if (result_type & MSSQL_ASSOC)
1573 				add_assoc_null(return_value, result->fields[i].name);
1574 		}
1575 	}
1576 	result->cur_row++;
1577 }
1578 /* }}} */
1579 
1580 /* {{{ proto array mssql_fetch_row(resource result_id)
1581    Returns an array of the current row in the result set specified by result_id */
1582 PHP_FUNCTION(mssql_fetch_row)
1583 {
1584 	php_mssql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, MSSQL_NUM);
1585 }
1586 /* }}} */
1587 
1588 /* {{{ proto object mssql_fetch_object(resource result_id)
1589    Returns a pseudo-object of the current row in the result set specified by result_id */
1590 PHP_FUNCTION(mssql_fetch_object)
1591 {
1592 	php_mssql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, MSSQL_ASSOC);
1593 	if (Z_TYPE_P(return_value)==IS_ARRAY) {
1594 		object_and_properties_init(return_value, ZEND_STANDARD_CLASS_DEF_PTR, Z_ARRVAL_P(return_value));
1595 	}
1596 }
1597 /* }}} */
1598 
1599 /* {{{ proto array mssql_fetch_array(resource result_id [, int result_type])
1600    Returns an associative array of the current row in the result set specified by result_id */
1601 PHP_FUNCTION(mssql_fetch_array)
1602 {
1603 	php_mssql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, MSSQL_BOTH);
1604 }
1605 /* }}} */
1606 
1607 /* {{{ proto array mssql_fetch_assoc(resource result_id)
1608    Returns an associative array of the current row in the result set specified by result_id */
1609 PHP_FUNCTION(mssql_fetch_assoc)
1610 {
1611 	php_mssql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, MSSQL_ASSOC);
1612 }
1613 /* }}} */
1614 
1615 /* {{{ proto bool mssql_data_seek(resource result_id, int offset)
1616    Moves the internal row pointer of the MS-SQL result associated with the specified result identifier to pointer to the specified row number */
1617 PHP_FUNCTION(mssql_data_seek)
1618 {
1619 	zval *mssql_result_index;
1620 	long offset;
1621 	mssql_result *result;
1622 
1623 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &mssql_result_index, &offset) == FAILURE) {
1624 		return;
1625 	}
1626 
1627 	ZEND_FETCH_RESOURCE(result, mssql_result *, &mssql_result_index, -1, "MS SQL-result", le_result);
1628 
1629 	if (offset < 0 || offset >= result->num_rows) {
1630 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad row offset");
1631 		RETURN_FALSE;
1632 	}
1633 
1634 	result->cur_row = offset;
1635 	RETURN_TRUE;
1636 }
1637 /* }}} */
1638 
1639 /* {{{ php_mssql_get_field_name
1640 */
1641 static char *php_mssql_get_field_name(int type)
1642 {
1643 	switch (type) {
1644 		case SQLBINARY:
1645 		case SQLVARBINARY:
1646 			return "blob";
1647 			break;
1648 		case SQLCHAR:
1649 		case SQLVARCHAR:
1650 			return "char";
1651 			break;
1652 		case SQLTEXT:
1653 			return "text";
1654 			break;
1655 		case SQLDATETIME:
1656 		case SQLDATETIM4:
1657 		case SQLDATETIMN:
1658 			return "datetime";
1659 			break;
1660 		case SQLDECIMAL:
1661 		case SQLFLT4:
1662 		case SQLFLT8:
1663 		case SQLFLTN:
1664 			return "real";
1665 			break;
1666 		case SQLINT1:
1667 		case SQLINT2:
1668 		case SQLINT4:
1669 		case SQLINTN:
1670 			return "int";
1671 			break;
1672 		case SQLNUMERIC:
1673 			return "numeric";
1674 			break;
1675 		case SQLMONEY:
1676 		case SQLMONEY4:
1677 		case SQLMONEYN:
1678 			return "money";
1679 			break;
1680 		case SQLBIT:
1681 			return "bit";
1682 			break;
1683 		case SQLIMAGE:
1684 			return "image";
1685 			break;
1686 #ifdef SQLUNIQUE
1687 		case SQLUNIQUE:
1688 			return "uniqueidentifier";
1689 			break;
1690 #endif
1691 		default:
1692 			return "unknown";
1693 			break;
1694 	}
1695 }
1696 /* }}} */
1697 
1698 /* {{{ proto object mssql_fetch_field(resource result_id [, int offset])
1699    Gets information about certain fields in a query result */
1700 PHP_FUNCTION(mssql_fetch_field)
1701 {
1702 	zval *mssql_result_index;
1703 	long field_offset = -1;
1704 	mssql_result *result;
1705 
1706 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &mssql_result_index, &field_offset) == FAILURE) {
1707 		return;
1708 	}
1709 
1710 	ZEND_FETCH_RESOURCE(result, mssql_result *, &mssql_result_index, -1, "MS SQL-result", le_result);
1711 
1712 	if (field_offset==-1) {
1713 		field_offset = result->cur_field;
1714 		result->cur_field++;
1715 	}
1716 
1717 	if (field_offset<0 || field_offset >= result->num_fields) {
1718 		if (ZEND_NUM_ARGS()==2) { /* field specified explicitly */
1719 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad column offset");
1720 		}
1721 		RETURN_FALSE;
1722 	}
1723 
1724 	object_init(return_value);
1725 
1726 	add_property_string(return_value, "name",result->fields[field_offset].name, 1);
1727 	add_property_long(return_value, "max_length",result->fields[field_offset].max_length);
1728 	add_property_string(return_value, "column_source",result->fields[field_offset].column_source, 1);
1729 	add_property_long(return_value, "numeric", result->fields[field_offset].numeric);
1730 	add_property_string(return_value, "type", php_mssql_get_field_name(Z_TYPE(result->fields[field_offset])), 1);
1731 }
1732 /* }}} */
1733 
1734 /* {{{ proto int mssql_field_length(resource result_id [, int offset])
1735    Get the length of a MS-SQL field */
1736 PHP_FUNCTION(mssql_field_length)
1737 {
1738 	zval *mssql_result_index;
1739 	long field_offset = -1;
1740 	mssql_result *result;
1741 
1742 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &mssql_result_index, &field_offset) == FAILURE) {
1743 		return;
1744 	}
1745 
1746 	ZEND_FETCH_RESOURCE(result, mssql_result *, &mssql_result_index, -1, "MS SQL-result", le_result);
1747 
1748 	if (field_offset==-1) {
1749 		field_offset = result->cur_field;
1750 		result->cur_field++;
1751 	}
1752 
1753 	if (field_offset<0 || field_offset >= result->num_fields) {
1754 		if (ZEND_NUM_ARGS()==2) { /* field specified explicitly */
1755 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad column offset");
1756 		}
1757 		RETURN_FALSE;
1758 	}
1759 
1760 	RETURN_LONG(result->fields[field_offset].max_length);
1761 }
1762 /* }}} */
1763 
1764 /* {{{ proto string mssql_field_name(resource result_id [, int offset])
1765    Returns the name of the field given by offset in the result set given by result_id */
1766 PHP_FUNCTION(mssql_field_name)
1767 {
1768 	zval *mssql_result_index;
1769 	long field_offset = -1;
1770 	mssql_result *result;
1771 
1772 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &mssql_result_index, &field_offset) == FAILURE) {
1773 		return;
1774 	}
1775 
1776 	ZEND_FETCH_RESOURCE(result, mssql_result *, &mssql_result_index, -1, "MS SQL-result", le_result);
1777 
1778 	if (field_offset==-1) {
1779 		field_offset = result->cur_field;
1780 		result->cur_field++;
1781 	}
1782 
1783 	if (field_offset<0 || field_offset >= result->num_fields) {
1784 		if (ZEND_NUM_ARGS()==2) { /* field specified explicitly */
1785 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad column offset");
1786 		}
1787 		RETURN_FALSE;
1788 	}
1789 
1790 	RETURN_STRINGL(result->fields[field_offset].name, strlen(result->fields[field_offset].name), 1);
1791 }
1792 /* }}} */
1793 
1794 /* {{{ proto string mssql_field_type(resource result_id [, int offset])
1795    Returns the type of a field */
1796 PHP_FUNCTION(mssql_field_type)
1797 {
1798 	zval *mssql_result_index;
1799 	long field_offset = -1;
1800 	mssql_result *result;
1801 
1802 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &mssql_result_index, &field_offset) == FAILURE) {
1803 		return;
1804 	}
1805 
1806 	ZEND_FETCH_RESOURCE(result, mssql_result *, &mssql_result_index, -1, "MS SQL-result", le_result);
1807 
1808 	if (field_offset==-1) {
1809 		field_offset = result->cur_field;
1810 		result->cur_field++;
1811 	}
1812 
1813 	if (field_offset<0 || field_offset >= result->num_fields) {
1814 		if (ZEND_NUM_ARGS()==2) { /* field specified explicitly */
1815 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad column offset");
1816 		}
1817 		RETURN_FALSE;
1818 	}
1819 
1820 	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);
1821 }
1822 /* }}} */
1823 
1824 /* {{{ proto bool mssql_field_seek(resource result_id, int offset)
1825    Seeks to the specified field offset */
1826 PHP_FUNCTION(mssql_field_seek)
1827 {
1828 	zval *mssql_result_index;
1829 	long field_offset;
1830 	mssql_result *result;
1831 
1832 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &mssql_result_index, &field_offset) == FAILURE) {
1833 		return;
1834 	}
1835 
1836 	ZEND_FETCH_RESOURCE(result, mssql_result *, &mssql_result_index, -1, "MS SQL-result", le_result);
1837 
1838 	if (field_offset<0 || field_offset >= result->num_fields) {
1839 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad column offset");
1840 		RETURN_FALSE;
1841 	}
1842 
1843 	result->cur_field = field_offset;
1844 	RETURN_TRUE;
1845 }
1846 /* }}} */
1847 
1848 /* {{{ proto string mssql_result(resource result_id, int row, mixed field)
1849    Returns the contents of one cell from a MS-SQL result set */
1850 PHP_FUNCTION(mssql_result)
1851 {
1852 	zval **field, *mssql_result_index;
1853 	long row;
1854 	int field_offset=0;
1855 	mssql_result *result;
1856 
1857 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rlZ", &mssql_result_index, &row, &field) == FAILURE) {
1858 		return;
1859 	}
1860 
1861 	ZEND_FETCH_RESOURCE(result, mssql_result *, &mssql_result_index, -1, "MS SQL-result", le_result);
1862 
1863 	if (row < 0 || row >= result->num_rows) {
1864 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad row offset (%ld)", row);
1865 		RETURN_FALSE;
1866 	}
1867 
1868 	switch(Z_TYPE_PP(field)) {
1869 		case IS_STRING: {
1870 			int i;
1871 
1872 			for (i=0; i<result->num_fields; i++) {
1873 				if (!strcasecmp(result->fields[i].name, Z_STRVAL_PP(field))) {
1874 					field_offset = i;
1875 					break;
1876 				}
1877 			}
1878 			if (i>=result->num_fields) { /* no match found */
1879 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s field not found in result", Z_STRVAL_PP(field));
1880 				RETURN_FALSE;
1881 			}
1882 			break;
1883 		}
1884 		default:
1885 			convert_to_long_ex(field);
1886 			field_offset = Z_LVAL_PP(field);
1887 			if (field_offset<0 || field_offset>=result->num_fields) {
1888 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad column offset specified");
1889 				RETURN_FALSE;
1890 			}
1891 			break;
1892 	}
1893 
1894 	*return_value = result->data[row][field_offset];
1895 	zval_copy_ctor(return_value);
1896 }
1897 /* }}} */
1898 
1899 /* {{{ proto bool mssql_next_result(resource result_id)
1900    Move the internal result pointer to the next result */
1901 PHP_FUNCTION(mssql_next_result)
1902 {
1903 	zval *mssql_result_index;
1904 	int retvalue;
1905 	mssql_result *result;
1906 	mssql_link *mssql_ptr;
1907 
1908 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &mssql_result_index) == FAILURE) {
1909 		return;
1910 	}
1911 
1912 	ZEND_FETCH_RESOURCE(result, mssql_result *, &mssql_result_index, -1, "MS SQL-result", le_result);
1913 
1914 	mssql_ptr = result->mssql_ptr;
1915 	retvalue = dbresults(mssql_ptr->link);
1916 
1917 	while (dbnumcols(mssql_ptr->link) <= 0 && retvalue == SUCCEED) {
1918 		retvalue = dbresults(mssql_ptr->link);
1919 	}
1920 
1921 	if (retvalue == FAIL) {
1922 		RETURN_FALSE;
1923 	}
1924 	else if (retvalue == NO_MORE_RESULTS || retvalue == NO_MORE_RPC_RESULTS) {
1925 		if (result->statement) {
1926 			_mssql_get_sp_result(mssql_ptr, result->statement TSRMLS_CC);
1927 		}
1928 		RETURN_FALSE;
1929 	}
1930 	else {
1931 		_free_result(result, 1);
1932 		result->cur_row=result->num_fields=result->num_rows=0;
1933 		dbclrbuf(mssql_ptr->link,DBLASTROW(mssql_ptr->link));
1934 		retvalue = dbnextrow(mssql_ptr->link);
1935 
1936 		result->num_fields = dbnumcols(mssql_ptr->link);
1937 		result->fields = (mssql_field *) safe_emalloc(sizeof(mssql_field), result->num_fields, 0);
1938 		result->have_fields = 0;
1939 		result->num_rows = _mssql_fetch_batch(mssql_ptr, result, retvalue TSRMLS_CC);
1940 		RETURN_TRUE;
1941 	}
1942 
1943 }
1944 /* }}} */
1945 
1946 
1947 /* {{{ proto void mssql_min_error_severity(int severity)
1948    Sets the lower error severity */
1949 PHP_FUNCTION(mssql_min_error_severity)
1950 {
1951 	long severity;
1952 
1953 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &severity) == FAILURE) {
1954 		return;
1955 	}
1956 
1957 	MS_SQL_G(min_error_severity) = severity;
1958 }
1959 
1960 /* }}} */
1961 
1962 /* {{{ proto void mssql_min_message_severity(int severity)
1963    Sets the lower message severity */
1964 PHP_FUNCTION(mssql_min_message_severity)
1965 {
1966 	long severity;
1967 
1968 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &severity) == FAILURE) {
1969 		return;
1970 	}
1971 
1972 	MS_SQL_G(min_message_severity) = severity;
1973 }
1974 /* }}} */
1975 
1976 /* {{{ proto int mssql_init(string sp_name [, resource conn_id])
1977    Initializes a stored procedure or a remote stored procedure  */
1978 PHP_FUNCTION(mssql_init)
1979 {
1980 	char *sp_name;
1981 	int sp_name_len;
1982 	zval *mssql_link_index = NULL;
1983 	mssql_link *mssql_ptr;
1984 	mssql_statement *statement;
1985 	int id = -1;
1986 
1987 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|r", &sp_name, &sp_name_len, &mssql_link_index) == FAILURE) {
1988 		return;
1989 	}
1990 
1991 	if (mssql_link_index == NULL) {
1992 		id = php_mssql_get_default_link(INTERNAL_FUNCTION_PARAM_PASSTHRU);
1993 		CHECK_LINK(id);
1994 	}
1995 
1996 	ZEND_FETCH_RESOURCE2(mssql_ptr, mssql_link *, &mssql_link_index, id, "MS SQL-Link", le_link, le_plink);
1997 
1998 	if (dbrpcinit(mssql_ptr->link, sp_name,0)==FAIL) {
1999 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to init stored procedure");
2000 		RETURN_FALSE;
2001 	}
2002 
2003 	statement=NULL;
2004 	statement = ecalloc(1,sizeof(mssql_statement));
2005 	statement->link = mssql_ptr;
2006 	statement->executed=FALSE;
2007 
2008 	statement->id = zend_list_insert(statement,le_statement);
2009 
2010 	RETURN_RESOURCE(statement->id);
2011 }
2012 /* }}} */
2013 
2014 /* {{{ proto bool mssql_bind(resource stmt, string param_name, mixed var, int type [, bool is_output [, bool is_null [, int maxlen]]])
2015    Adds a parameter to a stored procedure or a remote stored procedure  */
2016 PHP_FUNCTION(mssql_bind)
2017 {
2018 	char *param_name;
2019 	int param_name_len, datalen;
2020 	int status = 0;
2021 	long type = 0, maxlen = -1;
2022 	zval *stmt, **var;
2023 	zend_bool is_output = 0, is_null = 0;
2024 	mssql_link *mssql_ptr;
2025 	mssql_statement *statement;
2026 	mssql_bind bind,*bindp;
2027 	LPBYTE value = NULL;
2028 
2029 	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) {
2030 		return;
2031 	}
2032 
2033 	if (ZEND_NUM_ARGS() == 7 && !is_output) {
2034 		maxlen = -1;
2035 	}
2036 
2037 	ZEND_FETCH_RESOURCE(statement, mssql_statement *, &stmt, -1, "MS SQL-Statement", le_statement);
2038 
2039 	if (statement==NULL) {
2040 		RETURN_FALSE;
2041 	}
2042 	mssql_ptr=statement->link;
2043 
2044 	/* modify datalen and maxlen according to dbrpcparam documentation */
2045 	if ( (type==SQLVARCHAR) || (type==SQLCHAR) || (type==SQLTEXT) )	{	/* variable-length type */
2046 		if (is_null) {
2047 			maxlen=0;
2048 			datalen=0;
2049 		} else {
2050 			convert_to_string_ex(var);
2051 			datalen=Z_STRLEN_PP(var);
2052 			value=(LPBYTE)Z_STRVAL_PP(var);
2053 		}
2054 	} else {
2055 		/* fixed-length type */
2056 		if (is_null)	{
2057 			datalen=0;
2058 		} else {
2059 			datalen=-1;
2060 		}
2061 		maxlen=-1;
2062 
2063 		switch (type) {
2064 			case SQLFLT4:
2065 			case SQLFLT8:
2066 			case SQLFLTN:
2067 				convert_to_double_ex(var);
2068 				value=(LPBYTE)(&Z_DVAL_PP(var));
2069 				break;
2070 
2071 			case SQLBIT:
2072 			case SQLINT1:
2073 			case SQLINT2:
2074 			case SQLINT4:
2075 				convert_to_long_ex(var);
2076 				value=(LPBYTE)(&Z_LVAL_PP(var));
2077 				break;
2078 
2079 			default:
2080 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "unsupported type");
2081 				RETURN_FALSE;
2082 				break;
2083 		}
2084 	}
2085 
2086 	if (is_output) {
2087 		status=DBRPCRETURN;
2088 	}
2089 
2090 	/* hashtable of binds */
2091 	if (! statement->binds) {
2092 		ALLOC_HASHTABLE(statement->binds);
2093 		zend_hash_init(statement->binds, 13, NULL, _mssql_bind_hash_dtor, 0);
2094 	}
2095 
2096 	if (zend_hash_exists(statement->binds, param_name, param_name_len)) {
2097 		RETURN_FALSE;
2098 	}
2099 	else {
2100 		memset((void*)&bind,0,sizeof(mssql_bind));
2101 		zend_hash_add(statement->binds, param_name, param_name_len, &bind, sizeof(mssql_bind), (void **)&bindp);
2102 		if( NULL == bindp ) RETURN_FALSE;
2103 		bindp->zval=*var;
2104 		zval_add_ref(var);
2105 
2106 		/* no call to dbrpcparam if RETVAL */
2107 		if ( strcmp("RETVAL", param_name)!=0 ) {
2108 			if (dbrpcparam(mssql_ptr->link, param_name, (BYTE)status, type, maxlen, datalen, (LPBYTE)value)==FAIL) {
2109 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to set parameter");
2110 				RETURN_FALSE;
2111 			}
2112 		}
2113 	}
2114 
2115 	RETURN_TRUE;
2116 }
2117 /* }}} */
2118 
2119 /* {{{ proto mixed mssql_execute(resource stmt [, bool skip_results = false])
2120    Executes a stored procedure on a MS-SQL server database */
2121 PHP_FUNCTION(mssql_execute)
2122 {
2123 	zval *stmt;
2124 	zend_bool skip_results = 0;
2125 	int retvalue, retval_results;
2126 	mssql_link *mssql_ptr;
2127 	mssql_statement *statement;
2128 	mssql_result *result;
2129 	int num_fields;
2130 	int batchsize;
2131 	int exec_retval;
2132 
2133 	batchsize = MS_SQL_G(batchsize);
2134 
2135 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|b", &stmt, &skip_results) == FAILURE) {
2136 		return;
2137 	}
2138 
2139 	ZEND_FETCH_RESOURCE(statement, mssql_statement *, &stmt, -1, "MS SQL-Statement", le_statement);
2140 
2141 	mssql_ptr=statement->link;
2142 	exec_retval = dbrpcexec(mssql_ptr->link);
2143 
2144 	if (exec_retval == FAIL || dbsqlok(mssql_ptr->link) == FAIL) {
2145 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "stored procedure execution failed");
2146 
2147 		if (exec_retval == FAIL) {
2148 			dbcancel(mssql_ptr->link);
2149 		}
2150 
2151 		RETURN_FALSE;
2152 	}
2153 
2154 	retval_results=dbresults(mssql_ptr->link);
2155 
2156 	if (retval_results==FAIL) {
2157 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not retrieve results");
2158 		dbcancel(mssql_ptr->link);
2159 		RETURN_FALSE;
2160 	}
2161 
2162 	/* The following is just like mssql_query, fetch all rows from the first result
2163 	 *	set into the row buffer.
2164  	 */
2165 	result=NULL;
2166 	if (retval_results == SUCCEED) {
2167 		if (skip_results) {
2168 			do {
2169 				dbcanquery(mssql_ptr->link);
2170 				retval_results = dbresults(mssql_ptr->link);
2171 			} while (retval_results == SUCCEED);
2172 		}
2173 		else {
2174 			/* Skip results not returning any columns */
2175 			while ((num_fields = dbnumcols(mssql_ptr->link)) <= 0 && retval_results == SUCCEED) {
2176 				retval_results = dbresults(mssql_ptr->link);
2177 			}
2178 			if ((num_fields = dbnumcols(mssql_ptr->link)) > 0) {
2179 				retvalue = dbnextrow(mssql_ptr->link);
2180 				result = (mssql_result *) emalloc(sizeof(mssql_result));
2181 				result->batchsize = batchsize;
2182 				result->blocks_initialized = 1;
2183 				result->data = (zval **) safe_emalloc(sizeof(zval *), MSSQL_ROWS_BLOCK, 0);
2184 				result->mssql_ptr = mssql_ptr;
2185 				result->cur_field=result->cur_row=result->num_rows=0;
2186 				result->num_fields = num_fields;
2187 				result->have_fields = 0;
2188 
2189 				result->fields = (mssql_field *) safe_emalloc(sizeof(mssql_field), num_fields, 0);
2190 				result->statement = statement;
2191 				result->num_rows = _mssql_fetch_batch(mssql_ptr, result, retvalue TSRMLS_CC);
2192 			}
2193 		}
2194 	}
2195 	if (retval_results == NO_MORE_RESULTS || retval_results == NO_MORE_RPC_RESULTS) {
2196 		_mssql_get_sp_result(mssql_ptr, statement TSRMLS_CC);
2197 	}
2198 
2199 	if (result==NULL) {
2200 		RETURN_TRUE;	/* no recordset returned ...*/
2201 	}
2202 	else {
2203 		ZEND_REGISTER_RESOURCE(return_value, result, le_result);
2204 	}
2205 }
2206 /* }}} */
2207 
2208 /* {{{ proto bool mssql_free_statement(resource result_index)
2209    Free a MS-SQL statement index */
2210 PHP_FUNCTION(mssql_free_statement)
2211 {
2212 	zval *mssql_statement_index;
2213 	mssql_statement *statement;
2214 	int retvalue;
2215 
2216 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &mssql_statement_index) == FAILURE) {
2217 		return;
2218 	}
2219 
2220 	if (Z_RESVAL_P(mssql_statement_index) == 0) {
2221 		RETURN_FALSE;
2222 	}
2223 
2224 	ZEND_FETCH_RESOURCE(statement, mssql_statement *, &mssql_statement_index, -1, "MS SQL-statement", le_statement);
2225 	/* Release remaining results */
2226 	do {
2227 		dbcanquery(statement->link->link);
2228 		retvalue = dbresults(statement->link->link);
2229 	} while (retvalue == SUCCEED);
2230 
2231 	zend_list_delete(Z_RESVAL_P(mssql_statement_index));
2232 	RETURN_TRUE;
2233 }
2234 /* }}} */
2235 
2236 /* {{{ proto string mssql_guid_string(string binary [,bool short_format])
2237    Converts a 16 byte binary GUID to a string  */
2238 PHP_FUNCTION(mssql_guid_string)
2239 {
2240 	char *binary;
2241 	int binary_len;
2242 	zend_bool sf = 0;
2243 	char buffer[32+1];
2244 	char buffer2[36+1];
2245 
2246 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &binary, &binary_len, &sf) == FAILURE) {
2247 		return;
2248 	}
2249 
2250 	dbconvert(NULL, SQLBINARY, (BYTE*) binary, MIN(16, binary_len), SQLCHAR, buffer, -1);
2251 
2252 	if (sf) {
2253 		php_strtoupper(buffer, 32);
2254 		RETURN_STRING(buffer, 1);
2255 	}
2256 	else {
2257 		int i;
2258 		/* FIXME this works only on little endian machine */
2259 		for (i=0; i<4; i++) {
2260 			buffer2[2*i] = buffer[6-2*i];
2261 			buffer2[2*i+1] = buffer[7-2*i];
2262 		}
2263 		buffer2[8] = '-';
2264 		for (i=0; i<2; i++) {
2265 			buffer2[9+2*i] = buffer[10-2*i];
2266 			buffer2[10+2*i] = buffer[11-2*i];
2267 		}
2268 		buffer2[13] = '-';
2269 		for (i=0; i<2; i++) {
2270 			buffer2[14+2*i] = buffer[14-2*i];
2271 			buffer2[15+2*i] = buffer[15-2*i];
2272 		}
2273 		buffer2[18] = '-';
2274 		for (i=0; i<4; i++) {
2275 			buffer2[19+i] = buffer[16+i];
2276 		}
2277 		buffer2[23] = '-';
2278 		for (i=0; i<12; i++) {
2279 			buffer2[24+i] = buffer[20+i];
2280 		}
2281 		buffer2[36] = 0;
2282 
2283 		php_strtoupper(buffer2, 36);
2284 		RETURN_STRING(buffer2, 1);
2285 	}
2286 }
2287 /* }}} */
2288 
2289 #endif
2290