From 493b89c3b1d898dca6b7a0964ff967d4e22d113f Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Sat, 12 Jun 2004 03:09:48 +0000 Subject: [PATCH] Nearly complete implementation No date/time fields yet ... --- ext/pdo_firebird/CREDITS | 2 +- ext/pdo_firebird/config.w32 | 4 +- ext/pdo_firebird/firebird_driver.c | 198 ++++++++++++++-- ext/pdo_firebird/firebird_statement.c | 288 +++++++++++++++++++++++- ext/pdo_firebird/package.xml | 2 +- ext/pdo_firebird/php_pdo_firebird.h | 10 +- ext/pdo_firebird/php_pdo_firebird_int.h | 25 +- ext/pdo_firebird/tests/ddl.phpt | 37 +++ 8 files changed, 525 insertions(+), 41 deletions(-) create mode 100644 ext/pdo_firebird/tests/ddl.phpt diff --git a/ext/pdo_firebird/CREDITS b/ext/pdo_firebird/CREDITS index 7757c96ee0..a33294b69c 100644 --- a/ext/pdo_firebird/CREDITS +++ b/ext/pdo_firebird/CREDITS @@ -1,2 +1,2 @@ -Firebird/InterBase PDO module +Firebird/InterBase driver for PDO Ard Biesheuvel diff --git a/ext/pdo_firebird/config.w32 b/ext/pdo_firebird/config.w32 index 160689d2df..c04c55c65a 100644 --- a/ext/pdo_firebird/config.w32 +++ b/ext/pdo_firebird/config.w32 @@ -4,7 +4,9 @@ ARG_WITH("pdo-firebird", "Firebird support for PDO", "no"); if (PHP_PDO_FIREBIRD != "no") { - if (CHECK_LIB("fbclient_ms.lib", "pdo_firebird", PHP_PDO_FIREBIRD) && + + if ((CHECK_LIB("fbclient_ms.lib", "pdo_firebird", PHP_PDO_FIREBIRD) || + CHECK_LIB("gds32_ms.lib", "pdo_firebird", PHP_PDO_FIREBIRD)) && CHECK_HEADER_ADD_INCLUDE("ibase.h", "CFLAGS_PDO_FIREBIRD", PHP_PHP_BUILD + "\\include\\firebird;" + PHP_PDO_FIREBIRD)) { EXTENSION("pdo_firebird", "pdo_firebird.c firebird_driver.c firebird_statement.c"); ADD_FLAG('CFLAGS_PDO_FIREBIRD', "/I ..\\pecl"); diff --git a/ext/pdo_firebird/firebird_driver.c b/ext/pdo_firebird/firebird_driver.c index 4215b34a4c..beecaccedc 100644 --- a/ext/pdo_firebird/firebird_driver.c +++ b/ext/pdo_firebird/firebird_driver.c @@ -34,17 +34,72 @@ static int pdo_firebird_fetch_error_func(pdo_dbh_t *dbh, pdo_stmt_t *stmt, zval { pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data; ISC_STATUS *s = H->isc_status; - char buf[128]; + char buf[400]; + long i = 0, l; add_next_index_long(info, isc_sqlcode(s)); - while (isc_interprete(buf,&s)) { - add_next_index_string(info, buf, 1); + while (l = isc_interprete(&buf[i],&s)) { + i += l; + strcpy(&buf[i++], " "); } + add_next_index_string(info, buf, 1); + return 1; } +/* map driver specific error message to PDO error */ +void _firebird_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, char const *file, long line TSRMLS_DC) +{ + pdo_firebird_db_handle *H = stmt ? ((pdo_firebird_stmt *)stmt->driver_data)->H + : (pdo_firebird_db_handle *)dbh->driver_data; + long *error_code = stmt ? &stmt->error_code : &dbh->error_code; + + switch (isc_sqlcode(H->isc_status)) { + + case 0: + *error_code = PDO_ERR_NONE; + break; + default: + *error_code = PDO_ERR_CANT_MAP; + break; + case -104: + *error_code = PDO_ERR_SYNTAX; + break; + case -530: + case -803: + *error_code = PDO_ERR_CONSTRAINT; + break; + case -204: + case -205: + case -206: + case -829: + *error_code = PDO_ERR_NOT_FOUND; + break; + case -607: + *error_code = PDO_ERR_ALREADY_EXISTS; + break; + + *error_code = PDO_ERR_NOT_IMPLEMENTED; + break; + case -313: + case -804: + *error_code = PDO_ERR_MISMATCH; + break; + case -303: + case -314: + case -413: + *error_code = PDO_ERR_TRUNCATED; + break; + + *error_code = PDO_ERR_DISCONNECTED; + break; + } +} + +#define RECORD_ERROR(dbh) _firebird_error(dbh, NULL, __FILE__, __LINE__ TSRMLS_CC) + static int firebird_handle_closer(pdo_dbh_t *dbh TSRMLS_DC) /* {{{ */ { pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data; @@ -52,17 +107,17 @@ static int firebird_handle_closer(pdo_dbh_t *dbh TSRMLS_DC) /* {{{ */ if (dbh->in_txn) { if (dbh->auto_commit) { if (isc_commit_transaction(H->isc_status, &H->tr)) { - /* error */ + RECORD_ERROR(dbh); } } else { if (isc_rollback_transaction(H->isc_status, &H->tr)) { - /* error */ + RECORD_ERROR(dbh); } } } if (isc_detach_database(H->isc_status, &H->db)) { - /* error */ + RECORD_ERROR(dbh); } pefree(H, dbh->is_persistent); @@ -84,10 +139,16 @@ static int firebird_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_le 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; + } + /* prepare the statement */ - if (isc_dsql_prepare(H->isc_status, &H->tr, &s, (short)sql_len, /* sigh */ (char*) sql, + if (isc_dsql_prepare(H->isc_status, &H->tr, &s, (short)sql_len, const_cast(sql), PDO_FB_DIALECT, &num_sqlda)) { - /* error */ + RECORD_ERROR(dbh); break; } @@ -95,14 +156,31 @@ 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->out_sqlda.version = PDO_FB_SQLDA_VERSION; + S->out_sqlda.sqln = stmt->column_count = num_sqlda.sqld; + + if (isc_dsql_describe(H->isc_status, &s, PDO_FB_SQLDA_VERSION, &S->out_sqlda)) { + RECORD_ERROR(dbh); + break; + } - if (isc_dsql_describe(H->isc_status, &s, PDO_FB_SQLDA_VERSION, S->out_sqlda)) { - /* error */ + /* allocate the input descriptors */ + if (isc_dsql_describe_bind(H->isc_status, &s, PDO_FB_SQLDA_VERSION, &num_sqlda)) { + RECORD_ERROR(dbh); break; } - /* TODO what about input params */ + if (num_sqlda.sqld) { + S->in_sqlda = ecalloc(1,XSQLDA_LENGTH(num_sqlda.sqld)); + S->in_sqlda->version = PDO_FB_SQLDA_VERSION; + 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; + } + } + stmt->driver_data = S; stmt->methods = &firebird_stmt_methods; @@ -111,6 +189,9 @@ static int firebird_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_le } while (0); if (S) { + if (S->in_sqlda) { + efree(S->in_sqlda); + } efree(S); } @@ -124,31 +205,49 @@ static long firebird_handle_doer(pdo_dbh_t *dbh, const char *sql, long sql_len T static char info_count[] = { isc_info_sql_records }; char result[64]; int ret = 0; + XSQLDA in_sqlda, out_sqlda; + /* no placeholder in exec() for now */ + in_sqlda.version = out_sqlda.version = PDO_FB_SQLDA_VERSION; + in_sqlda.sqld = out_sqlda.sqld = 0; + if (dbh->auto_commit && !dbh->in_txn) { if (isc_start_transaction(H->isc_status, &H->tr, 1, &H->db, 0, NULL)) { - /* error */ + RECORD_ERROR(dbh); return -1; } dbh->in_txn = 1; } + /* allocate */ + if (isc_dsql_allocate_statement(H->isc_status, &H->db, &stmt)) { + RECORD_ERROR(dbh); + return -1; + } + + /* Firebird allows SQL statements up to 64k */ + if (sql_len > SHORT_MAX) { + dbh->error_code = PDO_ERR_TRUNCATED; + return -1; + } + /* prepare */ - if (isc_dsql_prepare(H->isc_status, &H->tr, &stmt, 0, (char*) sql, PDO_FB_DIALECT, NULL)) { - /* error */ + if (isc_dsql_prepare(H->isc_status, &H->tr, &stmt, (short) sql_len, const_cast(sql), + PDO_FB_DIALECT, &out_sqlda)) { + RECORD_ERROR(dbh); return -1; } /* execute */ - if (isc_dsql_execute2(H->isc_status, &H->tr, &stmt, PDO_FB_SQLDA_VERSION, NULL, NULL)) { - /* error */ + if (isc_dsql_execute2(H->isc_status, &H->tr, &stmt, PDO_FB_SQLDA_VERSION, &in_sqlda, &out_sqlda)) { + RECORD_ERROR(dbh); return -1; } /* return the number of affected rows */ if (isc_dsql_sql_info(H->isc_status, &stmt, sizeof(info_count), info_count, sizeof(result), result)) { - /* error */ + RECORD_ERROR(dbh); return -1; } @@ -166,18 +265,68 @@ static long firebird_handle_doer(pdo_dbh_t *dbh, const char *sql, long sql_len T /* commit? */ if (dbh->auto_commit && isc_commit_retaining(H->isc_status, &H->tr)) { - /* error */ + RECORD_ERROR(dbh); } return ret; } +static int firebird_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, int unquotedlen, + char **quoted, int *quotedlen TSRMLS_DC) +{ + pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data; + int qcount = 0; + char const *c; + + /* Firebird only requires single quotes to be doubled if string lengths are used */ + + /* count the number of ' characters */ + for (c = unquoted; c = strchr(c,'\''); qcount++, c++); + + if (!qcount) { + return 0; + } else { + char const *l, *r; + char *c; + + *quotedlen = unquotedlen + qcount; + *quoted = c = emalloc(*quotedlen+1); + + /* foreach (chunk that ends in a quote) */ + for (l = unquoted; r = strchr(l,'\''); l = r+1) { + + /* copy the chunk */ + strncpy(c, l, r-l); + c += (r-l); + + /* add the second quote */ + *c++ = '\''; + } + + /* copy the remainder */ + strncpy(c, l, *quotedlen-(c-*quoted)); + + return 1; + } +} + +static int firebird_handle_begin(pdo_dbh_t *dbh TSRMLS_DC) +{ + pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data; + + if (isc_start_transaction(H->isc_status, &H->tr, 1, &H->db, 0, NULL)) { + RECORD_ERROR(dbh); + return 0; + } + return 1; +} + static int firebird_handle_commit(pdo_dbh_t *dbh TSRMLS_DC) { pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data; if (isc_commit_transaction(H->isc_status, &H->tr)) { - /* error */ + RECORD_ERROR(dbh); return 0; } return 1; @@ -188,7 +337,7 @@ static int firebird_handle_rollback(pdo_dbh_t *dbh TSRMLS_DC) pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data; if (isc_rollback_transaction(H->isc_status, &H->tr)) { - /* error */ + RECORD_ERROR(dbh); return 0; } return 1; @@ -204,8 +353,8 @@ static int firebird_handle_set_attribute(pdo_dbh_t *dbh, long attr, zval *val TS if (dbh->in_txn) { /* Assume they want to commit whatever is outstanding */ - if (isc_commit_retaining(H->isc_status, &H->tr)) { - /* error */ + if (isc_commit_transaction(H->isc_status, &H->tr)) { + RECORD_ERROR(dbh); return 0; } dbh->in_txn = 0; @@ -227,8 +376,8 @@ static struct pdo_dbh_methods firebird_methods = { firebird_handle_closer, firebird_handle_preparer, firebird_handle_doer, - NULL, - NULL, + firebird_handle_quoter, + firebird_handle_begin, firebird_handle_commit, firebird_handle_rollback, firebird_handle_set_attribute, @@ -275,6 +424,7 @@ static int pdo_firebird_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRM dbh->alloc_own_columns = 0; dbh->supports_placeholders = PDO_PLACEHOLDER_POSITIONAL; dbh->native_case = PDO_CASE_UPPER; + dbh->alloc_own_columns = 1; ret = 1; diff --git a/ext/pdo_firebird/firebird_statement.c b/ext/pdo_firebird/firebird_statement.c index dc1f648799..c03b4b5ac0 100644 --- a/ext/pdo_firebird/firebird_statement.c +++ b/ext/pdo_firebird/firebird_statement.c @@ -27,17 +27,297 @@ #include "ext/standard/info.h" #include "pdo/php_pdo.h" #include "pdo/php_pdo_driver.h" +#include "php_pdo_firebird.h" +#include "php_pdo_firebird_int.h" -struct pdo_stmt_methods firebird_stmt_methods = {0,0,0,0,0,0}; -/* +#define RECORD_ERROR(stmt) _firebird_error(NULL, stmt, __FILE__, __LINE__ TSRMLS_CC) + +static void free_sqlda(XSQLDA const *sqlda) +{ + int i; + + for (i = 0; i < sqlda->sqld; ++i) { + XSQLVAR const *var = &sqlda->sqlvar[i]; + + if (var->sqlind) { + efree(var->sqlind); + } + } +} + +static int firebird_stmt_dtor(pdo_stmt_t *stmt TSRMLS_DC) +{ + pdo_firebird_stmt *S = (pdo_firebird_stmt*)stmt->driver_data; + + if (S->in_sqlda) { + free_sqlda(S->in_sqlda); + efree(S->in_sqlda); + } + + free_sqlda(&S->out_sqlda); + efree(S); + + return 1; +} + +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; + } + + S->exhausted = 0; + + return 1; +} + +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 (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; +} + +static int firebird_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC) +{ + pdo_firebird_stmt *S = (pdo_firebird_stmt*)stmt->driver_data; + struct pdo_column_data *col = &stmt->columns[colno]; + XSQLVAR *var = &S->out_sqlda.sqlvar[colno]; + + /* allocate storage for the column */ + var->sqlind = (void*)emalloc(var->sqllen + 2*sizeof(short)); + var->sqldata = &((char*)var->sqlind)[sizeof(short)]; + + col->precision = -var->sqlscale; + col->maxlen = var->sqllen; + col->namelen = var->aliasname_length; + col->name = estrndup(var->aliasname,var->aliasname_length); + + return 1; +} + +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_SHORT: + case SQL_LONG: + case SQL_INT64: + if (var->sqlscale < 0) { + case SQL_TEXT: + case SQL_VARYING: + *param_type = PDO_PARAM_STR; + } else { + *param_type = PDO_PARAM_INT; + } + break; + case SQL_FLOAT: + case SQL_DOUBLE: + *param_type = PDO_PARAM_DBL; + break; + } +} + +static int firebird_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *param, + enum pdo_param_event event_type TSRMLS_DC) +{ + pdo_firebird_stmt *S = (pdo_firebird_stmt*)stmt->driver_data; + XSQLDA *sqlda = param->is_param ? S->in_sqlda : &S->out_sqlda; + XSQLVAR *var = &sqlda->sqlvar[param->paramno]; + + if (event_type == PDO_PARAM_EVT_FREE) { /* not used */ + return 1; + } + + if (!sqlda || param->paramno >= sqlda->sqld) { + stmt->error_code = PDO_ERR_NOT_FOUND; + return 0; + } + + switch (event_type) { + zval *zparam; + + case PDO_PARAM_EVT_ALLOC: + + if (param->is_param) { + /* allocate the parameter */ + var->sqlind = (void*)emalloc(var->sqllen + 2*sizeof(short)); + var->sqldata = &((char*)var->sqlind)[sizeof(short)]; + } + break; + + case PDO_PARAM_EVT_EXEC_PRE: + + if (!param->is_param) { + break; + } + + zparam = param->parameter; + + /* check if a NULL should be inserted */ + switch (Z_TYPE_P(zparam)) { + int force_null; + + case IS_STRING: + force_null = 0; + + /* for these types, an empty string can be handled like a NULL value */ + switch (var->sqltype & ~1) { + case SQL_SHORT: + case SQL_LONG: + case SQL_INT64: + case SQL_FLOAT: + case SQL_DOUBLE: + case SQL_TIMESTAMP: + case SQL_TYPE_DATE: + case SQL_TYPE_TIME: + force_null = (Z_STRLEN_P(zparam) == 0); + } + if (! force_null) break; + + case IS_NULL: + /* complain if this field doesn't allow NULL values */ + if (! (var->sqltype & 1)) { + stmt->error_code = PDO_ERR_CONSTRAINT; + return 0; + } + *var->sqlind = -1; + return 1; + } + + *var->sqlind = 0; + + SEPARATE_ZVAL(&zparam); + + convert_to_string(zparam); + + var->sqltype = SQL_TEXT; + var->sqldata = Z_STRVAL_P(zparam); + var->sqllen = Z_STRLEN_P(zparam); + + 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; + + 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; + } +#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; +} + +static int firebird_stmt_set_attribute(pdo_stmt_t *stmt, long attr, zval *val TSRMLS_DC) +{ + pdo_firebird_stmt *S = (pdo_firebird_stmt*)stmt->driver_data; + + switch (attr) { + case PDO_ATTR_CURSOR_NAME: + convert_to_string(val); + + if (isc_dsql_set_cursor_name(S->H->isc_status, &S->stmt, Z_STRVAL_P(val),0)) { + RECORD_ERROR(stmt); + return 0; + } + strncpy(S->name, Z_STRVAL_P(val), sizeof(S->name)); + S->name[sizeof(S->name)] = 0; + break; + } + return 1; +} + +struct pdo_stmt_methods firebird_stmt_methods = { firebird_stmt_dtor, firebird_stmt_execute, firebird_stmt_fetch, firebird_stmt_describe, firebird_stmt_get_col, - firebird_stmt_param_hook + firebird_stmt_param_hook, + firebird_stmt_set_attribute }; -*/ + /* * Local variables: * tab-width: 4 diff --git a/ext/pdo_firebird/package.xml b/ext/pdo_firebird/package.xml index 99b689db24..ca429e5a15 100644 --- a/ext/pdo_firebird/package.xml +++ b/ext/pdo_firebird/package.xml @@ -1,6 +1,6 @@ - + PDO_Firebird Firebird/InterBase support for PDO diff --git a/ext/pdo_firebird/php_pdo_firebird.h b/ext/pdo_firebird/php_pdo_firebird.h index 9eb913dd59..83b2e9304a 100644 --- a/ext/pdo_firebird/php_pdo_firebird.h +++ b/ext/pdo_firebird/php_pdo_firebird.h @@ -25,9 +25,15 @@ extern zend_module_entry pdo_firebird_module_entry; #define phpext_pdo_firebird_ptr &pdo_firebird_module_entry #ifdef PHP_WIN32 -#define PHP_PDO_FB_API __declspec(dllexport) +# ifdef PDO_FIREBIRD_EXPORTS +# define PDO_FB_API __declspec(dllexport) +# elif defined(COMPILE_DL_PDO_FIREBIRD) +# define PDO_FB_API __declspec(dllimport) +# else +# define PDO_FB_API +# endif #else -#define PHP_PDO_FB_API +# define PDO_FB_API #endif #ifdef ZTS diff --git a/ext/pdo_firebird/php_pdo_firebird_int.h b/ext/pdo_firebird/php_pdo_firebird_int.h index da602e49f1..4e339b71b7 100644 --- a/ext/pdo_firebird/php_pdo_firebird_int.h +++ b/ext/pdo_firebird/php_pdo_firebird_int.h @@ -31,14 +31,10 @@ #define PDO_FB_DIALECT 3 +#define SHORT_MAX (1 << 8*sizeof(short)-1) -typedef struct { - const char *file; - int line; - long errcode; - char *errmsg; -} pdo_firebird_error_info; - +/* Firebird API has a couple of missing const decls in its API */ +#define const_cast(s) ((char*)(s)) typedef struct { @@ -62,8 +58,19 @@ typedef struct { /* the statement handle */ isc_stmt_handle stmt; + /* the name of the cursor (if it has one) */ + char name[32]; + + /* whether EOF was reached for this statement */ + unsigned exhausted:1; + + unsigned _reserved:31; + + /* the input SQLDA */ + XSQLDA *in_sqlda; + /* the output SQLDA */ - XSQLDA out_sqlda[1]; /* last member */ + XSQLDA out_sqlda; /* last member */ } pdo_firebird_stmt; @@ -71,6 +78,8 @@ extern pdo_driver_t pdo_firebird_driver; extern struct pdo_stmt_methods firebird_stmt_methods; +void _firebird_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, char const *file, long line TSRMLS_DC); + #endif /* PHP_PDO_FIREBIRD_INT_H */ /* diff --git a/ext/pdo_firebird/tests/ddl.phpt b/ext/pdo_firebird/tests/ddl.phpt new file mode 100644 index 0000000000..7709bb3f07 --- /dev/null +++ b/ext/pdo_firebird/tests/ddl.phpt @@ -0,0 +1,37 @@ +--TEST-- +PDO_Firebird: DDL/transactions +--SKIPIF-- + +--FILE-- +setAttribute(PDO_ATTR_ERRMODE, PDO_ERRMODE_WARNING); + + $db->exec("CREATE TABLE ddl (id INT NOT NULL PRIMARY KEY, text BLOB SUB_TYPE 1)"); + $db->exec("CREATE GENERATOR gen_ddl_id"); + $db->exec("CREATE TRIGGER ddl_bi FOR ddl BEFORE INSERT AS + BEGIN IF (NEW.id IS NULL) THEN NEW.id=GEN_ID(gen_ddl_id,1); END"); + + $db->setAttribute(PDO_ATTR_AUTOCOMMIT,0); + + $db->beginTransaction(); + var_dump($db->exec("INSERT INTO ddl (text) VALUES ('bla')")); + var_dump($db->exec("UPDATE ddl SET text='blabla'")); + $db->rollback(); + + $db->beginTransaction(); + var_dump($db->exec("DELETE FROM ddl")); + $db->commit(); + + unset($db); + echo "done\n"; + +?> +--EXPECT-- +int(1) +int(1) +int(0) +done -- 2.40.0