diff options
Diffstat (limited to 'ext/pdo_pgsql/pgsql_statement.c')
-rw-r--r-- | ext/pdo_pgsql/pgsql_statement.c | 257 |
1 files changed, 171 insertions, 86 deletions
diff --git a/ext/pdo_pgsql/pgsql_statement.c b/ext/pdo_pgsql/pgsql_statement.c index a6e6405a1c..a5ee2e993e 100644 --- a/ext/pdo_pgsql/pgsql_statement.c +++ b/ext/pdo_pgsql/pgsql_statement.c @@ -1,6 +1,6 @@ /* +----------------------------------------------------------------------+ - | PHP Version 5 | + | PHP Version 7 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2016 The PHP Group | +----------------------------------------------------------------------+ @@ -36,17 +36,33 @@ #endif /* from postgresql/src/include/catalog/pg_type.h */ +#define BOOLLABEL "bool" #define BOOLOID 16 +#define BYTEALABEL "bytea" #define BYTEAOID 17 -#define INT8OID 20 +#define DATELABEL "date" +#define DATEOID 1082 +#define INT2LABEL "int2" #define INT2OID 21 +#define INT4LABEL "int4" #define INT4OID 23 -#define TEXTOID 25 +#define INT8LABEL "int8" +#define INT8OID 20 #define OIDOID 26 +#define TEXTLABEL "text" +#define TEXTOID 25 +#define TIMESTAMPLABEL "timestamp" +#define TIMESTAMPOID 1114 +#define VARCHARLABEL "varchar" +#define VARCHAROID 1043 -static int pgsql_stmt_dtor(pdo_stmt_t *stmt TSRMLS_DC) + + +static int pgsql_stmt_dtor(pdo_stmt_t *stmt) { pdo_pgsql_stmt *S = (pdo_pgsql_stmt*)stmt->driver_data; + zend_bool server_obj_usable = IS_OBJ_VALID(EG(objects_store).object_buckets[Z_OBJ_HANDLE(stmt->database_object_handle)]) + && !(GC_FLAGS(Z_OBJ(stmt->database_object_handle)) & IS_OBJ_FREE_CALLED); if (S->result) { /* free the resource */ @@ -55,11 +71,11 @@ static int pgsql_stmt_dtor(pdo_stmt_t *stmt TSRMLS_DC) } if (S->stmt_name) { - pdo_pgsql_db_handle *H = S->H; - char *q = NULL; - PGresult *res; + if (S->is_prepared && server_obj_usable) { + pdo_pgsql_db_handle *H = S->H; + char *q = NULL; + PGresult *res; - if (S->is_prepared) { spprintf(&q, 0, "DEALLOCATE %s", S->stmt_name); res = PQexec(H->server, q); efree(q); @@ -92,14 +108,16 @@ static int pgsql_stmt_dtor(pdo_stmt_t *stmt TSRMLS_DC) } if (S->cursor_name) { - pdo_pgsql_db_handle *H = S->H; - char *q = NULL; - PGresult *res; + if (server_obj_usable) { + pdo_pgsql_db_handle *H = S->H; + char *q = NULL; + PGresult *res; - spprintf(&q, 0, "CLOSE %s", S->cursor_name); - res = PQexec(H->server, q); - efree(q); - if (res) PQclear(res); + spprintf(&q, 0, "CLOSE %s", S->cursor_name); + res = PQexec(H->server, q); + efree(q); + if (res) PQclear(res); + } efree(S->cursor_name); S->cursor_name = NULL; } @@ -113,7 +131,7 @@ static int pgsql_stmt_dtor(pdo_stmt_t *stmt TSRMLS_DC) return 1; } -static int pgsql_stmt_execute(pdo_stmt_t *stmt TSRMLS_DC) +static int pgsql_stmt_execute(pdo_stmt_t *stmt) { pdo_pgsql_stmt *S = (pdo_pgsql_stmt*)stmt->driver_data; pdo_pgsql_db_handle *H = S->H; @@ -230,17 +248,17 @@ stmt_retry: } if (status == PGRES_COMMAND_OK) { - stmt->row_count = (long)atoi(PQcmdTuples(S->result)); + ZEND_ATOL(stmt->row_count, PQcmdTuples(S->result)); H->pgoid = PQoidValue(S->result); } else { - stmt->row_count = (long)PQntuples(S->result); + stmt->row_count = (zend_long)PQntuples(S->result); } return 1; } static int pgsql_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *param, - enum pdo_param_event event_type TSRMLS_DC) + enum pdo_param_event event_type) { pdo_pgsql_stmt *S = (pdo_pgsql_stmt*)stmt->driver_data; @@ -255,16 +273,18 @@ static int pgsql_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data * case PDO_PARAM_EVT_NORMALIZE: /* decode name from $1, $2 into 0, 1 etc. */ if (param->name) { - if (param->name[0] == '$') { - param->paramno = atoi(param->name + 1); + if (ZSTR_VAL(param->name)[0] == '$') { + ZEND_ATOL(param->paramno, ZSTR_VAL(param->name) + 1); } else { /* resolve parameter name to rewritten name */ - char *nameptr; - if (stmt->bound_param_map && SUCCESS == zend_hash_find(stmt->bound_param_map, - param->name, param->namelen + 1, (void**)&nameptr)) { - param->paramno = atoi(nameptr + 1) - 1; + char *namevar; + + if (stmt->bound_param_map && (namevar = zend_hash_find_ptr(stmt->bound_param_map, + param->name)) != NULL) { + ZEND_ATOL(param->paramno, namevar + 1); + param->paramno--; } else { - pdo_raise_impl_error(stmt->dbh, stmt, "HY093", param->name TSRMLS_CC); + pdo_raise_impl_error(stmt->dbh, stmt, "HY093", ZSTR_VAL(param->name)); return 0; } } @@ -272,6 +292,13 @@ static int pgsql_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data * break; case PDO_PARAM_EVT_ALLOC: + if (!stmt->bound_param_map) { + return 1; + } + if (!zend_hash_index_exists(stmt->bound_param_map, param->paramno)) { + pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "parameter was not defined"); + return 0; + } case PDO_PARAM_EVT_EXEC_POST: case PDO_PARAM_EVT_FETCH_PRE: case PDO_PARAM_EVT_FETCH_POST: @@ -297,15 +324,25 @@ static int pgsql_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data * sizeof(Oid)); } if (param->paramno >= 0) { + zval *parameter; + + /* if (param->paramno >= zend_hash_num_elements(stmt->bound_params)) { - pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "parameter was not defined" TSRMLS_CC); + pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "parameter was not defined"); return 0; } + */ + + if (Z_ISREF(param->parameter)) { + parameter = Z_REFVAL(param->parameter); + } else { + parameter = ¶m->parameter; + } if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB && - Z_TYPE_P(param->parameter) == IS_RESOURCE) { + Z_TYPE_P(parameter) == IS_RESOURCE) { php_stream *stm; - php_stream_from_zval_no_verify(stm, ¶m->parameter); + php_stream_from_zval_no_verify(stm, parameter); if (stm) { if (php_stream_is(stm, &pdo_pgsql_lob_stream_ops)) { struct pdo_pgsql_lob_self *self = (struct pdo_pgsql_lob_self*)stm->abstract; @@ -322,15 +359,12 @@ static int pgsql_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data * S->param_types[param->paramno] = OIDOID; return 1; } else { - int len; - - SEPARATE_ZVAL_IF_NOT_REF(¶m->parameter); - Z_TYPE_P(param->parameter) = IS_STRING; - - if ((len = php_stream_copy_to_mem(stm, &Z_STRVAL_P(param->parameter), PHP_STREAM_COPY_ALL, 0)) > 0) { - Z_STRLEN_P(param->parameter) = len; + zend_string *str = php_stream_copy_to_mem(stm, PHP_STREAM_COPY_ALL, 0); + if (str != NULL) { + //??SEPARATE_ZVAL_IF_NOT_REF(¶m->parameter); + ZVAL_STR(parameter, str); } else { - ZVAL_EMPTY_STRING(param->parameter); + ZVAL_EMPTY_STRING(parameter); } } } else { @@ -341,18 +375,18 @@ static int pgsql_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data * } if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_NULL || - Z_TYPE_P(param->parameter) == IS_NULL) { + Z_TYPE_P(parameter) == IS_NULL) { S->param_values[param->paramno] = NULL; S->param_lengths[param->paramno] = 0; - } else if (Z_TYPE_P(param->parameter) == IS_BOOL) { - S->param_values[param->paramno] = Z_BVAL_P(param->parameter) ? "t" : "f"; + } else if (Z_TYPE_P(parameter) == IS_FALSE || Z_TYPE_P(parameter) == IS_TRUE) { + S->param_values[param->paramno] = Z_TYPE_P(parameter) == IS_TRUE ? "t" : "f"; S->param_lengths[param->paramno] = 1; S->param_formats[param->paramno] = 0; } else { - SEPARATE_ZVAL_IF_NOT_REF(¶m->parameter); - convert_to_string(param->parameter); - S->param_values[param->paramno] = Z_STRVAL_P(param->parameter); - S->param_lengths[param->paramno] = Z_STRLEN_P(param->parameter); + //SEPARATE_ZVAL_IF_NOT_REF(¶m->parameter); + convert_to_string_ex(parameter); + S->param_values[param->paramno] = Z_STRVAL_P(parameter); + S->param_lengths[param->paramno] = Z_STRLEN_P(parameter); S->param_formats[param->paramno] = 0; } @@ -369,17 +403,17 @@ static int pgsql_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data * /* We need to manually convert to a pg native boolean value */ if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_BOOL && ((param->param_type & PDO_PARAM_INPUT_OUTPUT) != PDO_PARAM_INPUT_OUTPUT)) { - SEPARATE_ZVAL(¶m->parameter); + const char *s = zend_is_true(¶m->parameter) ? "t" : "f"; param->param_type = PDO_PARAM_STR; - convert_to_boolean(param->parameter); - ZVAL_STRINGL(param->parameter, Z_BVAL_P(param->parameter) ? "t" : "f", 1, 1); + zval_ptr_dtor(¶m->parameter); + ZVAL_STRINGL(¶m->parameter, s, 1); } } return 1; } static int pgsql_stmt_fetch(pdo_stmt_t *stmt, - enum pdo_fetch_orientation ori, long offset TSRMLS_DC) + enum pdo_fetch_orientation ori, zend_long offset) { pdo_pgsql_stmt *S = (pdo_pgsql_stmt*)stmt->driver_data; @@ -393,8 +427,8 @@ static int pgsql_stmt_fetch(pdo_stmt_t *stmt, case PDO_FETCH_ORI_PRIOR: spprintf(&ori_str, 0, "BACKWARD"); break; case PDO_FETCH_ORI_FIRST: spprintf(&ori_str, 0, "FIRST"); break; case PDO_FETCH_ORI_LAST: spprintf(&ori_str, 0, "LAST"); break; - case PDO_FETCH_ORI_ABS: spprintf(&ori_str, 0, "ABSOLUTE %ld", offset); break; - case PDO_FETCH_ORI_REL: spprintf(&ori_str, 0, "RELATIVE %ld", offset); break; + case PDO_FETCH_ORI_ABS: spprintf(&ori_str, 0, "ABSOLUTE %pd", offset); break; + case PDO_FETCH_ORI_REL: spprintf(&ori_str, 0, "RELATIVE %pd", offset); break; default: return 0; } @@ -426,23 +460,24 @@ static int pgsql_stmt_fetch(pdo_stmt_t *stmt, } } -static int pgsql_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC) +static int pgsql_stmt_describe(pdo_stmt_t *stmt, int colno) { pdo_pgsql_stmt *S = (pdo_pgsql_stmt*)stmt->driver_data; struct pdo_column_data *cols = stmt->columns; struct pdo_bound_param_data *param; + char *str; if (!S->result) { return 0; } - cols[colno].name = estrdup(PQfname(S->result, colno)); - cols[colno].namelen = strlen(cols[colno].name); + str = PQfname(S->result, colno); + cols[colno].name = zend_string_init(str, strlen(str), 0); cols[colno].maxlen = PQfsize(S->result, colno); cols[colno].precision = PQfmod(S->result, colno); S->cols[colno].pgsql_type = PQftype(S->result, colno); - switch(S->cols[colno].pgsql_type) { + switch (S->cols[colno].pgsql_type) { case BOOLOID: cols[colno].param_type = PDO_PARAM_BOOL; @@ -451,11 +486,9 @@ static int pgsql_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC) case OIDOID: /* did the user bind the column as a LOB ? */ if (stmt->bound_columns && ( - SUCCESS == zend_hash_index_find(stmt->bound_columns, - colno, (void**)¶m) || - SUCCESS == zend_hash_find(stmt->bound_columns, - cols[colno].name, cols[colno].namelen, - (void**)¶m))) { + (param = zend_hash_index_find_ptr(stmt->bound_columns, colno)) != NULL || + (param = zend_hash_find_ptr(stmt->bound_columns, cols[colno].name)) != NULL)) { + if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB) { cols[colno].param_type = PDO_PARAM_LOB; break; @@ -470,7 +503,7 @@ static int pgsql_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC) break; case INT8OID: - if (sizeof(long)>=8) { + if (sizeof(zend_long)>=8) { cols[colno].param_type = PDO_PARAM_INT; } else { cols[colno].param_type = PDO_PARAM_STR; @@ -488,7 +521,7 @@ static int pgsql_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC) return 1; } -static int pgsql_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, unsigned long *len, int *caller_frees TSRMLS_DC) +static int pgsql_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, zend_ulong *len, int *caller_frees ) { pdo_pgsql_stmt *S = (pdo_pgsql_stmt*)stmt->driver_data; struct pdo_column_data *cols = stmt->columns; @@ -506,12 +539,12 @@ static int pgsql_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, unsigned *ptr = PQgetvalue(S->result, S->current_row - 1, colno); *len = PQgetlength(S->result, S->current_row - 1, colno); - switch(cols[colno].param_type) { + switch (cols[colno].param_type) { case PDO_PARAM_INT: - S->cols[colno].intval = atol(*ptr); + ZEND_ATOL(S->cols[colno].intval, *ptr); *ptr = (char *) &(S->cols[colno].intval); - *len = sizeof(long); + *len = sizeof(zend_long); break; case PDO_PARAM_BOOL: @@ -527,7 +560,7 @@ static int pgsql_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, unsigned Oid oid = (Oid)strtoul(*ptr, &end_ptr, 10); int loid = lo_open(S->H->server, oid, INV_READ); if (loid >= 0) { - *ptr = (char*)pdo_pgsql_create_lob_stream(stmt->dbh, loid, oid TSRMLS_CC); + *ptr = (char*)pdo_pgsql_create_lob_stream(&stmt->database_object_handle, loid, oid); *len = 0; return *ptr ? 1 : 0; } @@ -567,12 +600,40 @@ static int pgsql_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, unsigned return 1; } -static int pgsql_stmt_get_column_meta(pdo_stmt_t *stmt, long colno, zval *return_value TSRMLS_DC) +static zend_always_inline char * pdo_pgsql_translate_oid_to_table(Oid oid, PGconn *conn) +{ + char *table_name = NULL; + PGresult *tmp_res; + char *querystr = NULL; + + spprintf(&querystr, 0, "SELECT RELNAME FROM PG_CLASS WHERE OID=%d", oid); + + if ((tmp_res = PQexec(conn, querystr)) == NULL || PQresultStatus(tmp_res) != PGRES_TUPLES_OK) { + if (tmp_res) { + PQclear(tmp_res); + } + efree(querystr); + return 0; + } + efree(querystr); + + if ((table_name = PQgetvalue(tmp_res, 0, 0)) == NULL) { + PQclear(tmp_res); + return 0; + } + + PQclear(tmp_res); + return table_name; +} + +static int pgsql_stmt_get_column_meta(pdo_stmt_t *stmt, zend_long colno, zval *return_value) { pdo_pgsql_stmt *S = (pdo_pgsql_stmt*)stmt->driver_data; PGresult *res; char *q=NULL; ExecStatusType status; + Oid table_oid; + char *table_name=NULL; if (!S->result) { return FAILURE; @@ -585,32 +646,56 @@ static int pgsql_stmt_get_column_meta(pdo_stmt_t *stmt, long colno, zval *return array_init(return_value); add_assoc_long(return_value, "pgsql:oid", S->cols[colno].pgsql_type); - /* Fetch metadata from Postgres system catalogue */ - spprintf(&q, 0, "SELECT TYPNAME FROM PG_TYPE WHERE OID=%u", S->cols[colno].pgsql_type); - res = PQexec(S->H->server, q); - efree(q); - - status = PQresultStatus(res); - - if (status != PGRES_TUPLES_OK) { - /* Failed to get system catalogue, but return success - * with the data we have collected so far - */ - goto done; + table_oid = PQftable(S->result, colno); + add_assoc_long(return_value, "pgsql:table_oid", table_oid); + table_name = pdo_pgsql_translate_oid_to_table(table_oid, S->H->server); + if (table_name) { + add_assoc_string(return_value, "table", table_name); } - /* We want exactly one row returned */ - if (1 != PQntuples(res)) { - goto done; + switch (S->cols[colno].pgsql_type) { + case BOOLOID: + add_assoc_string(return_value, "native_type", BOOLLABEL); + break; + case BYTEAOID: + add_assoc_string(return_value, "native_type", BYTEALABEL); + break; + case INT8OID: + add_assoc_string(return_value, "native_type", INT8LABEL); + break; + case INT2OID: + add_assoc_string(return_value, "native_type", INT2LABEL); + break; + case INT4OID: + add_assoc_string(return_value, "native_type", INT4LABEL); + break; + case TEXTOID: + add_assoc_string(return_value, "native_type", TEXTLABEL); + break; + case VARCHAROID: + add_assoc_string(return_value, "native_type", VARCHARLABEL); + break; + case DATEOID: + add_assoc_string(return_value, "native_type", DATELABEL); + break; + case TIMESTAMPOID: + add_assoc_string(return_value, "native_type", TIMESTAMPLABEL); + break; + default: + /* Fetch metadata from Postgres system catalogue */ + spprintf(&q, 0, "SELECT TYPNAME FROM PG_TYPE WHERE OID=%u", S->cols[colno].pgsql_type); + res = PQexec(S->H->server, q); + efree(q); + status = PQresultStatus(res); + if (status == PGRES_TUPLES_OK && 1 == PQntuples(res)) { + add_assoc_string(return_value, "native_type", PQgetvalue(res, 0, 0)); + } + PQclear(res); } - - add_assoc_string(return_value, "native_type", PQgetvalue(res, 0, 0), 1); -done: - PQclear(res); return 1; } -static int pdo_pgsql_stmt_cursor_closer(pdo_stmt_t *stmt TSRMLS_DC) +static int pdo_pgsql_stmt_cursor_closer(pdo_stmt_t *stmt) { pdo_pgsql_stmt *S = (pdo_pgsql_stmt*)stmt->driver_data; |