35static int php_firebird_alloc_prepare_stmt(
pdo_dbh_t*,
const zend_string*, XSQLDA*, isc_stmt_handle*,
37static bool php_firebird_rollback_transaction(
pdo_dbh_t *dbh);
47static const char classes_array[] = {
178static inline char php_firebird_classes(
char idx)
180 unsigned char uidx = (
unsigned char) idx;
181 if (uidx > 127)
return 0;
182 return classes_array[uidx];
222 if (
p <
end && *
p ==
'*')
228 if (*
p++ ==
'*' &&
p <
end && *
p ==
'/')
242 if (
p <
end && *
p ==
'-')
249 if (
p <
end && *
p ==
'\n')
270 else if (php_firebird_classes(c) &
CHR_IDENT)
276 else if (php_firebird_classes(c) &
CHR_WHITE)
285 (*
p !=
'/') && (*
p !=
'-') && (*
p !=
':') && (*
p !=
'?') &&
286 (*
p !=
'\'') && (*
p !=
'"'))
298static int php_firebird_preprocess(
const zend_string* sql,
char* sql_out,
HashTable* named_params)
300 bool passAsIs = 1, execBlock = 0;
302 char pname[254], ident[253], ident2[253];
308 const char* i =
start;
312 tok = php_firebird_get_token(&
p,
end);
329 strncpy(ident, i, l);
336 tok = php_firebird_get_token(&
p,
end);
340 tok = php_firebird_get_token(&
p,
end);
354 strncpy(ident2, i2, l);
379 tok = php_firebird_get_token(&
p,
end);
383 tok = php_firebird_get_token(&
p,
end);
394 strncpy(pname,
start, l);
428 strncpy(ident,
start, l);
466static void set_coercing_output_data_types(XSQLDA* sqlda)
477 unsigned fb_client_major_version = (fb_client_version >> 8) & 0xFF;
478 for (i=0, var = sqlda->sqlvar; i < sqlda->sqld; i++, var++) {
479 dtype = (var->sqltype & ~1);
480 nullable = (var->sqltype & 1);
483 var->sqltype = SQL_VARYING + nullable;
489 var->sqltype = SQL_VARYING + nullable;
494 var->sqltype = SQL_VARYING + nullable;
498 case SQL_TIMESTAMP_TZ:
499 if (fb_client_major_version < 4) {
502 var->sqltype = SQL_VARYING + nullable;
508 if (fb_client_major_version < 4) {
511 var->sqltype = SQL_VARYING + nullable;
525 const char *
msg,
const size_t msg_len)
538 if (
H->isc_status && (
H->isc_status[0] == 1 &&
H->isc_status[1] > 0)) {
540 size_t buf_size =
sizeof(
buf), read_len = 0;
542 const ISC_STATUS *
s =
H->isc_status;
543 sqlcode = isc_sqlcode(
s);
545 while ((buf_size > (read_len + 1)) && (tmp_len = fb_interpret(&
buf[read_len], (buf_size - read_len - 1), &
s)) && tmp_len > 0) {
547 buf[read_len++] =
' ';
552 buf[read_len--] =
'\0';
564 }
else if (
msg && msg_len) {
584static void firebird_handle_closer(
pdo_dbh_t *dbh)
589 if (dbh->auto_commit) {
592 php_firebird_rollback_transaction(dbh);
595 H->in_manually_txn = 0;
598 if (
H->db && isc_detach_database(
H->isc_status, &
H->db)) {
602 if (
H->date_format) {
603 pefree(
H->date_format, dbh->is_persistent);
605 if (
H->time_format) {
606 pefree(
H->time_format, dbh->is_persistent);
608 if (
H->timestamp_format) {
609 pefree(
H->timestamp_format, dbh->is_persistent);
612 if (
H->einfo.errmsg) {
613 pefree(
H->einfo.errmsg, dbh->is_persistent);
614 H->einfo.errmsg =
NULL;
632 static char const info[] = { isc_info_sql_stmt_type };
642 if (!php_firebird_alloc_prepare_stmt(dbh, sql, &num_sqlda, &
s, np)) {
647 S =
ecalloc(1,
sizeof(*
S)-
sizeof(XSQLDA) + XSQLDA_LENGTH(num_sqlda.sqld));
651 S->out_sqlda.sqln = stmt->column_count = num_sqlda.sqld;
652 S->named_params = np;
655 if (isc_dsql_sql_info(
H->isc_status, &
s,
sizeof(info),
const_cast(info),
sizeof(
result),
669 set_coercing_output_data_types(&
S->out_sqlda);
677 if (num_sqlda.sqld) {
678 S->in_sqlda =
ecalloc(1,XSQLDA_LENGTH(num_sqlda.sqld));
680 S->in_sqlda->sqln = num_sqlda.sqld;
689 for (i = 0, var =
S->in_sqlda->sqlvar; i < S->in_sqlda->sqld; i++, var++) {
695 stmt->driver_data =
S;
724 static char const info_count[] = { isc_info_sql_records };
727 XSQLDA in_sqlda, out_sqlda;
731 in_sqlda.sqld = out_sqlda.sqld = 0;
735 if (!php_firebird_alloc_prepare_stmt(dbh, sql, &out_sqlda, &stmt, 0)) {
747 if (isc_dsql_sql_info(
H->isc_status, &stmt,
sizeof(info_count),
const_cast(info_count),
754 if (
result[0] == isc_info_sql_records) {
755 unsigned i = 3, result_size = isc_vax_integer(&
result[1],2);
757 if (result_size >
sizeof(
result)) {
761 while (
result[i] != isc_info_end && i < result_size) {
762 short len = (short)isc_vax_integer(&
result[i+1],2);
768 if (
result[i] != isc_info_req_select_count) {
775 if (dbh->auto_commit && !
H->in_manually_txn) {
783 if (isc_dsql_free_statement(
H->isc_status, &stmt, DSQL_drop)) {
795 char const *co, *l, *r;
806 for (co =
ZSTR_VAL(unquoted); (co =
strchr(co,
'\'')); qcount++, co++);
812 quotedlen =
ZSTR_LEN(unquoted) + qcount + 2;
813 quoted_str = zend_string_alloc(quotedlen, 0);
819 strncpy(c, l, r-l+1);
826 strncpy(c, l, quotedlen-(c-
ZSTR_VAL(quoted_str))-1);
827 ZSTR_VAL(quoted_str)[quotedlen-1] =
'\'';
828 ZSTR_VAL(quoted_str)[quotedlen] =
'\0';
835static bool php_firebird_begin_transaction(
pdo_dbh_t *dbh,
bool is_auto_commit_txn)
840 char tpb[4] = { isc_tpb_version3 };
844 tpb[1] =
H->is_writable_txn ? isc_tpb_write : isc_tpb_read;
846 if (is_auto_commit_txn) {
850 tpb[2] = isc_tpb_read_committed;
852 tpb[3] = isc_tpb_rec_version;
855 switch (
H->txn_isolation_level) {
863 tpb[2] = isc_tpb_read_committed;
865 tpb[3] = isc_tpb_rec_version;
870 tpb[2] = isc_tpb_consistency;
876 tpb[2] = isc_tpb_concurrency;
882 if (isc_start_transaction(
H->isc_status, &
H->tr, 1, &
H->db, tpb_size, tpb)) {
891static bool firebird_handle_manually_begin(
pdo_dbh_t *dbh)
904 if (!php_firebird_begin_transaction(dbh,
false)) {
907 H->in_manually_txn = 1;
926 if (isc_commit_retaining(
H->isc_status, &
H->tr)) {
931 if (isc_commit_transaction(
H->isc_status, &
H->tr)) {
941static bool firebird_handle_manually_commit(
pdo_dbh_t *dbh)
953 if (!php_firebird_begin_transaction(dbh,
true)) {
957 H->in_manually_txn = 0;
963static bool php_firebird_rollback_transaction(
pdo_dbh_t *dbh)
967 if (isc_rollback_transaction(
H->isc_status, &
H->tr)) {
976static bool firebird_handle_manually_rollback(
pdo_dbh_t *dbh)
980 if (!php_firebird_rollback_transaction(dbh)) {
989 if (!php_firebird_begin_transaction(dbh,
true)) {
993 H->in_manually_txn = 0;
1000 XSQLDA *out_sqlda, isc_stmt_handle *
s,
HashTable *named_params)
1006 if (isc_dsql_allocate_statement(
H->isc_status, &
H->db,
s)) {
1015 if (!php_firebird_preprocess(sql, new_sql, named_params)) {
1022 if (isc_dsql_prepare(
H->isc_status, &
H->tr,
s, 0, new_sql,
H->sql_dialect, out_sqlda)) {
1046 if (
H->in_manually_txn) {
1061 if (!php_firebird_begin_transaction(dbh,
true)) {
1085 H->fetch_table_names = bval;
1094 if (
H->date_format) {
1096 H->date_format =
NULL;
1109 if (
H->time_format) {
1111 H->time_format =
NULL;
1124 if (
H->timestamp_format) {
1126 H->timestamp_format =
NULL;
1139 if (
H->in_manually_txn) {
1140 pdo_raise_impl_error(dbh,
NULL,
"HY000",
"Cannot change transaction isolation level while a transaction is already open");
1145 if (
H->txn_isolation_level != lval) {
1154 H->txn_isolation_level = lval;
1156 zend_value_error(
"Pdo\\Firebird::TRANSACTION_ISOLATION_LEVEL must be a valid transaction isolation level "
1157 "(Pdo\\Firebird::READ_COMMITTED, Pdo\\Firebird::REPEATABLE_READ, or Pdo\\Firebird::SERIALIZABLE)");
1170 if (
H->in_manually_txn) {
1176 if (
H->is_writable_txn != bval) {
1177 H->is_writable_txn = bval;
1182 H->is_writable_txn = !bval;
1186 if (!php_firebird_begin_transaction(dbh,
true)) {
1188 H->is_writable_txn = !bval;
1200#define INFO_BUF_LEN 512
1203static void php_firebird_info_cb(
void *
arg,
char const *
s)
1231#if defined(__GNUC__) || defined(PHP_WIN32)
1236 HMODULE l = GetModuleHandle(
"fbclient");
1241 info_func = (
info_func_t)GetProcAddress(l,
"isc_get_client_version");
1257 if (!isc_version(&
H->db, php_firebird_info_cb, (
void*)tmp)) {
1308 if (
H->einfo.errmsg &&
H->einfo.errmsg_length) {
1315static bool pdo_firebird_in_manually_transaction(
pdo_dbh_t *dbh)
1323 return H->in_manually_txn;
1328 firebird_handle_closer,
1329 firebird_handle_preparer,
1330 firebird_handle_doer,
1331 firebird_handle_quoter,
1332 firebird_handle_manually_begin,
1333 firebird_handle_manually_commit,
1334 firebird_handle_manually_rollback,
1335 pdo_firebird_set_attribute,
1337 pdo_firebird_fetch_error_func,
1338 pdo_firebird_get_attribute,
1339 pdo_firebird_check_liveness,
1342 pdo_firebird_in_manually_transaction,
1349static int pdo_firebird_handle_factory(
pdo_dbh_t *dbh,
zval *driver_options)
1352 {
"dbname",
NULL, 0 },
1353 {
"charset",
NULL, 0 },
1354 {
"role",
NULL, 0 },
1355 {
"dialect",
"3", 0 },
1356 {
"user",
NULL, 0 },
1357 {
"password",
NULL, 0 }
1360 short buf_len = 256, dpb_len;
1366 if (!dbh->
username && vars[4].optval) {
1370 if (!dbh->
password && vars[5].optval) {
1374 H->in_manually_txn = 0;
1381 H->txn_isolation_level = txn_isolation_level;
1383 zend_value_error(
"Pdo\\Firebird::TRANSACTION_ISOLATION_LEVEL must be a valid transaction isolation level "
1384 "(Pdo\\Firebird::READ_COMMITTED, Pdo\\Firebird::REPEATABLE_READ, or Pdo\\Firebird::SERIALIZABLE)");
1389 static char const dpb_flags[] = {
1390 isc_dpb_user_name, isc_dpb_password, isc_dpb_lc_ctype, isc_dpb_sql_role_name };
1392 char dpb_buffer[256] = { isc_dpb_version1 }, *dpb;
1394 dpb = dpb_buffer + 1;
1397 for (i = 0; i <
sizeof(dpb_flags); ++i) {
1398 if (dpb_values[i] && buf_len > 0) {
1399 dpb_len =
slprintf(dpb, buf_len,
"%c%c%s", dpb_flags[i], (
unsigned char)
strlen(dpb_values[i]),
1408 H->sql_dialect = atoi(vars[3].
optval);
1412 if (isc_attach_database(
H->isc_status, 0, vars[0].optval, &
H->db,(
short)(dpb-dpb_buffer), dpb_buffer)) {
1416 dbh->
methods = &firebird_methods;
1424 for (i = 0; i <
sizeof(vars)/
sizeof(vars[0]); ++i) {
1432 const ISC_STATUS *
s =
H->isc_status;
1433 fb_interpret(errmsg,
sizeof(errmsg),&
s);
1435 "HY000",
H->isc_status[1], errmsg);
1439 ret = php_firebird_begin_transaction(dbh,
true);
1443 firebird_handle_closer(dbh);
1453 pdo_firebird_handle_factory
strchr(string $haystack, string $needle, bool $before_needle=false)
zend_ffi_ctype_name_buf buf
bool php_firebird_commit_transaction(pdo_dbh_t *dbh, bool retain)
const char CHR_INTRODUCER
void php_firebird_set_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, const char *state, const size_t state_len, const char *msg, const size_t msg_len)
const pdo_driver_t pdo_firebird_driver
const struct pdo_stmt_methods firebird_stmt_methods
PDO_API int php_pdo_parse_data_source(const char *data_source, zend_ulong data_source_len, struct pdo_data_src_parser *parsed, int nparams)
PDO_API zend_class_entry * php_pdo_get_exception(void)
PDO_API bool pdo_get_long_param(zend_long *lval, zval *value)
void pdo_raise_impl_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, pdo_error_type sqlstate, const char *supp)
PDO_API bool pdo_get_bool_param(bool *bval, zval *value)
void pdo_throw_exception(unsigned int driver_errcode, char *driver_errmsg, pdo_error_type *pdo_error)
unsigned fb_get_client_version(void)
unsigned const char * end
php_json_error_code error_code
struct _pdo_dbh_t pdo_dbh_t
#define PDO_DRIVER_HEADER(name)
struct _pdo_stmt_t pdo_stmt_t
@ PDO_PLACEHOLDER_POSITIONAL
@ PDO_ATTR_CONNECTION_STATUS
@ PDO_ATTR_SERVER_VERSION
@ PDO_ATTR_FETCH_TABLE_NAMES
@ PDO_ATTR_CLIENT_VERSION
#define PDO_FIREBIRD_HANDLE_INITIALIZER
#define PDO_FB_DEF_DATE_FMT
#define PDO_FB_SQLDA_VERSION
#define php_firebird_error(d)
#define PDO_FB_DEF_TIMESTAMP_FMT
@ PDO_FB_ATTR_TIME_FORMAT
@ PDO_FB_TRANSACTION_ISOLATION_LEVEL
@ PDO_FB_ATTR_TIMESTAMP_FORMAT
@ PDO_FB_WRITABLE_TRANSACTION
@ PDO_FB_ATTR_DATE_FORMAT
#define php_firebird_error_with_info(d, e, el, m, ml)
#define PDO_FB_DEF_TIME_FMT
pdo_error_type error_code
unsigned alloc_own_columns
const struct pdo_dbh_methods * methods
pdo_error_type error_code
ZEND_API ZEND_COLD void zend_value_error(const char *format,...)
ZEND_API zend_result add_next_index_stringl(zval *arg, const char *str, size_t length)
ZEND_API zend_result add_next_index_long(zval *arg, zend_long n)
#define ZVAL_STRING(z, s)
#define pestrdup(s, persistent)
#define ecalloc(nmemb, size)
#define pestrndup(s, length, persistent)
#define pefree(ptr, persistent)
#define FREE_HASHTABLE(ht)
#define pecalloc(nmemb, size, persistent)
#define ALLOC_HASHTABLE(ht)
strncmp(string $string1, string $string2, int $length)
zend_string_release_ex(func->internal_function.function_name, 0)
#define strcasecmp(s1, s2)
ZEND_API ZEND_COLD zend_object * zend_throw_exception_ex(zend_class_entry *exception_ce, zend_long code, const char *format,...)
uint32_t(* info_func_t)(const zend_call_info *call_info, const zend_ssa *ssa)
ZEND_API void ZEND_FASTCALL zend_hash_destroy(HashTable *ht)
ZEND_API zval *ZEND_FASTCALL zend_hash_str_update(HashTable *ht, const char *str, size_t len, zval *pData)
#define zend_hash_init(ht, nSize, pHashFunction, pDestructor, persistent)
struct _zend_string zend_string
#define UNEXPECTED(condition)
#define ZSTR_INIT_LITERAL(s, persistent)
struct _zend_array HashTable
ZEND_RESULT_CODE zend_result