abies           Tue Aug  5 09:17:16 2003 EDT

  Modified files:              
    /php-src/ext/interbase      config.m4 interbase.c php_interbase.h 
  Log:
  Significant changes to layout of internal data structures
  in order to accomodate and carry out the following changes:
  * Removal of arbitrary 'transactions-per-link' limit,
  * Transactions over multiple databases.
  
  Leak fixes in ibase_query() and ibase_execute() by replacing
  emalloc() with do_alloca()
  
  Changes to ibase_query() to enable the use of CREATE DATABASE ...
  
  Added ibase_drop_db()
  
  
  
Index: php-src/ext/interbase/config.m4
diff -u php-src/ext/interbase/config.m4:1.12 php-src/ext/interbase/config.m4:1.13
--- php-src/ext/interbase/config.m4:1.12        Fri Apr 25 04:57:49 2003
+++ php-src/ext/interbase/config.m4     Tue Aug  5 09:17:15 2003
@@ -1,5 +1,5 @@
 dnl
-dnl $Id: config.m4,v 1.12 2003/04/25 08:57:49 sniper Exp $
+dnl $Id: config.m4,v 1.13 2003/08/05 13:17:15 abies Exp $
 dnl
 
 PHP_ARG_WITH(interbase,for InterBase support,
@@ -25,10 +25,10 @@
     ], [
       AC_MSG_ERROR([libgds or libib_util not found! Check config.log for more 
information.])
     ], [
-      -L$IBASE_LIBDIR
+      -L$IBASE_LIBDIR -lcrypt
     ])
   ], [
-    -L$IBASE_LIBDIR
+    -L$IBASE_LIBDIR -lcrypt 
   ])
 
   PHP_ADD_LIBRARY_WITH_PATH($IBASE_LIBNAME, $IBASE_LIBDIR, INTERBASE_SHARED_LIBADD)
Index: php-src/ext/interbase/interbase.c
diff -u php-src/ext/interbase/interbase.c:1.112 php-src/ext/interbase/interbase.c:1.113
--- php-src/ext/interbase/interbase.c:1.112     Wed Jul  9 20:17:09 2003
+++ php-src/ext/interbase/interbase.c   Tue Aug  5 09:17:15 2003
@@ -17,7 +17,7 @@
    +----------------------------------------------------------------------+
  */
 
-/* $Id: interbase.c,v 1.112 2003/07/10 00:17:09 sniper Exp $ */
+/* $Id: interbase.c,v 1.113 2003/08/05 13:17:15 abies Exp $ */
 
 
 /* TODO: Arrays, roles?
@@ -25,6 +25,15 @@
 
 /*
        Changes:
+               2003-08-05: Ard Biesheuvel <[EMAIL PROTECTED]>
+                       - Significant changes to layout of internal data structures
+                         in order to accomodate and carry out the following changes:
+                         * Removal of arbitrary 'transactions-per-link' limit,
+                         * Transactions over multiple databases.
+                       - Leak fixes in ibase_query() and ibase_execute() by replacing
+                         emalloc() with do_alloca()
+                       - Changes to ibase_query() to enable the use of CREATE 
DATABASE ...
+                       - Added ibase_drop_db()
                2001-05-31: Jeremy Bettis <[EMAIL PROTECTED]>
                        - If a blob handle was expected and something else was
                          received create a blob and add the value to it.
@@ -65,10 +74,11 @@
 #define SQL_DIALECT_CURRENT 1
 #endif
 
-/*
-#define IBDEBUG(a) php_printf("::: %s (%d)\n", a, __LINE__);
-*/
+#ifdef ZEND_DEBUG
+#define IBDEBUG(a) php_printf("::: %s (%s:%d)\n", a, __FILE__, __LINE__);
+#else
 #define IBDEBUG(a)
+#endif
 
 #define SAFE_STRING(s) ((s)?(s):"")
 
@@ -77,6 +87,7 @@
        PHP_FE(ibase_connect, NULL)
        PHP_FE(ibase_pconnect, NULL)
        PHP_FE(ibase_close, NULL)
+       PHP_FE(ibase_drop_db, NULL)
        PHP_FE(ibase_query, NULL)
        PHP_FE(ibase_fetch_row, NULL)
        PHP_FE(ibase_fetch_assoc, NULL)
@@ -146,37 +157,96 @@
 
 /* }}} */
 
-/* {{{ internal macros, functions and structures */
+/* error handling ---------------------------- */
 
 #define IB_STATUS (IBG(status))
 
+/* {{{ proto string ibase_errmsg(void) 
+   Return error message */
+PHP_FUNCTION(ibase_errmsg)
+{
+       if (ZEND_NUM_ARGS() != 0) {
+               WRONG_PARAM_COUNT;
+       }
+
+       if (IBG(errmsg[0])) {
+               RETURN_STRING(IBG(errmsg), 1);
+       }
+
+       RETURN_FALSE;
+}
+/* }}} */
+
+/* {{{ _php_ibase_error(TSRMLS_D) 
+   print interbase error and save it for ibase_errmsg() */
+static void _php_ibase_error(TSRMLS_D)
+{
+       char *s;
+       ISC_STATUS *statusp;
+
+       s = IBG(errmsg);
+       statusp = IB_STATUS;
+
+       while ((s - IBG(errmsg)) < MAX_ERRMSG - (IBASE_MSGSIZE + 2) && 
isc_interprete(s, &statusp)) {
+               strcat(IBG(errmsg), " ");
+               s = IBG(errmsg) + strlen(IBG(errmsg));
+       }
+
+       php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", IBG(errmsg));
+}
+/* }}} */
+
+/* {{{ _php_ibase_module_error()
+   print php interbase module error and save it for ibase_errmsg() */
+static void _php_ibase_module_error(char *msg, ...)
+{
+       va_list ap;
+       TSRMLS_FETCH();
+
+       va_start(ap, msg);
+       /* vsnprintf NUL terminates the buf and writes at most n-1 chars+NUL */
+       vsnprintf(IBG(errmsg), MAX_ERRMSG, msg, ap);
+       va_end(ap);
+       
+       php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", IBG(errmsg));
+}
+/* }}} */
+
+/* {{{ internal macros, functions and structures */
+
+typedef struct {
+    isc_db_handle *db_ptr;
+    long tpb_len;
+    char *tpb_ptr;
+} ISC_TEB;
+
 /* Fill ib_link and trans_n with the correct database link and transaction slot 
number.
  */
