]> granicus.if.org Git - php/commitdiff
Removed dependency on regular interbase extension
authorArd Biesheuvel <abies@php.net>
Sat, 12 Jun 2004 16:07:52 +0000 (16:07 +0000)
committerArd Biesheuvel <abies@php.net>
Sat, 12 Jun 2004 16:07:52 +0000 (16:07 +0000)
Added support for all datatypes except BLOBs

ext/pdo_firebird/firebird_driver.c
ext/pdo_firebird/firebird_statement.c
ext/pdo_firebird/php_pdo_firebird_int.h
ext/pdo_firebird/tests/execute.phpt

index beecaccedc25ece682648b0cdcc791c4b9b5a8ef..4cf7b6c87026b8b49c57697badec0ca5eed218e5 100644 (file)
@@ -135,20 +135,20 @@ static int firebird_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_le
        do {
                isc_stmt_handle s = NULL;
                XSQLDA num_sqlda;
+               static char info[] = {isc_info_sql_stmt_type};
+               char result[8];
 
                num_sqlda.version = PDO_FB_SQLDA_VERSION;
                num_sqlda.sqln = 1;
 
                /* allocate */
                if (isc_dsql_allocate_statement(H->isc_status, &H->db, &s)) {
-                       RECORD_ERROR(dbh);
-                       return -1;
+                       break;
                }
 
                /* prepare the statement */
                if (isc_dsql_prepare(H->isc_status, &H->tr, &s, (short)sql_len, const_cast(sql),
                                PDO_FB_DIALECT, &num_sqlda)) {
-                       RECORD_ERROR(dbh);
                        break;
                }
                
@@ -156,9 +156,16 @@ static int firebird_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_le
                S = ecalloc(1, sizeof(*S)-sizeof(XSQLDA) + XSQLDA_LENGTH(num_sqlda.sqld));
                S->H = H;
                S->stmt = s;
+               S->fetch_buf = ecalloc(1,sizeof(char*) * num_sqlda.sqld);
                S->out_sqlda.version = PDO_FB_SQLDA_VERSION;
                S->out_sqlda.sqln = stmt->column_count = num_sqlda.sqld;
 
+               /* determine the statement type */
+               if (isc_dsql_sql_info(H->isc_status, &s, sizeof(info), info, sizeof(result), result)) {
+                       break;
+               }
+               S->statement_type = result[3];  
+               
                if (isc_dsql_describe(H->isc_status, &s, PDO_FB_SQLDA_VERSION, &S->out_sqlda)) {
                        RECORD_ERROR(dbh);
                        break;
@@ -166,7 +173,6 @@ static int firebird_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_le
                
                /* allocate the input descriptors */
                if (isc_dsql_describe_bind(H->isc_status, &s, PDO_FB_SQLDA_VERSION, &num_sqlda)) {
-                       RECORD_ERROR(dbh);
                        break;
                }
                
@@ -176,7 +182,6 @@ static int firebird_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_le
                        S->in_sqlda->sqln = num_sqlda.sqld;
                
                        if (isc_dsql_describe_bind(H->isc_status, &s, PDO_FB_SQLDA_VERSION, S->in_sqlda)) {
-                               RECORD_ERROR(dbh);
                                break;
                        }
                }
@@ -187,6 +192,8 @@ static int firebird_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_le
                return 1;
 
        } while (0);
