1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 5 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2013 The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Authors: Jouni Ahto <jouni.ahto@exdec.fi> |
16 | Andrew Avdeev <andy@rsc.mv.ru> |
17 | Ard Biesheuvel <a.k.biesheuvel@ewi.tudelft.nl> |
18 +----------------------------------------------------------------------+
19 */
20
21 /* $Id$ */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #define _GNU_SOURCE
28
29 #include "php.h"
30
31 #if HAVE_IBASE
32
33 #include "php_ini.h"
34 #include "ext/standard/php_standard.h"
35 #include "ext/standard/md5.h"
36 #include "php_interbase.h"
37 #include "php_ibase_includes.h"
38 #include "SAPI.h"
39
40 #include <time.h>
41
42 #define ROLLBACK 0
43 #define COMMIT 1
44 #define RETAIN 2
45
46 #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; } }
47
48 ZEND_DECLARE_MODULE_GLOBALS(ibase)
49 static PHP_GINIT_FUNCTION(ibase);
50
51 /* {{{ arginfo */
52 ZEND_BEGIN_ARG_INFO(arginfo_ibase_errmsg, 0)
53 ZEND_END_ARG_INFO()
54
55 ZEND_BEGIN_ARG_INFO(arginfo_ibase_errcode, 0)
56 ZEND_END_ARG_INFO()
57
58 ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_connect, 0, 0, 1)
59 ZEND_ARG_INFO(0, database)
60 ZEND_ARG_INFO(0, username)
61 ZEND_ARG_INFO(0, password)
62 ZEND_ARG_INFO(0, charset)
63 ZEND_ARG_INFO(0, buffers)
64 ZEND_ARG_INFO(0, dialect)
65 ZEND_ARG_INFO(0, role)
66 ZEND_END_ARG_INFO()
67
68 ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_pconnect, 0, 0, 1)
69 ZEND_ARG_INFO(0, database)
70 ZEND_ARG_INFO(0, username)
71 ZEND_ARG_INFO(0, password)
72 ZEND_ARG_INFO(0, charset)
73 ZEND_ARG_INFO(0, buffers)
74 ZEND_ARG_INFO(0, dialect)
75 ZEND_ARG_INFO(0, role)
76 ZEND_END_ARG_INFO()
77
78 ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_close, 0, 0, 0)
79 ZEND_ARG_INFO(0, link_identifier)
80 ZEND_END_ARG_INFO()
81
82 ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_drop_db, 0, 0, 0)
83 ZEND_ARG_INFO(0, link_identifier)
84 ZEND_END_ARG_INFO()
85
86 ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_trans, 0, 0, 0)
87 ZEND_ARG_INFO(0, trans_args)
88 ZEND_ARG_INFO(0, link_identifier)
89 ZEND_ARG_INFO(0, trans_args)
90 ZEND_ARG_INFO(0, link_identifier)
91 ZEND_END_ARG_INFO()
92
93 ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_commit, 0, 0, 1)
94 ZEND_ARG_INFO(0, link_identifier)
95 ZEND_END_ARG_INFO()
96
97 ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_rollback, 0, 0, 1)
98 ZEND_ARG_INFO(0, link_identifier)
99 ZEND_END_ARG_INFO()
100
101 ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_commit_ret, 0, 0, 1)
102 ZEND_ARG_INFO(0, link_identifier)
103 ZEND_END_ARG_INFO()
104
105 ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_rollback_ret, 0, 0, 1)
106 ZEND_ARG_INFO(0, link_identifier)
107 ZEND_END_ARG_INFO()
108
109 ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_gen_id, 0, 0, 1)
110 ZEND_ARG_INFO(0, generator)
111 ZEND_ARG_INFO(0, increment)
112 ZEND_ARG_INFO(0, link_identifier)
113 ZEND_END_ARG_INFO()
114
115 ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_blob_create, 0, 0, 0)
116 ZEND_ARG_INFO(0, link_identifier)
117 ZEND_END_ARG_INFO()
118
119 ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_blob_open, 0, 0, 0)
120 ZEND_ARG_INFO(0, link_identifier)
121 ZEND_ARG_INFO(0, blob_id)
122 ZEND_END_ARG_INFO()
123
124 ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_blob_add, 0, 0, 2)
125 ZEND_ARG_INFO(0, blob_handle)
126 ZEND_ARG_INFO(0, data)
127 ZEND_END_ARG_INFO()
128
129 ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_blob_get, 0, 0, 2)
130 ZEND_ARG_INFO(0, blob_handle)
131 ZEND_ARG_INFO(0, len)
132 ZEND_END_ARG_INFO()
133
134 ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_blob_close, 0, 0, 1)
135 ZEND_ARG_INFO(0, blob_handle)
136 ZEND_END_ARG_INFO()
137
138 ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_blob_cancel, 0, 0, 1)
139 ZEND_ARG_INFO(0, blob_handle)
140 ZEND_END_ARG_INFO()
141
142 ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_blob_info, 0, 0, 0)
143 ZEND_ARG_INFO(0, link_identifier)
144 ZEND_ARG_INFO(0, blob_id)
145 ZEND_END_ARG_INFO()
146
147 ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_blob_echo, 0, 0, 0)
148 ZEND_ARG_INFO(0, link_identifier)
149 ZEND_ARG_INFO(0, blob_id)
150 ZEND_END_ARG_INFO()
151
152 ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_blob_import, 0, 0, 0)
153 ZEND_ARG_INFO(0, link_identifier)
154 ZEND_ARG_INFO(0, file)
155 ZEND_END_ARG_INFO()
156
157 ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_query, 0, 0, 0)
158 ZEND_ARG_INFO(0, link_identifier)
159 ZEND_ARG_INFO(0, link_identifier)
160 ZEND_ARG_INFO(0, query)
161 ZEND_ARG_INFO(0, bind_arg)
162 ZEND_ARG_INFO(0, bind_arg)
163 ZEND_END_ARG_INFO()
164
165 ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_affected_rows, 0, 0, 0)
166 ZEND_ARG_INFO(0, link_identifier)
167 ZEND_END_ARG_INFO()
168
169 #if abies_0
170 ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_num_rows, 0, 0, 1)
171 ZEND_ARG_INFO(0, result_identifier)
172 ZEND_END_ARG_INFO()
173 #endif
174
175 ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_fetch_row, 0, 0, 1)
176 ZEND_ARG_INFO(0, result)
177 ZEND_ARG_INFO(0, fetch_flags)
178 ZEND_END_ARG_INFO()
179
180 ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_fetch_assoc, 0, 0, 1)
181 ZEND_ARG_INFO(0, result)
182 ZEND_ARG_INFO(0, fetch_flags)
183 ZEND_END_ARG_INFO()
184
185 ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_fetch_object, 0, 0, 1)
186 ZEND_ARG_INFO(0, result)
187 ZEND_ARG_INFO(0, fetch_flags)
188 ZEND_END_ARG_INFO()
189
190 ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_name_result, 0, 0, 2)
191 ZEND_ARG_INFO(0, result)
192 ZEND_ARG_INFO(0, name)
193 ZEND_END_ARG_INFO()
194
195 ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_free_result, 0, 0, 1)
196 ZEND_ARG_INFO(0, result)
197 ZEND_END_ARG_INFO()
198
199 ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_prepare, 0, 0, 0)
200 ZEND_ARG_INFO(0, link_identifier)
201 ZEND_ARG_INFO(0, query)
202 ZEND_END_ARG_INFO()
203
204 ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_execute, 0, 0, 1)
205 ZEND_ARG_INFO(0, query)
206 ZEND_ARG_INFO(0, bind_arg)
207 ZEND_ARG_INFO(0, bind_arg)
208 ZEND_END_ARG_INFO()
209
210 ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_free_query, 0, 0, 1)
211 ZEND_ARG_INFO(0, query)
212 ZEND_END_ARG_INFO()
213
214 ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_num_fields, 0, 0, 1)
215 ZEND_ARG_INFO(0, query_result)
216 ZEND_END_ARG_INFO()
217
218 ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_field_info, 0, 0, 2)
219 ZEND_ARG_INFO(0, query_result)
220 ZEND_ARG_INFO(0, field_number)
221 ZEND_END_ARG_INFO()
222
223 ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_num_params, 0, 0, 1)
224 ZEND_ARG_INFO(0, query)
225 ZEND_END_ARG_INFO()
226
227 ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_param_info, 0, 0, 2)
228 ZEND_ARG_INFO(0, query)
229 ZEND_ARG_INFO(0, field_number)
230 ZEND_END_ARG_INFO()
231
232 ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_add_user, 0, 0, 3)
233 ZEND_ARG_INFO(0, service_handle)
234 ZEND_ARG_INFO(0, user_name)
235 ZEND_ARG_INFO(0, password)
236 ZEND_ARG_INFO(0, first_name)
237 ZEND_ARG_INFO(0, middle_name)
238 ZEND_ARG_INFO(0, last_name)
239 ZEND_END_ARG_INFO()
240
241 ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_modify_user, 0, 0, 3)
242 ZEND_ARG_INFO(0, service_handle)
243 ZEND_ARG_INFO(0, user_name)
244 ZEND_ARG_INFO(0, password)
245 ZEND_ARG_INFO(0, first_name)
246 ZEND_ARG_INFO(0, middle_name)
247 ZEND_ARG_INFO(0, last_name)
248 ZEND_END_ARG_INFO()
249
250 ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_delete_user, 0, 0, 3)
251 ZEND_ARG_INFO(0, service_handle)
252 ZEND_ARG_INFO(0, user_name)
253 ZEND_ARG_INFO(0, password)
254 ZEND_ARG_INFO(0, first_name)
255 ZEND_ARG_INFO(0, middle_name)
256 ZEND_ARG_INFO(0, last_name)
257 ZEND_END_ARG_INFO()
258
259 ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_service_attach, 0, 0, 3)
260 ZEND_ARG_INFO(0, host)
261 ZEND_ARG_INFO(0, dba_username)
262 ZEND_ARG_INFO(0, dba_password)
263 ZEND_END_ARG_INFO()
264
265 ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_service_detach, 0, 0, 1)
266 ZEND_ARG_INFO(0, service_handle)
267 ZEND_END_ARG_INFO()
268
269 ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_backup, 0, 0, 3)
270 ZEND_ARG_INFO(0, service_handle)
271 ZEND_ARG_INFO(0, source_db)
272 ZEND_ARG_INFO(0, dest_file)
273 ZEND_ARG_INFO(0, options)
274 ZEND_ARG_INFO(0, verbose)
275 ZEND_END_ARG_INFO()
276
277 ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_restore, 0, 0, 3)
278 ZEND_ARG_INFO(0, service_handle)
279 ZEND_ARG_INFO(0, source_file)
280 ZEND_ARG_INFO(0, dest_db)
281 ZEND_ARG_INFO(0, options)
282 ZEND_ARG_INFO(0, verbose)
283 ZEND_END_ARG_INFO()
284
285 ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_maintain_db, 0, 0, 3)
286 ZEND_ARG_INFO(0, service_handle)
287 ZEND_ARG_INFO(0, db)
288 ZEND_ARG_INFO(0, action)
289 ZEND_ARG_INFO(0, argument)
290 ZEND_END_ARG_INFO()
291
292 ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_db_info, 0, 0, 3)
293 ZEND_ARG_INFO(0, service_handle)
294 ZEND_ARG_INFO(0, db)
295 ZEND_ARG_INFO(0, action)
296 ZEND_ARG_INFO(0, argument)
297 ZEND_END_ARG_INFO()
298
299 ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_server_info, 0, 0, 2)
300 ZEND_ARG_INFO(0, service_handle)
301 ZEND_ARG_INFO(0, action)
302 ZEND_END_ARG_INFO()
303
304 ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_wait_event, 0, 0, 1)
305 ZEND_ARG_INFO(0, link_identifier)
306 ZEND_ARG_INFO(0, event)
307 ZEND_ARG_INFO(0, event2)
308 ZEND_END_ARG_INFO()
309
310 ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_set_event_handler, 0, 0, 2)
311 ZEND_ARG_INFO(0, link_identifier)
312 ZEND_ARG_INFO(0, handler)
313 ZEND_ARG_INFO(0, event)
314 ZEND_ARG_INFO(0, event2)
315 ZEND_END_ARG_INFO()
316
317 ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_free_event_handler, 0, 0, 1)
318 ZEND_ARG_INFO(0, event)
319 ZEND_END_ARG_INFO()
320 /* }}} */
321
322 /* {{{ extension definition structures */
323 const zend_function_entry ibase_functions[] = {
324 PHP_FE(ibase_connect, arginfo_ibase_connect)
325 PHP_FE(ibase_pconnect, arginfo_ibase_pconnect)
326 PHP_FE(ibase_close, arginfo_ibase_close)
327 PHP_FE(ibase_drop_db, arginfo_ibase_drop_db)
328 PHP_FE(ibase_query, arginfo_ibase_query)
329 PHP_FE(ibase_fetch_row, arginfo_ibase_fetch_row)
330 PHP_FE(ibase_fetch_assoc, arginfo_ibase_fetch_assoc)
331 PHP_FE(ibase_fetch_object, arginfo_ibase_fetch_object)
332 PHP_FE(ibase_free_result, arginfo_ibase_free_result)
333 PHP_FE(ibase_name_result, arginfo_ibase_name_result)
334 PHP_FE(ibase_prepare, arginfo_ibase_prepare)
335 PHP_FE(ibase_execute, arginfo_ibase_execute)
336 PHP_FE(ibase_free_query, arginfo_ibase_free_query)
337 PHP_FE(ibase_gen_id, arginfo_ibase_gen_id)
338 PHP_FE(ibase_num_fields, arginfo_ibase_num_fields)
339 PHP_FE(ibase_num_params, arginfo_ibase_num_params)
340 #if abies_0
341 PHP_FE(ibase_num_rows, arginfo_ibase_num_rows)
342 #endif
343 PHP_FE(ibase_affected_rows, arginfo_ibase_affected_rows)
344 PHP_FE(ibase_field_info, arginfo_ibase_field_info)
345 PHP_FE(ibase_param_info, arginfo_ibase_param_info)
346
347 PHP_FE(ibase_trans, arginfo_ibase_trans)
348 PHP_FE(ibase_commit, arginfo_ibase_commit)
349 PHP_FE(ibase_rollback, arginfo_ibase_rollback)
350 PHP_FE(ibase_commit_ret, arginfo_ibase_commit_ret)
351 PHP_FE(ibase_rollback_ret, arginfo_ibase_rollback_ret)
352
353 PHP_FE(ibase_blob_info, arginfo_ibase_blob_info)
354 PHP_FE(ibase_blob_create, arginfo_ibase_blob_create)
355 PHP_FE(ibase_blob_add, arginfo_ibase_blob_add)
356 PHP_FE(ibase_blob_cancel, arginfo_ibase_blob_cancel)
357 PHP_FE(ibase_blob_close, arginfo_ibase_blob_close)
358 PHP_FE(ibase_blob_open, arginfo_ibase_blob_open)
359 PHP_FE(ibase_blob_get, arginfo_ibase_blob_get)
360 PHP_FE(ibase_blob_echo, arginfo_ibase_blob_echo)
361 PHP_FE(ibase_blob_import, arginfo_ibase_blob_import)
362 PHP_FE(ibase_errmsg, arginfo_ibase_errmsg)
363 PHP_FE(ibase_errcode, arginfo_ibase_errcode)
364
365 PHP_FE(ibase_add_user, arginfo_ibase_add_user)
366 PHP_FE(ibase_modify_user, arginfo_ibase_modify_user)
367 PHP_FE(ibase_delete_user, arginfo_ibase_delete_user)
368
369 PHP_FE(ibase_service_attach, arginfo_ibase_service_attach)
370 PHP_FE(ibase_service_detach, arginfo_ibase_service_detach)
371 PHP_FE(ibase_backup, arginfo_ibase_backup)
372 PHP_FE(ibase_restore, arginfo_ibase_restore)
373 PHP_FE(ibase_maintain_db, arginfo_ibase_maintain_db)
374 PHP_FE(ibase_db_info, arginfo_ibase_db_info)
375 PHP_FE(ibase_server_info, arginfo_ibase_server_info)
376
377 PHP_FE(ibase_wait_event, arginfo_ibase_wait_event)
378 PHP_FE(ibase_set_event_handler, arginfo_ibase_set_event_handler)
379 PHP_FE(ibase_free_event_handler, arginfo_ibase_free_event_handler)
380
381 /**
382 * These aliases are provided in order to maintain forward compatibility. As Firebird
383 * and InterBase are developed independently, functionality might be different between
384 * the two branches in future versions.
385 * Firebird users should use the aliases, so future InterBase-specific changes will
386 * not affect their code
387 */
388 PHP_FALIAS(fbird_connect, ibase_connect, arginfo_ibase_connect)
389 PHP_FALIAS(fbird_pconnect, ibase_pconnect, arginfo_ibase_pconnect)
390 PHP_FALIAS(fbird_close, ibase_close, arginfo_ibase_close)
391 PHP_FALIAS(fbird_drop_db, ibase_drop_db, arginfo_ibase_drop_db)
392 PHP_FALIAS(fbird_query, ibase_query, arginfo_ibase_query)
393 PHP_FALIAS(fbird_fetch_row, ibase_fetch_row, arginfo_ibase_fetch_row)
394 PHP_FALIAS(fbird_fetch_assoc, ibase_fetch_assoc, arginfo_ibase_fetch_assoc)
395 PHP_FALIAS(fbird_fetch_object, ibase_fetch_object, arginfo_ibase_fetch_object)
396 PHP_FALIAS(fbird_free_result, ibase_free_result, arginfo_ibase_free_result)
397 PHP_FALIAS(fbird_name_result, ibase_name_result, arginfo_ibase_name_result)
398 PHP_FALIAS(fbird_prepare, ibase_prepare, arginfo_ibase_prepare)
399 PHP_FALIAS(fbird_execute, ibase_execute, arginfo_ibase_execute)
400 PHP_FALIAS(fbird_free_query, ibase_free_query, arginfo_ibase_free_query)
401 PHP_FALIAS(fbird_gen_id, ibase_gen_id, arginfo_ibase_gen_id)
402 PHP_FALIAS(fbird_num_fields, ibase_num_fields, arginfo_ibase_num_fields)
403 PHP_FALIAS(fbird_num_params, ibase_num_params, arginfo_ibase_num_params)
404 #if abies_0
405 PHP_FALIAS(fbird_num_rows, ibase_num_rows, arginfo_ibase_num_rows)
406 #endif
407 PHP_FALIAS(fbird_affected_rows, ibase_affected_rows, arginfo_ibase_affected_rows)
408 PHP_FALIAS(fbird_field_info, ibase_field_info, arginfo_ibase_field_info)
409 PHP_FALIAS(fbird_param_info, ibase_param_info, arginfo_ibase_param_info)
410
411 PHP_FALIAS(fbird_trans, ibase_trans, arginfo_ibase_trans)
412 PHP_FALIAS(fbird_commit, ibase_commit, arginfo_ibase_commit)
413 PHP_FALIAS(fbird_rollback, ibase_rollback, arginfo_ibase_rollback)
414 PHP_FALIAS(fbird_commit_ret, ibase_commit_ret, arginfo_ibase_commit_ret)
415 PHP_FALIAS(fbird_rollback_ret, ibase_rollback_ret, arginfo_ibase_rollback_ret)
416
417 PHP_FALIAS(fbird_blob_info, ibase_blob_info, arginfo_ibase_blob_info)
418 PHP_FALIAS(fbird_blob_create, ibase_blob_create, arginfo_ibase_blob_create)
419 PHP_FALIAS(fbird_blob_add, ibase_blob_add, arginfo_ibase_blob_add)
420 PHP_FALIAS(fbird_blob_cancel, ibase_blob_cancel, arginfo_ibase_blob_cancel)
421 PHP_FALIAS(fbird_blob_close, ibase_blob_close, arginfo_ibase_blob_close)
422 PHP_FALIAS(fbird_blob_open, ibase_blob_open, arginfo_ibase_blob_open)
423 PHP_FALIAS(fbird_blob_get, ibase_blob_get, arginfo_ibase_blob_get)
424 PHP_FALIAS(fbird_blob_echo, ibase_blob_echo, arginfo_ibase_blob_echo)
425 PHP_FALIAS(fbird_blob_import, ibase_blob_import, arginfo_ibase_blob_import)
426 PHP_FALIAS(fbird_errmsg, ibase_errmsg, arginfo_ibase_errmsg)
427 PHP_FALIAS(fbird_errcode, ibase_errcode, arginfo_ibase_errcode)
428
429 PHP_FALIAS(fbird_add_user, ibase_add_user, arginfo_ibase_add_user)
430 PHP_FALIAS(fbird_modify_user, ibase_modify_user, arginfo_ibase_modify_user)
431 PHP_FALIAS(fbird_delete_user, ibase_delete_user, arginfo_ibase_delete_user)
432
433 PHP_FALIAS(fbird_service_attach, ibase_service_attach, arginfo_ibase_service_attach)
434 PHP_FALIAS(fbird_service_detach, ibase_service_detach, arginfo_ibase_service_detach)
435 PHP_FALIAS(fbird_backup, ibase_backup, arginfo_ibase_backup)
436 PHP_FALIAS(fbird_restore, ibase_restore, arginfo_ibase_restore)
437 PHP_FALIAS(fbird_maintain_db, ibase_maintain_db, arginfo_ibase_maintain_db)
438 PHP_FALIAS(fbird_db_info, ibase_db_info, arginfo_ibase_db_info)
439 PHP_FALIAS(fbird_server_info, ibase_server_info, arginfo_ibase_server_info)
440
441 PHP_FALIAS(fbird_wait_event, ibase_wait_event, arginfo_ibase_wait_event)
442 PHP_FALIAS(fbird_set_event_handler, ibase_set_event_handler, arginfo_ibase_set_event_handler)
443 PHP_FALIAS(fbird_free_event_handler, ibase_free_event_handler, arginfo_ibase_free_event_handler)
444 PHP_FE_END
445 };
446
447 zend_module_entry ibase_module_entry = {
448 STANDARD_MODULE_HEADER,
449 "interbase",
450 ibase_functions,
451 PHP_MINIT(ibase),
452 PHP_MSHUTDOWN(ibase),
453 NULL,
454 PHP_RSHUTDOWN(ibase),
455 PHP_MINFO(ibase),
456 NO_VERSION_YET,
457 PHP_MODULE_GLOBALS(ibase),
458 PHP_GINIT(ibase),
459 NULL,
460 NULL,
461 STANDARD_MODULE_PROPERTIES_EX
462 };
463
464 #ifdef COMPILE_DL_INTERBASE
ZEND_GET_MODULE(ibase)465 ZEND_GET_MODULE(ibase)
466 #endif
467
468 /* True globals, no need for thread safety */
469 int le_link, le_plink, le_trans;
470
471 /* }}} */
472
473 /* error handling ---------------------------- */
474
475 /* {{{ proto string ibase_errmsg(void)
476 Return error message */
477 PHP_FUNCTION(ibase_errmsg)
478 {
479 if (zend_parse_parameters_none() == FAILURE) {
480 return;
481 }
482
483 if (IBG(sql_code) != 0) {
484 RETURN_STRING(IBG(errmsg), 1);
485 }
486
487 RETURN_FALSE;
488 }
489 /* }}} */
490
491 /* {{{ proto int ibase_errcode(void)
492 Return error code */
PHP_FUNCTION(ibase_errcode)493 PHP_FUNCTION(ibase_errcode)
494 {
495 if (zend_parse_parameters_none() == FAILURE) {
496 return;
497 }
498
499 if (IBG(sql_code) != 0) {
500 RETURN_LONG(IBG(sql_code));
501 }
502 RETURN_FALSE;
503 }
504 /* }}} */
505
506 /* print interbase error and save it for ibase_errmsg() */
_php_ibase_error(TSRMLS_D)507 void _php_ibase_error(TSRMLS_D) /* {{{ */
508 {
509 char *s = IBG(errmsg);
510 ISC_STATUS *statusp = IB_STATUS;
511
512 IBG(sql_code) = isc_sqlcode(IB_STATUS);
513
514 while ((s - IBG(errmsg)) < MAX_ERRMSG - (IBASE_MSGSIZE + 2) && isc_interprete(s, &statusp)) {
515 strcat(IBG(errmsg), " ");
516 s = IBG(errmsg) + strlen(IBG(errmsg));
517 }
518
519 php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", IBG(errmsg));
520 }
521 /* }}} */
522
523 /* print php interbase module error and save it for ibase_errmsg() */
_php_ibase_module_error(char * msg TSRMLS_DC,...)524 void _php_ibase_module_error(char *msg TSRMLS_DC, ...) /* {{{ */
525 {
526 va_list ap;
527
528 #ifdef ZTS
529 va_start(ap, TSRMLS_C);
530 #else
531 va_start(ap, msg);
532 #endif
533
534 /* vsnprintf NUL terminates the buf and writes at most n-1 chars+NUL */
535 vsnprintf(IBG(errmsg), MAX_ERRMSG, msg, ap);
536 va_end(ap);
537
538 IBG(sql_code) = -999; /* no SQL error */
539
540 php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", IBG(errmsg));
541 }
542 /* }}} */
543
544 /* {{{ internal macros, functions and structures */
545 typedef struct {
546 isc_db_handle *db_ptr;
547 long tpb_len;
548 char *tpb_ptr;
549 } ISC_TEB;
550
551 /* }}} */
552
553 /* Fill ib_link and trans with the correct database link and transaction. */
_php_ibase_get_link_trans(INTERNAL_FUNCTION_PARAMETERS,zval ** link_id,ibase_db_link ** ib_link,ibase_trans ** trans)554 void _php_ibase_get_link_trans(INTERNAL_FUNCTION_PARAMETERS, /* {{{ */
555 zval **link_id, ibase_db_link **ib_link, ibase_trans **trans)
556 {
557 int type;
558
559 IBDEBUG("Transaction or database link?");
560 if (zend_list_find(Z_LVAL_PP(link_id), &type)) {
561 if (type == le_trans) {
562 /* Transaction resource: make sure it refers to one link only, then
563 fetch it; database link is stored in ib_trans->db_link[]. */
564 IBDEBUG("Type is le_trans");
565 ZEND_FETCH_RESOURCE(*trans, ibase_trans *, link_id, -1, LE_TRANS, le_trans);
566 if ((*trans)->link_cnt > 1) {
567 _php_ibase_module_error("Link id is ambiguous: transaction spans multiple connections."
568 TSRMLS_CC);
569 return;
570 }
571 *ib_link = (*trans)->db_link[0];
572 return;
573 }
574 }
575 IBDEBUG("Type is le_[p]link or id not found");
576 /* Database link resource, use default transaction. */
577 *trans = NULL;
578 ZEND_FETCH_RESOURCE2(*ib_link, ibase_db_link *, link_id, -1, LE_LINK, le_link, le_plink);
579 }
580 /* }}} */
581
582 /* destructors ---------------------- */
583
_php_ibase_commit_link(ibase_db_link * link TSRMLS_DC)584 static void _php_ibase_commit_link(ibase_db_link *link TSRMLS_DC) /* {{{ */
585 {
586 unsigned short i = 0, j;
587 ibase_tr_list *l;
588 ibase_event *e;
589 IBDEBUG("Checking transactions to close...");
590
591 for (l = link->tr_list; l != NULL; ++i) {
592 ibase_tr_list *p = l;
593 if (p->trans != NULL) {
594 if (i == 0) {
595 if (p->trans->handle != NULL) {
596 IBDEBUG("Committing default transaction...");
597 if (isc_commit_transaction(IB_STATUS, &p->trans->handle)) {
598 _php_ibase_error(TSRMLS_C);
599 }
600 }
601 efree(p->trans); /* default transaction is not a registered resource: clean up */
602 } else {
603 if (p->trans->handle != NULL) {
604 /* non-default trans might have been rolled back by other call of this dtor */
605 IBDEBUG("Rolling back other transactions...");
606 if (isc_rollback_transaction(IB_STATUS, &p->trans->handle)) {
607 _php_ibase_error(TSRMLS_C);
608 }
609 }
610 /* set this link pointer to NULL in the transaction */
611 for (j = 0; j < p->trans->link_cnt; ++j) {
612 if (p->trans->db_link[j] == link) {
613 p->trans->db_link[j] = NULL;
614 break;
615 }
616 }
617 }
618 }
619 l = l->next;
620 efree(p);
621 }
622 link->tr_list = NULL;
623
624 for (e = link->event_head; e; e = e->event_next) {
625 _php_ibase_free_event(e TSRMLS_CC);
626 e->link = NULL;
627 }
628 }
629
630 /* }}} */
631
php_ibase_commit_link_rsrc(zend_rsrc_list_entry * rsrc TSRMLS_DC)632 static void php_ibase_commit_link_rsrc(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
633 {
634 ibase_db_link *link = (ibase_db_link *) rsrc->ptr;
635
636 _php_ibase_commit_link(link TSRMLS_CC);
637 }
638 /* }}} */
639
_php_ibase_close_link(zend_rsrc_list_entry * rsrc TSRMLS_DC)640 static void _php_ibase_close_link(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
641 {
642 ibase_db_link *link = (ibase_db_link *) rsrc->ptr;
643
644 _php_ibase_commit_link(link TSRMLS_CC);
645 if (link->handle != NULL) {
646 IBDEBUG("Closing normal link...");
647 isc_detach_database(IB_STATUS, &link->handle);
648 }
649 IBG(num_links)--;
650 efree(link);
651 }
652 /* }}} */
653
_php_ibase_close_plink(zend_rsrc_list_entry * rsrc TSRMLS_DC)654 static void _php_ibase_close_plink(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
655 {
656 ibase_db_link *link = (ibase_db_link *) rsrc->ptr;
657
658 _php_ibase_commit_link(link TSRMLS_CC);
659 IBDEBUG("Closing permanent link...");
660 if (link->handle != NULL) {
661 isc_detach_database(IB_STATUS, &link->handle);
662 }
663 IBG(num_persistent)--;
664 IBG(num_links)--;
665 free(link);
666 }
667 /* }}} */
668
_php_ibase_free_trans(zend_rsrc_list_entry * rsrc TSRMLS_DC)669 static void _php_ibase_free_trans(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
670 {
671 ibase_trans *trans = (ibase_trans *)rsrc->ptr;
672 unsigned short i;
673
674 IBDEBUG("Cleaning up transaction resource...");
675 if (trans->handle != NULL) {
676 IBDEBUG("Rolling back unhandled transaction...");
677 if (isc_rollback_transaction(IB_STATUS, &trans->handle)) {
678 _php_ibase_error(TSRMLS_C);
679 }
680 }
681
682 /* now remove this transaction from all the connection-transaction lists */
683 for (i = 0; i < trans->link_cnt; ++i) {
684 if (trans->db_link[i] != NULL) {
685 ibase_tr_list **l;
686 for (l = &trans->db_link[i]->tr_list; *l != NULL; l = &(*l)->next) {
687 if ( (*l)->trans == trans) {
688 ibase_tr_list *p = *l;
689 *l = p->next;
690 efree(p);
691 break;
692 }
693 }
694 }
695 }
696 efree(trans);
697 }
698 /* }}} */
699
700 /* TODO this function should be part of either Zend or PHP API */
PHP_INI_DISP(php_ibase_password_displayer_cb)701 static PHP_INI_DISP(php_ibase_password_displayer_cb)
702 {
703 TSRMLS_FETCH();
704
705 if ((type == PHP_INI_DISPLAY_ORIG && ini_entry->orig_value)
706 || (type == PHP_INI_DISPLAY_ACTIVE && ini_entry->value)) {
707 PUTS("********");
708 } else if (!sapi_module.phpinfo_as_text) {
709 PUTS("<i>no value</i>");
710 } else {
711 PUTS("no value");
712 }
713 }
714
715 /* {{{ startup, shutdown and info functions */
716 PHP_INI_BEGIN()
717 PHP_INI_ENTRY_EX("ibase.allow_persistent", "1", PHP_INI_SYSTEM, NULL, zend_ini_boolean_displayer_cb)
718 PHP_INI_ENTRY_EX("ibase.max_persistent", "-1", PHP_INI_SYSTEM, NULL, display_link_numbers)
719 PHP_INI_ENTRY_EX("ibase.max_links", "-1", PHP_INI_SYSTEM, NULL, display_link_numbers)
720 PHP_INI_ENTRY("ibase.default_db", NULL, PHP_INI_SYSTEM, NULL)
721 PHP_INI_ENTRY("ibase.default_user", NULL, PHP_INI_ALL, NULL)
722 PHP_INI_ENTRY_EX("ibase.default_password", NULL, PHP_INI_ALL, NULL, php_ibase_password_displayer_cb)
723 PHP_INI_ENTRY("ibase.default_charset", NULL, PHP_INI_ALL, NULL)
724 PHP_INI_ENTRY("ibase.timestampformat", IB_DEF_DATE_FMT " " IB_DEF_TIME_FMT, PHP_INI_ALL, NULL)
725 PHP_INI_ENTRY("ibase.dateformat", IB_DEF_DATE_FMT, PHP_INI_ALL, NULL)
726 PHP_INI_ENTRY("ibase.timeformat", IB_DEF_TIME_FMT, PHP_INI_ALL, NULL)
PHP_INI_END()727 PHP_INI_END()
728
729 static PHP_GINIT_FUNCTION(ibase)
730 {
731 ibase_globals->num_persistent = ibase_globals->num_links = 0;
732 ibase_globals->sql_code = *ibase_globals->errmsg = 0;
733 ibase_globals->default_link = -1;
734 }
735
PHP_MINIT_FUNCTION(ibase)736 PHP_MINIT_FUNCTION(ibase)
737 {
738 REGISTER_INI_ENTRIES();
739
740 le_link = zend_register_list_destructors_ex(_php_ibase_close_link, NULL, LE_LINK, module_number);
741 le_plink = zend_register_list_destructors_ex(php_ibase_commit_link_rsrc, _php_ibase_close_plink, LE_PLINK, module_number);
742 le_trans = zend_register_list_destructors_ex(_php_ibase_free_trans, NULL, LE_TRANS, module_number);
743
744 REGISTER_LONG_CONSTANT("IBASE_DEFAULT", PHP_IBASE_DEFAULT, CONST_PERSISTENT);
745 REGISTER_LONG_CONSTANT("IBASE_CREATE", PHP_IBASE_CREATE, CONST_PERSISTENT);
746 REGISTER_LONG_CONSTANT("IBASE_TEXT", PHP_IBASE_FETCH_BLOBS, CONST_PERSISTENT); /* deprecated, for BC only */
747 REGISTER_LONG_CONSTANT("IBASE_FETCH_BLOBS", PHP_IBASE_FETCH_BLOBS, CONST_PERSISTENT);
748 REGISTER_LONG_CONSTANT("IBASE_FETCH_ARRAYS", PHP_IBASE_FETCH_ARRAYS, CONST_PERSISTENT);
749 REGISTER_LONG_CONSTANT("IBASE_UNIXTIME", PHP_IBASE_UNIXTIME, CONST_PERSISTENT);
750
751 /* transactions */
752 REGISTER_LONG_CONSTANT("IBASE_WRITE", PHP_IBASE_WRITE, CONST_PERSISTENT);
753 REGISTER_LONG_CONSTANT("IBASE_READ", PHP_IBASE_READ, CONST_PERSISTENT);
754 REGISTER_LONG_CONSTANT("IBASE_COMMITTED", PHP_IBASE_COMMITTED, CONST_PERSISTENT);
755 REGISTER_LONG_CONSTANT("IBASE_CONSISTENCY", PHP_IBASE_CONSISTENCY, CONST_PERSISTENT);
756 REGISTER_LONG_CONSTANT("IBASE_CONCURRENCY", PHP_IBASE_CONCURRENCY, CONST_PERSISTENT);
757 REGISTER_LONG_CONSTANT("IBASE_REC_VERSION", PHP_IBASE_REC_VERSION, CONST_PERSISTENT);
758 REGISTER_LONG_CONSTANT("IBASE_REC_NO_VERSION", PHP_IBASE_REC_NO_VERSION, CONST_PERSISTENT);
759 REGISTER_LONG_CONSTANT("IBASE_NOWAIT", PHP_IBASE_NOWAIT, CONST_PERSISTENT);
760 REGISTER_LONG_CONSTANT("IBASE_WAIT", PHP_IBASE_WAIT, CONST_PERSISTENT);
761
762 php_ibase_query_minit(INIT_FUNC_ARGS_PASSTHRU);
763 php_ibase_blobs_minit(INIT_FUNC_ARGS_PASSTHRU);
764 php_ibase_events_minit(INIT_FUNC_ARGS_PASSTHRU);
765 php_ibase_service_minit(INIT_FUNC_ARGS_PASSTHRU);
766
767 return SUCCESS;
768 }
769
PHP_MSHUTDOWN_FUNCTION(ibase)770 PHP_MSHUTDOWN_FUNCTION(ibase)
771 {
772 #ifndef PHP_WIN32
773 /**
774 * When the Interbase client API library libgds.so is first loaded, it registers a call to
775 * gds__cleanup() with atexit(), in order to clean up after itself when the process exits.
776 * This means that the library is called at process shutdown, and cannot be unloaded beforehand.
777 * PHP tries to unload modules after every request [dl()'ed modules], and right before the
778 * process shuts down [modules loaded from php.ini]. This results in a segfault for this module.
779 * By NULLing the dlopen() handle in the module entry, Zend omits the call to dlclose(),
780 * ensuring that the module will remain present until the process exits. However, the functions
781 * and classes exported by the module will not be available until the module is 'reloaded'.
782 * When reloaded, dlopen() will return the handle of the already loaded module. The module will
783 * be unloaded automatically when the process exits.
784 */
785 zend_module_entry *ibase_entry;
786 if (SUCCESS == zend_hash_find(&module_registry, ibase_module_entry.name,
787 strlen(ibase_module_entry.name) +1, (void*) &ibase_entry)) {
788 ibase_entry->handle = NULL;
789 }
790 #endif
791 UNREGISTER_INI_ENTRIES();
792 return SUCCESS;
793 }
794
PHP_RSHUTDOWN_FUNCTION(ibase)795 PHP_RSHUTDOWN_FUNCTION(ibase)
796 {
797 IBG(num_links) = IBG(num_persistent);
798 IBG(default_link)= -1;
799
800 RESET_ERRMSG;
801
802 return SUCCESS;
803 }
804
PHP_MINFO_FUNCTION(ibase)805 PHP_MINFO_FUNCTION(ibase)
806 {
807 char tmp[64], *s;
808
809 php_info_print_table_start();
810 php_info_print_table_row(2, "Firebird/InterBase Support",
811 #ifdef COMPILE_DL_INTERBASE
812 "dynamic");
813 #else
814 "static");
815 #endif
816
817 #ifdef FB_API_VER
818 snprintf( (s = tmp), sizeof(tmp), "Firebird API version %d", FB_API_VER);
819 #elif (SQLDA_CURRENT_VERSION > 1)
820 s = "Interbase 7.0 and up";
821 #elif !defined(DSC_null)
822 s = "Interbase 6";
823 #else
824 s = "Firebird 1.0";
825 #endif
826 php_info_print_table_row(2, "Compile-time Client Library Version", s);
827
828 #if defined(__GNUC__) || defined(PHP_WIN32)
829 do {
830 info_func_t info_func = NULL;
831 #ifdef __GNUC__
832 info_func = (info_func_t)dlsym(RTLD_DEFAULT, "isc_get_client_version");
833 #else
834 HMODULE l = GetModuleHandle("fbclient");
835
836 if (!l && !(l = GetModuleHandle("gds32"))) {
837 break;
838 }
839 info_func = (info_func_t)GetProcAddress(l, "isc_get_client_version");
840 #endif
841 if (info_func) {
842 info_func(s = tmp);
843 } else {
844 s = "Firebird 1.0/Interbase 6";
845 }
846 php_info_print_table_row(2, "Run-time Client Library Version", s);
847 } while (0);
848 #endif
849 php_info_print_table_end();
850
851 DISPLAY_INI_ENTRIES();
852
853 }
854 /* }}} */
855
856 enum connect_args { DB = 0, USER = 1, PASS = 2, CSET = 3, ROLE = 4, BUF = 0, DLECT = 1, SYNC = 2 };
857
858 static char const dpb_args[] = {
859 0, isc_dpb_user_name, isc_dpb_password, isc_dpb_lc_ctype, isc_dpb_sql_role_name, 0
860 };
861
_php_ibase_attach_db(char ** args,int * len,long * largs,isc_db_handle * db TSRMLS_DC)862 int _php_ibase_attach_db(char **args, int *len, long *largs, isc_db_handle *db TSRMLS_DC)
863 {
864 short i, dpb_len, buf_len = 257-2; /* version byte at the front, and a null at the end */
865 char dpb_buffer[257] = { isc_dpb_version1, 0 }, *dpb;
866
867 dpb = dpb_buffer + 1;
868
869 for (i = 0; i < sizeof(dpb_args); ++i) {
870 if (dpb_args[i] && args[i] && len[i] && buf_len > 0) {
871 dpb_len = slprintf(dpb, buf_len, "%c%c%s", dpb_args[i],(unsigned char)len[i],args[i]);
872 dpb += dpb_len;
873 buf_len -= dpb_len;
874 }
875 }
876 if (largs[BUF] && buf_len > 0) {
877 dpb_len = slprintf(dpb, buf_len, "%c\2%c%c", isc_dpb_num_buffers,
878 (char)(largs[BUF] >> 8), (char)(largs[BUF] & 0xff));
879 dpb += dpb_len;
880 buf_len -= dpb_len;
881 }
882 if (largs[SYNC] && buf_len > 0) {
883 dpb_len = slprintf(dpb, buf_len, "%c\1%c", isc_dpb_force_write, largs[SYNC] == isc_spb_prp_wm_sync ? 1 : 0);
884 dpb += dpb_len;
885 buf_len -= dpb_len;
886 }
887 if (isc_attach_database(IB_STATUS, (short)len[DB], args[DB], db, (short)(dpb-dpb_buffer), dpb_buffer)) {
888 _php_ibase_error(TSRMLS_C);
889 return FAILURE;
890 }
891 return SUCCESS;
892 }
893 /* }}} */
894
_php_ibase_connect(INTERNAL_FUNCTION_PARAMETERS,int persistent)895 static void _php_ibase_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) /* {{{ */
896 {
897 char *c, hash[16], *args[] = { NULL, NULL, NULL, NULL, NULL };
898 int i, len[] = { 0, 0, 0, 0, 0 };
899 long largs[] = { 0, 0, 0 };
900 PHP_MD5_CTX hash_context;
901 zend_rsrc_list_entry new_index_ptr, *le;
902 isc_db_handle db_handle = NULL;
903 ibase_db_link *ib_link;
904
905 RESET_ERRMSG;
906
907 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ssssllsl",
908 &args[DB], &len[DB], &args[USER], &len[USER], &args[PASS], &len[PASS],
909 &args[CSET], &len[CSET], &largs[BUF], &largs[DLECT], &args[ROLE], &len[ROLE],
910 &largs[SYNC])) {
911 RETURN_FALSE;
912 }
913
914 /* restrict to the server/db in the .ini if in safe mode */
915 if ((!len[DB] || PG(sql_safe_mode)) && (c = INI_STR("ibase.default_db"))) {
916 args[DB] = c;
917 len[DB] = strlen(c);
918 }
919 if (!len[USER] && (c = INI_STR("ibase.default_user"))) {
920 args[USER] = c;
921 len[USER] = strlen(c);
922 }
923 if (!len[PASS] && (c = INI_STR("ibase.default_password"))) {
924 args[PASS] = c;
925 len[PASS] = strlen(c);
926 }
927 if (!len[CSET] && (c = INI_STR("ibase.default_charset"))) {
928 args[CSET] = c;
929 len[CSET] = strlen(c);
930 }
931
932 /* don't want usernames and passwords floating around */
933 PHP_MD5Init(&hash_context);
934 for (i = 0; i < sizeof(args)/sizeof(char*); ++i) {
935 PHP_MD5Update(&hash_context,args[i],len[i]);
936 }
937 for (i = 0; i < sizeof(largs)/sizeof(long); ++i) {
938 PHP_MD5Update(&hash_context,(char*)&largs[i],sizeof(long));
939 }
940 PHP_MD5Final(hash, &hash_context);
941
942 /* try to reuse a connection */
943 if (SUCCESS == zend_hash_find(&EG(regular_list), hash, sizeof(hash), (void *) &le)) {
944 long xlink;
945 int type;
946
947 if (Z_TYPE_P(le) != le_index_ptr) {
948 RETURN_FALSE;
949 }
950
951 xlink = (long) le->ptr;
952 if (zend_list_find(xlink, &type) && ((!persistent && type == le_link) || type == le_plink)) {
953 zend_list_addref(xlink);
954 RETURN_RESOURCE(IBG(default_link) = xlink);
955 } else {
956 zend_hash_del(&EG(regular_list), hash, sizeof(hash));
957 }
958 }
959
960 /* ... or a persistent one */
961 switch (zend_hash_find(&EG(persistent_list), hash, sizeof(hash), (void *) &le)) {
962 long l;
963
964 static char info[] = { isc_info_base_level, isc_info_end };
965 char result[8];
966 ISC_STATUS status[20];
967
968 case SUCCESS:
969
970 if (Z_TYPE_P(le) != le_plink) {
971 RETURN_FALSE;
972 }
973 /* check if connection has timed out */
974 ib_link = (ibase_db_link *) le->ptr;
975 if (!isc_database_info(status, &ib_link->handle, sizeof(info), info, sizeof(result), result)) {
976 ZEND_REGISTER_RESOURCE(return_value, ib_link, le_plink);
977 break;
978 }
979 zend_hash_del(&EG(persistent_list), hash, sizeof(hash));
980
981 default:
982
983 /* no link found, so we have to open one */
984
985 if ((l = INI_INT("ibase.max_links")) != -1 && IBG(num_links) >= l) {
986 _php_ibase_module_error("Too many open links (%ld)" TSRMLS_CC, IBG(num_links));
987 RETURN_FALSE;
988 }
989
990 /* create the ib_link */
991 if (FAILURE == _php_ibase_attach_db(args, len, largs, &db_handle TSRMLS_CC)) {
992 RETURN_FALSE;
993 }
994
995 /* use non-persistent if allowed number of persistent links is exceeded */
996 if (!persistent || ((l = INI_INT("ibase.max_persistent") != -1) && IBG(num_persistent) >= l)) {
997 ib_link = (ibase_db_link *) emalloc(sizeof(ibase_db_link));
998 ZEND_REGISTER_RESOURCE(return_value, ib_link, le_link);
999 } else {
1000 zend_rsrc_list_entry new_le;
1001
1002 ib_link = (ibase_db_link *) malloc(sizeof(ibase_db_link));
1003 if (!ib_link) {
1004 RETURN_FALSE;
1005 }
1006
1007 /* hash it up */
1008 Z_TYPE(new_le) = le_plink;
1009 new_le.ptr = ib_link;
1010 if (FAILURE == zend_hash_update(&EG(persistent_list), hash, sizeof(hash),
1011 (void *) &new_le, sizeof(zend_rsrc_list_entry), NULL)) {
1012 free(ib_link);
1013 RETURN_FALSE;
1014 }
1015 ZEND_REGISTER_RESOURCE(return_value, ib_link, le_plink);
1016 ++IBG(num_persistent);
1017 }
1018 ib_link->handle = db_handle;
1019 ib_link->dialect = largs[DLECT] ? (unsigned short)largs[DLECT] : SQL_DIALECT_CURRENT;
1020 ib_link->tr_list = NULL;
1021 ib_link->event_head = NULL;
1022
1023 ++IBG(num_links);
1024 }
1025
1026 /* add it to the hash */
1027 new_index_ptr.ptr = (void *) Z_LVAL_P(return_value);
1028 Z_TYPE(new_index_ptr) = le_index_ptr;
1029 if (FAILURE == zend_hash_update(&EG(regular_list), hash, sizeof(hash),
1030 (void *) &new_index_ptr, sizeof(zend_rsrc_list_entry), NULL)) {
1031 RETURN_FALSE;
1032 }
1033 zend_list_addref(IBG(default_link) = Z_LVAL_P(return_value));
1034 }
1035 /* }}} */
1036
1037 /* {{{ proto resource ibase_connect(string database [, string username [, string password [, string charset [, int buffers [, int dialect [, string role]]]]]])
1038 Open a connection to an InterBase database */
PHP_FUNCTION(ibase_connect)1039 PHP_FUNCTION(ibase_connect)
1040 {
1041 _php_ibase_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
1042 }
1043 /* }}} */
1044
1045 /* {{{ proto resource ibase_pconnect(string database [, string username [, string password [, string charset [, int buffers [, int dialect [, string role]]]]]])
1046 Open a persistent connection to an InterBase database */
PHP_FUNCTION(ibase_pconnect)1047 PHP_FUNCTION(ibase_pconnect)
1048 {
1049 _php_ibase_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, INI_INT("ibase.allow_persistent"));
1050 }
1051 /* }}} */
1052
1053 /* {{{ proto bool ibase_close([resource link_identifier])
1054 Close an InterBase connection */
PHP_FUNCTION(ibase_close)1055 PHP_FUNCTION(ibase_close)
1056 {
1057 zval *link_arg = NULL;
1058 ibase_db_link *ib_link;
1059 int link_id;
1060
1061 RESET_ERRMSG;
1062
1063 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|r", &link_arg) == FAILURE) {
1064 return;
1065 }
1066
1067 if (ZEND_NUM_ARGS() == 0) {
1068 link_id = IBG(default_link);
1069 CHECK_LINK(link_id);
1070 IBG(default_link) = -1;
1071 } else {
1072 link_id = Z_RESVAL_P(link_arg);
1073 }
1074
1075 ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, &link_arg, link_id, LE_LINK, le_link, le_plink);
1076 zend_list_delete(link_id);
1077 RETURN_TRUE;
1078 }
1079 /* }}} */
1080
1081 /* {{{ proto bool ibase_drop_db([resource link_identifier])
1082 Drop an InterBase database */
PHP_FUNCTION(ibase_drop_db)1083 PHP_FUNCTION(ibase_drop_db)
1084 {
1085 zval *link_arg = NULL;
1086 ibase_db_link *ib_link;
1087 ibase_tr_list *l;
1088 int link_id;
1089
1090 RESET_ERRMSG;
1091
1092 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|r", &link_arg) == FAILURE) {
1093 return;
1094 }
1095
1096 if (ZEND_NUM_ARGS() == 0) {
1097 link_id = IBG(default_link);
1098 CHECK_LINK(link_id);
1099 IBG(default_link) = -1;
1100 } else {
1101 link_id = Z_RESVAL_P(link_arg);
1102 }
1103
1104 ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, &link_arg, link_id, LE_LINK, le_link, le_plink);
1105
1106 if (isc_drop_database(IB_STATUS, &ib_link->handle)) {
1107 _php_ibase_error(TSRMLS_C);
1108 RETURN_FALSE;
1109 }
1110
1111 /* isc_drop_database() doesn't invalidate the transaction handles */
1112 for (l = ib_link->tr_list; l != NULL; l = l->next) {
1113 if (l->trans != NULL) l->trans->handle = NULL;
1114 }
1115
1116 zend_list_delete(link_id);
1117 RETURN_TRUE;
1118 }
1119 /* }}} */
1120
1121 /* {{{ proto resource ibase_trans([int trans_args [, resource link_identifier [, ... ], int trans_args [, resource link_identifier [, ... ]] [, ...]]])
1122 Start a transaction over one or several databases */
1123
1124 #define TPB_MAX_SIZE (8*sizeof(char))
1125
PHP_FUNCTION(ibase_trans)1126 PHP_FUNCTION(ibase_trans)
1127 {
1128 unsigned short i, link_cnt = 0, tpb_len = 0;
1129 int argn;
1130 char last_tpb[TPB_MAX_SIZE];
1131 ibase_db_link **ib_link = NULL;
1132 ibase_trans *ib_trans;
1133 isc_tr_handle tr_handle = NULL;
1134 ISC_STATUS result;
1135
1136 RESET_ERRMSG;
1137
1138 argn = ZEND_NUM_ARGS();
1139
1140 /* (1+argn) is an upper bound for the number of links this trans connects to */
1141 ib_link = (ibase_db_link **) safe_emalloc(sizeof(ibase_db_link *),1+argn,0);
1142
1143 if (argn > 0) {
1144 long trans_argl = 0;
1145 char *tpb;
1146 ISC_TEB *teb;
1147 zval ***args = NULL;
1148
1149 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &args, &argn) == FAILURE) {
1150 efree(args);
1151 efree(ib_link);
1152 RETURN_FALSE;
1153 }
1154
1155 teb = (ISC_TEB *) safe_emalloc(sizeof(ISC_TEB),argn,0);
1156 tpb = (char *) safe_emalloc(TPB_MAX_SIZE,argn,0);
1157
1158 /* enumerate all the arguments: assume every non-resource argument
1159 specifies modifiers for the link ids that follow it */
1160 for (i = 0; i < argn; ++i) {
1161
1162 if (Z_TYPE_PP(args[i]) == IS_RESOURCE) {
1163
1164 if (!ZEND_FETCH_RESOURCE2_NO_RETURN(ib_link[link_cnt], ibase_db_link *, args[i], -1, LE_LINK, le_link, le_plink)) {
1165 efree(teb);
1166 efree(tpb);
1167 efree(ib_link);
1168 efree(args);
1169 RETURN_FALSE;
1170 }
1171
1172 /* copy the most recent modifier string into tbp[] */
1173 memcpy(&tpb[TPB_MAX_SIZE * link_cnt], last_tpb, TPB_MAX_SIZE);
1174
1175 /* add a database handle to the TEB with the most recently specified set of modifiers */
1176 teb[link_cnt].db_ptr = &ib_link[link_cnt]->handle;
1177 teb[link_cnt].tpb_len = tpb_len;
1178 teb[link_cnt].tpb_ptr = &tpb[TPB_MAX_SIZE * link_cnt];
1179
1180 ++link_cnt;
1181
1182 } else {
1183
1184 tpb_len = 0;
1185
1186 convert_to_long_ex(args[i]);
1187 trans_argl = Z_LVAL_PP(args[i]);
1188
1189 if (trans_argl != PHP_IBASE_DEFAULT) {
1190 last_tpb[tpb_len++] = isc_tpb_version3;
1191
1192 /* access mode */
1193 if (PHP_IBASE_READ == (trans_argl & PHP_IBASE_READ)) {
1194 last_tpb[tpb_len++] = isc_tpb_read;
1195 } else if (PHP_IBASE_WRITE == (trans_argl & PHP_IBASE_WRITE)) {
1196 last_tpb[tpb_len++] = isc_tpb_write;
1197 }
1198
1199 /* isolation level */
1200 if (PHP_IBASE_COMMITTED == (trans_argl & PHP_IBASE_COMMITTED)) {
1201 last_tpb[tpb_len++] = isc_tpb_read_committed;
1202 if (PHP_IBASE_REC_VERSION == (trans_argl & PHP_IBASE_REC_VERSION)) {
1203 last_tpb[tpb_len++] = isc_tpb_rec_version;
1204 } else if (PHP_IBASE_REC_NO_VERSION == (trans_argl & PHP_IBASE_REC_NO_VERSION)) {
1205 last_tpb[tpb_len++] = isc_tpb_no_rec_version;
1206 }
1207 } else if (PHP_IBASE_CONSISTENCY == (trans_argl & PHP_IBASE_CONSISTENCY)) {
1208 last_tpb[tpb_len++] = isc_tpb_consistency;
1209 } else if (PHP_IBASE_CONCURRENCY == (trans_argl & PHP_IBASE_CONCURRENCY)) {
1210 last_tpb[tpb_len++] = isc_tpb_concurrency;
1211 }
1212
1213 /* lock resolution */
1214 if (PHP_IBASE_NOWAIT == (trans_argl & PHP_IBASE_NOWAIT)) {
1215 last_tpb[tpb_len++] = isc_tpb_nowait;
1216 } else if (PHP_IBASE_WAIT == (trans_argl & PHP_IBASE_WAIT)) {
1217 last_tpb[tpb_len++] = isc_tpb_wait;
1218 }
1219 }
1220 }
1221 }
1222
1223 if (link_cnt > 0) {
1224 result = isc_start_multiple(IB_STATUS, &tr_handle, link_cnt, teb);
1225 }
1226
1227 efree(args);
1228 efree(tpb);
1229 efree(teb);
1230 }
1231
1232 if (link_cnt == 0) {
1233 link_cnt = 1;
1234 if (!ZEND_FETCH_RESOURCE2_NO_RETURN(ib_link[0], ibase_db_link *, NULL, IBG(default_link), LE_LINK, le_link, le_plink)) {
1235 efree(ib_link);
1236 RETURN_FALSE;
1237 }
1238 result = isc_start_transaction(IB_STATUS, &tr_handle, 1, &ib_link[0]->handle, tpb_len, last_tpb);
1239 }
1240
1241 /* start the transaction */
1242 if (result) {
1243 _php_ibase_error(TSRMLS_C);
1244 efree(ib_link);
1245 RETURN_FALSE;
1246 }
1247
1248 /* register the transaction in our own data structures */
1249 ib_trans = (ibase_trans *) safe_emalloc(link_cnt-1, sizeof(ibase_db_link *), sizeof(ibase_trans));
1250 ib_trans->handle = tr_handle;
1251 ib_trans->link_cnt = link_cnt;
1252 ib_trans->affected_rows = 0;
1253 for (i = 0; i < link_cnt; ++i) {
1254 ibase_tr_list **l;
1255 ib_trans->db_link[i] = ib_link[i];
1256
1257 /* the first item in the connection-transaction list is reserved for the default transaction */
1258 if (ib_link[i]->tr_list == NULL) {
1259 ib_link[i]->tr_list = (ibase_tr_list *) emalloc(sizeof(ibase_tr_list));
1260 ib_link[i]->tr_list->trans = NULL;
1261 ib_link[i]->tr_list->next = NULL;
1262 }
1263
1264 /* link the transaction into the connection-transaction list */
1265 for (l = &ib_link[i]->tr_list; *l != NULL; l = &(*l)->next);
1266 *l = (ibase_tr_list *) emalloc(sizeof(ibase_tr_list));
1267 (*l)->trans = ib_trans;
1268 (*l)->next = NULL;
1269 }
1270 efree(ib_link);
1271 ZEND_REGISTER_RESOURCE(return_value, ib_trans, le_trans);
1272 }
1273 /* }}} */
1274
_php_ibase_def_trans(ibase_db_link * ib_link,ibase_trans ** trans TSRMLS_DC)1275 int _php_ibase_def_trans(ibase_db_link *ib_link, ibase_trans **trans TSRMLS_DC) /* {{{ */
1276 {
1277 if (ib_link == NULL) {
1278 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid database link");
1279 return FAILURE;
1280 }
1281
1282 /* the first item in the connection-transaction list is reserved for the default transaction */
1283 if (ib_link->tr_list == NULL) {
1284 ib_link->tr_list = (ibase_tr_list *) emalloc(sizeof(ibase_tr_list));
1285 ib_link->tr_list->trans = NULL;
1286 ib_link->tr_list->next = NULL;
1287 }
1288
1289 if (*trans == NULL) {
1290 ibase_trans *tr = ib_link->tr_list->trans;
1291
1292 if (tr == NULL) {
1293 tr = (ibase_trans *) emalloc(sizeof(ibase_trans));
1294 tr->handle = NULL;
1295 tr->link_cnt = 1;
1296 tr->affected_rows = 0;
1297 tr->db_link[0] = ib_link;
1298 ib_link->tr_list->trans = tr;
1299 }
1300 if (tr->handle == NULL) {
1301 if (isc_start_transaction(IB_STATUS, &tr->handle, 1, &ib_link->handle, 0, NULL)) {
1302 _php_ibase_error(TSRMLS_C);
1303 return FAILURE;
1304 }
1305 }
1306 *trans = tr;
1307 }
1308 return SUCCESS;
1309 }
1310 /* }}} */
1311
_php_ibase_trans_end(INTERNAL_FUNCTION_PARAMETERS,int commit)1312 static void _php_ibase_trans_end(INTERNAL_FUNCTION_PARAMETERS, int commit) /* {{{ */
1313 {
1314 ibase_trans *trans = NULL;
1315 int res_id = 0;
1316 ISC_STATUS result;
1317 ibase_db_link *ib_link;
1318 zval *arg = NULL;
1319 int type;
1320
1321 RESET_ERRMSG;
1322
1323 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|r", &arg) == FAILURE) {
1324 return;
1325 }
1326
1327 if (ZEND_NUM_ARGS() == 0) {
1328 ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, NULL, IBG(default_link), LE_LINK, le_link, le_plink);
1329 if (ib_link->tr_list == NULL || ib_link->tr_list->trans == NULL) {
1330 /* this link doesn't have a default transaction */
1331 _php_ibase_module_error("Default link has no default transaction" TSRMLS_CC);
1332 RETURN_FALSE;
1333 }
1334 trans = ib_link->tr_list->trans;
1335 } else {
1336 /* one id was passed, could be db or trans id */
1337 if (zend_list_find(Z_RESVAL_P(arg), &type) && type == le_trans) {
1338 ZEND_FETCH_RESOURCE(trans, ibase_trans *, &arg, -1, LE_TRANS, le_trans);
1339 res_id = Z_RESVAL_P(arg);
1340 } else {
1341 ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, &arg, -1, LE_LINK, le_link, le_plink);
1342
1343 if (ib_link->tr_list == NULL || ib_link->tr_list->trans == NULL) {
1344 /* this link doesn't have a default transaction */
1345 _php_ibase_module_error("Link has no default transaction" TSRMLS_CC);
1346 RETURN_FALSE;
1347 }
1348 trans = ib_link->tr_list->trans;
1349 }
1350 }
1351
1352 switch (commit) {
1353 default: /* == case ROLLBACK: */
1354 result = isc_rollback_transaction(IB_STATUS, &trans->handle);
1355 break;
1356 case COMMIT:
1357 result = isc_commit_transaction(IB_STATUS, &trans->handle);
1358 break;
1359 case (ROLLBACK | RETAIN):
1360 result = isc_rollback_retaining(IB_STATUS, &trans->handle);
1361 break;
1362 case (COMMIT | RETAIN):
1363 result = isc_commit_retaining(IB_STATUS, &trans->handle);
1364 break;
1365 }
1366
1367 if (result) {
1368 _php_ibase_error(TSRMLS_C);
1369 RETURN_FALSE;
1370 }
1371
1372 /* Don't try to destroy implicitly opened transaction from list... */
1373 if ((commit & RETAIN) == 0 && res_id != 0) {
1374 zend_list_delete(res_id);
1375 }
1376 RETURN_TRUE;
1377 }
1378 /* }}} */
1379
1380 /* {{{ proto bool ibase_commit( resource link_identifier )
1381 Commit transaction */
PHP_FUNCTION(ibase_commit)1382 PHP_FUNCTION(ibase_commit)
1383 {
1384 _php_ibase_trans_end(INTERNAL_FUNCTION_PARAM_PASSTHRU, COMMIT);
1385 }
1386 /* }}} */
1387
1388 /* {{{ proto bool ibase_rollback( resource link_identifier )
1389 Rollback transaction */
PHP_FUNCTION(ibase_rollback)1390 PHP_FUNCTION(ibase_rollback)
1391 {
1392 _php_ibase_trans_end(INTERNAL_FUNCTION_PARAM_PASSTHRU, ROLLBACK);
1393 }
1394 /* }}} */
1395
1396 /* {{{ proto bool ibase_commit_ret( resource link_identifier )
1397 Commit transaction and retain the transaction context */
PHP_FUNCTION(ibase_commit_ret)1398 PHP_FUNCTION(ibase_commit_ret)
1399 {
1400 _php_ibase_trans_end(INTERNAL_FUNCTION_PARAM_PASSTHRU, COMMIT | RETAIN);
1401 }
1402 /* }}} */
1403
1404 /* {{{ proto bool ibase_rollback_ret( resource link_identifier )
1405 Rollback transaction and retain the transaction context */
PHP_FUNCTION(ibase_rollback_ret)1406 PHP_FUNCTION(ibase_rollback_ret)
1407 {
1408 _php_ibase_trans_end(INTERNAL_FUNCTION_PARAM_PASSTHRU, ROLLBACK | RETAIN);
1409 }
1410 /* }}} */
1411
1412 /* {{{ proto int ibase_gen_id(string generator [, int increment [, resource link_identifier ]])
1413 Increments the named generator and returns its new value */
PHP_FUNCTION(ibase_gen_id)1414 PHP_FUNCTION(ibase_gen_id)
1415 {
1416 zval *link = NULL;
1417 char query[128], *generator;
1418 int gen_len;
1419 long inc = 1;
1420 ibase_db_link *ib_link;
1421 ibase_trans *trans = NULL;
1422 XSQLDA out_sqlda;
1423 ISC_INT64 result;
1424
1425 RESET_ERRMSG;
1426
1427 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lr", &generator, &gen_len,
1428 &inc, &link)) {
1429 RETURN_FALSE;
1430 }
1431
1432 if (gen_len > 31) {
1433 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid generator name");
1434 RETURN_FALSE;
1435 }
1436
1437 PHP_IBASE_LINK_TRANS(link, ib_link, trans);
1438
1439 snprintf(query, sizeof(query), "SELECT GEN_ID(%s,%ld) FROM rdb$database", generator, inc);
1440
1441 /* allocate a minimal descriptor area */
1442 out_sqlda.sqln = out_sqlda.sqld = 1;
1443 out_sqlda.version = SQLDA_CURRENT_VERSION;
1444
1445 /* allocate the field for the result */
1446 out_sqlda.sqlvar[0].sqltype = SQL_INT64;
1447 out_sqlda.sqlvar[0].sqlscale = 0;
1448 out_sqlda.sqlvar[0].sqllen = sizeof(result);
1449 out_sqlda.sqlvar[0].sqldata = (void*) &result;
1450
1451 /* execute the query */
1452 if (isc_dsql_exec_immed2(IB_STATUS, &ib_link->handle, &trans->handle, 0, query,
1453 SQL_DIALECT_CURRENT, NULL, &out_sqlda)) {
1454 _php_ibase_error(TSRMLS_C);
1455 RETURN_FALSE;
1456 }
1457
1458 /* don't return the generator value as a string unless it doesn't fit in a long */
1459 #if SIZEOF_LONG < 8
1460 if (result < LONG_MIN || result > LONG_MAX) {
1461 char *res;
1462 int l;
1463
1464 l = spprintf(&res, 0, "%" LL_MASK "d", result);
1465 RETURN_STRINGL(res, l, 0);
1466 }
1467 #endif
1468 RETURN_LONG((long)result);
1469 }
1470
1471 /* }}} */
1472
1473 #endif /* HAVE_IBASE */
1474
1475 /*
1476 * Local variables:
1477 * tab-width: 4
1478 * c-basic-offset: 4
1479 * End:
1480 * vim600: sw=4 ts=4 fdm=marker
1481 * vim<600: sw=4 ts=4
1482 */
1483