-static void get_link_trans(INTERNAL_FUNCTION_PARAMETERS, zval **link_id, 
ibase_db_link **ib_link, int *trans_n, int *trans_id)
+static void _php_ibase_get_link_trans(INTERNAL_FUNCTION_PARAMETERS, zval **link_id, 
ibase_db_link **ib_link, ibase_trans **trans)
 {
        int type;
        void *resource = NULL;
-       ibase_tr_link *ib_trans;
 
        IBDEBUG("Transaction or database link?");
        if ((resource = zend_list_find(Z_LVAL_PP(link_id), &type))) {
                IBDEBUG("Found in list");
                if (type == le_trans) {
-                       /* Transaction resource. Fetch it, database link resource
-                          is stored in ib_trans->link_rsrc. */
+                       /* Transaction resource: make sure it refers to one link only, 
then 
+                          fetch it; database link is stored in ib_trans->link[]. */
                        IBDEBUG("Type is le_trans");
-                       *trans_id = (Z_LVAL_PP(link_id));
-                       ZEND_FETCH_RESOURCE(ib_trans, ibase_tr_link *, link_id, -1, 
"InterBase transaction", le_trans);
-                       *trans_n = ib_trans->trans_num;
-                       ZEND_FETCH_RESOURCE2(resource, ibase_db_link *, NULL, 
ib_trans->link_rsrc, "InterBase link", le_link, le_plink);
+                       ZEND_FETCH_RESOURCE(*trans, ibase_trans *, link_id, -1, 
"InterBase transaction", le_trans);
+                       if ((*trans)->link_cnt > 1) {
+                               _php_ibase_module_error("Link id is ambiguous: 
transaction spans multiple connections.");
+                               return;
+                       }                               
+                       *ib_link = (*trans)->link[0];
                } else {
                        IBDEBUG("Type is le_[p]link");
-                       /* Database link resource, use default transaction (=0). */
-                       *trans_n = 0;
-                       ZEND_FETCH_RESOURCE2(resource, ibase_db_link *, link_id, -1, 
"InterBase link", le_link, le_plink);
+                       /* Database link resource, use default transaction. */
+                       *trans = NULL;
+                       ZEND_FETCH_RESOURCE2(*ib_link, ibase_db_link *, link_id, -1, 
"InterBase link", le_link, le_plink);
                }
        }
-       *ib_link = resource;
 }
        
 #define RESET_ERRMSG { IBG(errmsg)[0] = '\0';}
@@ -241,59 +311,6 @@
 
 /* }}} */
 
-/* error handling ---------------------------- */
-
-/* {{{ proto string ibase_errmsg(void) 
-   Return error message */
-PHP_FUNCTION(ibase_errmsg)
-{
-       if (ZEND_NUM_ARGS() != 0) {
-               WRONG_PARAM_COUNT;
-       }
-
-       if (IBG(errmsg[0])) {
-               RETURN_STRING(IBG(errmsg), 1);
-       }
-
-       RETURN_FALSE;
-}
-/* }}} */
-
-/* {{{ _php_ibase_error(TSRMLS_D) 
-   print interbase error and save it for ibase_errmsg() */
-static void _php_ibase_error(TSRMLS_D)
-{
-       char *s;
-       ISC_STATUS *statusp;
-
-       s = IBG(errmsg);
-       statusp = IB_STATUS;
-
-       while ((s - IBG(errmsg)) < MAX_ERRMSG - (IBASE_MSGSIZE + 2) && 
isc_interprete(s, &statusp)) {
-               strcat(IBG(errmsg), " ");
-               s = IBG(errmsg) + strlen(IBG(errmsg));
-       }
-
-       php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", IBG(errmsg));
-}
-/* }}} */
-
-/* {{{ _php_ibase_module_error()
-   print php interbase module error and save it for ibase_errmsg() */
-static void _php_ibase_module_error(char *msg, ...)
-{
-       va_list ap;
-       TSRMLS_FETCH();
-
-       va_start(ap, msg);
-       /* vsnprintf NUL terminates the buf and writes at most n-1 chars+NUL */
-       vsnprintf(IBG(errmsg), MAX_ERRMSG, msg, ap);
-       va_end(ap);
-       
-       php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", IBG(errmsg));
-}
-/* }}} */
-
 
 /* destructors ---------------------- */
 
@@ -323,25 +340,40 @@
  */
 static void _php_ibase_commit_link(ibase_db_link *link TSRMLS_DC)
 {
-       int i;
-
+       int i = 0, j;
+       ibase_tr_list *l;
        IBDEBUG("Checking transactions to close...");
-       if (link->trans[0] != NULL) { /* commit default */
-               IBDEBUG("Committing default transaction...");
-               if (isc_commit_transaction(IB_STATUS, &link->trans[0])) {
-                       _php_ibase_error(TSRMLS_C);
-               }
-               link->trans[0] = NULL;
-       }
-       for (i = 1; i < IBASE_TRANS_ON_LINK; i++) {
-               if (link->trans[i] != NULL) {
-                       IBDEBUG("Rolling back other transactions...");
-                       if (isc_rollback_transaction(IB_STATUS, &link->trans[i])) {
-                               _php_ibase_error(TSRMLS_C);
+
+       for (l = link->trans; l != NULL; ++i) {
+               ibase_tr_list *p = l;
+               if (p->trans != NULL) {
+                       if (i == 0) {
+                               IBDEBUG("Committing default transaction...");
+                               if (isc_commit_transaction(IB_STATUS, 
&p->trans->handle)) {
+                                       _php_ibase_error(TSRMLS_C);
+                               }
+                               efree(p->trans); /* default transaction is not a 
registered resource: clean up */
+                       }
+                       else if (p->trans->handle != NULL) { 
+                               /* non-default transaction might have been rolled back 
by other call of this dtor */
+                               IBDEBUG("Rolling back other transactions...");
+                               if (isc_rollback_transaction(IB_STATUS, 
&p->trans->handle)) {
+                                       _php_ibase_error(TSRMLS_C);
+                               }
+
+                               /* set this link pointer to NULL in the transaction */
+                               for (j = 0; j < p->trans->link_cnt; ++j) {
+                                       if (p->trans->link[j] == link) {
+                                               p->trans->link[j] = NULL;
+                                               break;
+                                       }
+                               }
                        }
-                       link->trans[i] = NULL;
                }
+               l = l->next;
+               efree(p);
        }
+       link->trans = NULL;
 }
 /* }}} */
 
@@ -360,7 +392,9 @@
 
        _php_ibase_commit_link(link TSRMLS_CC);
        IBDEBUG("Closing normal link...");
-       isc_detach_database(IB_STATUS, &link->link);
+       if (link->link != NULL) {
+               isc_detach_database(IB_STATUS, &link->link);
+       }
        IBG(num_links)--;
        efree(link);
 }
@@ -374,7 +408,9 @@
 
        _php_ibase_commit_link(link TSRMLS_CC);
        IBDEBUG("Closing permanent link...");
-       isc_detach_database(IB_STATUS, &link->link);
+       if (link->link != NULL) {
+               isc_detach_database(IB_STATUS, &link->link);
+       }
        IBG(num_persistent)--;
        IBG(num_links)--;
        free(link);
@@ -486,26 +522,32 @@
 /* {{{ _php_ibase_free_trans() */
 static void _php_ibase_free_trans(zend_rsrc_list_entry *rsrc TSRMLS_DC)
 {
-       ibase_tr_link *ib_trans = (ibase_tr_link *)rsrc->ptr;
-       ibase_db_link *ib_link;
-       int type;
-       void *ptr;
+       ibase_trans *trans = (ibase_trans*)rsrc->ptr;
+       int i;
+       
+       IBDEBUG("Cleaning up transaction resource...");
+       if (trans->handle != NULL) {
+               IBDEBUG("Rolling back unhandled transaction...");
+               if (isc_rollback_transaction(IB_STATUS, &trans->handle)) {
+                       _php_ibase_error(TSRMLS_C);
+               }
+       }
 
-       ptr = zend_list_find(ib_trans->link_rsrc, &type);        /* check if the link 
is still there */
-       if (ptr && (type == le_link || type == le_plink)) {
-               ib_link = (ibase_db_link *) zend_fetch_resource(NULL TSRMLS_CC, 
ib_trans->link_rsrc, "InterBase link", NULL, 2, le_link, le_plink);
-       
-               if (ib_link) {
-                       if (ib_link->trans[ib_trans->trans_num] != NULL) {
-                               IBDEBUG("Rolling back unhandled transaction...");
-                               if (isc_rollback_transaction(IB_STATUS, 
&ib_link->trans[ib_trans->trans_num])) {
-                                       _php_ibase_error(TSRMLS_C);
+       /* now remove this transaction from all the connection-transaction lists */
+       for (i = 0; i < trans->link_cnt; ++i) {
+               if (trans->link[i] != NULL) {
+                       ibase_tr_list **l;
+                       for (l = &trans->link[i]->trans; *l != NULL; l = &(*l)->next) {
+                               if ( (*l)->trans == trans) {
+                                       ibase_tr_list *p = *l;
+                                       *l = p->next;
+                                       efree(p);
+                                       break;
                                }
-                               ib_link->trans[ib_trans->trans_num] = NULL;
                        }
                }
-       }       
-       efree(ib_trans);
+       }
+       efree(trans);
 }
 /* }}} */
 
@@ -628,7 +670,7 @@
 
        php_info_print_table_start();
        php_info_print_table_row(2, "Interbase Support", "enabled");
-       php_info_print_table_row(2, "Revision", "$Revision: 1.112 $");
+       php_info_print_table_row(2, "Revision", "$Revision: 1.113 $");
 #ifdef COMPILE_DL_INTERBASE
        php_info_print_table_row(2, "Dynamic Module", "yes");
 #endif
@@ -723,7 +765,7 @@
 {
        zval ***args;
        char *ib_server = NULL, *ib_uname, *ib_passwd, *ib_charset = NULL, *ib_buffers 
= NULL, *ib_dialect = NULL, *ib_role = NULL;
-       int i, ib_uname_len, ib_passwd_len;
+       int ib_uname_len, ib_passwd_len;
        isc_db_handle db_handle = NULL;
        char *hashed_details;
        int hashed_details_length = 0;
@@ -833,11 +875,8 @@
                        ib_link = (ibase_db_link *) malloc(sizeof(ibase_db_link));
                        ib_link->link = db_handle;
                        ib_link->dialect = (ib_dialect ? (unsigned short) 
strtoul(ib_dialect, NULL, 10) : SQL_DIALECT_CURRENT);
+                       ib_link->trans = NULL;
 
-                       for (i = 0; i < IBASE_TRANS_ON_LINK; i++) {
-                               ib_link->trans[i] = NULL;
-                       }
-                                               
                        /* hash it up */
                        Z_TYPE(new_le) = le_plink;
                        new_le.ptr = ib_link;
@@ -868,7 +907,7 @@
                        }
                        xlink = (int) index_ptr->ptr;
                        ptr = zend_list_find(xlink, &type);      /* check if the xlink 
is still there */
-                       if (ptr && (type == le_link || type == le_plink)) {
+                       if (    ptr && (type == le_link || type == le_plink)) {
                                zend_list_addref(xlink);
                                Z_LVAL_P(return_value) = xlink;
                                Z_TYPE_P(return_value) = IS_RESOURCE;
@@ -896,10 +935,7 @@
                ib_link = (ibase_db_link *) emalloc(sizeof(ibase_db_link));
                ib_link->link = db_handle;
                ib_link->dialect = (ib_dialect ? (unsigned short) strtoul(ib_dialect, 
NULL, 10) : SQL_DIALECT_CURRENT);
-
-               for (i = 0; i < IBASE_TRANS_ON_LINK; i++) {
-                       ib_link->trans[i] = NULL;
-               }
+               ib_link->trans = NULL;
                
                ZEND_REGISTER_RESOURCE(return_value, ib_link, le_link);
 
@@ -966,6 +1002,42 @@
 }
 /* }}} */
 
+/* {{{ proto bool ibase_drop_db([resource link_identifier])
+   Drop an InterBase database */
+PHP_FUNCTION(ibase_drop_db)
+{
+       zval **link_arg;
+       ibase_db_link *ib_link;
+       int link_id;
+       
+       RESET_ERRMSG;
+       
+       switch (ZEND_NUM_ARGS()) {
+               case 0:
+                       link_id = IBG(default_link);
+                       break;
+               case 1:
+                       if (zend_get_parameters_ex(1, &link_arg) == FAILURE) {
+                               RETURN_FALSE;
+                       }
+                       convert_to_long_ex(link_arg);
+                       link_id = Z_LVAL_PP(link_arg);
+                       break;
+               default:
+                       WRONG_PARAM_COUNT;
+                       break;
+       }
+
+       ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, link_arg, link_id, "InterBase 
link", le_link, le_plink);
+       if (isc_drop_database(IB_STATUS, &ib_link->link)) {
+               _php_ibase_error(TSRMLS_C);
+               RETURN_FALSE;
+       }
+       zend_list_delete(link_id);
+       RETURN_TRUE;
+}
+/* }}} */
+
 /* {{{ _php_ibase_alloc_array() */
 static int _php_ibase_alloc_array(ibase_array **ib_arrayp, int *array_cntp, XSQLDA 
*sqlda, isc_db_handle link, isc_tr_handle trans TSRMLS_DC)
 {
@@ -1509,34 +1581,36 @@
 PHP_FUNCTION(ibase_trans)
 {
        zval ***args;
-       char tpb[20], *tpbp = NULL;
+       char tpb[20];
        long trans_argl = 0;
-       int tpb_len = 0, argn, link_id, trans_n = 0, i;
-       ibase_db_link *ib_link;
-       ibase_tr_link *ib_trans;
+       int tpb_len = 0, argn, link_cnt, link_id[19], i;
+       ibase_db_link *ib_link[19];
+       ibase_trans *ib_trans;
+
+       ISC_TEB *teb;
+    isc_tr_handle tr_handle = NULL;
        
        RESET_ERRMSG;
 
-       link_id = IBG(default_link);
-
-       /* TODO: multi-databases trans */
        argn = ZEND_NUM_ARGS();
-       if (argn < 0 || argn > 20) {
+       if (argn < 0) {
                WRONG_PARAM_COUNT;
        }
 
        if (argn) {
+        /* the number of databases this transaction connects to */
+           link_cnt = argn-1;
+
                args = (zval ***) emalloc(sizeof(zval **) * argn);
                if (zend_get_parameters_array_ex(argn, args) == FAILURE) {
                        efree(args);
                        RETURN_FALSE;
                }
 
-               /* Handle all database links, although we don't support multibase
-                  transactions yet, so only the last one is will be used. */
-               for (i = argn-1; i > 0 && Z_TYPE_PP(args[i]) == IS_RESOURCE; i--) {
-                       ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, args[i], -1, 
"InterBase link", le_link, le_plink);
-                       link_id = Z_LVAL_PP(args[i]);
+               /* Handle all database links. */
+               for (i = argn-1; i > 0 && Z_TYPE_PP(args[i]) == IS_RESOURCE; --i) {
+                       ZEND_FETCH_RESOURCE2(ib_link[i-1], ibase_db_link *, args[i], 
-1, "InterBase link", le_link, le_plink);
+                       link_id[i-1] = Z_LVAL_PP(args[i]);
                }
 
                /* First argument is transaction parameters */
@@ -1547,12 +1621,13 @@
        }
 
        if (argn < 2) {
-               ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, NULL, link_id, 
"InterBase link", le_link, le_plink);
+           link_cnt = 1;
+               ZEND_FETCH_RESOURCE2(ib_link[0], ibase_db_link *, NULL, 
IBG(default_link), "InterBase link", le_link, le_plink);
        }
 
        if (trans_argl) {
                tpb[tpb_len++] = isc_tpb_version3;
-               tpbp = tpb;
+               /* tpbp = tpb; */
                /* access mode */
                if (trans_argl & PHP_IBASE_READ) { /* READ ONLY TRANSACTION */
                        tpb[tpb_len++] = isc_tpb_read;
@@ -1581,39 +1656,78 @@
                }
        }
 
-       /* find empty transaction slot */
-       for (trans_n = 0; trans_n < IBASE_TRANS_ON_LINK && ib_link->trans[trans_n]; 
trans_n++);
-       if (trans_n == IBASE_TRANS_ON_LINK) {
-               _php_ibase_module_error("Too many transactions on link");
-               RETURN_FALSE;
+       /* allocate a TEB array */
+       teb = (ISC_TEB*) emalloc(sizeof(ISC_TEB) * link_cnt);
+       for (i = 0; i < link_cnt; ++i) {
+           teb[i].db_ptr = &ib_link[i]->link;
+           teb[i].tpb_len = tpb_len;
+           teb[i].tpb_ptr = tpb;
        }
        
-       if (isc_start_transaction(IB_STATUS, &ib_link->trans[trans_n], 1, 
&ib_link->link, tpb_len, tpbp)) {
+       /* start the transaction */
+       if (isc_start_multiple(IB_STATUS, &tr_handle, link_cnt, teb)) {
                _php_ibase_error(TSRMLS_C);
+               efree(teb);
                RETURN_FALSE;
        }
 
-       ib_trans = (ibase_tr_link *) emalloc(sizeof(ibase_tr_link));
-       ib_trans->trans_num = trans_n;
-       ib_trans->link_rsrc = link_id;
+       /* register the transaction in our own data structures */
+       ib_trans = (ibase_trans *) emalloc(sizeof(ibase_trans) + 
(link_cnt-1)*sizeof(ibase_db_link*));
+       ib_trans->handle = tr_handle;
+       ib_trans->link_cnt = link_cnt;
+       for (i = 0; i < link_cnt; ++i) {
+               ibase_tr_list **l;
+               ib_trans->link[i] = ib_link[i];
+               
+               /* the first item in the connection-transaction list is reserved for 
+                       the default transaction */
+               if (ib_link[i]->trans == NULL) {
+                       ib_link[i]->trans = 
(ibase_tr_list*)emalloc(sizeof(ibase_tr_list));
+                       ib_link[i]->trans->trans = NULL;
+                       ib_link[i]->trans->next = NULL;
+               }
+                           
+               /* link the transaction into the connection-transaction list */
+               for (l = &ib_link[i]->trans; *l != NULL; l = &(*l)->next);
+               *l = (ibase_tr_list*) emalloc(sizeof(ibase_tr_list));
+               (*l)->trans = ib_trans;
+               (*l)->next = NULL;
+       }
+       efree(teb);
        ZEND_REGISTER_RESOURCE(return_value, ib_trans, le_trans);
 }
 /* }}} */
 
 /* {{{ _php_ibase_def_trans() */
 /* open default transaction */
-static int _php_ibase_def_trans(ibase_db_link * ib_link, int trans_n TSRMLS_DC)
+static int _php_ibase_def_trans(ibase_db_link *ib_link, ibase_trans **trans TSRMLS_DC)
 {
        if (ib_link == NULL) {
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid database link");
                return FAILURE;
        }
 
-       if (trans_n == 0 && ib_link->trans[0] == NULL) { 
-               if (isc_start_transaction(IB_STATUS, &ib_link->trans[0], 1, 
&ib_link->link, 0, NULL)) {
-                       _php_ibase_error(TSRMLS_C);
-                       return FAILURE;
+    /* the first item in the connection-transaction list is reserved for 
+       the default transaction */
+       if (ib_link->trans == NULL) {
+               ib_link->trans = (ibase_tr_list*)emalloc(sizeof(ibase_tr_list));
+               ib_link->trans->trans = NULL;
+               ib_link->trans->next = NULL;
+       }
+                           
+       if (*trans == NULL) {
+               if (ib_link->trans->trans == NULL) {
+                       ibase_trans *tr = (ibase_trans*)emalloc(sizeof(ibase_trans));
+                       tr->handle = NULL;
+                       if (isc_start_transaction(IB_STATUS, &tr->handle, 1, 
&ib_link->link, 0, NULL)) {
+                               _php_ibase_error(TSRMLS_C);
+                               return FAILURE;
+                       }
+                       tr->link_cnt = 1;
+                       tr->link[0] = ib_link->link;
+                       ib_link->trans->trans = tr;
                }
+               *trans = ib_link->trans->trans;
        }
        return SUCCESS;
 }
@@ -1624,56 +1738,53 @@
 #define ROLLBACK 0
 static void _php_ibase_trans_end(INTERNAL_FUNCTION_PARAMETERS, int commit)
 {
-       zval **link_trans_arg = NULL;
-       int link_id = 0, trans_n = 0, trans_id = 0;
-       ibase_db_link *ib_link;
+       ibase_trans *trans = NULL;
+       int res_id = 0;
 
        RESET_ERRMSG;
 
        switch (ZEND_NUM_ARGS()) {
+
+               ibase_db_link *ib_link;
+               zval **trans_arg;
+
                case 0:
-                       link_id = IBG(default_link);
-                       ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, link_trans_arg, 
link_id, "InterBase link", le_link, le_plink);
+                       ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, NULL, 
IBG(default_link), "InterBase link", le_link, le_plink);
+                       trans = ib_link->trans->trans;
                        break;
+
                case 1: 
-                       if (zend_get_parameters_ex(1, &link_trans_arg) == FAILURE) {
+                       if (zend_get_parameters_ex(1, &trans_arg) == FAILURE) {
                                RETURN_FALSE;
                        }
-                       get_link_trans(INTERNAL_FUNCTION_PARAM_PASSTHRU, 
link_trans_arg, &ib_link, &trans_n, &trans_id);
+                       ZEND_FETCH_RESOURCE(trans, ibase_trans *, trans_arg, -1, 
"InterBase transaction", le_trans);
+
+                       convert_to_long_ex(trans_arg);
+                       res_id = Z_LVAL_PP(trans_arg);
+
                        break;
+
                default:
                        WRONG_PARAM_COUNT;
                        break;
        }
 
-       if (ib_link == NULL) {
-               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid database link");
-               RETURN_FALSE;
-       }
-
-       if (ib_link->trans[trans_n] == NULL) {
-               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Trying to commit or 
rollback an already handled transaction");
-               RETURN_FALSE;
-       }
-
        if (commit) {
-               if (isc_commit_transaction(IB_STATUS, &ib_link->trans[trans_n])) {
+               if (isc_commit_transaction(IB_STATUS, &trans->handle)) {
                        _php_ibase_error(TSRMLS_C);
                        RETURN_FALSE;
                }
        } else {
-               if (isc_rollback_transaction(IB_STATUS, &ib_link->trans[trans_n])) {
+               if (isc_rollback_transaction(IB_STATUS, &trans->handle)) {
                        _php_ibase_error(TSRMLS_C);
                        RETURN_FALSE;
                }
        }
-       ib_link->trans[trans_n] = NULL;
-
-       /* Don't try to destroy imnplicitly opened transaction from list... */
-       if (trans_id) {
-               zend_list_delete(trans_id);
-       }
        
+       /* Don't try to destroy implicitly opened transaction from list... */
+       if (res_id != 0) {
+               zend_list_delete(res_id);
+       }
        RETURN_TRUE;
 }
 /* }}} */
@@ -1698,10 +1809,11 @@
    Execute a query */
 PHP_FUNCTION(ibase_query)
 {
-       zval ***args, **bind_args = NULL, **dummy = NULL;
-       int i, link_id = 0, trans_n = 0, bind_n = 0, trans_id = 0;
+       zval ***args, **bind_args = NULL;
+       int i, bind_n = 0;
        char *query;
-       ibase_db_link *ib_link;
+       ibase_db_link *ib_link = NULL;
+       ibase_trans *trans = NULL;
        ibase_query *ib_query;
        ibase_result *ib_result;
 
@@ -1711,58 +1823,86 @@
                WRONG_PARAM_COUNT;
        }
 
-       args = (zval ***) emalloc(sizeof(zval **) * ZEND_NUM_ARGS());
+       /* use stack to avoid leaks */
+       args = (zval ***) do_alloca(sizeof(zval **) * ZEND_NUM_ARGS());
        if (zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args) == FAILURE) {
-               efree(args);
                RETURN_FALSE;
        }
-
+       
        i = 0;
-       if (Z_TYPE_PP(args[i]) == IS_RESOURCE) { /* link or transaction argument */
-               get_link_trans(INTERNAL_FUNCTION_PARAM_PASSTHRU, args[i], &ib_link, 
&trans_n, &trans_id);
-               i++; /* next arg */
-       } else {
-               link_id = IBG(default_link);
-               ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, dummy, link_id, 
"InterBase link", le_link, le_plink);
+       while (Z_TYPE_PP(args[i++]) != IS_STRING) {
+               if (i > ZEND_NUM_ARGS()) {
+                       _php_ibase_module_error("Query argument missing");
+                       RETURN_FALSE;
+               }
        }
 
-       if (Z_TYPE_PP(args[i]) == IS_STRING) { /* query argument */
-               convert_to_string_ex(args[i]);
-               query = Z_STRVAL_PP(args[i]);
-               i++; /* next arg */
-       } else {
-               _php_ibase_module_error("Query argument missed");
-               efree(args);
-               RETURN_FALSE;
-       }
+       convert_to_string_ex(args[i-1]);
+       query = Z_STRVAL_PP(args[i-1]);
+
+       /* find out if the first one or two arguments refer to either a link id, 
+          a trans id or both */
+       switch (i) {
+               case 1:
+
+                       /* no link ids were passed: if there's no default link, use 
exec_immediate() with
+                          a NULL handle; this will enable the use of CREATE DATABASE 
statements. */
+                       if ( IBG(default_link) == -1) {
+                               isc_db_handle db = NULL;
+                               isc_tr_handle trans = NULL;
 
+                               if (isc_dsql_execute_immediate(IB_STATUS, &db, &trans, 
0, query, SQL_DIALECT_CURRENT, NULL)) {
+                                       _php_ibase_error(TSRMLS_C);
+                                       RETURN_FALSE;
+                               }
+                               if (isc_detach_database(IB_STATUS, &db)) {
+                                       _php_ibase_error(TSRMLS_C);
+                                       RETURN_FALSE;
+                               }
+                               RETURN_TRUE;
+                       }                                       
+                               
+                       ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, NULL, 
IBG(default_link), "InterBase link", le_link, le_plink);
+                       break;                  
+               case 2:
+                       /* one id was passed, could be db or trans id */
+                       _php_ibase_get_link_trans(INTERNAL_FUNCTION_PARAM_PASSTHRU, 
args[0], &ib_link, &trans);
+                       break;  
+               case 3:
+                       /* two ids were passed, first should be link and second should 
be trans;
+                       */
+                       ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link*, args[0], -1, 
"InterBase link", le_link, le_plink);
+                       ZEND_FETCH_RESOURCE(trans, ibase_trans*, args[1], -1, 
"InterBase transaction", le_trans);
+                       break;
+               default:
+                       /* more than two arguments preceed the SQL string */
+                       _php_ibase_module_error("Invalid arguments");
+                       RETURN_FALSE;
+       }
+                       
        if (ZEND_NUM_ARGS() > i) { /* have variables to bind */
-               /* XXX Remove or fix??? Variable placeholders and binding makes
-                  absolutely no sense if not using a prepared SQL statement.
-               */
+               /* Using variables in a query without preparing it can be
+                  useful, because it allows you to use (among other things) 
+                  SQL-queries as consts and the passing of string arguments 
+                  without the horror of [un]slashing them. */
                bind_n = ZEND_NUM_ARGS() - i;
                bind_args = args[i];
        }
        
        /* open default transaction */
-       if (_php_ibase_def_trans(ib_link, trans_n TSRMLS_CC) == FAILURE) {
-               efree(args);
+       if (_php_ibase_def_trans(ib_link, &trans TSRMLS_CC) == FAILURE) {
                RETURN_FALSE;
        }
 
-       if (_php_ibase_alloc_query(&ib_query, ib_link->link, ib_link->trans[trans_n], 
query, ib_link->dialect TSRMLS_CC) == FAILURE) {
-               efree(args);
+       if (_php_ibase_alloc_query(&ib_query, ib_link->link, trans->handle, query, 
ib_link->dialect TSRMLS_CC) == FAILURE) {
                RETURN_FALSE;
        }
 
        if (_php_ibase_exec(&ib_result, ib_query, bind_n, bind_args TSRMLS_CC) == 
FAILURE) {
                _php_ibase_free_query(ib_query TSRMLS_CC);
-               efree(args);
                RETURN_FALSE;
        }
        
-       efree(args);
-       
        if (ib_result) { /* select statement */
                ib_result->drop_stmt = 1; /* drop stmt when free result */
                ib_query->stmt = NULL; /* keep stmt when free query */
@@ -2145,11 +2285,13 @@
                                        
                                        if (isc_array_get_slice(IB_STATUS, 
&ib_result->link, &ib_result->trans, &ar_qd, &ib_array->ar_desc, ar_data, 
&ib_array->ar_size)) {
                                                _php_ibase_error(TSRMLS_C);
+                                               efree(ar_data);
                                                RETURN_FALSE;
                                        }
                                        
                                        tmp_ptr = ar_data; /* avoid changes in 
_arr_zval */
                                        if (_php_ibase_arr_zval(tmp, &tmp_ptr, 
ib_array, 0, flag TSRMLS_CC) == FAILURE) {
+                                               efree(ar_data);
                                                RETURN_FALSE;
                                        }
                                        efree(ar_data);
@@ -2250,9 +2392,9 @@
    Prepare a query for later execution */
 PHP_FUNCTION(ibase_prepare)
 {
-       zval **link_arg, **query_arg;
-       int link_id, trans_n = 0, trans_id = 0;
+       zval **link_arg, **trans_arg, **query_arg;
        ibase_db_link *ib_link;
+       ibase_trans *trans = NULL;
        ibase_query *ib_query;
        char *query;
 
@@ -2263,15 +2405,21 @@
                        if (zend_get_parameters_ex(1, &query_arg) == FAILURE) {
                                RETURN_FALSE;
                        }
-                       link_id = IBG(default_link);
-                       ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, NULL, link_id, 
"InterBase link", le_link, le_plink);
+                       ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, NULL, 
IBG(default_link), "InterBase link", le_link, le_plink);
                        break;
                case 2:
                        if (zend_get_parameters_ex(2, &link_arg, &query_arg) == 
FAILURE) {
                                RETURN_FALSE;
                        }
-                       get_link_trans(INTERNAL_FUNCTION_PARAM_PASSTHRU, link_arg, 
&ib_link, &trans_n, &trans_id);
+                       _php_ibase_get_link_trans(INTERNAL_FUNCTION_PARAM_PASSTHRU, 
link_arg, &ib_link, &trans);
                        break;
+               case 3:
+                       if (zend_get_parameters_ex(3, &link_arg, &trans_arg, 
&query_arg) == FAILURE) {
+                               RETURN_FALSE;
+                       }
+                       ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link*, link_arg, -1, 
"InterBase link", le_link, le_plink);
+                       ZEND_FETCH_RESOURCE(trans, ibase_trans*, trans_arg, -1, 
"InterBase transaction", le_trans);
+                       break;                  
                default:
                        WRONG_PARAM_COUNT;
                        break;
@@ -2281,16 +2429,16 @@
        query = Z_STRVAL_PP(query_arg);
 
        /* open default transaction */
-       if (_php_ibase_def_trans(ib_link, trans_n TSRMLS_CC) == FAILURE) {
+       if (_php_ibase_def_trans(ib_link, &trans TSRMLS_CC) == FAILURE) {
                RETURN_FALSE;
        }
        
-       if (_php_ibase_alloc_query(&ib_query, ib_link->link, ib_link->trans[trans_n], 
query, ib_link->dialect TSRMLS_CC) == FAILURE) {
+       if (_php_ibase_alloc_query(&ib_query, ib_link->link, trans->handle, query, 
ib_link->dialect TSRMLS_CC) == FAILURE) {
                RETURN_FALSE;
        }
        ib_query->cursor_open = 0;
 
-       zend_list_addref(link_id);
+       /* zend_list_addref(link_id); */
 
        ZEND_REGISTER_RESOURCE(return_value, ib_query, le_query);
 }
@@ -2310,9 +2458,9 @@
                WRONG_PARAM_COUNT;
        }
 
-       args = (zval ***) emalloc(ZEND_NUM_ARGS() * sizeof(zval **));
+       /* use stack to avoid leaks */
+       args = (zval ***) do_alloca(ZEND_NUM_ARGS() * sizeof(zval **));
        if (zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args) == FAILURE) {
-               efree(args);
                RETURN_FALSE;
        }
 
@@ -2326,18 +2474,14 @@
        if (ib_query->cursor_open) {
                IBDEBUG("Implicitly closing a cursor");
                if (isc_dsql_free_statement(IB_STATUS, &ib_query->stmt, DSQL_close)) {
-                       efree(args);
                        _php_ibase_error(TSRMLS_C);
                }
        }
 
        if (_php_ibase_exec(&ib_result, ib_query, ZEND_NUM_ARGS() - 1, bind_args 
TSRMLS_CC) == FAILURE) {
-               efree(args);
                RETURN_FALSE;
        }
        
-       efree(args);
-
        if (ib_result) { /* select statement */
                ib_query->cursor_open = 1;
                ZEND_REGISTER_RESOURCE(return_value, ib_result, le_result);
@@ -2587,22 +2731,21 @@
 PHP_FUNCTION(ibase_blob_create)
 {
        zval **link_arg;
-       int trans_n = 0, trans_id = 0, link_id;
        ibase_db_link *ib_link;
+       ibase_trans *trans = NULL;
        ibase_blob_handle *ib_blob;
 
        RESET_ERRMSG;
 
        switch (ZEND_NUM_ARGS()) {
                case 0:
-                       link_id = IBG(default_link);
-                       ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, NULL, link_id, 
"InterBase link", le_link, le_plink);
+                       ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, NULL, 
IBG(default_link), "InterBase link", le_link, le_plink);
                        break;
                case 1:
                        if (zend_get_parameters_ex(1, &link_arg) == FAILURE) {
                                RETURN_FALSE;
                        }
-                       get_link_trans(INTERNAL_FUNCTION_PARAM_PASSTHRU, link_arg, 
&ib_link, &trans_n, &trans_id);
+                       _php_ibase_get_link_trans(INTERNAL_FUNCTION_PARAM_PASSTHRU, 
link_arg, &ib_link, &trans);
                        break;
                default:
                        WRONG_PARAM_COUNT;
@@ -2610,12 +2753,12 @@
        }
        
        /* open default transaction */
-       if (_php_ibase_def_trans(ib_link, trans_n TSRMLS_CC) == FAILURE) {
+       if (_php_ibase_def_trans(ib_link, &trans TSRMLS_CC) == FAILURE) {
                RETURN_FALSE;
        }
        
        ib_blob = (ibase_blob_handle *) emalloc(sizeof(ibase_blob_handle));
-       ib_blob->trans_handle = ib_link->trans[trans_n];
+       ib_blob->trans_handle = trans->handle;
        ib_blob->link = ib_link->link;
        ib_blob->bl_handle = NULL;
        
@@ -2910,10 +3053,11 @@
 PHP_FUNCTION(ibase_blob_import)
 {
        zval **link_arg, **file_arg;
-       int trans_n = 0, link_id = 0, trans_id = 0, size;
+       int link_id = 0, size;
        unsigned short b;
        ibase_blob_handle ib_blob;
        ibase_db_link *ib_link;
+       ibase_trans *trans;
        char bl_data[IBASE_BLOB_SEG]; /* FIXME? blob_seg_size parameter?         */
        php_stream *stream;
 
@@ -2931,7 +3075,7 @@
                        if (zend_get_parameters_ex(2, &link_arg, &file_arg) == 
FAILURE) {
                                RETURN_FALSE;
                        }
-                       get_link_trans(INTERNAL_FUNCTION_PARAM_PASSTHRU, link_arg, 
&ib_link, &trans_n, &trans_id);
+                       _php_ibase_get_link_trans(INTERNAL_FUNCTION_PARAM_PASSTHRU, 
link_arg, &ib_link, &trans);
                        break;
                default:
                        WRONG_PARAM_COUNT;
@@ -2939,14 +3083,14 @@
        }
        
        /* open default transaction */
-       if (_php_ibase_def_trans(ib_link, trans_n TSRMLS_CC) == FAILURE) {
+       if (_php_ibase_def_trans(ib_link, &trans TSRMLS_CC) == FAILURE) {
                RETURN_FALSE;
        }
 
        php_stream_from_zval(stream, file_arg);
        
        ib_blob.link = ib_link->link;
-       ib_blob.trans_handle = ib_link->trans[trans_n];
+       ib_blob.trans_handle = trans->handle;
        ib_blob.bl_handle = NULL;
        ib_blob.bl_qd.gds_quad_high = 0;
        ib_blob.bl_qd.gds_quad_low = 0;
Index: php-src/ext/interbase/php_interbase.h
diff -u php-src/ext/interbase/php_interbase.h:1.34 
php-src/ext/interbase/php_interbase.h:1.35
--- php-src/ext/interbase/php_interbase.h:1.34  Wed Jul  9 21:40:01 2003
+++ php-src/ext/interbase/php_interbase.h       Tue Aug  5 09:17:16 2003
@@ -17,7 +17,7 @@
    +----------------------------------------------------------------------+
  */
 
-/* $Id: php_interbase.h,v 1.34 2003/07/10 01:40:01 sniper Exp $ */
+/* $Id: php_interbase.h,v 1.35 2003/08/05 13:17:16 abies Exp $ */
 
 #ifndef PHP_INTERBASE_H
 #define PHP_INTERBASE_H
@@ -49,6 +49,7 @@
 PHP_FUNCTION(ibase_connect);
 PHP_FUNCTION(ibase_pconnect);
 PHP_FUNCTION(ibase_close);
+PHP_FUNCTION(ibase_drop_db);
 PHP_FUNCTION(ibase_query);
 PHP_FUNCTION(ibase_fetch_row);
 PHP_FUNCTION(ibase_fetch_assoc);
@@ -86,7 +87,6 @@
 
 #define IBASE_MSGSIZE 256
 #define MAX_ERRMSG (IBASE_MSGSIZE*2)
-#define IBASE_TRANS_ON_LINK 10
 #define IBASE_BLOB_SEG 4096
 
 ZEND_BEGIN_MODULE_GLOBALS(ibase)
@@ -106,15 +106,21 @@
 ZEND_END_MODULE_GLOBALS(ibase)
 
 typedef struct {
-       isc_tr_handle trans[IBASE_TRANS_ON_LINK];
        isc_db_handle link;
+       struct tr_list *trans;
        unsigned short dialect;
 } ibase_db_link;
 
 typedef struct {
-       int trans_num;
-       int link_rsrc;
-} ibase_tr_link;
+       isc_tr_handle handle;
+       int link_cnt;
+       ibase_db_link *link[1];
+} ibase_trans;
+
+typedef struct tr_list {
+       ibase_trans *trans;
+       struct tr_list *next;
+} ibase_tr_list;
 
 typedef struct {
        ISC_ARRAY_DESC ar_desc;

-- 
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to