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