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, ¶m_name, ¶m_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