+
+       RECORD_ERROR(dbh);
        
        if (S) {
                if (S->in_sqlda) {
@@ -421,7 +428,6 @@ static int pdo_firebird_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRM
                }
                
                dbh->methods = &firebird_methods;
-               dbh->alloc_own_columns = 0;
                dbh->supports_placeholders = PDO_PLACEHOLDER_POSITIONAL;
                dbh->native_case = PDO_CASE_UPPER;
                dbh->alloc_own_columns = 1;
index c03b4b5ac0c21ad464f8b5236a9e0e0997bdacc8..ca636791ae3f647744cc09c5beba67ce3ffe4747 100644 (file)
@@ -30,6 +30,8 @@
 #include "php_pdo_firebird.h"
 #include "php_pdo_firebird_int.h"
 
+#include <time.h>
+       
 #define RECORD_ERROR(stmt) _firebird_error(NULL, stmt,  __FILE__, __LINE__ TSRMLS_CC)
 
 static void free_sqlda(XSQLDA const *sqlda)
@@ -48,6 +50,14 @@ static void free_sqlda(XSQLDA const *sqlda)
 static int firebird_stmt_dtor(pdo_stmt_t *stmt TSRMLS_DC)
 {
        pdo_firebird_stmt *S = (pdo_firebird_stmt*)stmt->driver_data;
+       int i;
+       
+       for (i = 0; i < S->out_sqlda.sqld; ++i) {
+               if (S->fetch_buf[i]) {
+                       efree(S->fetch_buf[i]);
+               }
+       }
+       efree(S->fetch_buf);
        
        if (S->in_sqlda) {
                free_sqlda(S->in_sqlda);
@@ -65,21 +75,35 @@ static int firebird_stmt_execute(pdo_stmt_t *stmt TSRMLS_DC)
        pdo_firebird_stmt *S = (pdo_firebird_stmt*)stmt->driver_data;
        pdo_firebird_db_handle *H = S->H;
 
-       /* named cursors should be closed first */
-       if (*S->name && isc_dsql_free_statement(H->isc_status, &S->stmt, DSQL_close)) {
-               RECORD_ERROR(stmt);
-               return 0;
-       }
-       
-       /* assume all params have been bound */
-       if (isc_dsql_execute(H->isc_status, &H->tr, &S->stmt, PDO_FB_SQLDA_VERSION, S->in_sqlda)) {
-               RECORD_ERROR(stmt);
-               return 0;
-       }
+       do {
+               /* named cursors should be closed first */
+               if (*S->name && isc_dsql_free_statement(H->isc_status, &S->stmt, DSQL_close)) {
+                       break;
+               }
+               
+               /* assume all params have been bound */
        
-       S->exhausted = 0;
+               if ((S->statement_type == isc_info_sql_stmt_exec_procedure &&
+                               isc_dsql_execute2(H->isc_status, &H->tr, &S->stmt, PDO_FB_SQLDA_VERSION,
+                                       S->in_sqlda, &S->out_sqlda))
+                               || isc_dsql_execute(H->isc_status, &H->tr, &S->stmt, PDO_FB_SQLDA_VERSION,
+                                       S->in_sqlda)) {
+                       break;
+               }
+               
+               /* commit? */
+               if (stmt->dbh->auto_commit && isc_commit_retaining(H->isc_status, &H->tr)) {
+                       break;
+               }
        
-       return 1;
+               S->exhausted = 0;
+               
+               return 1;
+       } while (0);
+
+       RECORD_ERROR(stmt->dbh);        
+
+       return 0;
 }
 
 static int firebird_stmt_fetch(pdo_stmt_t *stmt TSRMLS_DC)
@@ -87,18 +111,24 @@ static int firebird_stmt_fetch(pdo_stmt_t *stmt TSRMLS_DC)
        pdo_firebird_stmt *S = (pdo_firebird_stmt*)stmt->driver_data;
        pdo_firebird_db_handle *H = S->H;
 
-       switch (S->exhausted) {
-               default:
+       if (!S->exhausted) {
+
+               /* an EXECUTE PROCEDURE statement can be fetched from once, without calling the API, because
+                * the result was returned in the execute call */
+               if (S->statement_type == isc_info_sql_stmt_exec_procedure) {
+                       S->exhausted = 1;
+               } else {
                        if (isc_dsql_fetch(H->isc_status, &S->stmt, PDO_FB_SQLDA_VERSION, &S->out_sqlda)) {
                                if (H->isc_status[0] && H->isc_status[1]) {
                                        RECORD_ERROR(stmt);
                                }
                                S->exhausted = 1;
-               case 1:
                                return 0;
                        }
+               }
+               return 1;
        }
-       return 1;
+       return 0;
 }
 
 static int firebird_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC)
@@ -123,16 +153,23 @@ static void set_param_type(enum pdo_param_type *param_type, XSQLVAR const *var)
 {
        /* set the param type after the field type */
        switch (var->sqltype & ~1) {
+               case SQL_INT64:
+#if SIZEOF_LONG < 8
+                       if (0) /* always a string if its size exceeds native long */
+#endif
                case SQL_SHORT:
                case SQL_LONG:
-               case SQL_INT64:
-                       if (var->sqlscale < 0) {
-               case SQL_TEXT:
-               case SQL_VARYING:
-                               *param_type = PDO_PARAM_STR;
-                       } else {
+                       if (var->sqlscale == 0) {
                                *param_type = PDO_PARAM_INT;
+                               break;
                        }
+               case SQL_TEXT:
+               case SQL_VARYING:
+               case SQL_TYPE_DATE:
+               case SQL_TYPE_TIME:
+               case SQL_TIMESTAMP:
+               case SQL_BLOB:
+                       *param_type = PDO_PARAM_STR;
                        break;
                case SQL_FLOAT:
                case SQL_DOUBLE:
@@ -141,6 +178,121 @@ static void set_param_type(enum pdo_param_type *param_type, XSQLVAR const *var)
        }
 }
 
+#define FETCH_BUF(buf,type,len) ((buf) = (buf) ? (buf) : \
+       emalloc((len) ? (len * sizeof(type)) : ((len) = sizeof(type))))
+
+static int firebird_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, unsigned long *len TSRMLS_DC)
+{
+       pdo_firebird_stmt *S = (pdo_firebird_stmt*)stmt->driver_data;
+       XSQLVAR const *var = &S->out_sqlda.sqlvar[colno];
+
+       if (*var->sqlind == -1) {
+               /* A NULL value */
+               *ptr = NULL;
+               *len = 0;
+       } else {
+               /* override the column param type */
+               set_param_type(&stmt->columns[colno].param_type,var);
+               
+               if (var->sqlscale < 0) {
+                       static ISC_INT64 const scales[] = { 1, 10, 100, 1000, 10000, 100000, 1000000,
+                               100000000, 1000000000, 1000000000, LL_LIT(10000000000),LL_LIT(100000000000),
+                               LL_LIT(10000000000000), LL_LIT(100000000000000),LL_LIT(1000000000000000),
+                               LL_LIT(1000000000000000),LL_LIT(1000000000000000000) };
+                       ISC_INT64 n, f = scales[-var->sqlscale];
+
+                       switch (var->sqltype & ~1) {
+                               case SQL_SHORT:
+                                       n = *(short*)var->sqldata;
+                                       break;
+                               case SQL_LONG:
+                                       n = *(ISC_LONG*)var->sqldata;
+                                       break;
+                               case SQL_INT64:
+                                       n = *(ISC_INT64*)var->sqldata;
+                       }
+                               
+                       *len = 24;
+                       *ptr = FETCH_BUF(S->fetch_buf[colno], char, *len);
+                       
+                       if (n >= 0) {
+                               *len = sprintf(*ptr, "%" LL_MASK "d.%0*" LL_MASK "d", 
+                                       n / f, -var->sqlscale, n % f);
+                       } else if (n < -f) {
+                               *len = sprintf(*ptr, "%" LL_MASK "d.%0*" LL_MASK "d",
+                                       n / f, -var->sqlscale, -n % f);                         
+                        } else {
+                               *len = sprintf(*ptr, "-0.%0*" LL_MASK "d", -var->sqlscale, -n % f);
+                       }
+               } else {
+                       switch (var->sqltype & ~1) {
+                               struct tm t;
+                               char *fmt;                              
+                               
+                               case SQL_VARYING:
+                                       *ptr = &var->sqldata[2];
+                                       *len = *(short*)var->sqldata;
+                                       break;
+                               case SQL_TEXT:
+                                       *ptr = var->sqldata;
+                                       *len = var->sqllen;
+                                       break;
+                               case SQL_SHORT:
+                                       *ptr = FETCH_BUF(S->fetch_buf[colno], long, *len);
+                                       *(long*)*ptr = *(short*)var->sqldata;
+                                       break;
+                               case SQL_LONG:
+#if SIZEOF_LONG == 8
+                                       *ptr = FETCH_BUF(S->fetch_buf[colno], long, *len);
+                                       *(long*)*ptr = *(ISC_LONG*)var->sqldata;
+#else
+                                       *ptr = var->sqldata;
+#endif
+                                       break;
+                               case SQL_INT64:
+                                       *len = sizeof(long);
+#if SIZEOF_LONG == 8
+                                       *ptr = var->sqldata;
+#else
+                                       *len = 20;
+                                       *ptr = FETCH_BUF(S->fetch_buf[colno], char, *len);
+                                       *len = sprintf(*ptr, "%" LL_MASK "d", *(ISC_INT64*)var->sqldata);
+#endif
+                                       break;
+                       
+                               case SQL_FLOAT:
+                                       *ptr = FETCH_BUF(S->fetch_buf[colno], double, *len);
+                                       *(double*)*ptr = *(float*)var->sqldata;
+                                       break;
+                               case SQL_DOUBLE:
+                                       *ptr = var->sqldata;
+                                       *len = sizeof(double);
+                                       break;
+                               case SQL_TYPE_DATE:
+                                       isc_decode_sql_date((ISC_DATE*)var->sqldata, &t);
+                                       fmt = INI_STR("ibase.dateformat");
+                                       if (0) {
+                               case SQL_TYPE_TIME:
+                                               isc_decode_sql_time((ISC_TIME*)var->sqldata, &t);
+                                               fmt = INI_STR("ibase.timeformat");
+                                       } else if (0) {
+                               case SQL_TIMESTAMP:
+                                               isc_decode_timestamp((ISC_TIMESTAMP*)var->sqldata, &t);
+                                               fmt = INI_STR("ibase.timestampformat");
+                                       }
+                                       
+                                       /* convert the timestamp into a string */
+                                       
+                                       *len = 80;      /* TODO enough ? */
+                                       *ptr = FETCH_BUF(S->fetch_buf[colno], char, *len);
+                                       *len = strftime(*ptr, *len, fmt, &t);
+                                       break;
+                       }
+               }
+       }
+       return 1;
+}
+
 static int firebird_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *param,
        enum pdo_param_event event_type TSRMLS_DC)
 {
@@ -159,6 +311,8 @@ static int firebird_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_dat
 
        switch (event_type) {
                zval *zparam;
+               char *value;
+               unsigned long value_len;
                        
                case PDO_PARAM_EVT_ALLOC:
                                
@@ -221,71 +375,33 @@ static int firebird_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_dat
                        break;
 
                case PDO_PARAM_EVT_FETCH_POST:
-                       /* set the param value according to the fetched row */
-                       return SUCCESS == _php_ibase_var_zval(param->parameter, var->sqldata, var->sqltype,
-                               var->sqllen, var->sqlscale, 0 TSRMLS_CC);
-
-       }               
-
-       return 1;
-}
-
-static int firebird_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, unsigned long *len TSRMLS_DC)
-{
-       pdo_firebird_stmt *S = (pdo_firebird_stmt*)stmt->driver_data;
-       XSQLVAR *var = &S->out_sqlda.sqlvar[colno];
-
-       if (*var->sqlind == -1) {
-               /* A NULL value */
-               *ptr = NULL;
-               *len = 0;
-       } else {
-               /* override the column param type */
-               set_param_type(&stmt->columns[colno].param_type,var);
-               
-               switch (var->sqltype & ~1) {
-                       ISC_INT64 bint;
+                       value = NULL;
+                       value_len = 0;
                        
-                       case SQL_VARYING:
-                               *ptr = &var->sqldata[2];
-                               *len = *(short*)var->sqldata;
-                               break;
-                       case SQL_TEXT:
-                               *ptr = var->sqldata;
-                               *len = var->sqllen;
-                               break;
-                       case SQL_SHORT:
-                               *(long*)*ptr = *(short*)var->sqldata;
-                               *len = sizeof(short);
-                               break;
-                       case SQL_LONG:
-                               *(long*)*ptr = *(ISC_LONG*)var->sqldata;
-                               *len = sizeof(ISC_LONG);
-                               break;
-                       case SQL_INT64:
-                               *len = sizeof(long);
-#if SIZEOF_LONG == 8
-                               *ptr = var->sqldata;
-#else                          
-                               bint = *(ISC_INT64*)var->sqldata;
-
-                               if (bint >= LONG_MIN && bint <= LONG_MAX) {
-                                       *(long*)*ptr = (long)bint;
+                       if (firebird_stmt_get_col(stmt, param->paramno, &value, &value_len TSRMLS_CC)) {
+                               switch (param->param_type) {
+                                       case PDO_PARAM_STR:
+                                               if (value) {
+                                                       ZVAL_STRINGL(param->parameter, value, value_len, 1);
+                                                       break;
+                                               }
+                                       case PDO_PARAM_INT:
+                                               if (value) {
+                                                       ZVAL_LONG(param->parameter, *(long*)value);
+                                                       break;
+                                               }
+                                       case PDO_PARAM_DBL:
+                                               if (value) {
+                                                       ZVAL_DOUBLE(param->parameter, *(double*)value);
+                                                       break;
+                                               }
+                                       default:
+                                               ZVAL_NULL(param->parameter);
                                }
-#endif
-                               break;
-               
-                       case SQL_DOUBLE:
-                               *ptr = var->sqldata;
-                               *len = sizeof(double);
-                               break;
-                               
-                       case SQL_TYPE_DATE:
-                       case SQL_TYPE_TIME:
-                       case SQL_TIMESTAMP:
-                               ;                       
-               }
-       }
+                               return 1;
+                       }
+                       return 0;
+       }               
        return 1;
 }
 
