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