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