From: Ard Biesheuvel Date: Sat, 12 Jun 2004 16:07:52 +0000 (+0000) Subject: Removed dependency on regular interbase extension X-Git-Tag: php-5.0.0~215 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c8c0ddb73dd0dd0439124249401cfc08ef369c60;p=php Removed dependency on regular interbase extension Added support for all datatypes except BLOBs --- diff --git a/ext/pdo_firebird/firebird_driver.c b/ext/pdo_firebird/firebird_driver.c index beecaccedc..4cf7b6c870 100644 --- a/ext/pdo_firebird/firebird_driver.c +++ b/ext/pdo_firebird/firebird_driver.c @@ -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; diff --git a/ext/pdo_firebird/firebird_statement.c b/ext/pdo_firebird/firebird_statement.c index c03b4b5ac0..ca636791ae 100644 --- a/ext/pdo_firebird/firebird_statement.c +++ b/ext/pdo_firebird/firebird_statement.c @@ -30,6 +30,8 @@ #include "php_pdo_firebird.h" #include "php_pdo_firebird_int.h" +#include + #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 }; /* diff --git a/ext/pdo_firebird/php_pdo_firebird_int.h b/ext/pdo_firebird/php_pdo_firebird_int.h index 4e339b71b7..70bf160147 100644 --- a/ext/pdo_firebird/php_pdo_firebird_int.h +++ b/ext/pdo_firebird/php_pdo_firebird_int.h @@ -33,6 +33,19 @@ #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; diff --git a/ext/pdo_firebird/tests/execute.phpt b/ext/pdo_firebird/tests/execute.phpt index 6f9794c4f8..1ab33e20e2 100644 --- a/ext/pdo_firebird/tests/execute.phpt +++ b/ext/pdo_firebird/tests/execute.phpt @@ -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)