summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArd Biesheuvel <abies@php.net>2004-06-15 14:16:22 +0000
committerArd Biesheuvel <abies@php.net>2004-06-15 14:16:22 +0000
commit350e5aa862639bc77cf19ec0a920c008192be430 (patch)
treed385d0e19523f8caf54bf81f92164da5204962a2
parent196506caa114448313593d71abe25b1d6fa4a517 (diff)
downloadphp-git-350e5aa862639bc77cf19ec0a920c008192be430.tar.gz
Refactored statement allocation
Added emulated support for named input parameters
-rw-r--r--ext/pdo_firebird/firebird_driver.c217
-rw-r--r--ext/pdo_firebird/firebird_statement.c40
-rw-r--r--ext/pdo_firebird/php_pdo_firebird_int.h5
3 files changed, 198 insertions, 64 deletions
diff --git a/ext/pdo_firebird/firebird_driver.c b/ext/pdo_firebird/firebird_driver.c
index 1ee80c6217..663c250ff4 100644
--- a/ext/pdo_firebird/firebird_driver.c
+++ b/ext/pdo_firebird/firebird_driver.c
@@ -32,12 +32,15 @@
#include "php_pdo_firebird.h"
#include "php_pdo_firebird_int.h"
+static int firebird_alloc_prepare_stmt(pdo_dbh_t*, const char*, long, XSQLDA*, isc_stmt_handle*,
+ HashTable* TSRMLS_DC);
+
/* 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;
- enum pdo_error_type *error_code = stmt ? &stmt->error_code : &dbh->error_code;
+ enum pdo_error_type *const error_code = stmt ? &stmt->error_code : &dbh->error_code;
switch (isc_sqlcode(H->isc_status)) {
@@ -60,7 +63,7 @@ void _firebird_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, char const *file, long li
case -829:
*error_code = PDO_ERR_NOT_FOUND;
break;
- case -607:
+
*error_code = PDO_ERR_ALREADY_EXISTS;
break;
@@ -117,27 +120,25 @@ static int firebird_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_le
{
pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data;
pdo_firebird_stmt *S = NULL;
+ HashTable *np;
do {
isc_stmt_handle s = NULL;
XSQLDA num_sqlda;
- static char info[] = {isc_info_sql_stmt_type};
+ static char const info[] = { isc_info_sql_stmt_type };
char result[8];
num_sqlda.version = PDO_FB_SQLDA_VERSION;
num_sqlda.sqln = 1;
- /* allocate a statement handle */
- if (isc_dsql_allocate_statement(H->isc_status, &H->db, &s)) {
- break;
- }
-
- /* prepare the SQL statement */
- if (isc_dsql_prepare(H->isc_status, &H->tr, &s, (short)sql_len, const_cast(sql),
- PDO_FB_DIALECT, &num_sqlda)) {
+ ALLOC_HASHTABLE(np);
+ zend_hash_init(np, 8, NULL, NULL, 0);
+
+ /* allocate and prepare statement */
+ if (!firebird_alloc_prepare_stmt(dbh, sql, sql_len, &num_sqlda, &s, np TSRMLS_CC)) {
break;
}
-
+
/* allocate a statement handle struct of the right size (struct out_sqlda is inlined) */
S = ecalloc(1, sizeof(*S)-sizeof(XSQLDA) + XSQLDA_LENGTH(num_sqlda.sqld));
S->H = H;
@@ -145,9 +146,11 @@ static int firebird_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_le
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;
+ S->named_params = np;
/* determine the statement type */
- if (isc_dsql_sql_info(H->isc_status, &s, sizeof(info), info, sizeof(result), result)) {
+ if (isc_dsql_sql_info(H->isc_status, &s, sizeof(info), const_cast(info), sizeof(result),
+ result)) {
break;
}
S->statement_type = result[3];
@@ -182,6 +185,9 @@ static int firebird_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_le
RECORD_ERROR(dbh);
+ zend_hash_destroy(np);
+ FREE_HASHTABLE(np);
+
if (S) {
if (S->in_sqlda) {
efree(S->in_sqlda);
@@ -193,12 +199,12 @@ static int firebird_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_le
}
/* }}} */
-/* called by PDO to execute a statement that doesn't produce a result */
+/* called by PDO to execute a statement that doesn't produce a result set */
static long firebird_handle_doer(pdo_dbh_t *dbh, const char *sql, long sql_len TSRMLS_DC) /* {{{ */
{
pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data;
isc_stmt_handle stmt = NULL;
- static char info_count[] = { isc_info_sql_records };
+ static char const info_count[] = { isc_info_sql_records };
char result[64];
int ret = 0;
XSQLDA in_sqlda, out_sqlda;
@@ -207,31 +213,8 @@ static long firebird_handle_doer(pdo_dbh_t *dbh, const char *sql, long sql_len T
in_sqlda.version = out_sqlda.version = PDO_FB_SQLDA_VERSION;
in_sqlda.sqld = out_sqlda.sqld = 0;
- /* start a new transaction implicitly if auto_commit is enabled and no transaction is open */
- if (dbh->auto_commit && !dbh->in_txn) {
- if (isc_start_transaction(H->isc_status, &H->tr, 1, &H->db, 0, NULL)) {
- RECORD_ERROR(dbh);
- return -1;
- }
- dbh->in_txn = 1;
- }
-
- /* allocate the statement */
- if (isc_dsql_allocate_statement(H->isc_status, &H->db, &stmt)) {
- RECORD_ERROR(dbh);
- return -1;
- }
-
- /* Firebird allows SQL statements up to 64k, so bail if it doesn't fit */
- if (sql_len > SHORT_MAX) {
- dbh->error_code = PDO_ERR_TRUNCATED;
- return -1;
- }
-
- /* prepare the statement */
- if (isc_dsql_prepare(H->isc_status, &H->tr, &stmt, (short) sql_len, const_cast(sql),
- PDO_FB_DIALECT, &out_sqlda)) {
- RECORD_ERROR(dbh);
+ /* allocate and prepare statement */
+ if (!firebird_alloc_prepare_stmt(dbh, sql, sql_len, &out_sqlda, &stmt, 0 TSRMLS_CC)) {
return -1;
}
@@ -242,8 +225,8 @@ static long firebird_handle_doer(pdo_dbh_t *dbh, const char *sql, long sql_len T
}
/* find out how many rows were affected */
- if (isc_dsql_sql_info(H->isc_status, &stmt, sizeof(info_count), info_count, sizeof(result),
- result)) {
+ if (isc_dsql_sql_info(H->isc_status, &stmt, sizeof(info_count), const_cast(info_count),
+ sizeof(result), result)) {
RECORD_ERROR(dbh);
return -1;
}
@@ -313,8 +296,48 @@ static int firebird_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, int unqu
static int firebird_handle_begin(pdo_dbh_t *dbh TSRMLS_DC) /* {{{ */
{
pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data;
+ char tpb[8] = { isc_tpb_version3 }, *ptpb = tpb+1;
+#if abies_0
+ if (dbh->transaction_flags & PDO_TRANS_ISOLATION_LEVEL) {
+ if (dbh->transaction_flags & PDO_TRANS_READ_UNCOMMITTED) {
+ /* this is a poor fit, but it's all we have */
+ *ptpb++ = isc_tpb_read_committed;
+ *ptpb++ = isc_tpb_rec_version;
+ dbh->transaction_flags &= ~(PDO_TRANS_ISOLATION_LEVEL^PDO_TRANS_READ_UNCOMMITTED);
+ } else if (dbh->transaction_flags & PDO_TRANS_READ_COMMITTED) {
+ *ptpb++ = isc_tpb_read_committed;
+ *ptpb++ = isc_tpb_no_rec_version;
+ dbh->transaction_flags &= ~(PDO_TRANS_ISOLATION_LEVEL^PDO_TRANS_READ_COMMITTED);
+ } else if (dbh->transaction_flags & PDO_TRANS_REPEATABLE_READ) {
+ *ptpb++ = isc_tpb_concurrency;
+ dbh->transaction_flags &= ~(PDO_TRANS_ISOLATION_LEVEL^PDO_TRANS_REPEATABLE_READ);
+ } else {
+ *ptpb++ = isc_tpb_consistency;
+ dbh->transaction_flags &= ~(PDO_TRANS_ISOLATION_LEVEL^PDO_TRANS_SERIALIZABLE);
+ }
+ }
+
+ if (dbh->transaction_flags & PDO_TRANS_ACCESS_MODE) {
+ if (dbh->transaction_flags & PDO_TRANS_READONLY) {
+ *ptpb++ = isc_tpb_read;
+ dbh->transaction_flags &= ~(PDO_TRANS_ACCESS_MODE^PDO_TRANS_READONLY);
+ } else {
+ *ptpb++ = isc_tpb_write;
+ dbh->transaction_flags &= ~(PDO_TRANS_ACCESS_MODE^PDO_TRANS_READWRITE);
+ }
+ }
- if (isc_start_transaction(H->isc_status, &H->tr, 1, &H->db, 0, NULL)) {
+ if (dbh->transaction_flags & PDO_TRANS_CONFLICT_RESOLUTION) {
+ if (dbh->transaction_flags & PDO_TRANS_RETRY) {
+ *ptpb++ = isc_tpb_wait;
+ dbh->transaction_flags &= ~(PDO_TRANS_CONFLICT_RESOLUTION^PDO_TRANS_RETRY);
+ } else {
+ *ptpb++ = isc_tpb_nowait;
+ dbh->transaction_flags &= ~(PDO_TRANS_CONFLICT_RESOLUTION^PDO_TRANS_ABORT);
+ }
+ }
+#endif
+ if (isc_start_transaction(H->isc_status, &H->tr, 1, &H->db, (unsigned short)(ptpb-tpb), tpb)) {
RECORD_ERROR(dbh);
return 0;
}
@@ -348,6 +371,80 @@ static int firebird_handle_rollback(pdo_dbh_t *dbh TSRMLS_DC) /* {{{ */
}
/* }}} */
+/* used by prepare and exec to allocate a statement handle and prepare the SQL */
+static int firebird_alloc_prepare_stmt(pdo_dbh_t *dbh, const char *sql, long sql_len,
+ XSQLDA *out_sqlda, isc_stmt_handle *s, HashTable *named_params TSRMLS_DC)
+{
+ pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data;
+ char *c, *new_sql, in_quote, in_param, pname[64], *ppname;
+ long l, pindex = -1;
+
+ /* Firebird allows SQL statements up to 64k, so bail if it doesn't fit */
+ if (sql_len > SHORT_MAX) {
+ dbh->error_code = PDO_ERR_TRUNCATED;
+ return 0;
+ }
+
+ /* start a new transaction implicitly if auto_commit is enabled and no transaction is open */
+ if (dbh->auto_commit && !dbh->in_txn) {
+ /* dbh->transaction_flags = PDO_TRANS_READ_UNCOMMITTED; */
+
+ if (!firebird_handle_begin(dbh TSRMLS_CC)) {
+ return 0;
+ }
+ dbh->in_txn = 1;
+ }
+
+ /* allocate the statement */
+ if (isc_dsql_allocate_statement(H->isc_status, &H->db, s)) {
+ RECORD_ERROR(dbh);
+ return 0;
+ }
+
+ /* in order to support named params, which Firebird itself doesn't,
+ we need to replace :foo by ?, and store the name we just replaced */
+ new_sql = c = emalloc(sql_len+1);
+
+ for (l = in_quote = in_param = 0; l <= sql_len; ++l) {
+ if ( !(in_quote ^= (sql[l] == '\''))) {
+ if (!in_param) {
+ switch (sql[l]) {
+ case ':':
+ in_param = 1;
+ ppname = pname;
+ case '?':
+ *c++ = '?';
+ ++pindex;
+ continue;
+ }
+ } else {
+ if ((in_param &= (sql[l] == '_') || (sql[l] >= 'A' && sql[l] <= 'Z')
+ || (sql[l] >= 'a' && sql[l] <= 'z') || (sql[l] >= '0' && sql[l] <= '9'))) {
+ *ppname++ = sql[l];
+ continue;
+ } else {
+ *ppname++ = 0;
+ if (named_params) {
+ zend_hash_update(named_params, pname, (unsigned int)(ppname-pname),
+ (void*)&pindex, sizeof(long),NULL);
+ }
+ }
+ }
+ }
+ *c++ = sql[l];
+ }
+
+ /* prepare the statement */
+ if (isc_dsql_prepare(H->isc_status, &H->tr, s, 0, new_sql, PDO_FB_DIALECT, out_sqlda)) {
+ RECORD_ERROR(dbh);
+ efree(new_sql);
+ return 0;
+ }
+
+ efree(new_sql);
+ return 1;
+}
+
/* called by PDO to set a driver-specific dbh attribute */
static int firebird_handle_set_attribute(pdo_dbh_t *dbh, long attr, zval *val TSRMLS_DC) /* {{{ */
{
@@ -356,25 +453,25 @@ static int firebird_handle_set_attribute(pdo_dbh_t *dbh, long attr, zval *val TS
switch (attr) {
case PDO_ATTR_AUTOCOMMIT:
- convert_to_long(val);
+ convert_to_boolean(val);
- /* if (the value is really being changed and a transaction is open) */
- if ((Z_LVAL_P(val)?1:0) ^ dbh->auto_commit && dbh->in_txn) {
-
- if ((dbh->auto_commit = Z_BVAL_P(val))) {
- /* just keep the running transaction but commit it */
- if (isc_commit_retaining(H->isc_status, &H->tr)) {
- RECORD_ERROR(dbh);
- break;
- }
- } else {
- /* close the transaction */
- if (isc_commit_transaction(H->isc_status, &H->tr)) {
- RECORD_ERROR(dbh);
- break;
+ /* ignore if the new value equals the old one */
+ if (dbh->auto_commit ^ Z_BVAL_P(val)) {
+ if (dbh->in_txn) {
+ if (Z_BVAL_P(val)) {
+ /* turning on auto_commit with an open transaction is illegal, because
+ we won't know what to do with it */
+ H->last_app_error = "Cannot enable auto-commit while a transaction is already open";
+ return 0;
+ } else {
+ /* close the transaction */
+ if (!firebird_handle_commit(dbh TSRMLS_CC)) {
+ break;
+ }
+ dbh->in_txn = 0;
}
- dbh->in_txn = 0;
}
+ dbh->auto_commit = Z_BVAL_P(val);
}
return 1;
}
@@ -395,7 +492,7 @@ static void firebird_info_cb(void *arg, char const *s) /* {{{ */
/* }}} */
/* called by PDO to get a driver-specific dbh attribute */
-static int firebird_handle_get_attribute(pdo_dbh_t *dbh, long attr, zval *val TSRMLS_DC) /* {{{ */
+static int firebird_handle_get_attribute(pdo_dbh_t const *dbh, long attr, zval *val TSRMLS_DC) /* {{{ */
{
pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data;
diff --git a/ext/pdo_firebird/firebird_statement.c b/ext/pdo_firebird/firebird_statement.c
index 90ad2e13d6..5e605f46d1 100644
--- a/ext/pdo_firebird/firebird_statement.c
+++ b/ext/pdo_firebird/firebird_statement.c
@@ -194,10 +194,12 @@ static void set_param_type(enum pdo_param_type *param_type, XSQLVAR const *var)
case SQL_BLOB:
*param_type = PDO_PARAM_STR;
break;
+#if abies_0
case SQL_FLOAT:
case SQL_DOUBLE:
*param_type = PDO_PARAM_DBL;
break;
+#endif
}
}
/* }}} */
@@ -212,7 +214,7 @@ static int firebird_fetch_blob(pdo_stmt_t *stmt, int colno, char **ptr, /* {{{ *
pdo_firebird_stmt *S = (pdo_firebird_stmt*)stmt->driver_data;
pdo_firebird_db_handle *H = S->H;
isc_blob_handle blobh = NULL;
- static char bl_items[] = {isc_info_blob_total_length};
+ static char const bl_items[] = { isc_info_blob_total_length };
char bl_info[20];
unsigned short i;
int result = *len = 0;
@@ -222,7 +224,7 @@ static int firebird_fetch_blob(pdo_stmt_t *stmt, int colno, char **ptr, /* {{{ *
return 0;
}
- if (isc_blob_info(H->isc_status, &blobh, sizeof(bl_items), bl_items,
+ if (isc_blob_info(H->isc_status, &blobh, sizeof(bl_items), const_cast(bl_items),
sizeof(bl_info), bl_info)) {
RECORD_ERROR(stmt);
goto fetch_blob_end;
@@ -441,7 +443,7 @@ static int firebird_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_dat
{
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];
+ XSQLVAR *var;
if (event_type == PDO_PARAM_EVT_FREE) { /* not used */
return 1;
@@ -452,7 +454,37 @@ static int firebird_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_dat
S->H->last_app_error = "Invalid parameter index";
return 0;
}
+ if (param->is_param && param->paramno == -1) {
+ long *index;
+
+ /* try to determine the index by looking in the named_params hash */
+ if (SUCCESS == zend_hash_find(S->named_params, param->name, param->namelen+1, &index)) {
+ param->paramno = *index;
+ } else {
+ /* ... or by looking in the input descriptor */
+ int i;
+
+ for (i = 0; i < sqlda->sqld; ++i) {
+ XSQLVAR *var = &sqlda->sqlvar[i];
+
+ if ((var->aliasname_length && !strncasecmp(param->name, var->aliasname,
+ min(param->namelen, var->aliasname_length)))
+ || (var->sqlname_length && !strncasecmp(param->name, var->sqlname,
+ min(param->namelen, var->sqlname_length)))) {
+ param->paramno = i;
+ break;
+ }
+ }
+ if (i >= sqlda->sqld) {
+ stmt->error_code = PDO_ERR_NOT_FOUND;
+ S->H->last_app_error = "Invalid parameter name";
+ return 0;
+ }
+ }
+ }
+ var = &sqlda->sqlvar[param->paramno];
+
switch (event_type) {
char *value;
unsigned long value_len;
@@ -550,11 +582,13 @@ static int firebird_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_dat
ZVAL_LONG(param->parameter, *(long*)value);
break;
}
+#if abies_0
case PDO_PARAM_DBL:
if (value) {
ZVAL_DOUBLE(param->parameter, *(double*)value);
break;
}
+#endif
default:
ZVAL_NULL(param->parameter);
}
diff --git a/ext/pdo_firebird/php_pdo_firebird_int.h b/ext/pdo_firebird/php_pdo_firebird_int.h
index f67e7b2d9e..d037e98fb5 100644
--- a/ext/pdo_firebird/php_pdo_firebird_int.h
+++ b/ext/pdo_firebird/php_pdo_firebird_int.h
@@ -84,12 +84,15 @@ typedef struct {
char name[32];
/* the type of statement that was issued */
- char statement_type;
+ char statement_type:8;
/* whether EOF was reached for this statement */
unsigned exhausted:1;
unsigned _reserved:23;
+
+ /* the named params that were converted to ?'s by the driver */
+ HashTable *named_params;
/* allocated space to convert fields values to other types */
char **fetch_buf;