├── CREDITS ├── tests ├── skipif.inc ├── ibase_trans_001.phpt ├── ibase_close_001.phpt ├── ibase_errmsg_001.phpt ├── ibase_num_fields_001.phpt ├── bug45575.phpt ├── 002.phpt ├── ibase_trans_002.phpt ├── ibase_affected_rows_001.phpt ├── ibase_free_query_001.phpt ├── ibase_drop_db_001.phpt ├── ibase_num_params_001.phpt ├── bug46543.phpt ├── ibase_rollback_001.phpt ├── ibase_param_info_001.phpt ├── 008.phpt ├── bug46247.phpt ├── bug45373.phpt ├── interbase.inc ├── 007.phpt ├── 003.phpt ├── 005.phpt ├── 006.phpt └── 004.phpt ├── config.w32 ├── .gitignore ├── config.m4 ├── LICENSE ├── php_interbase.h ├── php_ibase_includes.h ├── ibase_events.c ├── php_ibase_udf.c ├── ibase_blobs.c ├── ibase_service.c └── interbase.c /CREDITS: -------------------------------------------------------------------------------- 1 | InterBase 2 | Jouni Ahto, Andrew Avdeev, Ard Biesheuvel 3 | -------------------------------------------------------------------------------- /tests/skipif.inc: -------------------------------------------------------------------------------- 1 | 9 | -------------------------------------------------------------------------------- /tests/ibase_trans_001.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | ibase_trans(): Basic test 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 17 | --EXPECTF-- 18 | resource(%d) of type (Firebird/InterBase transaction) 19 | resource(%d) of type (Firebird/InterBase transaction) 20 | bool(true) 21 | bool(true) 22 | -------------------------------------------------------------------------------- /tests/ibase_close_001.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | ibase_close(): Basic test 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 17 | --EXPECTF-- 18 | bool(true) 19 | bool(true) 20 | bool(true) 21 | 22 | Warning: ibase_close() expects parameter 1 to be resource, string given in %s on line %d 23 | NULL 24 | -------------------------------------------------------------------------------- /tests/ibase_errmsg_001.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | ibase_errmsg(): Basic test 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 19 | --EXPECTF-- 20 | Warning: ibase_query(): Dynamic SQL Error SQL error code = -104 %s on line %d 21 | string(%d) "Dynamic SQL Error SQL error code = -104 %s" 22 | bool(false) 23 | -------------------------------------------------------------------------------- /tests/ibase_num_fields_001.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | ibase_num_fields(): Basic test 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 18 | --EXPECTF-- 19 | int(2) 20 | 21 | Warning: ibase_num_fields() expects parameter 1 to be resource, int given in %s on line %d 22 | NULL 23 | 24 | Warning: ibase_num_fields() expects exactly 1 parameter, 0 given in %s on line %d 25 | NULL 26 | -------------------------------------------------------------------------------- /tests/bug45575.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Bug #45575 (Segfault with invalid non-string as event handler callback) 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 19 | --EXPECTF-- 20 | Warning: ibase_set_event_handler(): Callback argument is not a callable function in %s on line %d 21 | 22 | Warning: ibase_set_event_handler(): Callback argument 1 is not a callable function in %s on line %d 23 | -------------------------------------------------------------------------------- /tests/002.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | InterBase: connect, close and pconnect 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 27 | --EXPECT-- 28 | --- test1 --- 29 | 1 test table not created with isql 30 | --- 31 | --- test1 --- 32 | 1 test table not created with isql 33 | --- 34 | -------------------------------------------------------------------------------- /tests/ibase_trans_002.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | ibase_trans(): Basic operations 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 27 | --EXPECT-- 28 | int(1) 29 | array(2) { 30 | ["I"]=> 31 | int(100) 32 | ["C"]=> 33 | string(3) "100" 34 | } 35 | -------------------------------------------------------------------------------- /tests/ibase_affected_rows_001.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | ibase_affected_rows(): Basic test 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 27 | --EXPECTF-- 28 | int(3) 29 | int(0) 30 | 31 | Warning: ibase_query(): Dynamic SQL Error SQL error code = -104 %s on line %d 32 | int(0) 33 | -------------------------------------------------------------------------------- /config.w32: -------------------------------------------------------------------------------- 1 | // vim:ft=javascript 2 | 3 | ARG_WITH("interbase", "InterBase support", "no"); 4 | 5 | if (PHP_INTERBASE != "no") { 6 | 7 | if (CHECK_HEADER_ADD_INCLUDE("ibase.h", "CFLAGS_INTERBASE", 8 | PHP_PHP_BUILD + "\\include\\interbase;" + PHP_PHP_BUILD + "\\interbase\\include;" + PHP_INTERBASE) && 9 | (CHECK_LIB("fbclient_ms.lib", "interbase", PHP_PHP_BUILD + "\\interbase\\lib_ms;" + PHP_INTERBASE) || 10 | CHECK_LIB("gds32_ms.lib", "interbase", PHP_PHP_BUILD + "\\interbase\\lib_ms;" + PHP_INTERBASE))) { 11 | 12 | EXTENSION("interbase", "interbase.c ibase_query.c ibase_service.c ibase_events.c ibase_blobs.c", PHP_INTERBASE_SHARED, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); 13 | AC_DEFINE('HAVE_IBASE', 1, 'Have interbase library'); 14 | } else { 15 | WARNING("interbase not enabled; libraries and headers not found"); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/ibase_free_query_001.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | ibase_free_query(): Basic test 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 21 | --EXPECTF-- 22 | bool(true) 23 | 24 | Warning: ibase_free_query(): supplied resource is not a valid Firebird/InterBase query resource in %s on line %d 25 | bool(false) 26 | 27 | Warning: ibase_free_query(): supplied resource is not a valid Firebird/InterBase query resource in %s on line %d 28 | bool(false) 29 | -------------------------------------------------------------------------------- /tests/ibase_drop_db_001.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | ibase_drop_db(): Basic test 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 23 | --EXPECTF-- 24 | resource(%d) of type (Firebird/InterBase link) 25 | bool(true) 26 | 27 | Warning: ibase_drop_db() expects parameter 1 to be resource, int given in %s on line %d 28 | NULL 29 | 30 | Warning: ibase_drop_db() expects parameter 1 to be resource, null given in %s on line %d 31 | NULL 32 | -------------------------------------------------------------------------------- /tests/ibase_num_params_001.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | ibase_num_params(): Basic test 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 23 | --EXPECTF-- 24 | int(2) 25 | 26 | Warning: ibase_num_params() expects exactly 1 parameter, 0 given in %s on line %d 27 | NULL 28 | 29 | Warning: ibase_prepare(): Dynamic SQL Error SQL error code = -206 %s in %s on line %d 30 | 31 | Warning: ibase_num_params() expects parameter 1 to be resource, bool given in %s on line %d 32 | NULL 33 | -------------------------------------------------------------------------------- /tests/bug46543.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Bug #46543 (ibase_trans() memory leaks when using wrong parameters) 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 21 | --EXPECTF-- 22 | Warning: ibase_trans(): supplied resource is not a valid Firebird/InterBase link resource in %sbug46543.php on line %d 23 | 24 | Warning: ibase_trans(): supplied resource is not a valid Firebird/InterBase link resource in %sbug46543.php on line %d 25 | 26 | Warning: ibase_trans(): supplied resource is not a valid Firebird/InterBase link resource in %sbug46543.php on line %d 27 | 28 | Warning: ibase_trans(): supplied resource is not a valid Firebird/InterBase link resource in %sbug46543.php on line %d 29 | -------------------------------------------------------------------------------- /tests/ibase_rollback_001.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | ibase_rollback(): Basic test 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 28 | --EXPECTF-- 29 | array(1) { 30 | [0]=> 31 | int(3) 32 | } 33 | bool(true) 34 | array(1) { 35 | [0]=> 36 | int(0) 37 | } 38 | bool(true) 39 | 40 | Warning: ibase_rollback(): invalid transaction handle (expecting explicit transaction start) in %s on line %d 41 | bool(false) 42 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .deps 2 | .libs 3 | .php-version 4 | .rbenv-version 5 | acinclude.m4 6 | aclocal.m4 7 | autom4te.cache 8 | build 9 | config.guess 10 | config.h 11 | config.h.in 12 | config.log 13 | config.nice 14 | config.status 15 | config.sub 16 | configure 17 | configure.in 18 | configure.ac 19 | extras 20 | include 21 | install-sh 22 | libtool 23 | ltmain.sh 24 | ltmain.sh.backup 25 | Makefile 26 | Makefile.fragments 27 | Makefile.global 28 | Makefile.objects 29 | missing 30 | mkinstalldirs 31 | modules 32 | run-tests.php 33 | tmp-php.ini 34 | yaml.loT 35 | 36 | # General Ignores 37 | *~ 38 | .#* 39 | *. 40 | *.slo 41 | *.mk 42 | *.mem 43 | *.gcda 44 | *.gcno 45 | *.la 46 | *.lo 47 | *.o 48 | *.a 49 | *.ncb 50 | *.opt 51 | *.plg 52 | *swp 53 | *.patch 54 | *.tgz 55 | *.tar.gz 56 | *.tar.bz2 57 | .FBCIndex 58 | .FBCLockFolder 59 | core 60 | 61 | # Test specific Ignores 62 | tests/*.diff 63 | tests/*.exp 64 | tests/*.log 65 | tests/*.out 66 | tests/*.php 67 | tests/*.sh 68 | 69 | # coverage 70 | /coverage.info 71 | /reports 72 | -------------------------------------------------------------------------------- /tests/ibase_param_info_001.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | ibase_param_info(): Basic test 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 25 | --EXPECTF-- 26 | array(10) { 27 | [0]=> 28 | string(0) "" 29 | ["name"]=> 30 | string(0) "" 31 | [1]=> 32 | string(0) "" 33 | ["alias"]=> 34 | string(0) "" 35 | [2]=> 36 | string(0) "" 37 | ["relation"]=> 38 | string(0) "" 39 | [3]=> 40 | string(1) "4" 41 | ["length"]=> 42 | string(1) "4" 43 | [4]=> 44 | string(7) "INTEGER" 45 | ["type"]=> 46 | string(7) "INTEGER" 47 | } 48 | --- 49 | bool(false) 50 | --- 51 | 52 | Warning: ibase_param_info() expects exactly 2 parameters, 1 given in %s on line %d 53 | NULL 54 | -------------------------------------------------------------------------------- /tests/008.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | InterBase: event handling 3 | --SKIPIF-- 4 | 8 | --FILE-- 9 | 5) echo "FAIL ($count)\n"; 44 | echo "end of test\n"; 45 | 46 | ?> 47 | --EXPECT-- 48 | end of test 49 | -------------------------------------------------------------------------------- /tests/bug46247.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Bug #46247 (ibase_set_event_handler() is allowing to pass callback without event) 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 26 | --EXPECTF-- 27 | Warning: Wrong parameter count for ibase_set_event_handler() in %s on line %d 28 | 29 | Warning: ibase_set_event_handler(): supplied argument is not a valid InterBase link resource in %s on line %d 30 | 31 | Warning: ibase_set_event_handler(): Callback argument foo is not a callable function in %s on line %d 32 | 33 | Warning: ibase_set_event_handler(): Callback argument foo is not a callable function in %s on line %d 34 | 35 | Warning: ibase_set_event_handler(): supplied argument is not a valid InterBase link resource in %s on line %d 36 | -------------------------------------------------------------------------------- /tests/bug45373.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Bug #45373 (php crash on query with errors in params) 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 28 | --EXPECTF-- 29 | array(2) { 30 | ["I"]=> 31 | int(1) 32 | ["C"]=> 33 | string(32) "test table not created with isql" 34 | } 35 | 36 | Notice: ibase_execute(): Statement expects 2 arguments, 3 given in %s on line %d 37 | array(2) { 38 | ["I"]=> 39 | int(1) 40 | ["C"]=> 41 | string(32) "test table not created with isql" 42 | } 43 | 44 | Warning: ibase_execute(): Statement expects 2 arguments, 1 given in %s on line %d 45 | 46 | Warning: ibase_fetch_assoc() expects parameter 1 to be resource, bool given in %s on line %d 47 | NULL 48 | -------------------------------------------------------------------------------- /config.m4: -------------------------------------------------------------------------------- 1 | PHP_ARG_WITH([interbase], 2 | [for Firebird support], 3 | [AS_HELP_STRING([[--with-interbase[=DIR]]], 4 | [Include Firebird support. DIR is the Firebird base install directory 5 | [/opt/firebird]])]) 6 | 7 | if test "$PHP_INTERBASE" != "no"; then 8 | 9 | AC_PATH_PROG(FB_CONFIG, fb_config, no) 10 | 11 | if test -x "$FB_CONFIG" && test "$PHP_INTERBASE" = "yes"; then 12 | AC_MSG_CHECKING(for libfbconfig) 13 | FB_CFLAGS=`$FB_CONFIG --cflags` 14 | FB_LIBDIR=`$FB_CONFIG --libs` 15 | FB_VERSION=`$FB_CONFIG --version` 16 | AC_MSG_RESULT(version $FB_VERSION) 17 | PHP_EVAL_LIBLINE($FB_LIBDIR, INTERBASE_SHARED_LIBADD) 18 | PHP_EVAL_INCLINE($FB_CFLAGS) 19 | 20 | else 21 | if test "$PHP_INTERBASE" = "yes"; then 22 | IBASE_INCDIR=/opt/firebird/include 23 | IBASE_LIBDIR=/opt/firebird/lib 24 | else 25 | IBASE_INCDIR=$PHP_INTERBASE/include 26 | IBASE_LIBDIR=$PHP_INTERBASE/$PHP_LIBDIR 27 | fi 28 | 29 | PHP_CHECK_LIBRARY(fbclient, isc_detach_database, 30 | [ 31 | IBASE_LIBNAME=fbclient 32 | ], [ 33 | PHP_CHECK_LIBRARY(gds, isc_detach_database, 34 | [ 35 | IBASE_LIBNAME=gds 36 | ], [ 37 | PHP_CHECK_LIBRARY(ib_util, isc_detach_database, 38 | [ 39 | IBASE_LIBNAME=ib_util 40 | ], [ 41 | AC_MSG_ERROR([libfbclient, libgds or libib_util not found! Check config.log for more information.]) 42 | ], [ 43 | -L$IBASE_LIBDIR 44 | ]) 45 | ], [ 46 | -L$IBASE_LIBDIR 47 | ]) 48 | ], [ 49 | -L$IBASE_LIBDIR 50 | ]) 51 | 52 | PHP_ADD_LIBRARY_WITH_PATH($IBASE_LIBNAME, $IBASE_LIBDIR, INTERBASE_SHARED_LIBADD) 53 | PHP_ADD_INCLUDE($IBASE_INCDIR) 54 | fi 55 | 56 | AC_DEFINE(HAVE_IBASE,1,[ ]) 57 | PHP_NEW_EXTENSION(interbase, interbase.c ibase_query.c ibase_service.c ibase_events.c ibase_blobs.c, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1) 58 | PHP_SUBST(INTERBASE_SHARED_LIBADD) 59 | fi 60 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------- 2 | The PHP License, version 3.01 3 | Copyright (c) 1999 - 2019 The PHP Group. All rights reserved. 4 | -------------------------------------------------------------------- 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, is permitted provided that the following conditions 8 | are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright 11 | notice, this list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in 15 | the documentation and/or other materials provided with the 16 | distribution. 17 | 18 | 3. The name "PHP" must not be used to endorse or promote products 19 | derived from this software without prior written permission. For 20 | written permission, please contact group@php.net. 21 | 22 | 4. Products derived from this software may not be called "PHP", nor 23 | may "PHP" appear in their name, without prior written permission 24 | from group@php.net. You may indicate that your software works in 25 | conjunction with PHP by saying "Foo for PHP" instead of calling 26 | it "PHP Foo" or "phpfoo" 27 | 28 | 5. The PHP Group may publish revised and/or new versions of the 29 | license from time to time. Each version will be given a 30 | distinguishing version number. 31 | Once covered code has been published under a particular version 32 | of the license, you may always continue to use it under the terms 33 | of that version. You may also choose to use such covered code 34 | under the terms of any subsequent version of the license 35 | published by the PHP Group. No one other than the PHP Group has 36 | the right to modify the terms applicable to covered code created 37 | under this License. 38 | 39 | 6. Redistributions of any form whatsoever must retain the following 40 | acknowledgment: 41 | "This product includes PHP software, freely available from 42 | ". 43 | 44 | THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND 45 | ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 46 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 47 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP 48 | DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 49 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 50 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 51 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 52 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 53 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 54 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 55 | OF THE POSSIBILITY OF SUCH DAMAGE. 56 | 57 | -------------------------------------------------------------------- 58 | 59 | This software consists of voluntary contributions made by many 60 | individuals on behalf of the PHP Group. 61 | 62 | The PHP Group can be contacted via Email at group@php.net. 63 | 64 | For more information on the PHP Group and the PHP project, 65 | please see . 66 | 67 | PHP includes the Zend Engine, freely available at 68 | . 69 | -------------------------------------------------------------------------------- /tests/interbase.inc: -------------------------------------------------------------------------------- 1 | 121 | -------------------------------------------------------------------------------- /php_interbase.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 7 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 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 | 16 | | Andrew Avdeev | 17 | | Ard Biesheuvel | 18 | +----------------------------------------------------------------------+ 19 | */ 20 | 21 | #ifndef PHP_INTERBASE_H 22 | #define PHP_INTERBASE_H 23 | 24 | extern zend_module_entry ibase_module_entry; 25 | #define phpext_interbase_ptr &ibase_module_entry 26 | 27 | #include "php_version.h" 28 | #define PHP_INTERBASE_VERSION "1.0.0-dev" 29 | 30 | PHP_MINIT_FUNCTION(ibase); 31 | PHP_RINIT_FUNCTION(ibase); 32 | PHP_MSHUTDOWN_FUNCTION(ibase); 33 | PHP_RSHUTDOWN_FUNCTION(ibase); 34 | PHP_MINFO_FUNCTION(ibase); 35 | 36 | PHP_FUNCTION(ibase_connect); 37 | PHP_FUNCTION(ibase_pconnect); 38 | PHP_FUNCTION(ibase_close); 39 | PHP_FUNCTION(ibase_drop_db); 40 | PHP_FUNCTION(ibase_query); 41 | PHP_FUNCTION(ibase_fetch_row); 42 | PHP_FUNCTION(ibase_fetch_assoc); 43 | PHP_FUNCTION(ibase_fetch_object); 44 | PHP_FUNCTION(ibase_free_result); 45 | PHP_FUNCTION(ibase_name_result); 46 | PHP_FUNCTION(ibase_prepare); 47 | PHP_FUNCTION(ibase_execute); 48 | PHP_FUNCTION(ibase_free_query); 49 | 50 | PHP_FUNCTION(ibase_timefmt); 51 | 52 | PHP_FUNCTION(ibase_gen_id); 53 | PHP_FUNCTION(ibase_num_fields); 54 | PHP_FUNCTION(ibase_num_params); 55 | #if abies_0 56 | PHP_FUNCTION(ibase_num_rows); 57 | #endif 58 | PHP_FUNCTION(ibase_affected_rows); 59 | PHP_FUNCTION(ibase_field_info); 60 | PHP_FUNCTION(ibase_param_info); 61 | 62 | PHP_FUNCTION(ibase_trans); 63 | PHP_FUNCTION(ibase_commit); 64 | PHP_FUNCTION(ibase_rollback); 65 | PHP_FUNCTION(ibase_commit_ret); 66 | PHP_FUNCTION(ibase_rollback_ret); 67 | 68 | PHP_FUNCTION(ibase_blob_create); 69 | PHP_FUNCTION(ibase_blob_add); 70 | PHP_FUNCTION(ibase_blob_cancel); 71 | PHP_FUNCTION(ibase_blob_open); 72 | PHP_FUNCTION(ibase_blob_get); 73 | PHP_FUNCTION(ibase_blob_close); 74 | PHP_FUNCTION(ibase_blob_echo); 75 | PHP_FUNCTION(ibase_blob_info); 76 | PHP_FUNCTION(ibase_blob_import); 77 | 78 | PHP_FUNCTION(ibase_add_user); 79 | PHP_FUNCTION(ibase_modify_user); 80 | PHP_FUNCTION(ibase_delete_user); 81 | 82 | PHP_FUNCTION(ibase_service_attach); 83 | PHP_FUNCTION(ibase_service_detach); 84 | PHP_FUNCTION(ibase_backup); 85 | PHP_FUNCTION(ibase_restore); 86 | PHP_FUNCTION(ibase_maintain_db); 87 | PHP_FUNCTION(ibase_db_info); 88 | PHP_FUNCTION(ibase_server_info); 89 | 90 | PHP_FUNCTION(ibase_errmsg); 91 | PHP_FUNCTION(ibase_errcode); 92 | 93 | PHP_FUNCTION(ibase_wait_event); 94 | PHP_FUNCTION(ibase_set_event_handler); 95 | PHP_FUNCTION(ibase_free_event_handler); 96 | 97 | #else 98 | 99 | #define phpext_interbase_ptr NULL 100 | 101 | #endif /* PHP_INTERBASE_H */ 102 | -------------------------------------------------------------------------------- /tests/007.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | InterBase: array handling 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | V_CHAR[$i],$v_char[$i],strlen($v_char[$i])) != 0) { 78 | echo " CHAR[$i] fail:\n"; 79 | echo " in: ".$v_char[$i]."\n"; 80 | echo " out: ".$row->V_CHAR[$i]."\n"; 81 | } 82 | if($row->V_DATE[$i] != $v_date[$i]) { 83 | echo " DATE[$i] fail\n"; 84 | echo " in: ".$v_date[$i]."\n"; 85 | echo " out: ".$row->V_DATE[$i]."\n"; 86 | } 87 | if($row->V_DECIMAL[$i] != $v_decimal[$i]) { 88 | echo " DECIMAL[$i] fail\n"; 89 | echo " in: ".$v_decimal[$i]."\n"; 90 | echo " out: ".$row->V_DECIMAL[$i]."\n"; 91 | } 92 | if(abs($row->V_DOUBLE[$i] - $v_double[$i]) > abs($v_double[$i] / 1E15)) { 93 | echo " DOUBLE[$i] fail\n"; 94 | echo " in: ".$v_double[$i]."\n"; 95 | echo " out: ".$row->V_DOUBLE[$i]."\n"; 96 | } 97 | if(abs($row->V_FLOAT[$i] - $v_float[$i]) > abs($v_float[$i] / 1E7)) { 98 | echo " FLOAT[$i] fail\n"; 99 | echo " in: ".$v_float[$i]."\n"; 100 | echo " out: ".$row->V_FLOAT[$i]."\n"; 101 | } 102 | if($row->V_INTEGER[$i] != $v_integer[$i]) { 103 | echo " INTEGER[$i] fail\n"; 104 | echo " in: ".$v_integer[$i]."\n"; 105 | echo " out: ".$row->V_INTEGER[$i]."\n"; 106 | } 107 | if ($row->V_NUMERIC[$i] != $v_numeric[$i]) { 108 | echo " NUMERIC[$i] fail\n"; 109 | echo " in: ".$v_numeric[$i]."\n"; 110 | echo " out: ".$row->V_NUMERIC[$i]."\n"; 111 | } 112 | if ($row->V_SMALLINT[$i] != $v_smallint[$i]) { 113 | echo " SMALLINT[$i] fail\n"; 114 | echo " in: ".$v_smallint[$i]."\n"; 115 | echo " out: ".$row->V_SMALLINT[$i]."\n"; 116 | } 117 | if ($row->V_VARCHAR[$i] != $v_varchar[$i]) { 118 | echo " VARCHAR[$i] fail:\n"; 119 | echo " in: ".$v_varchar[$i]."\n"; 120 | echo " out: ".$row->V_VARCHAR[$i]."\n"; 121 | } 122 | } 123 | ibase_free_result($sel); 124 | }/* for($iter) */ 125 | 126 | echo "select\n"; 127 | 128 | $sel = ibase_query("SELECT v_multi[5,5,5],v_multi[10,10,10] FROM test7 WHERE iter = 0"); 129 | print_r(ibase_fetch_row($sel)); 130 | ibase_free_result($sel); 131 | 132 | for($iter = 1; $iter <= 3; $iter++) { 133 | 134 | if(!($sel = ibase_query( 135 | "select iter from test7 where v_char[$iter] LIKE ?", $v_char[$iter]."%")) || 136 | !ibase_fetch_row($sel)) { 137 | echo "CHAR fail\n"; 138 | } 139 | ibase_free_result($sel); 140 | 141 | if(!($sel = ibase_query( 142 | "select iter from test7 where v_date[$iter] = ?", $v_date[$iter])) || 143 | !ibase_fetch_row($sel)) { 144 | echo "DATE fail\n"; 145 | } 146 | ibase_free_result($sel); 147 | if(!($sel = ibase_query( 148 | "select iter from test7 where v_decimal[$iter] = ?", $v_decimal[$iter])) || 149 | !ibase_fetch_row($sel)) { 150 | echo "DECIMAL fail\n"; 151 | } 152 | ibase_free_result($sel); 153 | if(!($sel = ibase_query( 154 | "select iter from test7 where v_integer[$iter] = ?", $v_integer[$iter])) || 155 | !ibase_fetch_row($sel)) { 156 | echo "INTEGER fail\n"; 157 | } 158 | ibase_free_result($sel); 159 | if(!($sel = ibase_query( 160 | "select iter from test7 where v_numeric[$iter] = ?", $v_numeric[$iter])) || 161 | !ibase_fetch_row($sel)) { 162 | echo "NUMERIC fail\n"; 163 | } 164 | ibase_free_result($sel); 165 | if(!($sel = ibase_query( 166 | "select iter from test7 where v_smallint[$iter] = ?", $v_smallint[$iter])) || 167 | !ibase_fetch_row($sel)) { 168 | echo "SMALLINT fail\n"; 169 | } 170 | ibase_free_result($sel); 171 | } 172 | ibase_close(); 173 | echo "end of test\n"; 174 | ?> 175 | --EXPECT-- 176 | insert 177 | select 178 | Array 179 | ( 180 | [0] => 125 181 | [1] => 1000 182 | ) 183 | end of test 184 | -------------------------------------------------------------------------------- /tests/003.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | InterBase: misc sql types (may take a while) 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | V_CHAR,0,strlen($v_char)) != $v_char){ 58 | echo " CHAR fail:\n"; 59 | echo " in: $v_char\n"; 60 | echo " out: $row->V_CHAR\n"; 61 | } 62 | if($row->V_DATE != $v_date){ 63 | echo " DATE fail\n"; 64 | echo " in: $v_date\n"; 65 | echo " out: $row->V_DATE\n"; 66 | } 67 | if($row->V_DECIMAL4_2 != $v_decimal4_2){ 68 | echo " DECIMAL4_2 fail\n"; 69 | echo " in: $v_decimal4_2\n"; 70 | echo " out: $row->V_DECIMAL4_2\n"; 71 | } 72 | if($row->V_DECIMAL4_0 != $v_decimal4_0){ 73 | echo " DECIMAL4_0 fail\n"; 74 | echo " in: $v_decimal4_0\n"; 75 | echo " out: $row->V_DECIMAL4_0\n"; 76 | } 77 | if($row->V_DECIMAL7_2 != $v_decimal7_2){ 78 | echo " DECIMAL7_2 fail\n"; 79 | echo " in: $v_decimal7_2\n"; 80 | echo " out: $row->V_DECIMAL7_2\n"; 81 | } 82 | if($row->V_DECIMAL7_0 != $v_decimal7_0){ 83 | echo " DECIMAL7_0 fail\n"; 84 | echo " in: $v_decimal7_0\n"; 85 | echo " out: $row->V_DECIMAL7_0\n"; 86 | } 87 | if($row->V_NUMERIC15_15 != $v_numeric15_15){ 88 | echo " NUMERIC15_15 fail\n"; 89 | echo " in: $v_numeric15_15\n"; 90 | echo " out: $row->V_NUMERIC15_15\n"; 91 | } 92 | if($row->V_NUMERIC15_0 != (string)$v_numeric15_0){ 93 | echo " NUMERIC15_0 fail\n"; 94 | echo " in: $v_numeric15_0\n"; 95 | echo " out: $row->V_NUMERIC15_0\n"; 96 | } 97 | 98 | if(abs($row->V_DOUBLE - $v_double) > abs($v_double / 1E15)){ 99 | echo " DOUBLE fail\n"; 100 | echo " in: $v_double\n"; 101 | echo " out: $row->V_DOUBLE\n"; 102 | } 103 | if(abs($row->V_FLOAT - $v_float) > abs($v_float / 1E7)){ 104 | echo " FLOAT fail\n"; 105 | echo " in: $v_float\n"; 106 | echo " out: $row->V_FLOAT\n"; 107 | } 108 | if($row->V_INTEGER != $v_integer){ 109 | echo " INTEGER fail\n"; 110 | echo " in: $v_integer\n"; 111 | echo " out: $row->V_INTEGER\n"; 112 | } 113 | if($row->V_SMALLINT != $v_smallint){ 114 | echo " SMALLINT fail\n"; 115 | echo " in: $v_smallint\n"; 116 | echo " out: $row->V_SMALLINT\n"; 117 | } 118 | 119 | if(substr($row->V_VARCHAR,0,strlen($v_varchar)) != $v_varchar){ 120 | echo " VARCHAR fail:\n"; 121 | echo " in: $v_varchar\n"; 122 | echo " out: $row->V_VARCHAR\n"; 123 | } 124 | 125 | ibase_free_result($sel); 126 | } /* for($iter) */ 127 | 128 | /* check for correct handling of duplicate field names */ 129 | $q = ibase_query('SELECT 1 AS id, 2 AS id, 3 AS id, 4 AS id, 5 AS id, 6 AS id, 7 AS id, 8 AS id, 9 AS id, 130 | 10 AS id, 11 AS id, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22 FROM rdb$database'); 131 | var_dump(ibase_fetch_assoc($q)); 132 | 133 | ibase_close(); 134 | echo "end of test\n"; 135 | ?> 136 | --EXPECT-- 137 | array(22) { 138 | ["ID"]=> 139 | int(1) 140 | ["ID_01"]=> 141 | int(2) 142 | ["ID_02"]=> 143 | int(3) 144 | ["ID_03"]=> 145 | int(4) 146 | ["ID_04"]=> 147 | int(5) 148 | ["ID_05"]=> 149 | int(6) 150 | ["ID_06"]=> 151 | int(7) 152 | ["ID_07"]=> 153 | int(8) 154 | ["ID_08"]=> 155 | int(9) 156 | ["ID_09"]=> 157 | int(10) 158 | ["ID_10"]=> 159 | int(11) 160 | ["CONSTANT"]=> 161 | int(12) 162 | ["CONSTANT_01"]=> 163 | int(13) 164 | ["CONSTANT_02"]=> 165 | int(14) 166 | ["CONSTANT_03"]=> 167 | int(15) 168 | ["CONSTANT_04"]=> 169 | int(16) 170 | ["CONSTANT_05"]=> 171 | int(17) 172 | ["CONSTANT_06"]=> 173 | int(18) 174 | ["CONSTANT_07"]=> 175 | int(19) 176 | ["CONSTANT_08"]=> 177 | int(20) 178 | ["CONSTANT_09"]=> 179 | int(21) 180 | ["CONSTANT_10"]=> 181 | int(22) 182 | } 183 | end of test 184 | -------------------------------------------------------------------------------- /php_ibase_includes.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 7 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 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 | 16 | | Andrew Avdeev | 17 | | Ard Biesheuvel | 18 | +----------------------------------------------------------------------+ 19 | */ 20 | 21 | #ifndef PHP_IBASE_INCLUDES_H 22 | #define PHP_IBASE_INCLUDES_H 23 | 24 | #include 25 | 26 | #ifndef SQLDA_CURRENT_VERSION 27 | #define SQLDA_CURRENT_VERSION SQLDA_VERSION1 28 | #endif 29 | 30 | #ifndef METADATALENGTH 31 | #define METADATALENGTH 68 32 | #endif 33 | 34 | #define RESET_ERRMSG do { IBG(errmsg)[0] = '\0'; IBG(sql_code) = 0; } while (0) 35 | 36 | #define IB_STATUS (IBG(status)) 37 | 38 | #ifdef IBASE_DEBUG 39 | #define IBDEBUG(a) php_printf("::: %s (%d)\n", a, __LINE__); 40 | #endif 41 | 42 | #ifndef IBDEBUG 43 | #define IBDEBUG(a) 44 | #endif 45 | 46 | extern int le_link, le_plink, le_trans; 47 | 48 | #define LE_LINK "Firebird/InterBase link" 49 | #define LE_PLINK "Firebird/InterBase persistent link" 50 | #define LE_TRANS "Firebird/InterBase transaction" 51 | 52 | #define IBASE_MSGSIZE 512 53 | #define MAX_ERRMSG (IBASE_MSGSIZE*2) 54 | 55 | #define IB_DEF_DATE_FMT "%Y-%m-%d" 56 | #define IB_DEF_TIME_FMT "%H:%M:%S" 57 | 58 | /* this value should never be > USHRT_MAX */ 59 | #define IBASE_BLOB_SEG 4096 60 | 61 | ZEND_BEGIN_MODULE_GLOBALS(ibase) 62 | ISC_STATUS status[20]; 63 | zend_resource *default_link; 64 | zend_long num_links, num_persistent; 65 | char errmsg[MAX_ERRMSG]; 66 | zend_long sql_code; 67 | ZEND_END_MODULE_GLOBALS(ibase) 68 | 69 | ZEND_EXTERN_MODULE_GLOBALS(ibase) 70 | 71 | typedef struct { 72 | isc_db_handle handle; 73 | struct tr_list *tr_list; 74 | unsigned short dialect; 75 | struct event *event_head; 76 | } ibase_db_link; 77 | 78 | typedef struct { 79 | isc_tr_handle handle; 80 | unsigned short link_cnt; 81 | unsigned long affected_rows; 82 | ibase_db_link *db_link[1]; /* last member */ 83 | } ibase_trans; 84 | 85 | typedef struct tr_list { 86 | ibase_trans *trans; 87 | struct tr_list *next; 88 | } ibase_tr_list; 89 | 90 | typedef struct { 91 | isc_blob_handle bl_handle; 92 | unsigned short type; 93 | ISC_QUAD bl_qd; 94 | } ibase_blob; 95 | 96 | typedef struct event { 97 | ibase_db_link *link; 98 | zend_resource* link_res; 99 | ISC_LONG event_id; 100 | unsigned short event_count; 101 | char **events; 102 | char *event_buffer, *result_buffer; 103 | zval callback; 104 | void *thread_ctx; 105 | struct event *event_next; 106 | enum event_state { NEW, ACTIVE, DEAD } state; 107 | } ibase_event; 108 | 109 | enum php_interbase_option { 110 | PHP_IBASE_DEFAULT = 0, 111 | PHP_IBASE_CREATE = 0, 112 | /* fetch flags */ 113 | PHP_IBASE_FETCH_BLOBS = 1, 114 | PHP_IBASE_FETCH_ARRAYS = 2, 115 | PHP_IBASE_UNIXTIME = 4, 116 | /* transaction access mode */ 117 | PHP_IBASE_WRITE = 1, 118 | PHP_IBASE_READ = 2, 119 | /* transaction isolation level */ 120 | PHP_IBASE_CONCURRENCY = 4, 121 | PHP_IBASE_COMMITTED = 8, 122 | PHP_IBASE_REC_NO_VERSION = 32, 123 | PHP_IBASE_REC_VERSION = 64, 124 | PHP_IBASE_CONSISTENCY = 16, 125 | /* transaction lock resolution */ 126 | PHP_IBASE_WAIT = 128, 127 | PHP_IBASE_NOWAIT = 256 128 | }; 129 | 130 | #define IBG(v) ZEND_MODULE_GLOBALS_ACCESSOR(ibase, v) 131 | 132 | #if defined(ZTS) && defined(COMPILE_DL_INTERBASE) 133 | ZEND_TSRMLS_CACHE_EXTERN() 134 | #endif 135 | 136 | #define BLOB_ID_LEN 18 137 | #define BLOB_ID_MASK "0x%" LL_MASK "x" 138 | 139 | #define BLOB_INPUT 1 140 | #define BLOB_OUTPUT 2 141 | 142 | #ifdef PHP_WIN32 143 | #define LL_MASK "I64" 144 | #define LL_LIT(lit) lit ## I64 145 | typedef void (__stdcall *info_func_t)(char*); 146 | #else 147 | #define LL_MASK "ll" 148 | #define LL_LIT(lit) lit ## ll 149 | typedef void (*info_func_t)(char*); 150 | #endif 151 | 152 | void _php_ibase_error(void); 153 | void _php_ibase_module_error(char *, ...) 154 | PHP_ATTRIBUTE_FORMAT(printf,1,2); 155 | 156 | /* determine if a resource is a link or transaction handle */ 157 | #define PHP_IBASE_LINK_TRANS(zv, lh, th) \ 158 | do { \ 159 | if (!zv) { \ 160 | lh = (ibase_db_link *)zend_fetch_resource2( \ 161 | IBG(default_link), "InterBase link", le_link, le_plink); \ 162 | } else { \ 163 | _php_ibase_get_link_trans(INTERNAL_FUNCTION_PARAM_PASSTHRU, zv, &lh, &th); \ 164 | } \ 165 | if (SUCCESS != _php_ibase_def_trans(lh, &th)) { RETURN_FALSE; } \ 166 | } while (0) 167 | 168 | int _php_ibase_def_trans(ibase_db_link *ib_link, ibase_trans **trans); 169 | void _php_ibase_get_link_trans(INTERNAL_FUNCTION_PARAMETERS, zval *link_id, 170 | ibase_db_link **ib_link, ibase_trans **trans); 171 | 172 | /* provided by ibase_query.c */ 173 | void php_ibase_query_minit(INIT_FUNC_ARGS); 174 | 175 | /* provided by ibase_blobs.c */ 176 | void php_ibase_blobs_minit(INIT_FUNC_ARGS); 177 | int _php_ibase_string_to_quad(char const *id, ISC_QUAD *qd); 178 | zend_string *_php_ibase_quad_to_string(ISC_QUAD const qd); 179 | int _php_ibase_blob_get(zval *return_value, ibase_blob *ib_blob, zend_ulong max_len); 180 | int _php_ibase_blob_add(zval *string_arg, ibase_blob *ib_blob); 181 | 182 | /* provided by ibase_events.c */ 183 | void php_ibase_events_minit(INIT_FUNC_ARGS); 184 | void _php_ibase_free_event(ibase_event *event); 185 | 186 | /* provided by ibase_service.c */ 187 | void php_ibase_service_minit(INIT_FUNC_ARGS); 188 | 189 | #ifndef max 190 | #define max(a,b) ((a)>(b)?(a):(b)) 191 | #endif 192 | 193 | #endif /* PHP_IBASE_INCLUDES_H */ 194 | -------------------------------------------------------------------------------- /tests/005.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | InterBase: transactions 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 210 | --EXPECTF-- 211 | default transaction: 212 | empty table 213 | --- test5 --- 214 | --- 215 | one row 216 | --- test5 --- 217 | 1 218 | --- 219 | after rollback table empty again 220 | --- test5 --- 221 | --- 222 | one row 223 | --- test5 --- 224 | 2 225 | --- 226 | one row 227 | --- test5 --- 228 | 2 229 | --- 230 | one row... again. 231 | --- test5 --- 232 | 2 233 | --- 234 | one row. 235 | --- test5 --- 236 | 2 237 | --- 238 | one row 239 | --- test5 --- 240 | 2 241 | --- 242 | two rows 243 | --- test5 --- 244 | 2 245 | 3 246 | --- 247 | two rows again 248 | --- test5 --- 249 | 2 250 | 4 251 | --- 252 | one row in second transaction 253 | --- test5 --- 254 | 2 255 | --- 256 | three rows in third transaction 257 | --- test5 --- 258 | 2 259 | 3 260 | 4 261 | --- 262 | three rows in fourth transaction with deadlock 263 | --- test5 --- 264 | 2 265 | 3 266 | 4 267 | errmsg [lock conflict on no wait transaction deadlock %a] 268 | --- 269 | three rows 270 | --- test5 --- 271 | 2 272 | 3 273 | 4 274 | --- 275 | four rows 276 | --- test5 --- 277 | 2 278 | 3 279 | 4 280 | 5 281 | --- 282 | four rows again 283 | --- test5 --- 284 | 2 285 | 3 286 | 4 287 | 5 288 | --- 289 | end of test 290 | -------------------------------------------------------------------------------- /tests/006.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | InterBase: binding (may take a while) 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | V_CHAR,0,strlen($v_char)) != $v_char) { 61 | echo " CHAR fail:\n"; 62 | echo " in: $v_char\n"; 63 | echo " out: $row->V_CHAR\n"; 64 | } 65 | if($row->V_DATE != $v_date) { 66 | echo " DATE fail\n"; 67 | echo " in: $v_date\n"; 68 | echo " out: $row->V_DATE\n"; 69 | } 70 | if($row->V_DECIMAL != $v_decimal) { 71 | echo " DECIMAL fail\n"; 72 | echo " in: $v_decimal\n"; 73 | echo " out: $row->V_DECIMAL\n"; 74 | } 75 | if(abs($row->V_DOUBLE - $v_double) > abs($v_double / 1E15)) { 76 | echo " DOUBLE fail\n"; 77 | echo " in: $v_double\n"; 78 | echo " out: $row->V_DOUBLE\n"; 79 | } 80 | if(abs($row->V_FLOAT - $v_float) > abs($v_float / 1E7)) { 81 | echo " FLOAT fail\n"; 82 | echo " in: $v_float\n"; 83 | echo " out: $row->V_FLOAT\n"; 84 | } 85 | if($row->V_INTEGER != $v_integer) { 86 | echo " INTEGER fail\n"; 87 | echo " in: $v_integer\n"; 88 | echo " out: $row->V_INTEGER\n"; 89 | } 90 | if ($row->V_NUMERIC != $v_numeric) { 91 | echo " NUMERIC fail\n"; 92 | echo " in: $v_numeric\n"; 93 | echo " out: $row->V_NUMERIC\n"; 94 | } 95 | if ($row->V_SMALLINT != $v_smallint) { 96 | echo " SMALLINT fail\n"; 97 | echo " in: $v_smallint\n"; 98 | echo " out: $row->V_SMALLINT\n"; 99 | } 100 | if ($row->V_VARCHAR != $v_varchar) { 101 | echo " VARCHAR fail:\n"; 102 | echo " in: $v_varchar\n"; 103 | echo " out: $row->V_VARCHAR\n"; 104 | } 105 | ibase_free_result($sel); 106 | }/* for($iter)*/ 107 | 108 | echo "select\n"; 109 | for($iter = 0; $iter < 3; $iter++) { 110 | /* prepare data */ 111 | $v_char = rand_str(1000); 112 | $v_date = (int)rand_number(10,0,0); 113 | $v_decimal = rand_number(12,3); 114 | $v_double = rand_number(20); 115 | $v_float = rand_number(7); 116 | $v_integer = rand_number(9,0); 117 | $v_numeric = rand_number(4,2); 118 | $v_smallint = rand_number(5) % 32767; 119 | $v_varchar = rand_str(10000); 120 | 121 | /* clear table*/ 122 | ibase_query("delete from test6"); 123 | 124 | /* make one record */ 125 | ibase_query("insert into test6 126 | (iter, v_char,v_date,v_decimal, 127 | v_integer,v_numeric,v_smallint,v_varchar) 128 | values (666, '$v_char',?,$v_decimal, $v_integer, 129 | $v_numeric, $v_smallint, '$v_varchar')",$v_date); 130 | 131 | /* test all types */ 132 | if(!($sel = ibase_query( 133 | "select iter from test6 where v_char = ?", $v_char)) || 134 | !ibase_fetch_row($sel)) { 135 | echo "CHAR fail\n"; 136 | } 137 | ibase_free_result($sel); 138 | if(!($sel = ibase_query( 139 | "select iter from test6 where v_date = ?", $v_date)) || 140 | !ibase_fetch_row($sel)) { 141 | echo "DATE fail\n"; 142 | } 143 | ibase_free_result($sel); 144 | if(!($sel = ibase_query( 145 | "select iter from test6 where v_decimal = ?", $v_decimal)) || 146 | !ibase_fetch_row($sel)) { 147 | echo "DECIMAL fail\n"; 148 | } 149 | ibase_free_result($sel); 150 | if(!($sel = ibase_query( 151 | "select iter from test6 where v_integer = ?", $v_integer)) || 152 | !ibase_fetch_row($sel)) { 153 | echo "INTEGER fail\n"; 154 | } 155 | ibase_free_result($sel); 156 | if(!($sel = ibase_query( 157 | "select iter from test6 where v_numeric = ?", $v_numeric)) || 158 | !ibase_fetch_row($sel)) { 159 | echo "NUMERIC fail\n"; 160 | } 161 | ibase_free_result($sel); 162 | if(!($sel = ibase_query( 163 | "select iter from test6 where v_smallint = ?", $v_smallint)) || 164 | !ibase_fetch_row($sel)) { 165 | echo "SMALLINT fail\n"; 166 | } 167 | ibase_free_result($sel); 168 | if(!($sel = ibase_query( 169 | "select iter from test6 where v_varchar = ?", $v_varchar)) || 170 | !ibase_fetch_row($sel)) { 171 | echo "VARCHAR fail\n"; 172 | } 173 | ibase_free_result($sel); 174 | 175 | } /*for iter*/ 176 | 177 | echo "prepare and exec insert\n"; 178 | 179 | /* prepare table */ 180 | ibase_query("delete from test6"); 181 | 182 | /* prepare query */ 183 | $query = ibase_prepare( 184 | "insert into test6 (v_integer) values (?)"); 185 | 186 | for($i = 0; $i < 10; $i++) { 187 | ibase_execute($query, $i); 188 | } 189 | 190 | out_table("test6"); 191 | 192 | ibase_free_query($query); 193 | 194 | echo "prepare and exec select\n"; 195 | 196 | /* prepare query */ 197 | $query = ibase_prepare("select * from test6 198 | where v_integer between ? and ?"); 199 | 200 | $low_border = 2; 201 | $high_border = 6; 202 | 203 | $res = ibase_execute($query, $low_border, $high_border); 204 | out_result($res, "test6"); 205 | ibase_free_result($res); 206 | 207 | $low_border = 0; 208 | $high_border = 4; 209 | $res = ibase_execute($query, $low_border, $high_border); 210 | out_result($res, "test6"); 211 | ibase_free_result($res); 212 | 213 | $res = ibase_execute($query, "5", 7.499); 214 | out_result($res, "test6"); 215 | ibase_free_result($res); 216 | 217 | ibase_free_query($query); 218 | 219 | /* test execute procedure */ 220 | $query = ibase_prepare("execute procedure add1(?)"); 221 | $res = array(); 222 | for ($i = 0; $i < 10; $i++) { 223 | $res[] = ibase_execute($query,$i); 224 | } 225 | ibase_free_query($query); 226 | foreach ($res as $r) { 227 | out_result($r, "proc add1"); 228 | ibase_free_result($r); 229 | } 230 | 231 | ibase_close(); 232 | echo "end of test\n"; 233 | ?> 234 | --EXPECT-- 235 | insert 236 | select 237 | prepare and exec insert 238 | --- test6 --- 239 | 0 240 | 1 241 | 2 242 | 3 243 | 4 244 | 5 245 | 6 246 | 7 247 | 8 248 | 9 249 | --- 250 | prepare and exec select 251 | --- test6 --- 252 | 2 253 | 3 254 | 4 255 | 5 256 | 6 257 | --- 258 | --- test6 --- 259 | 0 260 | 1 261 | 2 262 | 3 263 | 4 264 | --- 265 | --- test6 --- 266 | 5 267 | 6 268 | 7 269 | --- 270 | --- proc add1 --- 271 | 1 272 | --- 273 | --- proc add1 --- 274 | 2 275 | --- 276 | --- proc add1 --- 277 | 3 278 | --- 279 | --- proc add1 --- 280 | 4 281 | --- 282 | --- proc add1 --- 283 | 5 284 | --- 285 | --- proc add1 --- 286 | 6 287 | --- 288 | --- proc add1 --- 289 | 7 290 | --- 291 | --- proc add1 --- 292 | 8 293 | --- 294 | --- proc add1 --- 295 | 9 296 | --- 297 | --- proc add1 --- 298 | 10 299 | --- 300 | end of test 301 | -------------------------------------------------------------------------------- /tests/004.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | InterBase: BLOB test 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | V_BLOB); 40 | 41 | $blob = ''; 42 | while($piece = ibase_blob_get($bl_h, 1 + rand() % 1024)) 43 | $blob .= $piece; 44 | if($blob != $blob_str) 45 | echo " BLOB 1 fail (1)\n"; 46 | ibase_blob_close($bl_h); 47 | 48 | $bl_h = ibase_blob_open($link,$row->V_BLOB); 49 | 50 | $blob = ''; 51 | while($piece = ibase_blob_get($bl_h, 100 * 1024)) 52 | $blob .= $piece; 53 | if($blob != $blob_str) 54 | echo " BLOB 1 fail (2)\n"; 55 | ibase_blob_close($bl_h); 56 | ibase_free_result($q); 57 | unset($blob); 58 | 59 | echo "create blob 2\n"; 60 | 61 | ibase_query("INSERT INTO test4 (v_integer, v_blob) VALUES (2, ?)", $blob_str); 62 | 63 | echo "test blob 2\n"; 64 | 65 | $q = ibase_query("SELECT v_blob FROM test4 WHERE v_integer = 2"); 66 | $row = ibase_fetch_object($q,IBASE_TEXT); 67 | 68 | if($row->V_BLOB != $blob_str) 69 | echo " BLOB 2 fail\n"; 70 | ibase_free_result($q); 71 | unset($blob); 72 | 73 | 74 | echo "create blob 3\n"; 75 | 76 | $bl_h = ibase_blob_create($link); 77 | 78 | ibase_blob_add($bl_h, "+----------------------------------------------------------------------+\n"); 79 | ibase_blob_add($bl_h, "| PHP HTML Embedded Scripting Language Version 3.0 |\n"); 80 | ibase_blob_add($bl_h, "+----------------------------------------------------------------------+\n"); 81 | ibase_blob_add($bl_h, "| Copyright (c) 1997-2000 PHP Development Team (See Credits file) |\n"); 82 | ibase_blob_add($bl_h, "+----------------------------------------------------------------------+\n"); 83 | ibase_blob_add($bl_h, "| This program is free software; you can redistribute it and/or modify |\n"); 84 | ibase_blob_add($bl_h, "| it under the terms of one of the following licenses: |\n"); 85 | ibase_blob_add($bl_h, "| |\n"); 86 | ibase_blob_add($bl_h, "| A) the GNU General Public License as published by the Free Software |\n"); 87 | ibase_blob_add($bl_h, "| Foundation; either version 2 of the License, or (at your option) |\n"); 88 | ibase_blob_add($bl_h, "| any later version. |\n"); 89 | ibase_blob_add($bl_h, "| |\n"); 90 | ibase_blob_add($bl_h, "| B) the PHP License as published by the PHP Development Team and |\n"); 91 | ibase_blob_add($bl_h, "| included in the distribution in the file: LICENSE |\n"); 92 | ibase_blob_add($bl_h, "| |\n"); 93 | ibase_blob_add($bl_h, "| This program is distributed in the hope that it will be useful, |\n"); 94 | ibase_blob_add($bl_h, "| but WITHOUT ANY WARRANTY; without even the implied warranty of |\n"); 95 | ibase_blob_add($bl_h, "| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |\n"); 96 | ibase_blob_add($bl_h, "| GNU General Public License for more details. |\n"); 97 | ibase_blob_add($bl_h, "| |\n"); 98 | ibase_blob_add($bl_h, "| You should have received a copy of both licenses referred to here. |\n"); 99 | ibase_blob_add($bl_h, "| If you did not, or have any questions about PHP licensing, please |\n"); 100 | ibase_blob_add($bl_h, "| contact core@php.net. |\n"); 101 | ibase_blob_add($bl_h, "+----------------------------------------------------------------------+\n"); 102 | $bl_s = ibase_blob_close($bl_h); 103 | ibase_query("INSERT INTO test4 (v_integer, v_blob) VALUES (3, ?)", $bl_s); 104 | ibase_commit(); 105 | echo "echo blob 3\n"; 106 | 107 | $q = ibase_query("SELECT v_blob FROM test4 WHERE v_integer = 3"); 108 | $row = ibase_fetch_object($q); 109 | ibase_commit(); 110 | ibase_close(); 111 | 112 | $link = ibase_connect($test_base); 113 | ibase_blob_echo($link, $row->V_BLOB); 114 | ibase_free_result($q); 115 | 116 | echo "fetch blob 3\n"; 117 | $q = ibase_query("SELECT v_blob FROM test4 WHERE v_integer = 3"); 118 | $row = ibase_fetch_object($q,IBASE_TEXT); 119 | echo $row->V_BLOB; 120 | ibase_free_result($q); 121 | 122 | ibase_close(); 123 | unlink($name); 124 | echo "end of test\n"; 125 | ?> 126 | --EXPECT-- 127 | import blob 1 128 | test blob 1 129 | create blob 2 130 | test blob 2 131 | create blob 3 132 | echo blob 3 133 | +----------------------------------------------------------------------+ 134 | | PHP HTML Embedded Scripting Language Version 3.0 | 135 | +----------------------------------------------------------------------+ 136 | | Copyright (c) 1997-2000 PHP Development Team (See Credits file) | 137 | +----------------------------------------------------------------------+ 138 | | This program is free software; you can redistribute it and/or modify | 139 | | it under the terms of one of the following licenses: | 140 | | | 141 | | A) the GNU General Public License as published by the Free Software | 142 | | Foundation; either version 2 of the License, or (at your option) | 143 | | any later version. | 144 | | | 145 | | B) the PHP License as published by the PHP Development Team and | 146 | | included in the distribution in the file: LICENSE | 147 | | | 148 | | This program is distributed in the hope that it will be useful, | 149 | | but WITHOUT ANY WARRANTY; without even the implied warranty of | 150 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 151 | | GNU General Public License for more details. | 152 | | | 153 | | You should have received a copy of both licenses referred to here. | 154 | | If you did not, or have any questions about PHP licensing, please | 155 | | contact core@php.net. | 156 | +----------------------------------------------------------------------+ 157 | fetch blob 3 158 | +----------------------------------------------------------------------+ 159 | | PHP HTML Embedded Scripting Language Version 3.0 | 160 | +----------------------------------------------------------------------+ 161 | | Copyright (c) 1997-2000 PHP Development Team (See Credits file) | 162 | +----------------------------------------------------------------------+ 163 | | This program is free software; you can redistribute it and/or modify | 164 | | it under the terms of one of the following licenses: | 165 | | | 166 | | A) the GNU General Public License as published by the Free Software | 167 | | Foundation; either version 2 of the License, or (at your option) | 168 | | any later version. | 169 | | | 170 | | B) the PHP License as published by the PHP Development Team and | 171 | | included in the distribution in the file: LICENSE | 172 | | | 173 | | This program is distributed in the hope that it will be useful, | 174 | | but WITHOUT ANY WARRANTY; without even the implied warranty of | 175 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 176 | | GNU General Public License for more details. | 177 | | | 178 | | You should have received a copy of both licenses referred to here. | 179 | | If you did not, or have any questions about PHP licensing, please | 180 | | contact core@php.net. | 181 | +----------------------------------------------------------------------+ 182 | end of test 183 | -------------------------------------------------------------------------------- /ibase_events.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 7 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 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: Ard Biesheuvel | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #ifdef HAVE_CONFIG_H 20 | #include "config.h" 21 | #endif 22 | 23 | #include "php.h" 24 | 25 | #if HAVE_IBASE 26 | 27 | #include "php_interbase.h" 28 | #include "php_ibase_includes.h" 29 | 30 | static int le_event; 31 | 32 | static void _php_ibase_event_free(char *event_buf, char *result_buf) /* {{{ */ 33 | { 34 | isc_free(event_buf); 35 | isc_free(result_buf); 36 | } 37 | /* }}} */ 38 | 39 | void _php_ibase_free_event(ibase_event *event) /* {{{ */ 40 | { 41 | unsigned short i; 42 | 43 | event->state = DEAD; 44 | 45 | if (event->link != NULL) { 46 | ibase_event **node; 47 | 48 | zend_list_delete(event->link_res); 49 | if (event->link->handle != 0 && 50 | isc_cancel_events(IB_STATUS, &event->link->handle, &event->event_id)) { 51 | _php_ibase_error(); 52 | } 53 | 54 | /* delete this event from the link struct */ 55 | for (node = &event->link->event_head; *node != event; node = &(*node)->event_next); 56 | *node = event->event_next; 57 | } 58 | 59 | if (Z_TYPE(event->callback) != IS_UNDEF) { 60 | zval_ptr_dtor(&event->callback); 61 | ZVAL_UNDEF(&event->callback); 62 | 63 | _php_ibase_event_free(event->event_buffer,event->result_buffer); 64 | 65 | for (i = 0; i < event->event_count; ++i) { 66 | if (event->events[i]) { 67 | efree(event->events[i]); 68 | } 69 | } 70 | efree(event->events); 71 | } 72 | } 73 | /* }}} */ 74 | 75 | static void _php_ibase_free_event_rsrc(zend_resource *rsrc) /* {{{ */ 76 | { 77 | ibase_event *e = (ibase_event *) rsrc->ptr; 78 | 79 | _php_ibase_free_event(e); 80 | 81 | efree(e); 82 | } 83 | /* }}} */ 84 | 85 | void php_ibase_events_minit(INIT_FUNC_ARGS) /* {{{ */ 86 | { 87 | le_event = zend_register_list_destructors_ex(_php_ibase_free_event_rsrc, NULL, 88 | "interbase event", module_number); 89 | } 90 | /* }}} */ 91 | 92 | static void _php_ibase_event_block(ibase_db_link *ib_link, unsigned short count, /* {{{ */ 93 | char **events, unsigned short *l, char **event_buf, char **result_buf) 94 | { 95 | ISC_STATUS dummy_result[20]; 96 | ISC_ULONG dummy_count[15]; 97 | 98 | /** 99 | * Unfortunately, there's no clean and portable way in C to pass arguments to 100 | * a variadic function if you don't know the number of arguments at compile time. 101 | * (And even if there were a way, the Interbase API doesn't provide a version of 102 | * this function that takes a va_list as an argument) 103 | * 104 | * In this case, the number of arguments is limited to 18 by the underlying API, 105 | * so we can work around it. 106 | */ 107 | 108 | *l = (unsigned short) isc_event_block(event_buf, result_buf, count, events[0], 109 | events[1], events[2], events[3], events[4], events[5], events[6], events[7], 110 | events[8], events[9], events[10], events[11], events[12], events[13], events[14]); 111 | 112 | /** 113 | * Currently, this is the only way to correctly initialize an event buffer. 114 | * This is clearly something that should be fixed, cause the semantics of 115 | * isc_wait_for_event() indicate that it blocks until an event occurs. 116 | * If the Firebird people ever fix this, these lines should be removed, 117 | * otherwise, events will have to fire twice before ibase_wait_event() returns. 118 | */ 119 | 120 | isc_wait_for_event(dummy_result, &ib_link->handle, *l, *event_buf, *result_buf); 121 | isc_event_counts(dummy_count, *l, *event_buf, *result_buf); 122 | } 123 | /* }}} */ 124 | 125 | /* {{{ proto string ibase_wait_event([resource link_identifier,] string event [, string event [, ...]]) 126 | Waits for any one of the passed Interbase events to be posted by the database, and returns its name */ 127 | PHP_FUNCTION(ibase_wait_event) 128 | { 129 | zval *args; 130 | ibase_db_link *ib_link; 131 | int num_args; 132 | char *event_buffer, *result_buffer, *events[15]; 133 | unsigned short i = 0, event_count = 0, buffer_size; 134 | ISC_ULONG occurred_event[15]; 135 | 136 | RESET_ERRMSG; 137 | 138 | /* no more than 15 events */ 139 | if (ZEND_NUM_ARGS() < 1 || ZEND_NUM_ARGS() > 16) { 140 | WRONG_PARAM_COUNT; 141 | } 142 | 143 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &num_args) == FAILURE) { 144 | return; 145 | } 146 | 147 | if (Z_TYPE(args[0]) == IS_RESOURCE) { 148 | if ((ib_link = (ibase_db_link *)zend_fetch_resource2_ex(&args[0], "InterBase link", le_link, le_plink)) == NULL) { 149 | RETURN_FALSE; 150 | } 151 | i = 1; 152 | } else { 153 | if (ZEND_NUM_ARGS() > 15) { 154 | WRONG_PARAM_COUNT; 155 | } 156 | if ((ib_link = (ibase_db_link *)zend_fetch_resource2(IBG(default_link), "InterBase link", le_link, le_plink)) == NULL) { 157 | RETURN_FALSE; 158 | } 159 | } 160 | 161 | for (; i < ZEND_NUM_ARGS(); ++i) { 162 | convert_to_string_ex(&args[i]); 163 | events[event_count++] = Z_STRVAL(args[i]); 164 | } 165 | 166 | /* fills the required data structure with information about the events */ 167 | _php_ibase_event_block(ib_link, event_count, events, &buffer_size, &event_buffer, &result_buffer); 168 | 169 | /* now block until an event occurs */ 170 | if (isc_wait_for_event(IB_STATUS, &ib_link->handle, buffer_size, event_buffer, result_buffer)) { 171 | _php_ibase_error(); 172 | _php_ibase_event_free(event_buffer,result_buffer); 173 | RETURN_FALSE; 174 | } 175 | 176 | /* find out which event occurred */ 177 | isc_event_counts(occurred_event, buffer_size, event_buffer, result_buffer); 178 | for (i = 0; i < event_count; ++i) { 179 | if (occurred_event[i]) { 180 | zend_string *result = zend_string_init(events[i], strlen(events[i]), 0); 181 | _php_ibase_event_free(event_buffer,result_buffer); 182 | RETURN_STR(result); 183 | } 184 | } 185 | 186 | /* If we reach this line, isc_wait_for_event() did return, but we don't know 187 | which event fired. */ 188 | _php_ibase_event_free(event_buffer,result_buffer); 189 | RETURN_FALSE; 190 | } 191 | /* }}} */ 192 | 193 | #if FB_API_VER >= 20 194 | #define PHP_ISC_CALLBACK ISC_EVENT_CALLBACK 195 | static ISC_EVENT_CALLBACK _php_ibase_callback(ibase_event *event, /* {{{ */ 196 | ISC_USHORT buffer_size, ISC_UCHAR *result_buf) 197 | #else 198 | #define PHP_ISC_CALLBACK isc_callback 199 | static isc_callback _php_ibase_callback(ibase_event *event, /* {{{ */ 200 | unsigned short buffer_size, char *result_buf) 201 | #endif 202 | { 203 | /* this function is called asynchronously by the Interbase client library. */ 204 | TSRMLS_FETCH_FROM_CTX(event->thread_ctx); 205 | 206 | /** 207 | * The callback function is called when the event is first registered and when the event 208 | * is cancelled. I consider this is a bug. By clearing event->callback first and setting 209 | * it to -1 later, we make sure nothing happens if no event was actually posted. 210 | */ 211 | switch (event->state) { 212 | unsigned short i; 213 | ISC_ULONG occurred_event[15]; 214 | zval return_value, args[2]; 215 | 216 | default: /* == DEAD */ 217 | break; 218 | case ACTIVE: 219 | /* copy the updated results into the result buffer */ 220 | memcpy(event->result_buffer, result_buf, buffer_size); 221 | 222 | ZVAL_RES(&args[1], event->link_res); 223 | 224 | /* find out which event occurred */ 225 | isc_event_counts(occurred_event, buffer_size, event->event_buffer, event->result_buffer); 226 | for (i = 0; i < event->event_count; ++i) { 227 | if (occurred_event[i]) { 228 | ZVAL_STRING(&args[0], event->events[i]); 229 | //efree(event->events[i]); 230 | break; 231 | } 232 | } 233 | 234 | /* call the callback provided by the user */ 235 | if (SUCCESS != call_user_function(NULL, NULL, 236 | &event->callback, &return_value, 2, args)) { 237 | _php_ibase_module_error("Error calling callback %s", Z_STRVAL(event->callback)); 238 | break; 239 | } 240 | 241 | if (Z_TYPE(return_value) == IS_FALSE) { 242 | event->state = DEAD; 243 | break; 244 | } 245 | case NEW: 246 | /* re-register the event */ 247 | if (isc_que_events(IB_STATUS, &event->link->handle, &event->event_id, buffer_size, 248 | event->event_buffer,(PHP_ISC_CALLBACK)_php_ibase_callback, (void *)event)) { 249 | 250 | _php_ibase_error(); 251 | } 252 | event->state = ACTIVE; 253 | } 254 | return 0; 255 | } 256 | /* }}} */ 257 | 258 | /* {{{ proto resource ibase_set_event_handler([resource link_identifier,] callback handler, string event [, string event [, ...]]) 259 | Register the callback for handling each of the named events */ 260 | PHP_FUNCTION(ibase_set_event_handler) 261 | { 262 | /** 263 | * The callback passed to this function should take an event name (string) and a 264 | * link resource id (int) as arguments. The value returned from the function is 265 | * used to determine if the event handler should remain set. 266 | */ 267 | zval *args, *cb_arg; 268 | ibase_db_link *ib_link; 269 | ibase_event *event; 270 | unsigned short i = 1, buffer_size; 271 | int num_args; 272 | zend_resource *link_res; 273 | 274 | RESET_ERRMSG; 275 | 276 | /* Minimum and maximum number of arguments allowed */ 277 | if (ZEND_NUM_ARGS() < 2 || ZEND_NUM_ARGS() > 17) { 278 | WRONG_PARAM_COUNT; 279 | } 280 | 281 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &num_args) == FAILURE) { 282 | return; 283 | } 284 | 285 | /* get a working link */ 286 | if (Z_TYPE(args[0]) != IS_STRING) { 287 | /* resource, callback, event_1 [, ... event_15] 288 | * No more than 15 events 289 | */ 290 | if (ZEND_NUM_ARGS() < 3 || ZEND_NUM_ARGS() > 17) { 291 | WRONG_PARAM_COUNT; 292 | } 293 | 294 | cb_arg = &args[1]; 295 | i = 2; 296 | 297 | if ((ib_link = (ibase_db_link *)zend_fetch_resource2_ex(&args[0], "InterBase link", le_link, le_plink)) == NULL) { 298 | RETURN_FALSE; 299 | } 300 | 301 | link_res = Z_RES(args[0]); 302 | 303 | } else { 304 | /* callback, event_1 [, ... event_15] 305 | * No more than 15 events 306 | */ 307 | if (ZEND_NUM_ARGS() < 2 || ZEND_NUM_ARGS() > 16) { 308 | WRONG_PARAM_COUNT; 309 | } 310 | 311 | cb_arg = &args[0]; 312 | 313 | if ((ib_link = (ibase_db_link *)zend_fetch_resource2(IBG(default_link), "InterBase link", le_link, le_plink)) == NULL) { 314 | RETURN_FALSE; 315 | } 316 | link_res = IBG(default_link); 317 | } 318 | 319 | /* get the callback */ 320 | if (!zend_is_callable(cb_arg, 0, NULL)) { 321 | zend_string *cb_name = zend_get_callable_name(cb_arg); 322 | _php_ibase_module_error("Callback argument %s is not a callable function", ZSTR_VAL(cb_name)); 323 | zend_string_release_ex(cb_name, 0); 324 | RETURN_FALSE; 325 | } 326 | 327 | /* allocate the event resource */ 328 | event = (ibase_event *) safe_emalloc(sizeof(ibase_event), 1, 0); 329 | TSRMLS_SET_CTX(event->thread_ctx); 330 | event->link_res = link_res; 331 | GC_ADDREF(link_res); 332 | event->link = ib_link; 333 | event->event_count = 0; 334 | event->state = NEW; 335 | event->events = (char **) safe_emalloc(sizeof(char *), 15, 0); 336 | 337 | ZVAL_DUP(&event->callback, cb_arg); 338 | 339 | for (; i < 15; ++i) { 340 | if (i < ZEND_NUM_ARGS()) { 341 | convert_to_string_ex(&args[i]); 342 | event->events[event->event_count++] = estrdup(Z_STRVAL(args[i])); 343 | } else { 344 | event->events[i] = NULL; 345 | } 346 | } 347 | 348 | /* fills the required data structure with information about the events */ 349 | _php_ibase_event_block(ib_link, event->event_count, event->events, 350 | &buffer_size, &event->event_buffer, &event->result_buffer); 351 | 352 | /* now register the events with the Interbase API */ 353 | if (isc_que_events(IB_STATUS, &ib_link->handle, &event->event_id, buffer_size, 354 | event->event_buffer,(PHP_ISC_CALLBACK)_php_ibase_callback, (void *)event)) { 355 | 356 | _php_ibase_error(); 357 | efree(event); 358 | RETURN_FALSE; 359 | } 360 | 361 | event->event_next = ib_link->event_head; 362 | ib_link->event_head = event; 363 | 364 | RETVAL_RES(zend_register_resource(event, le_event)); 365 | Z_TRY_ADDREF_P(return_value); 366 | } 367 | /* }}} */ 368 | 369 | /* {{{ proto bool ibase_free_event_handler(resource event) 370 | Frees the event handler set by ibase_set_event_handler() */ 371 | PHP_FUNCTION(ibase_free_event_handler) 372 | { 373 | zval *event_arg; 374 | 375 | RESET_ERRMSG; 376 | 377 | if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "r", &event_arg)) { 378 | ibase_event *event; 379 | 380 | event = (ibase_event *)zend_fetch_resource_ex(event_arg, "Interbase event", le_event); 381 | 382 | event->state = DEAD; 383 | 384 | zend_list_delete(Z_RES_P(event_arg)); 385 | RETURN_TRUE; 386 | } else { 387 | RETURN_FALSE; 388 | } 389 | } 390 | /* }}} */ 391 | 392 | #endif /* HAVE_IBASE */ 393 | -------------------------------------------------------------------------------- /php_ibase_udf.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 7 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Author: Ard Biesheuvel | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | /** 20 | * This UDF library adds the ability to call PHP functions from SQL 21 | * statements. Because of SQL's strong typing, you will have to declare 22 | * an external function for every combination { output type, #args } that 23 | * your application requires. 24 | * 25 | * Declare the functions like this: 26 | * 27 | * DECLARE EXTERNAL FUNCTION CALL_PHP1 28 | * CSTRING(xx), 29 | * BY DESCRIPTOR, 30 | * INTEGER BY DESCRIPTOR 31 | * RETURNS PARAMETER 2 32 | * ENTRY_POINT 'udf_call_php1' MODULE_NAME 'php_ibase_udf' 33 | * 34 | * DECLARE EXTERNAL FUNCTION CALL_PHP2 35 | * CSTRING(xx), 36 | * BY DESCRIPTOR, 37 | * INTEGER BY DESCRIPTOR, 38 | * INTEGER BY DESCRIPTOR 39 | * RETURNS PARAMETER 2 40 | * ENTRY_POINT 'udf_call_php2' MODULE_NAME 'php_ibase_udf' 41 | * 42 | * ... and so on. [for up to 8 input arguments] 43 | * 44 | * The first input parameter contains the name of the PHP function you want 45 | * to call. The second argument is the result. (omit this argument when calling 46 | * the function) The return type of the function is the declared type of the 47 | * result. The value returned from the PHP function being called will 48 | * automatically be converted if necessary. 49 | * The arguments should have their types declared as well, but you're free 50 | * to pass arguments of other types instead. They will be converted to the 51 | * best matching PHP type before being passed to the PHP function. 52 | * 53 | * The declared functions can be called from SQL like: 54 | * 55 | * SELECT * FROM WHERE CALL_PHP1('soundex',) NOT LIKE ? 56 | * or 57 | * UPDATE
SET = CALL_PHP1('ucwords',) 58 | * 59 | * Additionally, there's a function 'exec_php' which allows the contents 60 | * of text BLOB fields to be parsed and executed by PHP. This is most useful 61 | * for declaring functions that can then be called with CALL_PHPx. 62 | * 63 | * DECLARE EXTERNAL FUNCTION EXEC_PHP 64 | * BLOB, 65 | * INTEGER BY DESCRIPTOR, 66 | * SMALLINT 67 | * RETURNS PARAMETER 2 68 | * ENTRY_POINT 'exec_php' MODULE_NAME 'php_ibase_udf' 69 | * 70 | * The function will return 1 if execution succeeded and 0 if an error 71 | * occurred. The result that is returned from the executed PHP code is 72 | * ignored. You can pass a non-zero value as second argument to force 73 | * the embedded PHP engine to re-initialise. 74 | * 75 | * There are several ways to build this library, depending on which way the 76 | * database is accessed. If you're using the classic server on a local 77 | * connection, you should compile the library like this: 78 | * 79 | * gcc -shared `php-config --includes` `php-config --ldflags` \ 80 | * `php-config --libs` -o php_ibase_udf.so php_ibase_udf.c 81 | * 82 | * If you connect to the classic server by TCP/IP, you should build the 83 | * PHP embedded static library and link against that. 84 | * 85 | * gcc -shared `php-config --includes` `php-config --ldflags` \ 86 | * `php-config --libs` -o php_ibase_udf.so php_ibase_udf.c \ 87 | * /usr/lib/libphp7.a 88 | * 89 | * If you use the super server, you should also link against the embedded 90 | * library, but be sure to enable thread safety, as the super server is 91 | * multi-threaded. After building, copy the resulting file to the folder 92 | * where your database expects to find its UDFs. 93 | */ 94 | 95 | #include "zend.h" 96 | #include "zend_API.h" 97 | 98 | #include "php.h" 99 | #include "php_ini.h" 100 | 101 | #include "ibase.h" 102 | 103 | #define min(a,b) ((a)<(b)?(a):(b)) 104 | 105 | #ifdef PHP_WIN32 106 | #define LL_LIT(lit) lit ## I64 107 | #else 108 | #define LL_LIT(lit) lit ## ll 109 | #endif 110 | 111 | #ifdef ZTS 112 | # include 113 | 114 | static void ***tsrm_ls; 115 | pthread_mutex_t mtx_res = PTHREAD_MUTEX_INITIALIZER; 116 | 117 | #define LOCK() do { pthread_mutex_lock(&mtx_res); } while (0) 118 | #define UNLOCK() do { pthread_mutex_unlock(&mtx_res); } while (0) 119 | #else 120 | #define LOCK() 121 | #define UNLOCK() 122 | #endif 123 | 124 | #ifdef PHP_EMBED 125 | # include "php_main.h" 126 | # include "sapi/embed/php_embed.h" 127 | 128 | static void __attribute__((constructor)) init() 129 | { 130 | php_embed_init(0, NULL P); 131 | } 132 | 133 | static void __attribute__((destructor)) fini() 134 | { 135 | php_embed_shutdown(); 136 | } 137 | 138 | #endif 139 | 140 | /** 141 | * Gets the contents of the BLOB b and offers it to Zend for parsing/execution 142 | */ 143 | void exec_php(BLOBCALLBACK b, PARAMDSC *res, ISC_SHORT *init) 144 | { 145 | int result, remaining = b->blob_total_length, i = 0; 146 | char *code = pemalloc(remaining+1, 1); 147 | ISC_USHORT read; 148 | 149 | for (code[remaining] = '\0'; remaining > 0; remaining -= read) 150 | b->blob_get_segment(b->blob_handle, &code[i++<<16],min(0x10000,remaining), &read); 151 | 152 | LOCK(); 153 | 154 | switch (init && *init) { 155 | 156 | default: 157 | #ifdef PHP_EMBED 158 | php_request_shutdown(NULL); 159 | if (FAILURE == (result = php_request_startup())) { 160 | break; 161 | } 162 | case 0: 163 | #endif 164 | /* feed it to the parser */ 165 | zend_first_try { 166 | result = zend_eval_stringl(code, b->blob_total_length, NULL, "Firebird Embedded PHP engine"); 167 | } zend_end_try(); 168 | } 169 | 170 | UNLOCK(); 171 | 172 | free(code); 173 | 174 | res->dsc_dtype = dtype_long; 175 | *(ISC_LONG*)res->dsc_address = (result == SUCCESS); 176 | } 177 | 178 | static ISC_INT64 const scales[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 100000000, 1000000000, 179 | 1000000000, LL_LIT(10000000000),LL_LIT(100000000000),LL_LIT(10000000000000),LL_LIT(100000000000000), 180 | LL_LIT(1000000000000000),LL_LIT(1000000000000000),LL_LIT(1000000000000000000) }; 181 | 182 | 183 | static void call_php(char *name, PARAMDSC *r, int argc, PARAMDSC **argv) 184 | { 185 | do { 186 | zval callback, args[4], return_value; 187 | PARAMVARY *res = (PARAMVARY*)r->dsc_address; 188 | int i; 189 | 190 | ZVAL_STRING(&callback, name); 191 | 192 | LOCK(); 193 | 194 | /* check if the requested function exists */ 195 | if (!zend_is_callable(&callback, 0, NULL)) { 196 | break; 197 | } 198 | 199 | UNLOCK(); 200 | 201 | /* create the argument array */ 202 | for (i = 0; i < argc; ++i) { 203 | 204 | /* test arg for null */ 205 | if (argv[i]->dsc_flags & DSC_null) { 206 | ZVAL_NULL(&args[i]); 207 | continue; 208 | } 209 | 210 | switch (argv[i]->dsc_dtype) { 211 | ISC_INT64 l; 212 | struct tm t; 213 | char const *fmt; 214 | char d[64]; 215 | 216 | case dtype_cstring: 217 | //??? 218 | ZVAL_STRING(&args[i], (char*)argv[i]->dsc_address); 219 | break; 220 | 221 | case dtype_text: 222 | //??? 223 | ZVAL_STRINGL(&args[i], (char*)argv[i]->dsc_address, argv[i]->dsc_length); 224 | break; 225 | 226 | case dtype_varying: 227 | //??? 228 | ZVAL_STRINGL(&args[i], ((PARAMVARY*)argv[i]->dsc_address)->vary_string, 229 | ((PARAMVARY*)argv[i]->dsc_address)->vary_length); 230 | break; 231 | 232 | case dtype_short: 233 | if (argv[i]->dsc_scale == 0) { 234 | ZVAL_LONG(&args[i], *(short*)argv[i]->dsc_address); 235 | } else { 236 | ZVAL_DOUBLE(&args[i], 237 | ((double)*(short*)argv[i]->dsc_address)/scales[-argv[i]->dsc_scale]); 238 | } 239 | break; 240 | 241 | case dtype_long: 242 | if (argv[i]->dsc_scale == 0) { 243 | ZVAL_LONG(&args[i], *(ISC_LONG*)argv[i]->dsc_address); 244 | } else { 245 | ZVAL_DOUBLE(&args[i], 246 | ((double)*(ISC_LONG*)argv[i]->dsc_address)/scales[-argv[i]->dsc_scale]); 247 | } 248 | break; 249 | 250 | case dtype_int64: 251 | l = *(ISC_INT64*)argv[i]->dsc_address; 252 | 253 | if (argv[i]->dsc_scale == 0 && l <= ZEND_LONG_MAX && l >= ZEND_LONG_MIN) { 254 | ZVAL_LONG(&args[i], (zend_long)l); 255 | } else { 256 | ZVAL_DOUBLE(&args[i], ((double)l)/scales[-argv[i]->dsc_scale]); 257 | } 258 | break; 259 | 260 | case dtype_real: 261 | ZVAL_DOUBLE(&args[i], *(float*)argv[i]->dsc_address); 262 | break; 263 | 264 | case dtype_double: 265 | ZVAL_DOUBLE(&args[i], *(double*)argv[i]->dsc_address); 266 | break; 267 | 268 | case dtype_sql_date: 269 | isc_decode_sql_date((ISC_DATE*)argv[i]->dsc_address, &t); 270 | ZVAL_STRINGL(&args[i], d, strftime(d, sizeof(d), INI_STR("ibase.dateformat"), &t),1); 271 | break; 272 | 273 | case dtype_sql_time: 274 | isc_decode_sql_time((ISC_TIME*)argv[i]->dsc_address, &t); 275 | ZVAL_STRINGL(&args[i], d, strftime(d, sizeof(d), INI_STR("ibase.timeformat"), &t),1); 276 | break; 277 | 278 | case dtype_timestamp: 279 | isc_decode_timestamp((ISC_TIMESTAMP*)argv[i]->dsc_address, &t); 280 | ZVAL_STRINGL(&args[i], d, strftime(d, sizeof(d), INI_STR("ibase.timestampformat"), &t)); 281 | break; 282 | } 283 | } 284 | 285 | LOCK(); 286 | 287 | /* now call the function */ 288 | if (FAILURE == call_user_function(NULL, NULL, 289 | &callback, &return_value, argc, args)) { 290 | UNLOCK(); 291 | break; 292 | } 293 | 294 | UNLOCK(); 295 | 296 | for (i = 0; i < argc; ++i) { 297 | switch (argv[i]->dsc_dtype) { 298 | case dtype_sql_date: 299 | case dtype_sql_time: 300 | case dtype_timestamp: 301 | zval_ptr_dtor_nogc(&args[i]); 302 | } 303 | } 304 | 305 | zval_ptr_dtor_str(&callback); 306 | 307 | /* return whatever type we got back from the callback: let DB handle conversion */ 308 | switch (Z_TYPE(return_value)) { 309 | 310 | case IS_LONG: 311 | r->dsc_dtype = dtype_long; 312 | *(zend_long*)r->dsc_address = Z_LVAL(return_value); 313 | r->dsc_length = sizeof(zend_long); 314 | break; 315 | 316 | case IS_DOUBLE: 317 | r->dsc_dtype = dtype_double; 318 | *(double*)r->dsc_address = Z_DVAL(return_value); 319 | r->dsc_length = sizeof(double); 320 | break; 321 | 322 | case IS_NULL: 323 | r->dsc_flags |= DSC_null; 324 | break; 325 | 326 | default: 327 | convert_to_string(&return_value); 328 | 329 | case IS_STRING: 330 | r->dsc_dtype = dtype_varying; 331 | memcpy(res->vary_string, Z_STRVAL(return_value), 332 | (res->vary_length = min(r->dsc_length-2,Z_STRLEN(return_value)))); 333 | r->dsc_length = res->vary_length+2; 334 | break; 335 | } 336 | 337 | zval_ptr_dtor(&return_value); 338 | 339 | return; 340 | 341 | } while (0); 342 | 343 | /** 344 | * If we end up here, we should report an error back to the DB engine, but 345 | * that's not possible. We can however report it back to PHP. 346 | */ 347 | LOCK(); 348 | php_error_docref(NULL, E_WARNING, "Error calling function '%s' from database", name); 349 | UNLOCK(); 350 | } 351 | 352 | 353 | /* Entry points for the DB engine */ 354 | 355 | void udf_call_php1(char *name, PARAMDSC *r, PARAMDSC *arg1) 356 | { 357 | PARAMDSC *args[1] = { arg1 }; 358 | call_php(name, r, 1, args); 359 | } 360 | 361 | void udf_call_php2(char *name, PARAMDSC *r, PARAMDSC *arg1, PARAMDSC *arg2) 362 | { 363 | PARAMDSC *args[2] = { arg1, arg2 }; 364 | call_php(name, r, 2, args); 365 | } 366 | 367 | void udf_call_php3(char *name, PARAMDSC *r, PARAMDSC *arg1, PARAMDSC *arg2, PARAMDSC *arg3) 368 | { 369 | PARAMDSC *args[3] = { arg1, arg2, arg3 }; 370 | call_php(name, r, 3, args); 371 | } 372 | 373 | void udf_call_php4(char *name, PARAMDSC *r, PARAMDSC *arg1, PARAMDSC *arg2, PARAMDSC *arg3, 374 | PARAMDSC *arg4) 375 | { 376 | PARAMDSC *args[4] = { arg1, arg2, arg3, arg4 }; 377 | call_php(name, r, 4, args); 378 | } 379 | 380 | void udf_call_php5(char *name, PARAMDSC *r, PARAMDSC *arg1, PARAMDSC *arg2, PARAMDSC *arg3, 381 | PARAMDSC *arg4, PARAMDSC *arg5) 382 | { 383 | PARAMDSC *args[5] = { arg1, arg2, arg3, arg4, arg5 }; 384 | call_php(name, r, 5, args); 385 | } 386 | 387 | void udf_call_php6(char *name, PARAMDSC *r, PARAMDSC *arg1, PARAMDSC *arg2, PARAMDSC *arg3, 388 | PARAMDSC *arg4, PARAMDSC *arg5, PARAMDSC *arg6) 389 | { 390 | PARAMDSC *args[6] = { arg1, arg2, arg3, arg4, arg5, arg6 }; 391 | call_php(name, r, 6, args); 392 | } 393 | 394 | void udf_call_php7(char *name, PARAMDSC *r, PARAMDSC *arg1, PARAMDSC *arg2, PARAMDSC *arg3, 395 | PARAMDSC *arg4, PARAMDSC *arg5, PARAMDSC *arg6, PARAMDSC *arg7) 396 | { 397 | PARAMDSC *args[7] = { arg1, arg2, arg3, arg4, arg5, arg6, arg7 }; 398 | call_php(name, r, 7, args); 399 | } 400 | 401 | void udf_call_php8(char *name, PARAMDSC *r, PARAMDSC *arg1, PARAMDSC *arg2, PARAMDSC *arg3, 402 | PARAMDSC *arg4, PARAMDSC *arg5, PARAMDSC *arg6, PARAMDSC *arg7, PARAMDSC *arg8) 403 | { 404 | PARAMDSC *args[8] = { arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 }; 405 | call_php(name, r, 8, args); 406 | } 407 | -------------------------------------------------------------------------------- /ibase_blobs.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 7 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 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: Ard Biesheuvel | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #ifdef HAVE_CONFIG_H 20 | #include "config.h" 21 | #endif 22 | 23 | #include "php.h" 24 | 25 | #if HAVE_IBASE 26 | 27 | #include "php_interbase.h" 28 | #include "php_ibase_includes.h" 29 | 30 | #define BLOB_CLOSE 1 31 | #define BLOB_CANCEL 2 32 | 33 | #define PARSE_PARAMETERS \ 34 | switch (ZEND_NUM_ARGS()) { \ 35 | default: \ 36 | WRONG_PARAM_COUNT; \ 37 | case 1: \ 38 | if (FAILURE == zend_parse_parameters(1, "s", &blob_id, &blob_id_len)) { \ 39 | RETURN_FALSE; \ 40 | } \ 41 | break; \ 42 | case 2: \ 43 | if (FAILURE == zend_parse_parameters(2, "rs", &link, &blob_id, &blob_id_len)) { \ 44 | RETURN_FALSE; \ 45 | } \ 46 | break; \ 47 | } \ 48 | 49 | static int le_blob; 50 | 51 | static void _php_ibase_free_blob(zend_resource *rsrc) /* {{{ */ 52 | { 53 | ibase_blob *ib_blob = (ibase_blob *)rsrc->ptr; 54 | 55 | if (ib_blob->bl_handle != 0) { /* blob open*/ 56 | if (isc_cancel_blob(IB_STATUS, &ib_blob->bl_handle)) { 57 | _php_ibase_module_error("You can lose data. Close any blob after reading from or " 58 | "writing to it. Use ibase_blob_close() before calling ibase_close()"); 59 | } 60 | } 61 | efree(ib_blob); 62 | } 63 | /* }}} */ 64 | 65 | void php_ibase_blobs_minit(INIT_FUNC_ARGS) /* {{{ */ 66 | { 67 | le_blob = zend_register_list_destructors_ex(_php_ibase_free_blob, NULL, 68 | "interbase blob", module_number); 69 | } 70 | /* }}} */ 71 | 72 | int _php_ibase_string_to_quad(char const *id, ISC_QUAD *qd) /* {{{ */ 73 | { 74 | /* shortcut for most common case */ 75 | if (sizeof(ISC_QUAD) == sizeof(ISC_UINT64)) { 76 | return sscanf(id, BLOB_ID_MASK, (ISC_UINT64 *) qd); 77 | } else { 78 | ISC_UINT64 res; 79 | if (sscanf(id, BLOB_ID_MASK, &res)) { 80 | qd->gds_quad_high = (ISC_LONG) (res >> 0x20); 81 | qd->gds_quad_low = (ISC_LONG) (res & 0xFFFFFFFF); 82 | return 1; 83 | } 84 | return 0; 85 | } 86 | } 87 | /* }}} */ 88 | 89 | zend_string *_php_ibase_quad_to_string(ISC_QUAD const qd) /* {{{ */ 90 | { 91 | /* shortcut for most common case */ 92 | if (sizeof(ISC_QUAD) == sizeof(ISC_UINT64)) { 93 | return strpprintf(BLOB_ID_LEN+1, "0x%0*" LL_MASK "x", 16, *(ISC_UINT64*)(void *) &qd); 94 | } else { 95 | ISC_UINT64 res = ((ISC_UINT64) qd.gds_quad_high << 0x20) | qd.gds_quad_low; 96 | return strpprintf(BLOB_ID_LEN+1, "0x%0*" LL_MASK "x", 16, res); 97 | } 98 | } 99 | /* }}} */ 100 | 101 | typedef struct { /* {{{ */ 102 | ISC_LONG max_segment; /* Length of longest segment */ 103 | ISC_LONG num_segments; /* Total number of segments */ 104 | ISC_LONG total_length; /* Total length of blob */ 105 | int bl_stream; /* blob is stream ? */ 106 | /* }}} */ 107 | } IBASE_BLOBINFO; 108 | 109 | int _php_ibase_blob_get(zval *return_value, ibase_blob *ib_blob, zend_ulong max_len) /* {{{ */ 110 | { 111 | if (ib_blob->bl_qd.gds_quad_high || ib_blob->bl_qd.gds_quad_low) { /*not null ?*/ 112 | 113 | ISC_STATUS stat; 114 | zend_string *bl_data; 115 | zend_ulong cur_len; 116 | unsigned short seg_len; 117 | 118 | bl_data = zend_string_safe_alloc(1, max_len, 0, 0); 119 | 120 | for (cur_len = stat = 0; (stat == 0 || stat == isc_segment) && cur_len < max_len; cur_len += seg_len) { 121 | 122 | unsigned short chunk_size = (max_len-cur_len) > USHRT_MAX ? USHRT_MAX 123 | : (unsigned short)(max_len-cur_len); 124 | 125 | stat = isc_get_segment(IB_STATUS, &ib_blob->bl_handle, &seg_len, chunk_size, &ZSTR_VAL(bl_data)[cur_len]); 126 | } 127 | 128 | if (IB_STATUS[0] == 1 && (stat != 0 && stat != isc_segstr_eof && stat != isc_segment)) { 129 | zend_string_free(bl_data); 130 | _php_ibase_error(); 131 | return FAILURE; 132 | } 133 | ZSTR_VAL(bl_data)[cur_len] = '\0'; 134 | ZSTR_LEN(bl_data) = cur_len; 135 | RETVAL_NEW_STR(bl_data); 136 | } else { /* null blob */ 137 | RETVAL_EMPTY_STRING(); /* empty string */ 138 | } 139 | return SUCCESS; 140 | } 141 | /* }}} */ 142 | 143 | int _php_ibase_blob_add(zval *string_arg, ibase_blob *ib_blob) /* {{{ */ 144 | { 145 | zend_ulong put_cnt = 0, rem_cnt; 146 | unsigned short chunk_size; 147 | 148 | convert_to_string_ex(string_arg); 149 | 150 | for (rem_cnt = Z_STRLEN_P(string_arg); rem_cnt > 0; rem_cnt -= chunk_size) { 151 | 152 | chunk_size = rem_cnt > USHRT_MAX ? USHRT_MAX : (unsigned short)rem_cnt; 153 | 154 | if (isc_put_segment(IB_STATUS, &ib_blob->bl_handle, chunk_size, &Z_STRVAL_P(string_arg)[put_cnt] )) { 155 | _php_ibase_error(); 156 | return FAILURE; 157 | } 158 | put_cnt += chunk_size; 159 | } 160 | return SUCCESS; 161 | } 162 | /* }}} */ 163 | 164 | static int _php_ibase_blob_info(isc_blob_handle bl_handle, IBASE_BLOBINFO *bl_info) /* {{{ */ 165 | { 166 | static char bl_items[] = { 167 | isc_info_blob_num_segments, 168 | isc_info_blob_max_segment, 169 | isc_info_blob_total_length, 170 | isc_info_blob_type 171 | }; 172 | 173 | char bl_inf[sizeof(zend_long)*8], *p; 174 | 175 | bl_info->max_segment = 0; 176 | bl_info->num_segments = 0; 177 | bl_info->total_length = 0; 178 | bl_info->bl_stream = 0; 179 | 180 | if (isc_blob_info(IB_STATUS, &bl_handle, sizeof(bl_items), bl_items, sizeof(bl_inf), bl_inf)) { 181 | _php_ibase_error(); 182 | return FAILURE; 183 | } 184 | 185 | for (p = bl_inf; *p != isc_info_end && p < bl_inf + sizeof(bl_inf);) { 186 | unsigned short item_len; 187 | int item = *p++; 188 | 189 | item_len = (short) isc_vax_integer(p, 2); 190 | p += 2; 191 | switch (item) { 192 | case isc_info_blob_num_segments: 193 | bl_info->num_segments = isc_vax_integer(p, item_len); 194 | break; 195 | case isc_info_blob_max_segment: 196 | bl_info->max_segment = isc_vax_integer(p, item_len); 197 | break; 198 | case isc_info_blob_total_length: 199 | bl_info->total_length = isc_vax_integer(p, item_len); 200 | break; 201 | case isc_info_blob_type: 202 | bl_info->bl_stream = isc_vax_integer(p, item_len); 203 | break; 204 | case isc_info_end: 205 | break; 206 | case isc_info_truncated: 207 | case isc_info_error: /* hmm. don't think so...*/ 208 | _php_ibase_module_error("PHP module internal error"); 209 | return FAILURE; 210 | } /* switch */ 211 | p += item_len; 212 | } /* for */ 213 | return SUCCESS; 214 | } 215 | /* }}} */ 216 | 217 | /* {{{ proto resource ibase_blob_create([resource link_identifier]) 218 | Create blob for adding data */ 219 | PHP_FUNCTION(ibase_blob_create) 220 | { 221 | zval *link = NULL; 222 | ibase_db_link *ib_link; 223 | ibase_trans *trans = NULL; 224 | ibase_blob *ib_blob; 225 | 226 | RESET_ERRMSG; 227 | 228 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "|r", &link)) { 229 | RETURN_FALSE; 230 | } 231 | 232 | PHP_IBASE_LINK_TRANS(link, ib_link, trans); 233 | 234 | ib_blob = (ibase_blob *) emalloc(sizeof(ibase_blob)); 235 | ib_blob->bl_handle = 0; 236 | ib_blob->type = BLOB_INPUT; 237 | 238 | if (isc_create_blob(IB_STATUS, &ib_link->handle, &trans->handle, &ib_blob->bl_handle, &ib_blob->bl_qd)) { 239 | _php_ibase_error(); 240 | efree(ib_blob); 241 | RETURN_FALSE; 242 | } 243 | 244 | RETVAL_RES(zend_register_resource(ib_blob, le_blob)); 245 | Z_TRY_ADDREF_P(return_value); 246 | } 247 | /* }}} */ 248 | 249 | /* {{{ proto resource ibase_blob_open([ resource link_identifier, ] string blob_id) 250 | Open blob for retrieving data parts */ 251 | PHP_FUNCTION(ibase_blob_open) 252 | { 253 | char *blob_id; 254 | size_t blob_id_len; 255 | zval *link = NULL; 256 | ibase_db_link *ib_link; 257 | ibase_trans *trans = NULL; 258 | ibase_blob *ib_blob; 259 | 260 | RESET_ERRMSG; 261 | PARSE_PARAMETERS; 262 | 263 | PHP_IBASE_LINK_TRANS(link, ib_link, trans); 264 | 265 | ib_blob = (ibase_blob *) emalloc(sizeof(ibase_blob)); 266 | ib_blob->bl_handle = 0; 267 | ib_blob->type = BLOB_OUTPUT; 268 | 269 | do { 270 | if (! _php_ibase_string_to_quad(blob_id, &ib_blob->bl_qd)) { 271 | _php_ibase_module_error("String is not a BLOB ID"); 272 | break; 273 | } 274 | 275 | if (isc_open_blob(IB_STATUS, &ib_link->handle, &trans->handle, &ib_blob->bl_handle, 276 | &ib_blob->bl_qd)) { 277 | _php_ibase_error(); 278 | break; 279 | } 280 | 281 | RETVAL_RES(zend_register_resource(ib_blob, le_blob)); 282 | Z_TRY_ADDREF_P(return_value); 283 | return; 284 | 285 | } while (0); 286 | 287 | efree(ib_blob); 288 | RETURN_FALSE; 289 | } 290 | /* }}} */ 291 | 292 | /* {{{ proto bool ibase_blob_add(resource blob_handle, string data) 293 | Add data into created blob */ 294 | PHP_FUNCTION(ibase_blob_add) 295 | { 296 | zval *blob_arg, *string_arg; 297 | ibase_blob *ib_blob; 298 | 299 | RESET_ERRMSG; 300 | 301 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "rz", &blob_arg, &string_arg)) { 302 | return; 303 | } 304 | 305 | ib_blob = (ibase_blob *)zend_fetch_resource_ex(blob_arg, "Interbase blob", le_blob); 306 | 307 | if (ib_blob->type != BLOB_INPUT) { 308 | _php_ibase_module_error("BLOB is not open for input"); 309 | RETURN_FALSE; 310 | } 311 | 312 | if (_php_ibase_blob_add(string_arg, ib_blob) != SUCCESS) { 313 | RETURN_FALSE; 314 | } 315 | } 316 | /* }}} */ 317 | 318 | /* {{{ proto string ibase_blob_get(resource blob_handle, int len) 319 | Get len bytes data from open blob */ 320 | PHP_FUNCTION(ibase_blob_get) 321 | { 322 | zval *blob_arg; 323 | zend_ulong len_arg; 324 | ibase_blob *ib_blob; 325 | 326 | RESET_ERRMSG; 327 | 328 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "rl", &blob_arg, &len_arg)) { 329 | return; 330 | } 331 | 332 | ib_blob = (ibase_blob *)zend_fetch_resource_ex(blob_arg, "Interbase blob", le_blob); 333 | 334 | if (ib_blob->type != BLOB_OUTPUT) { 335 | _php_ibase_module_error("BLOB is not open for output"); 336 | RETURN_FALSE; 337 | } 338 | 339 | if (_php_ibase_blob_get(return_value, ib_blob, len_arg) != SUCCESS) { 340 | RETURN_FALSE; 341 | } 342 | } 343 | /* }}} */ 344 | 345 | static void _php_ibase_blob_end(INTERNAL_FUNCTION_PARAMETERS, int bl_end) /* {{{ */ 346 | { 347 | zval *blob_arg; 348 | ibase_blob *ib_blob; 349 | 350 | RESET_ERRMSG; 351 | 352 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "r", &blob_arg)) { 353 | return; 354 | } 355 | 356 | ib_blob = (ibase_blob *)zend_fetch_resource_ex(blob_arg, "Interbase blob", le_blob); 357 | 358 | if (bl_end == BLOB_CLOSE) { /* return id here */ 359 | 360 | if (ib_blob->bl_qd.gds_quad_high || ib_blob->bl_qd.gds_quad_low) { /*not null ?*/ 361 | if (isc_close_blob(IB_STATUS, &ib_blob->bl_handle)) { 362 | _php_ibase_error(); 363 | RETURN_FALSE; 364 | } 365 | } 366 | ib_blob->bl_handle = 0; 367 | 368 | RETVAL_NEW_STR(_php_ibase_quad_to_string(ib_blob->bl_qd)); 369 | } else { /* discard created blob */ 370 | if (isc_cancel_blob(IB_STATUS, &ib_blob->bl_handle)) { 371 | _php_ibase_error(); 372 | RETURN_FALSE; 373 | } 374 | ib_blob->bl_handle = 0; 375 | RETVAL_TRUE; 376 | } 377 | zend_list_delete(Z_RES_P(blob_arg)); 378 | } 379 | /* }}} */ 380 | 381 | /* {{{ proto string ibase_blob_close(resource blob_handle) 382 | Close blob */ 383 | PHP_FUNCTION(ibase_blob_close) 384 | { 385 | _php_ibase_blob_end(INTERNAL_FUNCTION_PARAM_PASSTHRU, BLOB_CLOSE); 386 | } 387 | /* }}} */ 388 | 389 | /* {{{ proto bool ibase_blob_cancel(resource blob_handle) 390 | Cancel creating blob */ 391 | PHP_FUNCTION(ibase_blob_cancel) 392 | { 393 | _php_ibase_blob_end(INTERNAL_FUNCTION_PARAM_PASSTHRU, BLOB_CANCEL); 394 | } 395 | /* }}} */ 396 | 397 | /* {{{ proto array ibase_blob_info([ resource link_identifier, ] string blob_id) 398 | Return blob length and other useful info */ 399 | PHP_FUNCTION(ibase_blob_info) 400 | { 401 | char *blob_id; 402 | size_t blob_id_len; 403 | zval *link = NULL; 404 | ibase_db_link *ib_link; 405 | ibase_trans *trans = NULL; 406 | ibase_blob ib_blob = { 0, BLOB_INPUT }; 407 | IBASE_BLOBINFO bl_info; 408 | 409 | RESET_ERRMSG; 410 | PARSE_PARAMETERS; 411 | 412 | PHP_IBASE_LINK_TRANS(link, ib_link, trans); 413 | 414 | if (! _php_ibase_string_to_quad(blob_id, &ib_blob.bl_qd)) { 415 | _php_ibase_module_error("Unrecognized BLOB ID"); 416 | RETURN_FALSE; 417 | } 418 | 419 | if (ib_blob.bl_qd.gds_quad_high || ib_blob.bl_qd.gds_quad_low) { /* not null ? */ 420 | if (isc_open_blob(IB_STATUS, &ib_link->handle, &trans->handle, &ib_blob.bl_handle, 421 | &ib_blob.bl_qd)) { 422 | _php_ibase_error(); 423 | RETURN_FALSE; 424 | } 425 | 426 | if (_php_ibase_blob_info(ib_blob.bl_handle, &bl_info)) { 427 | RETURN_FALSE; 428 | } 429 | if (isc_close_blob(IB_STATUS, &ib_blob.bl_handle)) { 430 | _php_ibase_error(); 431 | RETURN_FALSE; 432 | } 433 | } else { /* null blob, all values to zero */ 434 | bl_info.max_segment = 0; 435 | bl_info.num_segments = 0; 436 | bl_info.total_length = 0; 437 | bl_info.bl_stream = 0; 438 | } 439 | 440 | array_init(return_value); 441 | 442 | add_index_long(return_value, 0, bl_info.total_length); 443 | add_assoc_long(return_value, "length", bl_info.total_length); 444 | 445 | add_index_long(return_value, 1, bl_info.num_segments); 446 | add_assoc_long(return_value, "numseg", bl_info.num_segments); 447 | 448 | add_index_long(return_value, 2, bl_info.max_segment); 449 | add_assoc_long(return_value, "maxseg", bl_info.max_segment); 450 | 451 | add_index_bool(return_value, 3, bl_info.bl_stream); 452 | add_assoc_bool(return_value, "stream", bl_info.bl_stream); 453 | 454 | add_index_bool(return_value, 4, (!ib_blob.bl_qd.gds_quad_high && !ib_blob.bl_qd.gds_quad_low)); 455 | add_assoc_bool(return_value, "isnull", (!ib_blob.bl_qd.gds_quad_high && !ib_blob.bl_qd.gds_quad_low)); 456 | } 457 | /* }}} */ 458 | 459 | /* {{{ proto bool ibase_blob_echo([ resource link_identifier, ] string blob_id) 460 | Output blob contents to browser */ 461 | PHP_FUNCTION(ibase_blob_echo) 462 | { 463 | char *blob_id; 464 | size_t blob_id_len; 465 | zval *link = NULL; 466 | ibase_db_link *ib_link; 467 | ibase_trans *trans = NULL; 468 | ibase_blob ib_blob_id = { 0, BLOB_OUTPUT }; 469 | char bl_data[IBASE_BLOB_SEG]; 470 | unsigned short seg_len; 471 | 472 | RESET_ERRMSG; 473 | PARSE_PARAMETERS; 474 | 475 | PHP_IBASE_LINK_TRANS(link, ib_link, trans); 476 | 477 | if (! _php_ibase_string_to_quad(blob_id, &ib_blob_id.bl_qd)) { 478 | _php_ibase_module_error("Unrecognized BLOB ID"); 479 | RETURN_FALSE; 480 | } 481 | 482 | do { 483 | if (isc_open_blob(IB_STATUS, &ib_link->handle, &trans->handle, &ib_blob_id.bl_handle, 484 | &ib_blob_id.bl_qd)) { 485 | break; 486 | } 487 | 488 | while (!isc_get_segment(IB_STATUS, &ib_blob_id.bl_handle, &seg_len, sizeof(bl_data), bl_data) 489 | || IB_STATUS[1] == isc_segment) { 490 | PHPWRITE(bl_data, seg_len); 491 | } 492 | 493 | if (IB_STATUS[0] && (IB_STATUS[1] != isc_segstr_eof)) { 494 | break; 495 | } 496 | 497 | if (isc_close_blob(IB_STATUS, &ib_blob_id.bl_handle)) { 498 | break; 499 | } 500 | RETURN_TRUE; 501 | } while (0); 502 | 503 | _php_ibase_error(); 504 | RETURN_FALSE; 505 | } 506 | /* }}} */ 507 | 508 | /* {{{ proto string ibase_blob_import([ resource link_identifier, ] resource file) 509 | Create blob, copy file in it, and close it */ 510 | PHP_FUNCTION(ibase_blob_import) 511 | { 512 | zval *link = NULL, *file; 513 | int size; 514 | unsigned short b; 515 | ibase_blob ib_blob = { 0, 0 }; 516 | ibase_db_link *ib_link; 517 | ibase_trans *trans = NULL; 518 | char bl_data[IBASE_BLOB_SEG]; 519 | php_stream *stream; 520 | 521 | RESET_ERRMSG; 522 | 523 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "r|r", 524 | (ZEND_NUM_ARGS()-1) ? &link : &file, &file)) { 525 | RETURN_FALSE; 526 | } 527 | 528 | PHP_IBASE_LINK_TRANS(link, ib_link, trans); 529 | 530 | php_stream_from_zval(stream, file); 531 | 532 | do { 533 | if (isc_create_blob(IB_STATUS, &ib_link->handle, &trans->handle, &ib_blob.bl_handle, 534 | &ib_blob.bl_qd)) { 535 | break; 536 | } 537 | 538 | for (size = 0; (b = php_stream_read(stream, bl_data, sizeof(bl_data))); size += b) { 539 | if (isc_put_segment(IB_STATUS, &ib_blob.bl_handle, b, bl_data)) { 540 | break; 541 | } 542 | } 543 | 544 | if (isc_close_blob(IB_STATUS, &ib_blob.bl_handle)) { 545 | break; 546 | } 547 | RETURN_NEW_STR(_php_ibase_quad_to_string(ib_blob.bl_qd)); 548 | } while (0); 549 | 550 | _php_ibase_error(); 551 | RETURN_FALSE; 552 | } 553 | /* }}} */ 554 | 555 | #endif /* HAVE_IBASE */ 556 | -------------------------------------------------------------------------------- /ibase_service.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 7 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 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: Ard Biesheuvel | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #ifdef HAVE_CONFIG_H 20 | #include "config.h" 21 | #endif 22 | 23 | #include "php.h" 24 | 25 | #if HAVE_IBASE 26 | 27 | #include "php_interbase.h" 28 | #include "php_ibase_includes.h" 29 | 30 | typedef struct { 31 | isc_svc_handle handle; 32 | char *hostname; 33 | char *username; 34 | zend_resource *res; 35 | } ibase_service; 36 | 37 | static int le_service; 38 | 39 | static void _php_ibase_free_service(zend_resource *rsrc) /* {{{ */ 40 | { 41 | ibase_service *sv = (ibase_service *) rsrc->ptr; 42 | 43 | if (isc_service_detach(IB_STATUS, &sv->handle)) { 44 | _php_ibase_error(); 45 | } 46 | 47 | if (sv->hostname) { 48 | efree(sv->hostname); 49 | } 50 | if (sv->username) { 51 | efree(sv->username); 52 | } 53 | 54 | efree(sv); 55 | } 56 | /* }}} */ 57 | 58 | /* the svc api seems to get confused after an error has occurred, 59 | so invalidate the handle on errors */ 60 | #define IBASE_SVC_ERROR(svm) \ 61 | do { zend_list_delete(svm->res); _php_ibase_error(); } while (0) 62 | 63 | 64 | void php_ibase_service_minit(INIT_FUNC_ARGS) /* {{{ */ 65 | { 66 | le_service = zend_register_list_destructors_ex(_php_ibase_free_service, NULL, 67 | "interbase service manager handle", module_number); 68 | 69 | /* backup options */ 70 | REGISTER_LONG_CONSTANT("IBASE_BKP_IGNORE_CHECKSUMS", isc_spb_bkp_ignore_checksums, CONST_PERSISTENT); 71 | REGISTER_LONG_CONSTANT("IBASE_BKP_IGNORE_LIMBO", isc_spb_bkp_ignore_limbo, CONST_PERSISTENT); 72 | REGISTER_LONG_CONSTANT("IBASE_BKP_METADATA_ONLY", isc_spb_bkp_metadata_only, CONST_PERSISTENT); 73 | REGISTER_LONG_CONSTANT("IBASE_BKP_NO_GARBAGE_COLLECT", isc_spb_bkp_no_garbage_collect, CONST_PERSISTENT); 74 | REGISTER_LONG_CONSTANT("IBASE_BKP_OLD_DESCRIPTIONS", isc_spb_bkp_old_descriptions, CONST_PERSISTENT); 75 | REGISTER_LONG_CONSTANT("IBASE_BKP_NON_TRANSPORTABLE", isc_spb_bkp_non_transportable, CONST_PERSISTENT); 76 | REGISTER_LONG_CONSTANT("IBASE_BKP_CONVERT", isc_spb_bkp_convert, CONST_PERSISTENT); 77 | 78 | /* restore options */ 79 | REGISTER_LONG_CONSTANT("IBASE_RES_DEACTIVATE_IDX", isc_spb_res_deactivate_idx, CONST_PERSISTENT); 80 | REGISTER_LONG_CONSTANT("IBASE_RES_NO_SHADOW", isc_spb_res_no_shadow, CONST_PERSISTENT); 81 | REGISTER_LONG_CONSTANT("IBASE_RES_NO_VALIDITY", isc_spb_res_no_validity, CONST_PERSISTENT); 82 | REGISTER_LONG_CONSTANT("IBASE_RES_ONE_AT_A_TIME", isc_spb_res_one_at_a_time, CONST_PERSISTENT); 83 | REGISTER_LONG_CONSTANT("IBASE_RES_REPLACE", isc_spb_res_replace, CONST_PERSISTENT); 84 | REGISTER_LONG_CONSTANT("IBASE_RES_CREATE", isc_spb_res_create, CONST_PERSISTENT); 85 | REGISTER_LONG_CONSTANT("IBASE_RES_USE_ALL_SPACE", isc_spb_res_use_all_space, CONST_PERSISTENT); 86 | 87 | /* manage options */ 88 | REGISTER_LONG_CONSTANT("IBASE_PRP_PAGE_BUFFERS", isc_spb_prp_page_buffers, CONST_PERSISTENT); 89 | REGISTER_LONG_CONSTANT("IBASE_PRP_SWEEP_INTERVAL", isc_spb_prp_sweep_interval, CONST_PERSISTENT); 90 | REGISTER_LONG_CONSTANT("IBASE_PRP_SHUTDOWN_DB", isc_spb_prp_shutdown_db, CONST_PERSISTENT); 91 | REGISTER_LONG_CONSTANT("IBASE_PRP_DENY_NEW_TRANSACTIONS", isc_spb_prp_deny_new_transactions, CONST_PERSISTENT); 92 | REGISTER_LONG_CONSTANT("IBASE_PRP_DENY_NEW_ATTACHMENTS", isc_spb_prp_deny_new_attachments, CONST_PERSISTENT); 93 | REGISTER_LONG_CONSTANT("IBASE_PRP_RESERVE_SPACE", isc_spb_prp_reserve_space, CONST_PERSISTENT); 94 | REGISTER_LONG_CONSTANT("IBASE_PRP_RES_USE_FULL", isc_spb_prp_res_use_full, CONST_PERSISTENT); 95 | REGISTER_LONG_CONSTANT("IBASE_PRP_RES", isc_spb_prp_res, CONST_PERSISTENT); 96 | REGISTER_LONG_CONSTANT("IBASE_PRP_WRITE_MODE", isc_spb_prp_write_mode, CONST_PERSISTENT); 97 | REGISTER_LONG_CONSTANT("IBASE_PRP_WM_ASYNC", isc_spb_prp_wm_async, CONST_PERSISTENT); 98 | REGISTER_LONG_CONSTANT("IBASE_PRP_WM_SYNC", isc_spb_prp_wm_sync, CONST_PERSISTENT); 99 | REGISTER_LONG_CONSTANT("IBASE_PRP_ACCESS_MODE", isc_spb_prp_access_mode, CONST_PERSISTENT); 100 | REGISTER_LONG_CONSTANT("IBASE_PRP_AM_READONLY", isc_spb_prp_am_readonly, CONST_PERSISTENT); 101 | REGISTER_LONG_CONSTANT("IBASE_PRP_AM_READWRITE", isc_spb_prp_am_readwrite, CONST_PERSISTENT); 102 | REGISTER_LONG_CONSTANT("IBASE_PRP_SET_SQL_DIALECT", isc_spb_prp_set_sql_dialect, CONST_PERSISTENT); 103 | REGISTER_LONG_CONSTANT("IBASE_PRP_ACTIVATE", isc_spb_prp_activate, CONST_PERSISTENT); 104 | REGISTER_LONG_CONSTANT("IBASE_PRP_DB_ONLINE", isc_spb_prp_db_online, CONST_PERSISTENT); 105 | 106 | /* repair options */ 107 | REGISTER_LONG_CONSTANT("IBASE_RPR_CHECK_DB", isc_spb_rpr_check_db, CONST_PERSISTENT); 108 | REGISTER_LONG_CONSTANT("IBASE_RPR_IGNORE_CHECKSUM", isc_spb_rpr_ignore_checksum, CONST_PERSISTENT); 109 | REGISTER_LONG_CONSTANT("IBASE_RPR_KILL_SHADOWS", isc_spb_rpr_kill_shadows, CONST_PERSISTENT); 110 | REGISTER_LONG_CONSTANT("IBASE_RPR_MEND_DB", isc_spb_rpr_mend_db, CONST_PERSISTENT); 111 | REGISTER_LONG_CONSTANT("IBASE_RPR_VALIDATE_DB", isc_spb_rpr_validate_db, CONST_PERSISTENT); 112 | REGISTER_LONG_CONSTANT("IBASE_RPR_FULL", isc_spb_rpr_full, CONST_PERSISTENT); 113 | REGISTER_LONG_CONSTANT("IBASE_RPR_SWEEP_DB", isc_spb_rpr_sweep_db, CONST_PERSISTENT); 114 | 115 | /* db info arguments */ 116 | REGISTER_LONG_CONSTANT("IBASE_STS_DATA_PAGES", isc_spb_sts_data_pages, CONST_PERSISTENT); 117 | REGISTER_LONG_CONSTANT("IBASE_STS_DB_LOG", isc_spb_sts_db_log, CONST_PERSISTENT); 118 | REGISTER_LONG_CONSTANT("IBASE_STS_HDR_PAGES", isc_spb_sts_hdr_pages, CONST_PERSISTENT); 119 | REGISTER_LONG_CONSTANT("IBASE_STS_IDX_PAGES", isc_spb_sts_idx_pages, CONST_PERSISTENT); 120 | REGISTER_LONG_CONSTANT("IBASE_STS_SYS_RELATIONS", isc_spb_sts_sys_relations, CONST_PERSISTENT); 121 | 122 | /* server info arguments */ 123 | REGISTER_LONG_CONSTANT("IBASE_SVC_SERVER_VERSION", isc_info_svc_server_version, CONST_PERSISTENT); 124 | REGISTER_LONG_CONSTANT("IBASE_SVC_IMPLEMENTATION", isc_info_svc_implementation, CONST_PERSISTENT); 125 | REGISTER_LONG_CONSTANT("IBASE_SVC_GET_ENV", isc_info_svc_get_env, CONST_PERSISTENT); 126 | REGISTER_LONG_CONSTANT("IBASE_SVC_GET_ENV_LOCK", isc_info_svc_get_env_lock, CONST_PERSISTENT); 127 | REGISTER_LONG_CONSTANT("IBASE_SVC_GET_ENV_MSG", isc_info_svc_get_env_msg, CONST_PERSISTENT); 128 | REGISTER_LONG_CONSTANT("IBASE_SVC_USER_DBPATH", isc_info_svc_user_dbpath, CONST_PERSISTENT); 129 | REGISTER_LONG_CONSTANT("IBASE_SVC_SVR_DB_INFO", isc_info_svc_svr_db_info, CONST_PERSISTENT); 130 | REGISTER_LONG_CONSTANT("IBASE_SVC_GET_USERS", isc_info_svc_get_users, CONST_PERSISTENT); 131 | } 132 | /* }}} */ 133 | 134 | static void _php_ibase_user(INTERNAL_FUNCTION_PARAMETERS, char operation) /* {{{ */ 135 | { 136 | /* user = 0, password = 1, first_name = 2, middle_name = 3, last_name = 4 */ 137 | static char const user_flags[] = { isc_spb_sec_username, isc_spb_sec_password, 138 | isc_spb_sec_firstname, isc_spb_sec_middlename, isc_spb_sec_lastname }; 139 | char buf[128], *args[] = { NULL, NULL, NULL, NULL, NULL }; 140 | int i, args_len[] = { 0, 0, 0, 0, 0 }; 141 | unsigned short spb_len = 1; 142 | zval *res; 143 | ibase_service *svm; 144 | 145 | RESET_ERRMSG; 146 | 147 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), 148 | (operation == isc_action_svc_delete_user) ? "rs" : "rss|sss", 149 | &res, &args[0], &args_len[0], &args[1], &args_len[1], &args[2], &args_len[2], 150 | &args[3], &args_len[3], &args[4], &args_len[4])) { 151 | RETURN_FALSE; 152 | } 153 | 154 | svm = (ibase_service *)zend_fetch_resource_ex(res, "Interbase service manager handle", 155 | le_service); 156 | 157 | buf[0] = operation; 158 | 159 | for (i = 0; i < sizeof(user_flags); ++i) { 160 | if (args[i] != NULL) { 161 | int chunk = slprintf(&buf[spb_len], sizeof(buf) - spb_len, "%c%c%c%s", 162 | user_flags[i], (char)args_len[i], (char)(args_len[i] >> 8), args[i]); 163 | 164 | if ((spb_len + chunk) > sizeof(buf) || chunk <= 0) { 165 | _php_ibase_module_error("Internal error: insufficient buffer space for SPB (%d)", spb_len); 166 | RETURN_FALSE; 167 | } 168 | spb_len += chunk; 169 | } 170 | } 171 | 172 | /* now start the job */ 173 | if (isc_service_start(IB_STATUS, &svm->handle, NULL, spb_len, buf)) { 174 | IBASE_SVC_ERROR(svm); 175 | RETURN_FALSE; 176 | } 177 | 178 | RETURN_TRUE; 179 | } 180 | /* }}} */ 181 | 182 | /* {{{ proto bool ibase_add_user(resource service_handle, string user_name, string password [, string first_name [, string middle_name [, string last_name]]]) 183 | Add a user to security database */ 184 | PHP_FUNCTION(ibase_add_user) 185 | { 186 | _php_ibase_user(INTERNAL_FUNCTION_PARAM_PASSTHRU, isc_action_svc_add_user); 187 | } 188 | /* }}} */ 189 | 190 | /* {{{ proto bool ibase_modify_user(resource service_handle, string user_name, string password [, string first_name [, string middle_name [, string last_name]]]) 191 | Modify a user in security database */ 192 | PHP_FUNCTION(ibase_modify_user) 193 | { 194 | _php_ibase_user(INTERNAL_FUNCTION_PARAM_PASSTHRU, isc_action_svc_modify_user); 195 | } 196 | /* }}} */ 197 | 198 | /* {{{ proto bool ibase_delete_user(resource service_handle, string user_name, string password [, string first_name [, string middle_name [, string last_name]]]) 199 | Delete a user from security database */ 200 | PHP_FUNCTION(ibase_delete_user) 201 | { 202 | _php_ibase_user(INTERNAL_FUNCTION_PARAM_PASSTHRU, isc_action_svc_delete_user); 203 | } 204 | /* }}} */ 205 | 206 | /* {{{ proto resource ibase_service_attach(string host, string dba_username, string dba_password) 207 | Connect to the service manager */ 208 | PHP_FUNCTION(ibase_service_attach) 209 | { 210 | size_t hlen, ulen, plen, spb_len; 211 | ibase_service *svm; 212 | char buf[128], *host, *user, *pass, *loc; 213 | isc_svc_handle handle = 0; 214 | 215 | RESET_ERRMSG; 216 | 217 | if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "sss", 218 | &host, &hlen, &user, &ulen, &pass, &plen)) { 219 | 220 | RETURN_FALSE; 221 | } 222 | 223 | /* construct the spb, hack the service name into it as well */ 224 | spb_len = slprintf(buf, sizeof(buf), "%c%c%c%c%s%c%c%s" "%s:service_mgr", 225 | isc_spb_version, isc_spb_current_version, isc_spb_user_name, (char)ulen, 226 | user, isc_spb_password, (char)plen, pass, host); 227 | 228 | if (spb_len > sizeof(buf) || spb_len == -1) { 229 | _php_ibase_module_error("Internal error: insufficient buffer space for SPB (%zd)", spb_len); 230 | RETURN_FALSE; 231 | } 232 | 233 | spb_len -= hlen + 12; 234 | loc = buf + spb_len; /* points to %s:service_mgr part */ 235 | 236 | /* attach to the service manager */ 237 | if (isc_service_attach(IB_STATUS, 0, loc, &handle, (unsigned short)spb_len, buf)) { 238 | _php_ibase_error(); 239 | RETURN_FALSE; 240 | } 241 | 242 | svm = (ibase_service*)emalloc(sizeof(ibase_service)); 243 | svm->handle = handle; 244 | svm->hostname = estrdup(host); 245 | svm->username = estrdup(user); 246 | 247 | RETVAL_RES(zend_register_resource(svm, le_service)); 248 | Z_TRY_ADDREF_P(return_value); 249 | svm->res = Z_RES_P(return_value); 250 | } 251 | /* }}} */ 252 | 253 | /* {{{ proto bool ibase_service_detach(resource service_handle) 254 | Disconnect from the service manager */ 255 | PHP_FUNCTION(ibase_service_detach) 256 | { 257 | zval *res; 258 | 259 | RESET_ERRMSG; 260 | 261 | if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "r", &res)) { 262 | RETURN_FALSE; 263 | } 264 | 265 | zend_list_delete(Z_RES_P(res)); 266 | 267 | RETURN_TRUE; 268 | } 269 | /* }}} */ 270 | 271 | static void _php_ibase_service_query(INTERNAL_FUNCTION_PARAMETERS, /* {{{ */ 272 | ibase_service *svm, char info_action) 273 | { 274 | static char spb[] = { isc_info_svc_timeout, 10, 0, 0, 0 }; 275 | 276 | char res_buf[400], *result, *heap_buf = NULL, *heap_p; 277 | zend_long heap_buf_size = 200, line_len; 278 | 279 | /* info about users requires an action first */ 280 | if (info_action == isc_info_svc_get_users) { 281 | static char action[] = { isc_action_svc_display_user }; 282 | 283 | if (isc_service_start(IB_STATUS, &svm->handle, NULL, sizeof(action), action)) { 284 | IBASE_SVC_ERROR(svm); 285 | RETURN_FALSE; 286 | } 287 | } 288 | 289 | query_loop: 290 | result = res_buf; 291 | 292 | if (isc_service_query(IB_STATUS, &svm->handle, NULL, sizeof(spb), spb, 293 | 1, &info_action, sizeof(res_buf), res_buf)) { 294 | 295 | IBASE_SVC_ERROR(svm); 296 | RETURN_FALSE; 297 | } 298 | while (*result != isc_info_end) { 299 | switch (*result++) { 300 | default: 301 | RETURN_FALSE; 302 | 303 | case isc_info_svc_line: 304 | if (! (line_len = isc_vax_integer(result, 2))) { 305 | /* done */ 306 | if (heap_buf) { 307 | RETVAL_STRING(heap_buf); 308 | efree(heap_buf); 309 | return; 310 | } else { 311 | RETURN_TRUE; 312 | } 313 | } 314 | if (!heap_buf || (heap_p - heap_buf + line_len +2) > heap_buf_size) { 315 | zend_long res_size = heap_buf ? heap_p - heap_buf : 0; 316 | 317 | while (heap_buf_size < (res_size + line_len +2)) { 318 | heap_buf_size *= 2; 319 | } 320 | heap_buf = (char*) erealloc(heap_buf, heap_buf_size); 321 | heap_p = heap_buf + res_size; 322 | } 323 | result += 2; 324 | *(result+line_len) = 0; 325 | snprintf(heap_p, heap_buf_size - (heap_p - heap_buf), "%s\n", result); 326 | heap_p += line_len +1; 327 | goto query_loop; /* repeat until result is exhausted */ 328 | 329 | case isc_info_svc_server_version: 330 | case isc_info_svc_implementation: 331 | case isc_info_svc_get_env: 332 | case isc_info_svc_get_env_lock: 333 | case isc_info_svc_get_env_msg: 334 | case isc_info_svc_user_dbpath: 335 | RETURN_STRINGL(result + 2, isc_vax_integer(result, 2)); 336 | 337 | case isc_info_svc_svr_db_info: 338 | array_init(return_value); 339 | 340 | do { 341 | switch (*result++) { 342 | int len; 343 | 344 | case isc_spb_num_att: 345 | add_assoc_long(return_value, "attachments", isc_vax_integer(result,4)); 346 | result += 4; 347 | break; 348 | 349 | case isc_spb_num_db: 350 | add_assoc_long(return_value, "databases", isc_vax_integer(result,4)); 351 | result += 4; 352 | break; 353 | 354 | case isc_spb_dbname: 355 | len = isc_vax_integer(result,2); 356 | add_next_index_stringl(return_value, result +2, len); 357 | result += len+2; 358 | } 359 | } while (*result != isc_info_flag_end); 360 | return; 361 | 362 | case isc_info_svc_get_users: { 363 | zval user; 364 | array_init(return_value); 365 | 366 | while (*result != isc_info_end) { 367 | 368 | switch (*result++) { 369 | int len; 370 | 371 | case isc_spb_sec_username: 372 | /* it appears that the username is always first */ 373 | array_init(&user); 374 | add_next_index_zval(return_value, &user); 375 | 376 | len = isc_vax_integer(result,2); 377 | add_assoc_stringl(&user, "user_name", result +2, len); 378 | result += len+2; 379 | break; 380 | 381 | case isc_spb_sec_firstname: 382 | len = isc_vax_integer(result,2); 383 | add_assoc_stringl(&user, "first_name", result +2, len); 384 | result += len+2; 385 | break; 386 | 387 | case isc_spb_sec_middlename: 388 | len = isc_vax_integer(result,2); 389 | add_assoc_stringl(&user, "middle_name", result +2, len); 390 | result += len+2; 391 | break; 392 | 393 | case isc_spb_sec_lastname: 394 | len = isc_vax_integer(result,2); 395 | add_assoc_stringl(&user, "last_name", result +2, len); 396 | result += len+2; 397 | break; 398 | 399 | case isc_spb_sec_userid: 400 | add_assoc_long(&user, "user_id", isc_vax_integer(result, 4)); 401 | result += 4; 402 | break; 403 | 404 | case isc_spb_sec_groupid: 405 | add_assoc_long(&user, "group_id", isc_vax_integer(result, 4)); 406 | result += 4; 407 | break; 408 | } 409 | } 410 | return; 411 | } 412 | } 413 | } 414 | } 415 | /* }}} */ 416 | 417 | static void _php_ibase_backup_restore(INTERNAL_FUNCTION_PARAMETERS, char operation) /* {{{ */ 418 | { 419 | /** 420 | * It appears that the service API is a little bit confused about which flag 421 | * to use for the source and destination in the case of a restore operation. 422 | * When passing the backup file as isc_spb_dbname and the destination db as 423 | * bpk_file, things work well. 424 | */ 425 | zval *res; 426 | char *db, *bk, buf[200]; 427 | size_t dblen, bklen, spb_len; 428 | zend_long opts = 0; 429 | zend_bool verbose = 0; 430 | ibase_service *svm; 431 | 432 | RESET_ERRMSG; 433 | 434 | if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "rss|lb", 435 | &res, &db, &dblen, &bk, &bklen, &opts, &verbose)) { 436 | RETURN_FALSE; 437 | } 438 | 439 | svm = (ibase_service *)zend_fetch_resource_ex(res, 440 | "Interbase service manager handle", le_service); 441 | 442 | /* fill the param buffer */ 443 | spb_len = slprintf(buf, sizeof(buf), "%c%c%c%c%s%c%c%c%s%c%c%c%c%c", 444 | operation, isc_spb_dbname, (char)dblen, (char)(dblen >> 8), db, 445 | isc_spb_bkp_file, (char)bklen, (char)(bklen >> 8), bk, isc_spb_options, 446 | (char)opts,(char)(opts >> 8), (char)(opts >> 16), (char)(opts >> 24)); 447 | 448 | if (verbose) { 449 | buf[spb_len++] = isc_spb_verbose; 450 | } 451 | 452 | if (spb_len > sizeof(buf) || spb_len <= 0) { 453 | _php_ibase_module_error("Internal error: insufficient buffer space for SPB (%zd)", spb_len); 454 | RETURN_FALSE; 455 | } 456 | 457 | /* now start the backup/restore job */ 458 | if (isc_service_start(IB_STATUS, &svm->handle, NULL, (unsigned short)spb_len, buf)) { 459 | IBASE_SVC_ERROR(svm); 460 | RETURN_FALSE; 461 | } 462 | 463 | if (!verbose) { 464 | RETURN_TRUE; 465 | } else { 466 | _php_ibase_service_query(INTERNAL_FUNCTION_PARAM_PASSTHRU, svm, isc_info_svc_line); 467 | } 468 | } 469 | /* }}} */ 470 | 471 | /* {{{ proto mixed ibase_backup(resource service_handle, string source_db, string dest_file [, int options [, bool verbose]]) 472 | Initiates a backup task in the service manager and returns immediately */ 473 | PHP_FUNCTION(ibase_backup) 474 | { 475 | _php_ibase_backup_restore(INTERNAL_FUNCTION_PARAM_PASSTHRU, isc_action_svc_backup); 476 | } 477 | /* }}} */ 478 | 479 | /* {{{ proto mixed ibase_restore(resource service_handle, string source_file, string dest_db [, int options [, bool verbose]]) 480 | Initiates a restore task in the service manager and returns immediately */ 481 | PHP_FUNCTION(ibase_restore) 482 | { 483 | _php_ibase_backup_restore(INTERNAL_FUNCTION_PARAM_PASSTHRU, isc_action_svc_restore); 484 | } 485 | /* }}} */ 486 | 487 | static void _php_ibase_service_action(INTERNAL_FUNCTION_PARAMETERS, char svc_action) /* {{{ */ 488 | { 489 | zval *res; 490 | char buf[128], *db; 491 | size_t dblen; 492 | int spb_len; 493 | zend_long action, argument = 0; 494 | ibase_service *svm; 495 | 496 | RESET_ERRMSG; 497 | 498 | if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "rsl|l", 499 | &res, &db, &dblen, &action, &argument)) { 500 | RETURN_FALSE; 501 | } 502 | 503 | svm = (ibase_service *)zend_fetch_resource_ex(res, 504 | "Interbase service manager handle", le_service); 505 | 506 | if (svc_action == isc_action_svc_db_stats) { 507 | switch (action) { 508 | default: 509 | goto unknown_option; 510 | 511 | case isc_spb_sts_data_pages: 512 | case isc_spb_sts_db_log: 513 | case isc_spb_sts_hdr_pages: 514 | case isc_spb_sts_idx_pages: 515 | case isc_spb_sts_sys_relations: 516 | goto options_argument; 517 | } 518 | } else { 519 | /* these actions all expect different types of arguments */ 520 | switch (action) { 521 | default: 522 | unknown_option: 523 | _php_ibase_module_error("Unrecognised option (" ZEND_LONG_FMT ")", action); 524 | RETURN_FALSE; 525 | 526 | case isc_spb_rpr_check_db: 527 | case isc_spb_rpr_ignore_checksum: 528 | case isc_spb_rpr_kill_shadows: 529 | case isc_spb_rpr_mend_db: 530 | case isc_spb_rpr_validate_db: 531 | case isc_spb_rpr_sweep_db: 532 | svc_action = isc_action_svc_repair; 533 | 534 | case isc_spb_prp_activate: 535 | case isc_spb_prp_db_online: 536 | options_argument: 537 | argument |= action; 538 | action = isc_spb_options; 539 | 540 | case isc_spb_prp_page_buffers: 541 | case isc_spb_prp_sweep_interval: 542 | case isc_spb_prp_shutdown_db: 543 | case isc_spb_prp_deny_new_transactions: 544 | case isc_spb_prp_deny_new_attachments: 545 | case isc_spb_prp_set_sql_dialect: 546 | spb_len = slprintf(buf, sizeof(buf), "%c%c%c%c%s%c%c%c%c%c", 547 | svc_action, isc_spb_dbname, (char)dblen, (char)(dblen >> 8), db, 548 | (char)action, (char)argument, (char)(argument >> 8), (char)(argument >> 16), 549 | (char)(argument >> 24)); 550 | break; 551 | 552 | case isc_spb_prp_reserve_space: 553 | case isc_spb_prp_write_mode: 554 | case isc_spb_prp_access_mode: 555 | spb_len = slprintf(buf, sizeof(buf), "%c%c%c%c%s%c%c", 556 | isc_action_svc_properties, isc_spb_dbname, (char)dblen, (char)(dblen >> 8), 557 | db, (char)action, (char)argument); 558 | } 559 | } 560 | 561 | if (spb_len > sizeof(buf) || spb_len == -1) { 562 | _php_ibase_module_error("Internal error: insufficient buffer space for SPB (%d)", spb_len); 563 | RETURN_FALSE; 564 | } 565 | 566 | if (isc_service_start(IB_STATUS, &svm->handle, NULL, (unsigned short)spb_len, buf)) { 567 | IBASE_SVC_ERROR(svm); 568 | RETURN_FALSE; 569 | } 570 | 571 | if (svc_action == isc_action_svc_db_stats) { 572 | _php_ibase_service_query(INTERNAL_FUNCTION_PARAM_PASSTHRU, svm, isc_info_svc_line); 573 | } else { 574 | RETURN_TRUE; 575 | } 576 | } 577 | /* }}} */ 578 | 579 | /* {{{ proto bool ibase_maintain_db(resource service_handle, string db, int action [, int argument]) 580 | Execute a maintenance command on the database server */ 581 | PHP_FUNCTION(ibase_maintain_db) 582 | { 583 | _php_ibase_service_action(INTERNAL_FUNCTION_PARAM_PASSTHRU, isc_action_svc_properties); 584 | } 585 | /* }}} */ 586 | 587 | /* {{{ proto string ibase_db_info(resource service_handle, string db, int action [, int argument]) 588 | Request statistics about a database */ 589 | PHP_FUNCTION(ibase_db_info) 590 | { 591 | _php_ibase_service_action(INTERNAL_FUNCTION_PARAM_PASSTHRU, isc_action_svc_db_stats); 592 | } 593 | /* }}} */ 594 | 595 | /* {{{ proto string ibase_server_info(resource service_handle, int action) 596 | Request information about a database server */ 597 | PHP_FUNCTION(ibase_server_info) 598 | { 599 | zval *res; 600 | zend_long action; 601 | ibase_service *svm; 602 | 603 | RESET_ERRMSG; 604 | 605 | if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "rl", &res, &action)) { 606 | RETURN_FALSE; 607 | } 608 | 609 | svm = (ibase_service *)zend_fetch_resource_ex(res, 610 | "Interbase service manager handle", le_service); 611 | 612 | _php_ibase_service_query(INTERNAL_FUNCTION_PARAM_PASSTHRU, svm, (char)action); 613 | } 614 | /* }}} */ 615 | 616 | #else 617 | 618 | void php_ibase_register_service_constants(INIT_FUNC_ARGS) { /* nop */ } 619 | 620 | #endif /* HAVE_IBASE */ 621 | -------------------------------------------------------------------------------- /interbase.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 7 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 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 | 16 | | Andrew Avdeev | 17 | | Ard Biesheuvel | 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 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 */ 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 */ 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() */ 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() */ 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. */ 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 | 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 | 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 | 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 | 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 | 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 */ 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("no value"); 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) 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 | 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 | 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 | 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 | 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 | php_info_print_table_row(2, "Interbase extension version", PHP_INTERBASE_VERSION); 813 | 814 | #ifdef FB_API_VER 815 | snprintf( (s = tmp), sizeof(tmp), "Firebird API version %d", FB_API_VER); 816 | #elif (SQLDA_CURRENT_VERSION > 1) 817 | s = "Interbase 7.0 and up"; 818 | #endif 819 | php_info_print_table_row(2, "Compile-time Client Library Version", s); 820 | 821 | #if defined(__GNUC__) || defined(PHP_WIN32) 822 | do { 823 | info_func_t info_func = NULL; 824 | #ifdef __GNUC__ 825 | info_func = (info_func_t)dlsym(RTLD_DEFAULT, "isc_get_client_version"); 826 | #else 827 | HMODULE l = GetModuleHandle("fbclient"); 828 | 829 | if (!l && !(l = GetModuleHandle("gds32"))) { 830 | break; 831 | } 832 | info_func = (info_func_t)GetProcAddress(l, "isc_get_client_version"); 833 | #endif 834 | if (info_func) { 835 | info_func(s = tmp); 836 | } 837 | php_info_print_table_row(2, "Run-time Client Library Version", s); 838 | } while (0); 839 | #endif 840 | php_info_print_table_end(); 841 | 842 | DISPLAY_INI_ENTRIES(); 843 | 844 | } 845 | /* }}} */ 846 | 847 | enum connect_args { DB = 0, USER = 1, PASS = 2, CSET = 3, ROLE = 4, BUF = 0, DLECT = 1, SYNC = 2 }; 848 | 849 | static char const dpb_args[] = { 850 | 0, isc_dpb_user_name, isc_dpb_password, isc_dpb_lc_ctype, isc_dpb_sql_role_name, 0 851 | }; 852 | 853 | int _php_ibase_attach_db(char **args, size_t *len, zend_long *largs, isc_db_handle *db) /* {{{ */ 854 | { 855 | short i, dpb_len, buf_len = 257-2; /* version byte at the front, and a null at the end */ 856 | char dpb_buffer[257] = { isc_dpb_version1, 0 }, *dpb; 857 | 858 | dpb = dpb_buffer + 1; 859 | 860 | for (i = 0; i < sizeof(dpb_args); ++i) { 861 | if (dpb_args[i] && args[i] && len[i] && buf_len > 0) { 862 | dpb_len = slprintf(dpb, buf_len, "%c%c%s", dpb_args[i],(unsigned char)len[i],args[i]); 863 | dpb += dpb_len; 864 | buf_len -= dpb_len; 865 | } 866 | } 867 | if (largs[BUF] && buf_len > 0) { 868 | dpb_len = slprintf(dpb, buf_len, "%c\2%c%c", isc_dpb_num_buffers, 869 | (char)(largs[BUF] >> 8), (char)(largs[BUF] & 0xff)); 870 | dpb += dpb_len; 871 | buf_len -= dpb_len; 872 | } 873 | if (largs[SYNC] && buf_len > 0) { 874 | dpb_len = slprintf(dpb, buf_len, "%c\1%c", isc_dpb_force_write, largs[SYNC] == isc_spb_prp_wm_sync); 875 | dpb += dpb_len; 876 | buf_len -= dpb_len; 877 | } 878 | if (isc_attach_database(IB_STATUS, (short)len[DB], args[DB], db, (short)(dpb-dpb_buffer), dpb_buffer)) { 879 | _php_ibase_error(); 880 | return FAILURE; 881 | } 882 | return SUCCESS; 883 | } 884 | /* }}} */ 885 | 886 | static void _php_ibase_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) /* {{{ */ 887 | { 888 | char *c, hash[16], *args[] = { NULL, NULL, NULL, NULL, NULL }; 889 | int i; 890 | size_t len[] = { 0, 0, 0, 0, 0 }; 891 | zend_long largs[] = { 0, 0, 0 }; 892 | PHP_MD5_CTX hash_context; 893 | zend_resource new_index_ptr, *le; 894 | isc_db_handle db_handle = 0; 895 | ibase_db_link *ib_link; 896 | 897 | RESET_ERRMSG; 898 | 899 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "|ssssllsl", 900 | &args[DB], &len[DB], &args[USER], &len[USER], &args[PASS], &len[PASS], 901 | &args[CSET], &len[CSET], &largs[BUF], &largs[DLECT], &args[ROLE], &len[ROLE], 902 | &largs[SYNC])) { 903 | RETURN_FALSE; 904 | } 905 | 906 | /* restrict to the server/db in the .ini if in safe mode */ 907 | if (!len[DB] && (c = INI_STR("ibase.default_db"))) { 908 | args[DB] = c; 909 | len[DB] = strlen(c); 910 | } 911 | if (!len[USER] && (c = INI_STR("ibase.default_user"))) { 912 | args[USER] = c; 913 | len[USER] = strlen(c); 914 | } 915 | if (!len[PASS] && (c = INI_STR("ibase.default_password"))) { 916 | args[PASS] = c; 917 | len[PASS] = strlen(c); 918 | } 919 | if (!len[CSET] && (c = INI_STR("ibase.default_charset"))) { 920 | args[CSET] = c; 921 | len[CSET] = strlen(c); 922 | } 923 | 924 | /* don't want usernames and passwords floating around */ 925 | PHP_MD5Init(&hash_context); 926 | for (i = 0; i < sizeof(args)/sizeof(char*); ++i) { 927 | PHP_MD5Update(&hash_context,args[i],len[i]); 928 | } 929 | for (i = 0; i < sizeof(largs)/sizeof(zend_long); ++i) { 930 | PHP_MD5Update(&hash_context,(char*)&largs[i],sizeof(zend_long)); 931 | } 932 | PHP_MD5Final((unsigned char*)hash, &hash_context); 933 | 934 | /* try to reuse a connection */ 935 | if ((le = zend_hash_str_find_ptr(&EG(regular_list), hash, sizeof(hash)-1)) != NULL) { 936 | zend_resource *xlink; 937 | 938 | if (le->type != le_index_ptr) { 939 | RETURN_FALSE; 940 | } 941 | 942 | xlink = (zend_resource*) le->ptr; 943 | if ((!persistent && xlink->type == le_link) || xlink->type == le_plink) { 944 | if (IBG(default_link) != xlink) { 945 | GC_ADDREF(xlink); 946 | if (IBG(default_link)) { 947 | zend_list_delete(IBG(default_link)); 948 | } 949 | IBG(default_link) = xlink; 950 | } 951 | GC_ADDREF(xlink); 952 | RETURN_RES(xlink); 953 | } else { 954 | zend_hash_str_del(&EG(regular_list), hash, sizeof(hash)-1); 955 | } 956 | } 957 | 958 | /* ... or a persistent one */ 959 | do { 960 | zend_long l; 961 | static char info[] = { isc_info_base_level, isc_info_end }; 962 | char result[8]; 963 | ISC_STATUS status[20]; 964 | 965 | if ((le = zend_hash_str_find_ptr(&EG(persistent_list), hash, sizeof(hash)-1)) != NULL) { 966 | if (le->type != le_plink) { 967 | RETURN_FALSE; 968 | } 969 | /* check if connection has timed out */ 970 | ib_link = (ibase_db_link *) le->ptr; 971 | if (!isc_database_info(status, &ib_link->handle, sizeof(info), info, sizeof(result), result)) { 972 | RETVAL_RES(zend_register_resource(ib_link, le_plink)); 973 | break; 974 | } 975 | zend_hash_str_del(&EG(persistent_list), hash, sizeof(hash)-1); 976 | } 977 | 978 | /* no link found, so we have to open one */ 979 | 980 | if ((l = INI_INT("ibase.max_links")) != -1 && IBG(num_links) >= l) { 981 | _php_ibase_module_error("Too many open links (%ld)", IBG(num_links)); 982 | RETURN_FALSE; 983 | } 984 | 985 | /* create the ib_link */ 986 | if (FAILURE == _php_ibase_attach_db(args, len, largs, &db_handle)) { 987 | RETURN_FALSE; 988 | } 989 | 990 | /* use non-persistent if allowed number of persistent links is exceeded */ 991 | if (!persistent || ((l = INI_INT("ibase.max_persistent") != -1) && IBG(num_persistent) >= l)) { 992 | ib_link = (ibase_db_link *) emalloc(sizeof(ibase_db_link)); 993 | RETVAL_RES(zend_register_resource(ib_link, le_link)); 994 | } else { 995 | ib_link = (ibase_db_link *) malloc(sizeof(ibase_db_link)); 996 | if (!ib_link) { 997 | RETURN_FALSE; 998 | } 999 | 1000 | /* hash it up */ 1001 | if (zend_register_persistent_resource(hash, sizeof(hash)-1, ib_link, le_plink) == NULL) { 1002 | free(ib_link); 1003 | RETURN_FALSE; 1004 | } 1005 | RETVAL_RES(zend_register_resource(ib_link, le_plink)); 1006 | ++IBG(num_persistent); 1007 | } 1008 | ib_link->handle = db_handle; 1009 | ib_link->dialect = largs[DLECT] ? (unsigned short)largs[DLECT] : SQL_DIALECT_CURRENT; 1010 | ib_link->tr_list = NULL; 1011 | ib_link->event_head = NULL; 1012 | 1013 | ++IBG(num_links); 1014 | } while (0); 1015 | 1016 | /* add it to the hash */ 1017 | new_index_ptr.ptr = (void *) Z_RES_P(return_value); 1018 | new_index_ptr.type = le_index_ptr; 1019 | zend_hash_str_update_mem(&EG(regular_list), hash, sizeof(hash)-1, 1020 | (void *) &new_index_ptr, sizeof(zend_resource)); 1021 | if (IBG(default_link)) { 1022 | zend_list_delete(IBG(default_link)); 1023 | } 1024 | IBG(default_link) = Z_RES_P(return_value); 1025 | Z_TRY_ADDREF_P(return_value); 1026 | Z_TRY_ADDREF_P(return_value); 1027 | } 1028 | /* }}} */ 1029 | 1030 | /* {{{ proto resource ibase_connect([string database [, string username [, string password [, string charset [, int buffers [, int dialect [, string role]]]]]]]) 1031 | Open a connection to an InterBase database */ 1032 | PHP_FUNCTION(ibase_connect) 1033 | { 1034 | _php_ibase_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); 1035 | } 1036 | /* }}} */ 1037 | 1038 | /* {{{ proto resource ibase_pconnect([string database [, string username [, string password [, string charset [, int buffers [, int dialect [, string role]]]]]]]) 1039 | Open a persistent connection to an InterBase database */ 1040 | PHP_FUNCTION(ibase_pconnect) 1041 | { 1042 | _php_ibase_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, INI_INT("ibase.allow_persistent")); 1043 | } 1044 | /* }}} */ 1045 | 1046 | /* {{{ proto bool ibase_close([resource link_identifier]) 1047 | Close an InterBase connection */ 1048 | PHP_FUNCTION(ibase_close) 1049 | { 1050 | zval *link_arg = NULL; 1051 | zend_resource *link_res; 1052 | 1053 | RESET_ERRMSG; 1054 | 1055 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "|r", &link_arg) == FAILURE) { 1056 | return; 1057 | } 1058 | 1059 | if (ZEND_NUM_ARGS() == 0) { 1060 | link_res = IBG(default_link); 1061 | CHECK_LINK(link_res); 1062 | IBG(default_link) = NULL; 1063 | } else { 1064 | link_res = Z_RES_P(link_arg); 1065 | } 1066 | 1067 | /* we have at least 3 additional references to this resource ??? */ 1068 | if (GC_REFCOUNT(link_res) < 4) { 1069 | zend_list_close(link_res); 1070 | } else { 1071 | zend_list_delete(link_res); 1072 | } 1073 | RETURN_TRUE; 1074 | } 1075 | /* }}} */ 1076 | 1077 | /* {{{ proto bool ibase_drop_db([resource link_identifier]) 1078 | Drop an InterBase database */ 1079 | PHP_FUNCTION(ibase_drop_db) 1080 | { 1081 | zval *link_arg = NULL; 1082 | ibase_db_link *ib_link; 1083 | ibase_tr_list *l; 1084 | zend_resource *link_res; 1085 | 1086 | RESET_ERRMSG; 1087 | 1088 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "|r", &link_arg) == FAILURE) { 1089 | return; 1090 | } 1091 | 1092 | if (ZEND_NUM_ARGS() == 0) { 1093 | link_res = IBG(default_link); 1094 | CHECK_LINK(link_res); 1095 | IBG(default_link) = NULL; 1096 | } else { 1097 | link_res = Z_RES_P(link_arg); 1098 | } 1099 | 1100 | ib_link = (ibase_db_link *)zend_fetch_resource2(link_res, LE_LINK, le_link, le_plink); 1101 | 1102 | if (!ib_link) { 1103 | RETURN_FALSE; 1104 | } 1105 | 1106 | if (isc_drop_database(IB_STATUS, &ib_link->handle)) { 1107 | _php_ibase_error(); 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 = 0; 1114 | } 1115 | 1116 | zend_list_delete(link_res); 1117 | 1118 | RETURN_TRUE; 1119 | } 1120 | /* }}} */ 1121 | 1122 | /* {{{ proto resource ibase_trans([int trans_args [, resource link_identifier [, ... ], int trans_args [, resource link_identifier [, ... ]] [, ...]]]) 1123 | Start a transaction over one or several databases */ 1124 | 1125 | #define TPB_MAX_SIZE (8*sizeof(char)) 1126 | 1127 | PHP_FUNCTION(ibase_trans) 1128 | { 1129 | unsigned short i, link_cnt = 0, tpb_len = 0; 1130 | int argn = ZEND_NUM_ARGS(); 1131 | char last_tpb[TPB_MAX_SIZE]; 1132 | ibase_db_link **ib_link = NULL; 1133 | ibase_trans *ib_trans; 1134 | isc_tr_handle tr_handle = 0; 1135 | ISC_STATUS result; 1136 | 1137 | RESET_ERRMSG; 1138 | 1139 | /* (1+argn) is an upper bound for the number of links this trans connects to */ 1140 | ib_link = (ibase_db_link **) safe_emalloc(sizeof(ibase_db_link *),1+argn,0); 1141 | 1142 | if (argn > 0) { 1143 | zend_long trans_argl = 0; 1144 | char *tpb; 1145 | ISC_TEB *teb; 1146 | zval *args = NULL; 1147 | 1148 | if (zend_parse_parameters(argn, "+", &args, &argn) == FAILURE) { 1149 | efree(ib_link); 1150 | RETURN_FALSE; 1151 | } 1152 | 1153 | teb = (ISC_TEB *) safe_emalloc(sizeof(ISC_TEB),argn,0); 1154 | tpb = (char *) safe_emalloc(TPB_MAX_SIZE,argn,0); 1155 | 1156 | /* enumerate all the arguments: assume every non-resource argument 1157 | specifies modifiers for the link ids that follow it */ 1158 | for (i = 0; i < argn; ++i) { 1159 | 1160 | if (Z_TYPE(args[i]) == IS_RESOURCE) { 1161 | 1162 | if ((ib_link[link_cnt] = (ibase_db_link *)zend_fetch_resource2_ex(&args[i], LE_LINK, le_link, le_plink)) == NULL) { 1163 | efree(teb); 1164 | efree(tpb); 1165 | efree(ib_link); 1166 | RETURN_FALSE; 1167 | } 1168 | 1169 | /* copy the most recent modifier string into tbp[] */ 1170 | memcpy(&tpb[TPB_MAX_SIZE * link_cnt], last_tpb, TPB_MAX_SIZE); 1171 | 1172 | /* add a database handle to the TEB with the most recently specified set of modifiers */ 1173 | teb[link_cnt].db_ptr = &ib_link[link_cnt]->handle; 1174 | teb[link_cnt].tpb_len = tpb_len; 1175 | teb[link_cnt].tpb_ptr = &tpb[TPB_MAX_SIZE * link_cnt]; 1176 | 1177 | ++link_cnt; 1178 | 1179 | } else { 1180 | 1181 | tpb_len = 0; 1182 | 1183 | convert_to_long_ex(&args[i]); 1184 | trans_argl = Z_LVAL(args[i]); 1185 | 1186 | if (trans_argl != PHP_IBASE_DEFAULT) { 1187 | last_tpb[tpb_len++] = isc_tpb_version3; 1188 | 1189 | /* access mode */ 1190 | if (PHP_IBASE_READ == (trans_argl & PHP_IBASE_READ)) { 1191 | last_tpb[tpb_len++] = isc_tpb_read; 1192 | } else if (PHP_IBASE_WRITE == (trans_argl & PHP_IBASE_WRITE)) { 1193 | last_tpb[tpb_len++] = isc_tpb_write; 1194 | } 1195 | 1196 | /* isolation level */ 1197 | if (PHP_IBASE_COMMITTED == (trans_argl & PHP_IBASE_COMMITTED)) { 1198 | last_tpb[tpb_len++] = isc_tpb_read_committed; 1199 | if (PHP_IBASE_REC_VERSION == (trans_argl & PHP_IBASE_REC_VERSION)) { 1200 | last_tpb[tpb_len++] = isc_tpb_rec_version; 1201 | } else if (PHP_IBASE_REC_NO_VERSION == (trans_argl & PHP_IBASE_REC_NO_VERSION)) { 1202 | last_tpb[tpb_len++] = isc_tpb_no_rec_version; 1203 | } 1204 | } else if (PHP_IBASE_CONSISTENCY == (trans_argl & PHP_IBASE_CONSISTENCY)) { 1205 | last_tpb[tpb_len++] = isc_tpb_consistency; 1206 | } else if (PHP_IBASE_CONCURRENCY == (trans_argl & PHP_IBASE_CONCURRENCY)) { 1207 | last_tpb[tpb_len++] = isc_tpb_concurrency; 1208 | } 1209 | 1210 | /* lock resolution */ 1211 | if (PHP_IBASE_NOWAIT == (trans_argl & PHP_IBASE_NOWAIT)) { 1212 | last_tpb[tpb_len++] = isc_tpb_nowait; 1213 | } else if (PHP_IBASE_WAIT == (trans_argl & PHP_IBASE_WAIT)) { 1214 | last_tpb[tpb_len++] = isc_tpb_wait; 1215 | } 1216 | } 1217 | } 1218 | } 1219 | 1220 | if (link_cnt > 0) { 1221 | result = isc_start_multiple(IB_STATUS, &tr_handle, link_cnt, teb); 1222 | } 1223 | 1224 | efree(tpb); 1225 | efree(teb); 1226 | } 1227 | 1228 | if (link_cnt == 0) { 1229 | link_cnt = 1; 1230 | if ((ib_link[0] = (ibase_db_link *)zend_fetch_resource2(IBG(default_link), LE_LINK, le_link, le_plink)) == NULL) { 1231 | efree(ib_link); 1232 | RETURN_FALSE; 1233 | } 1234 | result = isc_start_transaction(IB_STATUS, &tr_handle, 1, &ib_link[0]->handle, tpb_len, last_tpb); 1235 | } 1236 | 1237 | /* start the transaction */ 1238 | if (result) { 1239 | _php_ibase_error(); 1240 | efree(ib_link); 1241 | RETURN_FALSE; 1242 | } 1243 | 1244 | /* register the transaction in our own data structures */ 1245 | ib_trans = (ibase_trans *) safe_emalloc(link_cnt-1, sizeof(ibase_db_link *), sizeof(ibase_trans)); 1246 | ib_trans->handle = tr_handle; 1247 | ib_trans->link_cnt = link_cnt; 1248 | ib_trans->affected_rows = 0; 1249 | for (i = 0; i < link_cnt; ++i) { 1250 | ibase_tr_list **l; 1251 | ib_trans->db_link[i] = ib_link[i]; 1252 | 1253 | /* the first item in the connection-transaction list is reserved for the default transaction */ 1254 | if (ib_link[i]->tr_list == NULL) { 1255 | ib_link[i]->tr_list = (ibase_tr_list *) emalloc(sizeof(ibase_tr_list)); 1256 | ib_link[i]->tr_list->trans = NULL; 1257 | ib_link[i]->tr_list->next = NULL; 1258 | } 1259 | 1260 | /* link the transaction into the connection-transaction list */ 1261 | for (l = &ib_link[i]->tr_list; *l != NULL; l = &(*l)->next); 1262 | *l = (ibase_tr_list *) emalloc(sizeof(ibase_tr_list)); 1263 | (*l)->trans = ib_trans; 1264 | (*l)->next = NULL; 1265 | } 1266 | efree(ib_link); 1267 | RETVAL_RES(zend_register_resource(ib_trans, le_trans)); 1268 | Z_TRY_ADDREF_P(return_value); 1269 | } 1270 | /* }}} */ 1271 | 1272 | int _php_ibase_def_trans(ibase_db_link *ib_link, ibase_trans **trans) /* {{{ */ 1273 | { 1274 | if (ib_link == NULL) { 1275 | php_error_docref(NULL, E_WARNING, "Invalid database link"); 1276 | return FAILURE; 1277 | } 1278 | 1279 | /* the first item in the connection-transaction list is reserved for the default transaction */ 1280 | if (ib_link->tr_list == NULL) { 1281 | ib_link->tr_list = (ibase_tr_list *) emalloc(sizeof(ibase_tr_list)); 1282 | ib_link->tr_list->trans = NULL; 1283 | ib_link->tr_list->next = NULL; 1284 | } 1285 | 1286 | if (*trans == NULL) { 1287 | ibase_trans *tr = ib_link->tr_list->trans; 1288 | 1289 | if (tr == NULL) { 1290 | tr = (ibase_trans *) emalloc(sizeof(ibase_trans)); 1291 | tr->handle = 0; 1292 | tr->link_cnt = 1; 1293 | tr->affected_rows = 0; 1294 | tr->db_link[0] = ib_link; 1295 | ib_link->tr_list->trans = tr; 1296 | } 1297 | if (tr->handle == 0) { 1298 | if (isc_start_transaction(IB_STATUS, &tr->handle, 1, &ib_link->handle, 0, NULL)) { 1299 | _php_ibase_error(); 1300 | return FAILURE; 1301 | } 1302 | } 1303 | *trans = tr; 1304 | } 1305 | return SUCCESS; 1306 | } 1307 | /* }}} */ 1308 | 1309 | static void _php_ibase_trans_end(INTERNAL_FUNCTION_PARAMETERS, int commit) /* {{{ */ 1310 | { 1311 | ibase_trans *trans = NULL; 1312 | int res_id = 0; 1313 | ISC_STATUS result; 1314 | ibase_db_link *ib_link; 1315 | zval *arg = NULL; 1316 | 1317 | RESET_ERRMSG; 1318 | 1319 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "|r", &arg) == FAILURE) { 1320 | return; 1321 | } 1322 | 1323 | if (ZEND_NUM_ARGS() == 0) { 1324 | ib_link = (ibase_db_link *)zend_fetch_resource2(IBG(default_link), LE_LINK, le_link, le_plink); 1325 | if (ib_link->tr_list == NULL || ib_link->tr_list->trans == NULL) { 1326 | /* this link doesn't have a default transaction */ 1327 | _php_ibase_module_error("Default link has no default transaction"); 1328 | RETURN_FALSE; 1329 | } 1330 | trans = ib_link->tr_list->trans; 1331 | } else { 1332 | /* one id was passed, could be db or trans id */ 1333 | if (Z_RES_P(arg)->type == le_trans) { 1334 | trans = (ibase_trans *)zend_fetch_resource_ex(arg, LE_TRANS, le_trans); 1335 | res_id = Z_RES_P(arg)->handle; 1336 | } else { 1337 | ib_link = (ibase_db_link *)zend_fetch_resource2_ex(arg, LE_LINK, le_link, le_plink); 1338 | 1339 | if (ib_link->tr_list == NULL || ib_link->tr_list->trans == NULL) { 1340 | /* this link doesn't have a default transaction */ 1341 | _php_ibase_module_error("Link has no default transaction"); 1342 | RETURN_FALSE; 1343 | } 1344 | trans = ib_link->tr_list->trans; 1345 | } 1346 | } 1347 | 1348 | switch (commit) { 1349 | default: /* == case ROLLBACK: */ 1350 | result = isc_rollback_transaction(IB_STATUS, &trans->handle); 1351 | break; 1352 | case COMMIT: 1353 | result = isc_commit_transaction(IB_STATUS, &trans->handle); 1354 | break; 1355 | case (ROLLBACK | RETAIN): 1356 | result = isc_rollback_retaining(IB_STATUS, &trans->handle); 1357 | break; 1358 | case (COMMIT | RETAIN): 1359 | result = isc_commit_retaining(IB_STATUS, &trans->handle); 1360 | break; 1361 | } 1362 | 1363 | if (result) { 1364 | _php_ibase_error(); 1365 | RETURN_FALSE; 1366 | } 1367 | 1368 | /* Don't try to destroy implicitly opened transaction from list... */ 1369 | if ((commit & RETAIN) == 0 && res_id != 0) { 1370 | zend_list_delete(Z_RES_P(arg)); 1371 | } 1372 | RETURN_TRUE; 1373 | } 1374 | /* }}} */ 1375 | 1376 | /* {{{ proto bool ibase_commit( resource link_identifier ) 1377 | Commit transaction */ 1378 | PHP_FUNCTION(ibase_commit) 1379 | { 1380 | _php_ibase_trans_end(INTERNAL_FUNCTION_PARAM_PASSTHRU, COMMIT); 1381 | } 1382 | /* }}} */ 1383 | 1384 | /* {{{ proto bool ibase_rollback( resource link_identifier ) 1385 | Rollback transaction */ 1386 | PHP_FUNCTION(ibase_rollback) 1387 | { 1388 | _php_ibase_trans_end(INTERNAL_FUNCTION_PARAM_PASSTHRU, ROLLBACK); 1389 | } 1390 | /* }}} */ 1391 | 1392 | /* {{{ proto bool ibase_commit_ret( resource link_identifier ) 1393 | Commit transaction and retain the transaction context */ 1394 | PHP_FUNCTION(ibase_commit_ret) 1395 | { 1396 | _php_ibase_trans_end(INTERNAL_FUNCTION_PARAM_PASSTHRU, COMMIT | RETAIN); 1397 | } 1398 | /* }}} */ 1399 | 1400 | /* {{{ proto bool ibase_rollback_ret( resource link_identifier ) 1401 | Rollback transaction and retain the transaction context */ 1402 | PHP_FUNCTION(ibase_rollback_ret) 1403 | { 1404 | _php_ibase_trans_end(INTERNAL_FUNCTION_PARAM_PASSTHRU, ROLLBACK | RETAIN); 1405 | } 1406 | /* }}} */ 1407 | 1408 | /* {{{ proto int ibase_gen_id(string generator [, int increment [, resource link_identifier ]]) 1409 | Increments the named generator and returns its new value */ 1410 | PHP_FUNCTION(ibase_gen_id) 1411 | { 1412 | zval *link = NULL; 1413 | char query[128], *generator; 1414 | size_t gen_len; 1415 | zend_long inc = 1; 1416 | ibase_db_link *ib_link; 1417 | ibase_trans *trans = NULL; 1418 | XSQLDA out_sqlda; 1419 | ISC_INT64 result; 1420 | 1421 | RESET_ERRMSG; 1422 | 1423 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "s|lr", &generator, &gen_len, 1424 | &inc, &link)) { 1425 | RETURN_FALSE; 1426 | } 1427 | 1428 | if (gen_len > 31) { 1429 | php_error_docref(NULL, E_WARNING, "Invalid generator name"); 1430 | RETURN_FALSE; 1431 | } 1432 | 1433 | PHP_IBASE_LINK_TRANS(link, ib_link, trans); 1434 | 1435 | snprintf(query, sizeof(query), "SELECT GEN_ID(%s,%ld) FROM rdb$database", generator, inc); 1436 | 1437 | /* allocate a minimal descriptor area */ 1438 | out_sqlda.sqln = out_sqlda.sqld = 1; 1439 | out_sqlda.version = SQLDA_CURRENT_VERSION; 1440 | 1441 | /* allocate the field for the result */ 1442 | out_sqlda.sqlvar[0].sqltype = SQL_INT64; 1443 | out_sqlda.sqlvar[0].sqlscale = 0; 1444 | out_sqlda.sqlvar[0].sqllen = sizeof(result); 1445 | out_sqlda.sqlvar[0].sqldata = (void*) &result; 1446 | 1447 | /* execute the query */ 1448 | if (isc_dsql_exec_immed2(IB_STATUS, &ib_link->handle, &trans->handle, 0, query, 1449 | SQL_DIALECT_CURRENT, NULL, &out_sqlda)) { 1450 | _php_ibase_error(); 1451 | RETURN_FALSE; 1452 | } 1453 | 1454 | /* don't return the generator value as a string unless it doesn't fit in a long */ 1455 | #if SIZEOF_ZEND_LONG < 8 1456 | if (result < ZEND_LONG_MIN || result > ZEND_LONG_MAX) { 1457 | char *res; 1458 | int l; 1459 | 1460 | l = spprintf(&res, 0, "%" LL_MASK "d", result); 1461 | RETURN_STRINGL(res, l); 1462 | } 1463 | #endif 1464 | RETURN_LONG((zend_long)result); 1465 | } 1466 | 1467 | /* }}} */ 1468 | 1469 | #endif /* HAVE_IBASE */ 1470 | --------------------------------------------------------------------------------