@@ -294,6 +410,8 @@ static int firebird_stmt_set_attribute(pdo_stmt_t *stmt, long attr, zval *val TS
        pdo_firebird_stmt *S = (pdo_firebird_stmt*)stmt->driver_data;
        
        switch (attr) {
+               default:
+                       return 0;
                case PDO_ATTR_CURSOR_NAME:
                        convert_to_string(val);
                        
@@ -308,6 +426,24 @@ static int firebird_stmt_set_attribute(pdo_stmt_t *stmt, long attr, zval *val TS
        return 1;
 }
 
+static int firebird_stmt_get_attribute(pdo_stmt_t *stmt, long attr, zval *val TSRMLS_DC)
+{
+       pdo_firebird_stmt *S = (pdo_firebird_stmt*)stmt->driver_data;
+       
+       switch (attr) {
+               default:
+                       return 0;
+               case PDO_ATTR_CURSOR_NAME:
+                       if (*S->name) {
+                               ZVAL_STRING(val,S->name,1);
+                       } else {
+                               ZVAL_NULL(val);
+                       }
+                       break;
+       }
+       return 1;
+}
+
 struct pdo_stmt_methods firebird_stmt_methods = {
        firebird_stmt_dtor,
        firebird_stmt_execute,
@@ -315,7 +451,8 @@ struct pdo_stmt_methods firebird_stmt_methods = {
        firebird_stmt_describe,
        firebird_stmt_get_col,
        firebird_stmt_param_hook,
-       firebird_stmt_set_attribute
+       firebird_stmt_set_attribute,
+       firebird_stmt_get_attribute
 };
 
 /*
index 4e339b71b75f8de801898b819030438cc13aea77..70bf160147b55ce6e9f84db99801cce133f049c4 100644 (file)
 
 #define SHORT_MAX (1 << 8*sizeof(short)-1)
 
+#if SIZEOF_LONG == 8
+# define LL_MASK l
+# define LL_LIT(lit) lit ## L
+#else
+# ifdef PHP_WIN32
+#  define LL_MASK "I64"
+#  define LL_LIT(lit) lit ## I64
+# else
+#  define LL_MASK "ll"
+#  define LL_LIT(lit) lit ## LL
+# endif
+#endif
+
 /* Firebird API has a couple of missing const decls in its API */
 #define const_cast(s) ((char*)(s))
 
@@ -61,10 +74,16 @@ typedef struct {
        /* the name of the cursor (if it has one) */
        char name[32];
        
+       /* the type of statement that was issued */
+       char statement_type;
+       
        /* whether EOF was reached for this statement */
        unsigned exhausted:1;
 
-       unsigned _reserved:31;
+       unsigned _reserved:23;
+       
+       /* allocated space to convert fields values to other types */
+       char **fetch_buf;
        
        /* the input SQLDA */
        XSQLDA *in_sqlda;
index 6f9794c4f87e74d9dcc75ee7a6206ccdfa9f48c9..1ab33e20e20aee35eb78b11b3e0c7997cdb65fbb 100644 (file)
@@ -10,13 +10,14 @@ PDO_Firebird: prepare/execute/binding
        $db = new PDO("firebird:dbname=$test_base",$user,$password) or die;
        $db->setAttribute(PDO_ATTR_ERRMODE, PDO_ERRMODE_WARNING);
 
-       $db->exec("CREATE TABLE ddl (id SMALLINT NOT NULL PRIMARY KEY, text VARCHAR(32))");
-       $db->exec("INSERT INTO ddl VALUES (1,'bla')");
+       $db->exec("CREATE TABLE ddl (id SMALLINT NOT NULL PRIMARY KEY, text VARCHAR(32),
+               datetime TIMESTAMP DEFAULT '2000-02-12' NOT NULL)");
+       $db->exec("INSERT INTO ddl (id,text) VALUES (1,'bla')");
        
        $s = $db->prepare("SELECT * FROM ddl WHERE id=? FOR UPDATE");
 
        $s->bindParam(1,$id = 0);
-       $s->bindColumn(2,$var = null);
+       $s->bindColumn("TEXT",$var = null);
        $id = 1;
        $s->execute();
        $s->setAttribute(PDO_ATTR_CURSOR_NAME, "c");
@@ -38,7 +39,7 @@ PDO_Firebird: prepare/execute/binding
 ?>
 --EXPECT--
 int(1)
-array(4) {
+array(6) {
   ["ID"]=>
   int(1)
   [0]=>
@@ -47,6 +48,10 @@ array(4) {
   string(3) "bla"
   [1]=>
   string(3) "bla"
+  ["DATETIME"]=>
+  string(19) "2000-02-12 00:00:00"
+  [2]=>
+  string(19) "2000-02-12 00:00:00"
 }
 string(3) "bla"
 int(1)