root/ext/pdo_pgsql/pgsql_statement.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pgsql_stmt_dtor
  2. pgsql_stmt_execute
  3. pgsql_stmt_param_hook
  4. pgsql_stmt_fetch
  5. pgsql_stmt_describe
  6. pgsql_stmt_get_col
  7. pgsql_stmt_get_column_meta
  8. pdo_pgsql_stmt_cursor_closer

   1 /*
   2   +----------------------------------------------------------------------+
   3   | PHP Version 7                                                        |
   4   +----------------------------------------------------------------------+
   5   | Copyright (c) 1997-2016 The PHP Group                                |
   6   +----------------------------------------------------------------------+
   7   | This source file is subject to version 3.01 of the PHP license,      |
   8   | that is bundled with this package in the file LICENSE, and is        |
   9   | available through the world-wide-web at the following url:           |
  10   | http://www.php.net/license/3_01.txt                                  |
  11   | If you did not receive a copy of the PHP license and are unable to   |
  12   | obtain it through the world-wide-web, please send a note to          |
  13   | license@php.net so we can mail you a copy immediately.               |
  14   +----------------------------------------------------------------------+
  15   | Authors: Edin Kadribasic <edink@emini.dk>                            |
  16   |          Ilia Alshanestsky <ilia@prohost.org>                        |
  17   |          Wez Furlong <wez@php.net>                                   |
  18   +----------------------------------------------------------------------+
  19 */
  20 
  21 /* $Id$ */
  22 
  23 #ifdef HAVE_CONFIG_H
  24 #include "config.h"
  25 #endif
  26 
  27 #include "php.h"
  28 #include "php_ini.h"
  29 #include "ext/standard/info.h"
  30 #include "pdo/php_pdo.h"
  31 #include "pdo/php_pdo_driver.h"
  32 #include "php_pdo_pgsql.h"
  33 #include "php_pdo_pgsql_int.h"
  34 #if HAVE_NETINET_IN_H
  35 #include <netinet/in.h>
  36 #endif
  37 
  38 /* from postgresql/src/include/catalog/pg_type.h */
  39 #define BOOLOID     16
  40 #define BYTEAOID    17
  41 #define INT8OID     20
  42 #define INT2OID     21
  43 #define INT4OID     23
  44 #define TEXTOID     25
  45 #define OIDOID      26
  46 
  47 static int pgsql_stmt_dtor(pdo_stmt_t *stmt)
  48 {
  49         pdo_pgsql_stmt *S = (pdo_pgsql_stmt*)stmt->driver_data;
  50 
  51         if (S->result) {
  52                 /* free the resource */
  53                 PQclear(S->result);
  54                 S->result = NULL;
  55         }
  56 
  57         if (S->stmt_name) {
  58                 pdo_pgsql_db_handle *H = S->H;
  59                 char *q = NULL;
  60                 PGresult *res;
  61 
  62                 if (S->is_prepared) {
  63                         spprintf(&q, 0, "DEALLOCATE %s", S->stmt_name);
  64                         res = PQexec(H->server, q);
  65                         efree(q);
  66                         if (res) {
  67                                 PQclear(res);
  68                         }
  69                 }
  70                 efree(S->stmt_name);
  71                 S->stmt_name = NULL;
  72         }
  73         if (S->param_lengths) {
  74                 efree(S->param_lengths);
  75                 S->param_lengths = NULL;
  76         }
  77         if (S->param_values) {
  78                 efree(S->param_values);
  79                 S->param_values = NULL;
  80         }
  81         if (S->param_formats) {
  82                 efree(S->param_formats);
  83                 S->param_formats = NULL;
  84         }
  85         if (S->param_types) {
  86                 efree(S->param_types);
  87                 S->param_types = NULL;
  88         }
  89         if (S->query) {
  90                 efree(S->query);
  91                 S->query = NULL;
  92         }
  93 
  94         if (S->cursor_name) {
  95                 pdo_pgsql_db_handle *H = S->H;
  96                 char *q = NULL;
  97                 PGresult *res;
  98 
  99                 spprintf(&q, 0, "CLOSE %s", S->cursor_name);
 100                 res = PQexec(H->server, q);
 101                 efree(q);
 102                 if (res) PQclear(res);
 103                 efree(S->cursor_name);
 104                 S->cursor_name = NULL;
 105         }
 106 
 107         if(S->cols) {
 108                 efree(S->cols);
 109                 S->cols = NULL;
 110         }
 111         efree(S);
 112         stmt->driver_data = NULL;
 113         return 1;
 114 }
 115 
 116 static int pgsql_stmt_execute(pdo_stmt_t *stmt)
 117 {
 118         pdo_pgsql_stmt *S = (pdo_pgsql_stmt*)stmt->driver_data;
 119         pdo_pgsql_db_handle *H = S->H;
 120         ExecStatusType status;
 121 
 122         /* ensure that we free any previous unfetched results */
 123         if(S->result) {
 124                 PQclear(S->result);
 125                 S->result = NULL;
 126         }
 127 
 128         S->current_row = 0;
 129 
 130         if (S->cursor_name) {
 131                 char *q = NULL;
 132 
 133                 if (S->is_prepared) {
 134                         spprintf(&q, 0, "CLOSE %s", S->cursor_name);
 135                         S->result = PQexec(H->server, q);
 136                         efree(q);
 137                 }
 138 
 139                 spprintf(&q, 0, "DECLARE %s SCROLL CURSOR WITH HOLD FOR %s", S->cursor_name, stmt->active_query_string);
 140                 S->result = PQexec(H->server, q);
 141                 efree(q);
 142 
 143                 /* check if declare failed */
 144                 status = PQresultStatus(S->result);
 145                 if (status != PGRES_COMMAND_OK && status != PGRES_TUPLES_OK) {
 146                         pdo_pgsql_error_stmt(stmt, status, pdo_pgsql_sqlstate(S->result));
 147                         return 0;
 148                 }
 149 
 150                 /* the cursor was declared correctly */
 151                 S->is_prepared = 1;
 152 
 153                 /* fetch to be able to get the number of tuples later, but don't advance the cursor pointer */
 154                 spprintf(&q, 0, "FETCH FORWARD 0 FROM %s", S->cursor_name);
 155                 S->result = PQexec(H->server, q);
 156                 efree(q);
 157         } else if (S->stmt_name) {
 158                 /* using a prepared statement */
 159 
 160                 if (!S->is_prepared) {
 161 stmt_retry:
 162                         /* we deferred the prepare until now, because we didn't
 163                          * know anything about the parameter types; now we do */
 164                         S->result = PQprepare(H->server, S->stmt_name, S->query,
 165                                                 stmt->bound_params ? zend_hash_num_elements(stmt->bound_params) : 0,
 166                                                 S->param_types);
 167                         status = PQresultStatus(S->result);
 168                         switch (status) {
 169                                 case PGRES_COMMAND_OK:
 170                                 case PGRES_TUPLES_OK:
 171                                         /* it worked */
 172                                         S->is_prepared = 1;
 173                                         PQclear(S->result);
 174                                         break;
 175                                 default: {
 176                                         char *sqlstate = pdo_pgsql_sqlstate(S->result);
 177                                         /* 42P05 means that the prepared statement already existed. this can happen if you use
 178                                          * a connection pooling software line pgpool which doesn't close the db-connection once
 179                                          * php disconnects. if php dies (no chance to run RSHUTDOWN) during execution it has no
 180                                          * chance to DEALLOCATE the prepared statements it has created. so, if we hit a 42P05 we
 181                                          * deallocate it and retry ONCE (thies 2005.12.15)
 182                                          */
 183                                         if (sqlstate && !strcmp(sqlstate, "42P05")) {
 184                                                 char buf[100]; /* stmt_name == "pdo_crsr_%08x" */
 185                                                 PGresult *res;
 186                                                 snprintf(buf, sizeof(buf), "DEALLOCATE %s", S->stmt_name);
 187                                                 res = PQexec(H->server, buf);
 188                                                 if (res) {
 189                                                         PQclear(res);
 190                                                 }
 191                                                 goto stmt_retry;
 192                                         } else {
 193                                                 pdo_pgsql_error_stmt(stmt, status, sqlstate);
 194                                                 return 0;
 195                                         }
 196                                 }
 197                         }
 198                 }
 199                 S->result = PQexecPrepared(H->server, S->stmt_name,
 200                                 stmt->bound_params ?
 201                                         zend_hash_num_elements(stmt->bound_params) :
 202                                         0,
 203                                 (const char**)S->param_values,
 204                                 S->param_lengths,
 205                                 S->param_formats,
 206                                 0);
 207         } else if (stmt->supports_placeholders == PDO_PLACEHOLDER_NAMED) {
 208                 /* execute query with parameters */
 209                 S->result = PQexecParams(H->server, S->query,
 210                                 stmt->bound_params ? zend_hash_num_elements(stmt->bound_params) : 0,
 211                                 S->param_types,
 212                                 (const char**)S->param_values,
 213                                 S->param_lengths,
 214                                 S->param_formats,
 215                                 0);
 216         } else {
 217                 /* execute plain query (with embedded parameters) */
 218                 S->result = PQexec(H->server, stmt->active_query_string);
 219         }
 220         status = PQresultStatus(S->result);
 221 
 222         if (status != PGRES_COMMAND_OK && status != PGRES_TUPLES_OK) {
 223                 pdo_pgsql_error_stmt(stmt, status, pdo_pgsql_sqlstate(S->result));
 224                 return 0;
 225         }
 226 
 227         if (!stmt->executed && (!stmt->column_count || S->cols == NULL)) {
 228                 stmt->column_count = (int) PQnfields(S->result);
 229                 S->cols = ecalloc(stmt->column_count, sizeof(pdo_pgsql_column));
 230         }
 231 
 232         if (status == PGRES_COMMAND_OK) {
 233                 ZEND_ATOL(stmt->row_count, PQcmdTuples(S->result));
 234                 H->pgoid = PQoidValue(S->result);
 235         } else {
 236                 stmt->row_count = (zend_long)PQntuples(S->result);
 237         }
 238 
 239         return 1;
 240 }
 241 
 242 static int pgsql_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *param,
 243                 enum pdo_param_event event_type)
 244 {
 245         pdo_pgsql_stmt *S = (pdo_pgsql_stmt*)stmt->driver_data;
 246 
 247         if (stmt->supports_placeholders == PDO_PLACEHOLDER_NAMED && param->is_param) {
 248                 switch (event_type) {
 249                         case PDO_PARAM_EVT_FREE:
 250                                 if (param->driver_data) {
 251                                         efree(param->driver_data);
 252                                 }
 253                                 break;
 254 
 255                         case PDO_PARAM_EVT_NORMALIZE:
 256                                 /* decode name from $1, $2 into 0, 1 etc. */
 257                                 if (param->name) {
 258                                         if (ZSTR_VAL(param->name)[0] == '$') {
 259                                                 ZEND_ATOL(param->paramno, ZSTR_VAL(param->name) + 1);
 260                                         } else {
 261                                                 /* resolve parameter name to rewritten name */
 262                                                 char *namevar;
 263 
 264                                                 if (stmt->bound_param_map && (namevar = zend_hash_find_ptr(stmt->bound_param_map,
 265                                                                 param->name)) != NULL) {
 266                                                         ZEND_ATOL(param->paramno, namevar + 1);
 267                                                         param->paramno--;
 268                                                 } else {
 269                                                         pdo_raise_impl_error(stmt->dbh, stmt, "HY093", ZSTR_VAL(param->name));
 270                                                         return 0;
 271                                                 }
 272                                         }
 273                                 }
 274                                 break;
 275 
 276                         case PDO_PARAM_EVT_ALLOC:
 277                         case PDO_PARAM_EVT_EXEC_POST:
 278                         case PDO_PARAM_EVT_FETCH_PRE:
 279                         case PDO_PARAM_EVT_FETCH_POST:
 280                                 /* work is handled by EVT_NORMALIZE */
 281                                 return 1;
 282 
 283                         case PDO_PARAM_EVT_EXEC_PRE:
 284                                 if (!stmt->bound_param_map) {
 285                                         return 0;
 286                                 }
 287                                 if (!S->param_values) {
 288                                         S->param_values = ecalloc(
 289                                                         zend_hash_num_elements(stmt->bound_param_map),
 290                                                         sizeof(char*));
 291                                         S->param_lengths = ecalloc(
 292                                                         zend_hash_num_elements(stmt->bound_param_map),
 293                                                         sizeof(int));
 294                                         S->param_formats = ecalloc(
 295                                                         zend_hash_num_elements(stmt->bound_param_map),
 296                                                         sizeof(int));
 297                                         S->param_types = ecalloc(
 298                                                         zend_hash_num_elements(stmt->bound_param_map),
 299                                                         sizeof(Oid));
 300                                 }
 301                                 if (param->paramno >= 0) {
 302                                         zval *parameter;
 303 
 304                                         if (param->paramno >= zend_hash_num_elements(stmt->bound_params)) {
 305                                                 pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "parameter was not defined");
 306                                                 return 0;
 307                                         }
 308 
 309                                         if (Z_ISREF(param->parameter)) {
 310                                                 parameter = Z_REFVAL(param->parameter);
 311                                         } else {
 312                                                 parameter = &param->parameter;
 313                                         }
 314 
 315                                         if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB &&
 316                                                         Z_TYPE_P(parameter) == IS_RESOURCE) {
 317                                                 php_stream *stm;
 318                                                 php_stream_from_zval_no_verify(stm, parameter);
 319                                                 if (stm) {
 320                                                         if (php_stream_is(stm, &pdo_pgsql_lob_stream_ops)) {
 321                                                                 struct pdo_pgsql_lob_self *self = (struct pdo_pgsql_lob_self*)stm->abstract;
 322                                                                 pdo_pgsql_bound_param *P = param->driver_data;
 323 
 324                                                                 if (P == NULL) {
 325                                                                         P = ecalloc(1, sizeof(*P));
 326                                                                         param->driver_data = P;
 327                                                                 }
 328                                                                 P->oid = htonl(self->oid);
 329                                                                 S->param_values[param->paramno] = (char*)&P->oid;
 330                                                                 S->param_lengths[param->paramno] = sizeof(P->oid);
 331                                                                 S->param_formats[param->paramno] = 1;
 332                                                                 S->param_types[param->paramno] = OIDOID;
 333                                                                 return 1;
 334                                                         } else {
 335                                                                 zend_string *str = php_stream_copy_to_mem(stm, PHP_STREAM_COPY_ALL, 0);
 336                                                                 if (str != NULL) {
 337                                                                         //??SEPARATE_ZVAL_IF_NOT_REF(&param->parameter);
 338                                                                         ZVAL_STR(parameter, str);
 339                                                                 } else {
 340                                                                         ZVAL_EMPTY_STRING(parameter);
 341                                                                 }
 342                                                         }
 343                                                 } else {
 344                                                         /* expected a stream resource */
 345                                                         pdo_pgsql_error_stmt(stmt, PGRES_FATAL_ERROR, "HY105");
 346                                                         return 0;
 347                                                 }
 348                                         }
 349 
 350                                         if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_NULL ||
 351                                                         Z_TYPE_P(parameter) == IS_NULL) {
 352                                                 S->param_values[param->paramno] = NULL;
 353                                                 S->param_lengths[param->paramno] = 0;
 354                                         } else if (Z_TYPE_P(parameter) == IS_FALSE || Z_TYPE_P(parameter) == IS_TRUE) {
 355                                                 S->param_values[param->paramno] = Z_TYPE_P(parameter) == IS_TRUE ? "t" : "f";
 356                                                 S->param_lengths[param->paramno] = 1;
 357                                                 S->param_formats[param->paramno] = 0;
 358                                         } else {
 359                                                 //SEPARATE_ZVAL_IF_NOT_REF(&param->parameter);
 360                                                 convert_to_string_ex(parameter);
 361                                                 S->param_values[param->paramno] = Z_STRVAL_P(parameter);
 362                                                 S->param_lengths[param->paramno] = Z_STRLEN_P(parameter);
 363                                                 S->param_formats[param->paramno] = 0;
 364                                         }
 365 
 366                                         if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB) {
 367                                                 S->param_types[param->paramno] = 0;
 368                                                 S->param_formats[param->paramno] = 1;
 369                                         } else {
 370                                                 S->param_types[param->paramno] = 0;
 371                                         }
 372                                 }
 373                                 break;
 374                 }
 375         } else if (param->is_param) {
 376                 /* We need to manually convert to a pg native boolean value */
 377                 if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_BOOL &&
 378                         ((param->param_type & PDO_PARAM_INPUT_OUTPUT) != PDO_PARAM_INPUT_OUTPUT)) {
 379                         const char *s = zend_is_true(&param->parameter) ? "t" : "f";
 380                         param->param_type = PDO_PARAM_STR;
 381                         zval_ptr_dtor(&param->parameter);
 382                         ZVAL_STRINGL(&param->parameter, s, 1);
 383                 }
 384         }
 385         return 1;
 386 }
 387 
 388 static int pgsql_stmt_fetch(pdo_stmt_t *stmt,
 389         enum pdo_fetch_orientation ori, zend_long offset)
 390 {
 391         pdo_pgsql_stmt *S = (pdo_pgsql_stmt*)stmt->driver_data;
 392 
 393         if (S->cursor_name) {
 394                 char *ori_str = NULL;
 395                 char *q = NULL;
 396                 ExecStatusType status;
 397 
 398                 switch (ori) {
 399                         case PDO_FETCH_ORI_NEXT:        spprintf(&ori_str, 0, "NEXT"); break;
 400                         case PDO_FETCH_ORI_PRIOR:       spprintf(&ori_str, 0, "BACKWARD"); break;
 401                         case PDO_FETCH_ORI_FIRST:       spprintf(&ori_str, 0, "FIRST"); break;
 402                         case PDO_FETCH_ORI_LAST:        spprintf(&ori_str, 0, "LAST"); break;
 403                         case PDO_FETCH_ORI_ABS:         spprintf(&ori_str, 0, "ABSOLUTE %pd", offset); break;
 404                         case PDO_FETCH_ORI_REL:         spprintf(&ori_str, 0, "RELATIVE %pd", offset); break;
 405                         default:
 406                                 return 0;
 407                 }
 408 
 409                 spprintf(&q, 0, "FETCH %s FROM %s", ori_str, S->cursor_name);
 410                 efree(ori_str);
 411                 S->result = PQexec(S->H->server, q);
 412                 efree(q);
 413                 status = PQresultStatus(S->result);
 414 
 415                 if (status != PGRES_COMMAND_OK && status != PGRES_TUPLES_OK) {
 416                         pdo_pgsql_error_stmt(stmt, status, pdo_pgsql_sqlstate(S->result));
 417                         return 0;
 418                 }
 419 
 420                 if (PQntuples(S->result)) {
 421                         S->current_row = 1;
 422                         return 1;
 423                 } else {
 424                         return 0;
 425                 }
 426         } else {
 427                 if (S->current_row < stmt->row_count) {
 428                         S->current_row++;
 429                         return 1;
 430                 } else {
 431                         return 0;
 432                 }
 433         }
 434 }
 435 
 436 static int pgsql_stmt_describe(pdo_stmt_t *stmt, int colno)
 437 {
 438         pdo_pgsql_stmt *S = (pdo_pgsql_stmt*)stmt->driver_data;
 439         struct pdo_column_data *cols = stmt->columns;
 440         struct pdo_bound_param_data *param;
 441         char *str;
 442 
 443         if (!S->result) {
 444                 return 0;
 445         }
 446 
 447         str = PQfname(S->result, colno);
 448         cols[colno].name = zend_string_init(str, strlen(str), 0);
 449         cols[colno].maxlen = PQfsize(S->result, colno);
 450         cols[colno].precision = PQfmod(S->result, colno);
 451         S->cols[colno].pgsql_type = PQftype(S->result, colno);
 452 
 453         switch (S->cols[colno].pgsql_type) {
 454 
 455                 case BOOLOID:
 456                         cols[colno].param_type = PDO_PARAM_BOOL;
 457                         break;
 458 
 459                 case OIDOID:
 460                         /* did the user bind the column as a LOB ? */
 461                         if (stmt->bound_columns && (
 462                                         (param = zend_hash_index_find_ptr(stmt->bound_columns, colno)) != NULL ||
 463                                         (param = zend_hash_find_ptr(stmt->bound_columns, cols[colno].name)) != NULL)) {
 464 
 465                                 if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB) {
 466                                         cols[colno].param_type = PDO_PARAM_LOB;
 467                                         break;
 468                                 }
 469                         }
 470                         cols[colno].param_type = PDO_PARAM_INT;
 471                         break;
 472 
 473                 case INT2OID:
 474                 case INT4OID:
 475                         cols[colno].param_type = PDO_PARAM_INT;
 476                         break;
 477 
 478                 case INT8OID:
 479                         if (sizeof(zend_long)>=8) {
 480                                 cols[colno].param_type = PDO_PARAM_INT;
 481                         } else {
 482                                 cols[colno].param_type = PDO_PARAM_STR;
 483                         }
 484                         break;
 485 
 486                 case BYTEAOID:
 487                         cols[colno].param_type = PDO_PARAM_LOB;
 488                         break;
 489 
 490                 default:
 491                         cols[colno].param_type = PDO_PARAM_STR;
 492         }
 493 
 494         return 1;
 495 }
 496 
 497 static int pgsql_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, zend_ulong *len, int *caller_frees )
 498 {
 499         pdo_pgsql_stmt *S = (pdo_pgsql_stmt*)stmt->driver_data;
 500         struct pdo_column_data *cols = stmt->columns;
 501         size_t tmp_len;
 502 
 503         if (!S->result) {
 504                 return 0;
 505         }
 506 
 507         /* We have already increased count by 1 in pgsql_stmt_fetch() */
 508         if (PQgetisnull(S->result, S->current_row - 1, colno)) { /* Check if we got NULL */
 509                 *ptr = NULL;
 510                 *len = 0;
 511         } else {
 512                 *ptr = PQgetvalue(S->result, S->current_row - 1, colno);
 513                 *len = PQgetlength(S->result, S->current_row - 1, colno);
 514 
 515                 switch (cols[colno].param_type) {
 516 
 517                         case PDO_PARAM_INT:
 518                                 ZEND_ATOL(S->cols[colno].intval, *ptr);
 519                                 *ptr = (char *) &(S->cols[colno].intval);
 520                                 *len = sizeof(zend_long);
 521                                 break;
 522 
 523                         case PDO_PARAM_BOOL:
 524                                 S->cols[colno].boolval = **ptr == 't' ? 1: 0;
 525                                 *ptr = (char *) &(S->cols[colno].boolval);
 526                                 *len = sizeof(zend_bool);
 527                                 break;
 528 
 529                         case PDO_PARAM_LOB:
 530                                 if (S->cols[colno].pgsql_type == OIDOID) {
 531                                         /* ooo, a real large object */
 532                                         char *end_ptr;
 533                                         Oid oid = (Oid)strtoul(*ptr, &end_ptr, 10);
 534                                         int loid = lo_open(S->H->server, oid, INV_READ);
 535                                         if (loid >= 0) {
 536                                                 *ptr = (char*)pdo_pgsql_create_lob_stream(&stmt->database_object_handle, loid, oid);
 537                                                 *len = 0;
 538                                                 return *ptr ? 1 : 0;
 539                                         }
 540                                         *ptr = NULL;
 541                                         *len = 0;
 542                                         return 0;
 543                                 } else {
 544                                         char *tmp_ptr = (char *)PQunescapeBytea((unsigned char *)*ptr, &tmp_len);
 545                                         if (!tmp_ptr) {
 546                                                 /* PQunescapeBytea returned an error */
 547                                                 *len = 0;
 548                                                 return 0;
 549                                         }
 550                                         if (!tmp_len) {
 551                                                 /* Empty string, return as empty stream */
 552                                                 *ptr = (char *)php_stream_memory_open(TEMP_STREAM_READONLY, "", 0);
 553                                                 PQfreemem(tmp_ptr);
 554                                                 *len = 0;
 555                                         } else {
 556                                                 *ptr = estrndup(tmp_ptr, tmp_len);
 557                                                 PQfreemem(tmp_ptr);
 558                                                 *len = tmp_len;
 559                                                 *caller_frees = 1;
 560                                         }
 561                                 }
 562                                 break;
 563                         case PDO_PARAM_NULL:
 564                         case PDO_PARAM_STR:
 565                         case PDO_PARAM_STMT:
 566                         case PDO_PARAM_INPUT_OUTPUT:
 567                         case PDO_PARAM_ZVAL:
 568                         default:
 569                                 break;
 570                 }
 571         }
 572 
 573         return 1;
 574 }
 575 
 576 static int pgsql_stmt_get_column_meta(pdo_stmt_t *stmt, zend_long colno, zval *return_value)
 577 {
 578         pdo_pgsql_stmt *S = (pdo_pgsql_stmt*)stmt->driver_data;
 579         PGresult *res;
 580         char *q=NULL;
 581         ExecStatusType status;
 582 
 583         if (!S->result) {
 584                 return FAILURE;
 585         }
 586 
 587         if (colno >= stmt->column_count) {
 588                 return FAILURE;
 589         }
 590 
 591         array_init(return_value);
 592         add_assoc_long(return_value, "pgsql:oid", S->cols[colno].pgsql_type);
 593 
 594         /* Fetch metadata from Postgres system catalogue */
 595         spprintf(&q, 0, "SELECT TYPNAME FROM PG_TYPE WHERE OID=%u", S->cols[colno].pgsql_type);
 596         res = PQexec(S->H->server, q);
 597         efree(q);
 598 
 599         status = PQresultStatus(res);
 600 
 601         if (status != PGRES_TUPLES_OK) {
 602                 /* Failed to get system catalogue, but return success
 603                  * with the data we have collected so far
 604                  */
 605                 goto done;
 606         }
 607 
 608         /* We want exactly one row returned */
 609         if (1 != PQntuples(res)) {
 610                 goto done;
 611         }
 612 
 613         add_assoc_string(return_value, "native_type", PQgetvalue(res, 0, 0));
 614 done:
 615         PQclear(res);
 616         return 1;
 617 }
 618 
 619 static int pdo_pgsql_stmt_cursor_closer(pdo_stmt_t *stmt)
 620 {
 621         pdo_pgsql_stmt *S = (pdo_pgsql_stmt*)stmt->driver_data;
 622 
 623         if (S->cols != NULL){
 624                 efree(S->cols);
 625                 S->cols = NULL;
 626         }
 627         return 1;
 628 }
 629 
 630 struct pdo_stmt_methods pgsql_stmt_methods = {
 631         pgsql_stmt_dtor,
 632         pgsql_stmt_execute,
 633         pgsql_stmt_fetch,
 634         pgsql_stmt_describe,
 635         pgsql_stmt_get_col,
 636         pgsql_stmt_param_hook,
 637         NULL, /* set_attr */
 638         NULL, /* get_attr */
 639         pgsql_stmt_get_column_meta,
 640         NULL,  /* next_rowset */
 641         pdo_pgsql_stmt_cursor_closer
 642 };
 643 
 644 /*
 645  * Local variables:
 646  * tab-width: 4
 647  * c-basic-offset: 4
 648  * End:
 649  * vim600: noet sw=4 ts=4 fdm=marker
 650  * vim<600: noet sw=4 ts=4
 651  */

/* [<][>][^][v][top][bottom][index][help] */