32#define READ_AND_RETURN_USING_MEMCPY(type, sqldata) do { \
34 memcpy(&ret, sqldata, sizeof(ret)); \
38static zend_always_inline ISC_INT64 php_get_isc_int64_from_sqldata(
const ISC_SCHAR *sqldata)
43static zend_always_inline ISC_LONG php_get_isc_long_from_sqldata(
const ISC_SCHAR *sqldata)
58static zend_always_inline ISC_TIMESTAMP php_get_isc_timestamp_from_sqldata(
const ISC_SCHAR *sqldata)
63static zend_always_inline ISC_QUAD php_get_isc_quad_from_sqldata(
const ISC_SCHAR *sqldata)
70static zend_always_inline ISC_TIME_TZ php_get_isc_time_tz_from_sqldata(
const ISC_SCHAR *sqldata)
75static zend_always_inline ISC_TIMESTAMP_TZ php_get_isc_timestamp_tz_from_sqldata(
const ISC_SCHAR *sqldata)
84 unsigned hours = 0, minutes = 0, seconds = 0, fractions = 0;
85 char timeZoneBuffer[40] = {0};
89 char timeBuf[80] = {0};
90 char timeTzBuf[124] = {0};
91 if (fb_decode_time_tz(
S->H->isc_status, timeTz, &hours, &minutes, &seconds, &fractions,
sizeof(timeZoneBuffer), timeZoneBuffer)) {
95 isc_decode_sql_time(&
time, &t);
98 size_t len =
strftime(timeBuf,
sizeof(timeBuf), fmt, &t);
103 size_t time_tz_len =
sprintf(timeTzBuf,
"%s %s", timeBuf, timeZoneBuffer);
109static int get_formatted_timestamp_tz(
pdo_stmt_t *stmt,
const ISC_TIMESTAMP_TZ* timestampTz,
zval *
result)
112 unsigned year, month, day, hours, minutes, seconds, fractions;
113 char timeZoneBuffer[40] = {0};
117 char timestampBuf[80] = {0};
118 char timestampTzBuf[124] = {0};
119 if (fb_decode_timestamp_tz(
S->H->isc_status, timestampTz, &year, &month, &day, &hours, &minutes, &seconds, &fractions,
sizeof(timeZoneBuffer), timeZoneBuffer)) {
123 ts.timestamp_time =
fb_encode_time(hours, minutes, seconds, fractions);
124 isc_decode_timestamp(&ts, &t);
128 size_t len =
strftime(timestampBuf,
sizeof(timestampBuf), fmt, &t);
133 size_t timestamp_tz_len =
sprintf(timestampTzBuf,
"%s %s", timestampBuf, timeZoneBuffer);
141static void php_firebird_free_sqlda(XSQLDA
const *sqlda)
145 for (i = 0; i < sqlda->sqld; ++i) {
146 XSQLVAR
const *var = &sqlda->sqlvar[i];
156static int pdo_firebird_stmt_dtor(
pdo_stmt_t *stmt)
163 bool server_obj_usable = !
Z_ISUNDEF(stmt->database_object_handle)
169 if (server_obj_usable && isc_dsql_free_statement(
S->H->isc_status, &
S->stmt, DSQL_drop)) {
179 php_firebird_free_sqlda(
S->in_sqlda);
183 php_firebird_free_sqlda(&
S->out_sqlda);
191static int pdo_firebird_stmt_execute(
pdo_stmt_t *stmt)
196 static char info_count[] = {isc_info_sql_records};
201 if ((*
S->name ||
S->cursor_open) && isc_dsql_free_statement(
H->isc_status, &
S->stmt, DSQL_close)) {
207 if (
S->out_sqlda.sqld) {
209 for (i = 0; i <
S->out_sqlda.sqld; i++) {
210 XSQLVAR *var = &
S->out_sqlda.sqlvar[i];
214 var->sqlind = (
void*)
ecalloc(1, var->sqllen + 2 *
sizeof(
short));
215 var->sqldata = &((
char*)var->sqlind)[
sizeof(short)];
219 if (
S->statement_type == isc_info_sql_stmt_exec_procedure) {
230 stmt->row_count = affected_rows;
232 switch (
S->statement_type) {
233 case isc_info_sql_stmt_insert:
234 case isc_info_sql_stmt_update:
235 case isc_info_sql_stmt_delete:
236 case isc_info_sql_stmt_exec_procedure:
237 if (isc_dsql_sql_info(
H->isc_status, &
S->stmt,
sizeof ( info_count),
241 if (
result[0] == isc_info_sql_records) {
242 unsigned i = 3, result_size = isc_vax_integer(&
result[1], 2);
243 if (result_size >
sizeof(
result)) {
246 while (
result[i] != isc_info_end && i < result_size) {
247 short len = (short) isc_vax_integer(&
result[i + 1], 2);
251 if (
result[i] != isc_info_req_select_count) {
252 affected_rows += isc_vax_integer(&
result[i + 3],
len);
256 stmt->row_count = affected_rows;
268 S->cursor_open =
S->out_sqlda.sqln && (
S->statement_type != isc_info_sql_stmt_exec_procedure);
269 S->exhausted = !
S->out_sqlda.sqln;
282static int pdo_firebird_stmt_fetch(
pdo_stmt_t *stmt,
288 if (!stmt->executed) {
289 const char *
msg =
"Cannot fetch from a closed cursor";
291 }
else if (!
S->exhausted) {
292 if (
S->statement_type == isc_info_sql_stmt_exec_procedure) {
298 if (
H->isc_status[0] &&
H->isc_status[1]) {
312static int pdo_firebird_stmt_describe(
pdo_stmt_t *stmt,
int colno)
316 XSQLVAR *var = &
S->out_sqlda.sqlvar[colno];
320 if ((var->sqltype & ~1) == SQL_TEXT) {
321 var->sqltype = SQL_VARYING | (var->sqltype & 1);
323 colname_len = (
S->H->fetch_table_names && var->relname_length)
324 ? (var->aliasname_length + var->relname_length + 1)
325 : (var->aliasname_length);
327 col->
maxlen = var->sqllen;
328 col->
name = zend_string_alloc(colname_len, 0);
330 if (colname_len > var->aliasname_length) {
331 memmove(
cp, var->relname, var->relname_length);
332 cp += var->relname_length;
335 memmove(
cp, var->aliasname, var->aliasname_length);
336 *(
cp+var->aliasname_length) =
'\0';
345 XSQLVAR *var = &
S->out_sqlda.sqlvar[colno];
348 if (var->sqlscale < 0) {
351 switch (var->sqltype & ~1) {
354#if SIZEOF_ZEND_LONG >= 8
379 char const bl_item = isc_info_blob_total_length;
385 if (isc_open_blob(
H->isc_status, &
H->db, &
H->tr, &blobh, blob_id)) {
390 if (isc_blob_info(
H->isc_status, &blobh, 1,
const_cast(&bl_item),
391 sizeof(bl_info), bl_info)) {
397 for (i = 0; i <
sizeof(bl_info); ) {
398 unsigned short item_len;
399 char item = bl_info[i++];
401 if (item == isc_info_end || item == isc_info_truncated || item == isc_info_error
402 || i >=
sizeof(bl_info)) {
403 const char *
msg =
"Couldn't determine BLOB size";
408 item_len = (
unsigned short) isc_vax_integer(&bl_info[i], 2);
410 if (item == isc_info_blob_total_length) {
411 len = isc_vax_integer(&bl_info[i+2], item_len);
421 unsigned short seg_len;
431 str = zend_string_alloc(
len, 0);
433 for (cur_len =
stat = 0; (!
stat ||
stat == isc_segment) && cur_len <
len; cur_len += seg_len) {
435 unsigned short chunk_size = (
len - cur_len) > USHRT_MAX ? USHRT_MAX
436 : (unsigned short)(
len - cur_len);
438 stat = isc_get_segment(
H->isc_status, &blobh, &seg_len, chunk_size,
ZSTR_VAL(str) + cur_len);
444 if (
H->isc_status[0] == 1 && (
stat != 0 &&
stat != isc_segstr_eof &&
stat != isc_segment)) {
445 const char *
msg =
"Error reading from BLOB";
453 if (isc_close_blob(
H->isc_status, &blobh)) {
461static int pdo_firebird_stmt_get_col(
465 XSQLVAR
const *var = &
S->out_sqlda.sqlvar[colno];
467 if (*var->sqlind == -1) {
470 if (var->sqlscale < 0) {
471 static ISC_INT64
const scales[] = { 1, 10, 100, 1000,
484 LL_LIT(10000000000000000),
485 LL_LIT(100000000000000000),
486 LL_LIT(1000000000000000000)
488 ISC_INT64
n, f = scales[-var->sqlscale];
491 switch (var->sqltype & ~1) {
493 n = *(
short*)var->sqldata;
496 n = php_get_isc_long_from_sqldata(var->sqldata);
499 n = php_get_isc_int64_from_sqldata(var->sqldata);
507 str =
zend_strpprintf(0,
"%.*F", -var->sqlscale, php_get_double_from_sqldata(var->sqldata));
510 n / f, -var->sqlscale,
n % f);
511 }
else if (
n <= -f) {
513 n / f, -var->sqlscale, -
n % f);
519 switch (var->sqltype & ~1) {
536#if SIZEOF_ZEND_LONG >= 8
554 isc_decode_sql_date((ISC_DATE*)var->sqldata, &t);
558 isc_decode_sql_time((ISC_TIME*)var->sqldata, &t);
563 ISC_TIMESTAMP timestamp = php_get_isc_timestamp_from_sqldata(var->sqldata);
564 isc_decode_timestamp(×tamp, &t);
575 ISC_TIME_TZ
time = php_get_isc_time_tz_from_sqldata(var->sqldata);
576 return get_formatted_time_tz(stmt, &
time,
result);
578 case SQL_TIMESTAMP_TZ: {
579 ISC_TIMESTAMP_TZ ts = php_get_isc_timestamp_tz_from_sqldata(var->sqldata);
580 return get_formatted_timestamp_tz(stmt, &ts,
result);
584 ISC_QUAD quad = php_get_isc_quad_from_sqldata(var->sqldata);
585 return php_firebird_fetch_blob(stmt, colno,
result, &quad);
593static int php_firebird_bind_blob(
pdo_stmt_t *stmt, ISC_QUAD *blob_id,
zval *param)
600 unsigned short chunk_size;
603 if (isc_create_blob(
H->isc_status, &
H->db, &
H->tr, &h, blob_id)) {
614 for (rem_cnt =
Z_STRLEN(
data); rem_cnt > 0; rem_cnt -= chunk_size) {
615 chunk_size = rem_cnt > USHRT_MAX ? USHRT_MAX : (
unsigned short)rem_cnt;
616 if (isc_put_segment(
H->isc_status, &h, chunk_size, &
Z_STRVAL(
data)[put_cnt])) {
621 put_cnt += chunk_size;
625 zval_ptr_dtor_str(&
data);
628 if (isc_close_blob(
H->isc_status, &h)) {
639 XSQLDA *sqlda = param->is_param ?
S->in_sqlda : &
S->out_sqlda;
646 if (!sqlda || param->paramno >= sqlda->sqld) {
647 const char *
msg =
"Invalid parameter index";
651 if (param->is_param && param->paramno == -1) {
661 for (i = 0; i < sqlda->sqld; ++i) {
662 XSQLVAR *var = &sqlda->sqlvar[i];
665 min(
ZSTR_LEN(param->name), var->aliasname_length)))
667 min(
ZSTR_LEN(param->name), var->sqlname_length)))) {
672 if (i >= sqlda->sqld) {
673 const char *
msg =
"Invalid parameter name";
680 var = &sqlda->sqlvar[param->paramno];
682 switch (event_type) {
686 if (param->is_param) {
691 var->sqlind = (
void*)
emalloc(var->sqllen + 2*
sizeof(
short));
692 var->sqldata = &((
char*)var->sqlind)[
sizeof(short)];
697 if (!param->is_param) {
702 if (
Z_ISREF(param->parameter)) {
703 parameter =
Z_REFVAL(param->parameter);
705 parameter = ¶m->parameter;
722 switch (var->sqltype & ~1) {
725 const char *
msg =
"Cannot bind to array field";
733 if (~var->sqltype & 1) {
734 const char *
msg =
"Parameter requires non-null value";
741 ISC_QUAD quad = php_get_isc_quad_from_sqldata(var->sqldata);
742 if (php_firebird_bind_blob(stmt, &quad, parameter) != 0) {
743 memcpy(var->sqldata, &quad,
sizeof(quad));
751 if ((var->sqltype & ~1) == SQL_BOOLEAN) {
757 *(FB_BOOLEAN*)var->sqldata =
zend_is_true(parameter) ? FB_TRUE : FB_FALSE;
765 *(FB_BOOLEAN*)var->sqldata = FB_FALSE;
771 *(FB_BOOLEAN*)var->sqldata = (lval != 0) ? FB_TRUE : FB_FALSE;
774 *(FB_BOOLEAN*)var->sqldata = (
dval != 0) ? FB_TRUE : FB_FALSE;
778 *(FB_BOOLEAN*)var->sqldata = FB_TRUE;
780 *(FB_BOOLEAN*)var->sqldata = FB_FALSE;
782 const char *
msg =
"Cannot convert string to boolean";
795 const char *
msg =
"Binding arrays/objects is not supported";
809 var->sqltype = (
sizeof(
zend_long) == 8 ? SQL_INT64 : SQL_LONG) | (var->sqltype & 1);
810 var->sqldata = (
void*)&
Z_LVAL_P(parameter);
815 var->sqltype =
SQL_DOUBLE | (var->sqltype & 1);
816 var->sqldata = (
void*)&
Z_DVAL_P(parameter);
817 var->sqllen =
sizeof(double);
823 switch (var->sqltype & ~1) {
836 case SQL_TIMESTAMP_TZ:
843 var->sqltype = SQL_TEXT | (var->sqltype & 1);
851 if (~var->sqltype & 1) {
852 const char *
msg =
"Parameter requires non-null value";
860 const char *
msg =
"Binding arrays/objects is not supported";
868 if (param->paramno == -1) {
871 if (param->is_param) {
874 if (
Z_ISREF(param->parameter)) {
875 parameter =
Z_REFVAL(param->parameter);
877 parameter = ¶m->parameter;
881 return pdo_firebird_stmt_get_col(stmt, param->paramno, parameter,
NULL);
897 if (!try_convert_to_string(
val)) {
901 if (isc_dsql_set_cursor_name(
S->H->isc_status, &
S->stmt,
Z_STRVAL_P(
val),0)) {
931static int pdo_firebird_stmt_cursor_closer(
pdo_stmt_t *stmt)
936 if ((*
S->name ||
S->cursor_open) && isc_dsql_free_statement(
S->H->isc_status, &
S->stmt, DSQL_close)) {
948 pdo_firebird_stmt_dtor,
949 pdo_firebird_stmt_execute,
950 pdo_firebird_stmt_fetch,
951 pdo_firebird_stmt_describe,
952 pdo_firebird_stmt_get_col,
953 pdo_firebird_stmt_param_hook,
954 pdo_firebird_stmt_set_attribute,
955 pdo_firebird_stmt_get_attribute,
956 pdo_firebird_stmt_get_column_meta,
958 pdo_firebird_stmt_cursor_closer
sizeof(Countable|array $value, int $mode=COUNT_NORMAL)
zend_ffi_ctype_name_buf buf
bool php_firebird_commit_transaction(pdo_dbh_t *dbh, bool retain)
const struct pdo_stmt_methods firebird_stmt_methods
#define READ_AND_RETURN_USING_MEMCPY(type, sqldata)
sprintf("0x%X", $numelems)
void pdo_raise_impl_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, pdo_error_type sqlstate, const char *supp)
ISC_DATE fb_encode_date(unsigned year, unsigned month, unsigned day)
ISC_TIME fb_encode_time(unsigned hours, unsigned minutes, unsigned seconds, unsigned fractions)
strftime(string $format, ?int $timestamp=null)
struct _pdo_stmt_t pdo_stmt_t
@ PDO_PARAM_EVT_FETCH_POST
#define PDO_FIREBIRD_HANDLE_INITIALIZER
#define PDO_FB_DEF_DATE_FMT
#define php_firebird_error_stmt(s)
#define PDO_FB_SQLDA_VERSION
#define PDO_FB_DEF_TIMESTAMP_FMT
#define PDO_FB_DEF_TIME_FMT
#define php_firebird_error_stmt_with_info(s, e, el, m, ml)
struct _php_stream php_stream
#define PHP_STREAM_COPY_ALL
#define php_stream_copy_to_mem(src, maxlen, persistent)
#define php_stream_from_zval_no_verify(xstr, pzval)
ZEND_API zend_string * zend_strpprintf(size_t max_len, const char *format,...)
ZEND_API zend_string * zend_strpprintf_unchecked(size_t max_len, const char *format,...)
#define ZVAL_STRING(z, s)
#define ZVAL_STRINGL(z, s, l)
#define ZVAL_STRINGL_FAST(z, s, l)
#define ecalloc(nmemb, size)
#define FREE_HASHTABLE(ht)
#define strncasecmp(s1, s2, n)
ZEND_API void ZEND_FASTCALL zend_hash_destroy(HashTable *ht)
ZEND_API zval *ZEND_FASTCALL zend_hash_find(const HashTable *ht, zend_string *key)
struct _zend_string zend_string
ZEND_API bool ZEND_FASTCALL zend_is_true(const zval *op)
ZEND_API zend_string *ZEND_FASTCALL zval_get_string_func(zval *op)
ZEND_API int ZEND_FASTCALL zend_binary_strncasecmp(const char *s1, size_t len1, const char *s2, size_t len2, size_t length)
#define zend_always_inline
#define EMPTY_SWITCH_DEFAULT_CASE()
#define ZSTR_EMPTY_ALLOC()
#define Z_STRVAL_P(zval_p)
#define IS_OBJ_FREE_CALLED
#define Z_STRLEN_P(zval_p)
#define Z_OBJ_HANDLE(zval)
#define ZVAL_COPY_VALUE(z, v)
ZEND_API void zval_ptr_dtor(zval *zval_ptr)