I attached the patch as a single file. There are currently no tests written for the new methods.
I'll provide them if needed to integrate the patch in the pdo_pgsql driver. Denis ----- Messaggio originale ----- > Da: "Denis Gasparin" <denis.gaspa...@edistar.com> > A: "Ilia Alshanetsky" <i...@prohost.org> > Cc: internals@lists.php.net > Inviato: Lunedì, 24 maggio 2010 21:45:30 > Oggetto: Re: [PHP-DEV] [PATCH] New PDO methods for PostgreSQL driver > I'll provide the patches in a single file as soon as possible. > > Actually all the methods are wrappers against the native PostgreSQL > commands (connection status, copy to/from). > > I needed to develop them as methods because it is not possible to get > the same results with a sql statement (in particular for connection > status). > > It was not possible also for COPY TO/FROM because of the way > PostgreSQL handle them ( special functions were developed also for the > old pgsql driver). > > We are currently using them in production and we needed them in order > to avoid additional connections to database (one with the old driver > and one with PDO). > > Denis > > > ----- Messaggio originale ----- > > Da: "Ilia Alshanetsky" <i...@prohost.org> > > A: "Denis Gasparin" <denis.gaspa...@edistar.com> > > Cc: internals@lists.php.net > > Inviato: Lunedì, 24 maggio 2010 19:54:46 > > Oggetto: Re: [PHP-DEV] [PATCH] New PDO methods for PostgreSQL driver > > > Denis, > > > > > > Could you merge the patches into a single for easier code review. > > Also, the copy to/from file seems like it would just be a wrapper > > against the native COPY PostgreSQL command, is there really a need > > to provide a method for it? > > > > > > On Mon, May 24, 2010 at 4:57 AM, Denis Gasparin < > > denis.gaspa...@edistar.com > wrote: > > > > > > Hi. > > > > I developed some patches for PDO/Postgresql driver in order to add > > some useful methods that were available in the original pgsql > > driver. > > > > The attached patches apply on 5.3.2 and svn 5.3.x. > > If needed, i have patches also for 5.2.x. > > > > Please comment and tell me improvements or tips. > > > > Thank you in advance, > > > > Denis Gasparin > > > > Documentation of the added methods follows: > > > > pgsqlIsInTransaction() > > > > It uses the native Postgresql functions to check transaction > > status.. > > It returns one of the following status codes: > > * PDO::PGSQL_TRANSACTION_IDLE: connection in idle status > > * PDO::PGSQL_TRANSACTION_ACTIVE: connection is executing a command > > * PDO::PGSQL_TRANSACTION_INTRANS: connection is idle in a valid > > transaction block > > * PDO::PGSQL_TRANSACTION_INERROR: connection is idle, in a failed > > transaction block > > * PDO::PGSQL_TRANSACTION_UNKNOWN: connection is in a bad status > > > > > > > > pgsqlCopyFromArray($table,Array $data,$delimiter,$null, Array > > $fields) > > > > It uses the native Postgresql copy construct to append $data to > > $table. It returns boolean. > > Parameters: * (mandatory) $table: table to append data to > > * (mandatory) $data: Array of rows with data in table field order > > (or as specified in the $fields array). Fields must be separated by > > $delimiter or by > > postgresql standard \t) > > * $delimiter: alternative delimiter to use in place of the standard > > postgres delimiter ("\t") > > * $null: alternative string to use as null value. Default is "\N" > > * $fields: array with table fields that are specified in $data > > parameter > > > > > > > > pgsqlCopyFromFile($table,$filename,$delimiter,$null,$fields) > > > > It uses the native Postgresql copy construct to append $filename > > contents to $table. > > It returns boolean. > > Parameters: * (mandatory) $table: table to append data to. > > * (mandatory) $filename: file with contents to append to $table. See > > Postgresql documentation for the format. > > * $delimiter: alternative delimiter to use in place of the standard > > postgres delimiter ("\t") > > * $null: alternative string to use as null value. Default is "\N" > > * $fields: array with table fields that are specified in $filename > > file > > > > pgsqlCopyToArray($table,$delimiter,$null,$fields) > > > > It uses the native Postgresql copy construct to retrieve $table > > contents and store them to an array. > > It returns an array of rows or false in case of problems. > > The format of the rows into the array is indicated in the > > $delimiter, $null and $fields parameters. > > Parameters: * (mandatory) $table: table to retrieve data from. > > * $delimiter: alternative delimiter to use in place of the standard > > postgres delimiter ("\t") > > * $null: alternative string to use as null value. Default is "\N" > > * $fields: array with table fields to include in the row of the > > array. > > > > > > pgsqlCopyToFile($table,$filename,$delimiter,$null,$fields) > > > > > > It uses the native Postgresql copy construct to retrieve $table > > contents and store them into a file. > > It returns boolean. > > The format of the rows stored into the file is indicated in the > > $delimiter, $null and $fields parameters. > > Parameters: * (mandatory) $table: table to retrieve data from. > > * (mandatory) $filename: file where to store the contents of the > > table * $delimiter: alternative delimiter to use in place of the > > standard postgres delimiter ("\t") > > * $null: alternative string to use as null value. Default is "\N" > > * $fields: array with table fields to include in the row of the > > array. > > > > -- PHP Internals - PHP Runtime Development Mailing List > > To unsubscribe, visit: http://www.php.net/unsub.php > > -- PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: http://www.php.net/unsub.php
diff -u php-src-5.3/ext/pdo_pgsql/pdo_pgsql.c php-src-5.3.patched/ext/pdo_pgsql/pdo_pgsql.c --- php-src-5.3/ext/pdo_pgsql/pdo_pgsql.c 2010-05-24 22:22:27.833522150 +0200 +++ php-src-5.3.patched/ext/pdo_pgsql/pdo_pgsql.c 2010-05-24 10:20:30.674038241 +0200 @@ -29,6 +29,7 @@ #include "pdo/php_pdo_driver.h" #include "php_pdo_pgsql.h" #include "php_pdo_pgsql_int.h" +#include "ext/standard/php_smart_str.h" #ifdef HAVE_PG_CONFIG_H #undef PACKAGE_BUGREPORT @@ -79,6 +80,16 @@ ZEND_GET_MODULE(pdo_pgsql) #endif + +static void php_pdo_pgsql_list_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC) { + char * str = (char *)rsrc->ptr; + pefree(str,1); +} + + +static int le_pdo_pgsql_descriptor; + + /* true global environment */ /* {{{ PHP_MINIT_FUNCTION @@ -86,7 +97,13 @@ PHP_MINIT_FUNCTION(pdo_pgsql) { REGISTER_PDO_CLASS_CONST_LONG("PGSQL_ATTR_DISABLE_NATIVE_PREPARED_STATEMENT", PDO_PGSQL_ATTR_DISABLE_NATIVE_PREPARED_STATEMENT); + le_pdo_pgsql_descriptor = zend_register_list_destructors_ex(NULL, php_pdo_pgsql_list_dtor, PHP_PDO_PGSQL_RES_NAME, module_number); php_pdo_register_driver(&pdo_pgsql_driver); + REGISTER_PDO_CLASS_CONST_LONG("PGSQL_TRANSACTION_IDLE", (long)PGSQL_TRANSACTION_IDLE); + REGISTER_PDO_CLASS_CONST_LONG("PGSQL_TRANSACTION_ACTIVE", (long)PGSQL_TRANSACTION_ACTIVE); + REGISTER_PDO_CLASS_CONST_LONG("PGSQL_TRANSACTION_INTRANS", (long)PGSQL_TRANSACTION_INTRANS); + REGISTER_PDO_CLASS_CONST_LONG("PGSQL_TRANSACTION_INERROR", (long)PGSQL_TRANSACTION_INERROR); + REGISTER_PDO_CLASS_CONST_LONG("PGSQL_TRANSACTION_UNKNOWN", (long)PGSQL_TRANSACTION_UNKNOWN); return SUCCESS; } /* }}} */ @@ -134,6 +151,91 @@ } /* }}} */ + +int _pgsql_stmt_get_column_meta(pdo_stmt_t *stmt, long colno, zval *return_value TSRMLS_DC) +{ + pdo_pgsql_stmt *S = (pdo_pgsql_stmt*)stmt->driver_data; + PGresult *result; + char *q=NULL; + ExecStatusType status; + smart_str str = {0}; + zend_rsrc_list_entry *field_type; + char *ret=NULL; + zval *resource_val=NULL; + + HashTable *list = &EG(persistent_list); + + if (!S->result) { + return FAILURE; + } + + if (colno >= stmt->column_count) { + return FAILURE; + } + + array_init(return_value); + add_assoc_long(return_value, "pgsql:oid", S->cols[colno].pgsql_type); + + /* try to lookup the type in the resource list */ + smart_str_appends(&str, "pgsql_oid_"); + smart_str_append_unsigned(&str, S->cols[colno].pgsql_type); + smart_str_0(&str); + + if (zend_hash_find(list,str.c,str.len+1,(void **) &field_type)==SUCCESS) { + ret = estrdup((char *)field_type->ptr); + } else { /* hash all oid's */ + int i,num_rows; + int oid_offset,name_offset; + char *tmp_oid, *end_ptr, *tmp_name,*type_name; + zend_rsrc_list_entry new_oid_entry; + + if ((result = PQexec(S->H->server,"select oid,typname from pg_type")) == NULL || PQresultStatus(result) != PGRES_TUPLES_OK) { + if (result) { + PQclear(result); + } + smart_str_free(&str); + return 0; + } + num_rows = PQntuples(result); + oid_offset = PQfnumber(result,"oid"); + name_offset = PQfnumber(result,"typname"); + + for (i=0; i<num_rows; i++) { + if ((tmp_oid = PQgetvalue(result,i,oid_offset))==NULL) { + continue; + } + + str.len = 0; + smart_str_appends(&str, "pgsql_oid_"); + smart_str_appends(&str, tmp_oid); + smart_str_0(&str); + + if ((tmp_name = PQgetvalue(result,i,name_offset))==NULL) { + continue; + } + type_name = pemalloc(strlen(tmp_name)+1,1); + memcpy(type_name,tmp_name,strlen(tmp_name)+1); + //type_name = pestrdup(tmp_name); + ZEND_REGISTER_RESOURCE(resource_val, type_name,le_pdo_pgsql_descriptor); + + new_oid_entry.type = le_pdo_pgsql_descriptor; + new_oid_entry.ptr = type_name; + zend_hash_update(list,str.c,str.len+1,(void *) &new_oid_entry, sizeof(zend_rsrc_list_entry), NULL); + if (!ret && strtoul(tmp_oid, &end_ptr, 10)==S->cols[colno].pgsql_type) { + ret = estrdup(tmp_name); + } + } + PQclear(result); + } + + smart_str_free(&str); + + add_assoc_string(return_value, "native_type", ret, 1); + return 1; + +} + + /* * Local variables: * tab-width: 4 diff -u php-src-5.3/ext/pdo_pgsql/pgsql_driver.c php-src-5.3.patched/ext/pdo_pgsql/pgsql_driver.c --- php-src-5.3/ext/pdo_pgsql/pgsql_driver.c 2010-05-24 22:22:27.833522150 +0200 +++ php-src-5.3.patched/ext/pdo_pgsql/pgsql_driver.c 2010-05-24 10:20:27.323869345 +0200 @@ -29,6 +29,7 @@ #include "ext/standard/info.h" #include "pdo/php_pdo.h" #include "pdo/php_pdo_driver.h" +#include "ext/standard/file.h" #undef PACKAGE_BUGREPORT #undef PACKAGE_NAME @@ -496,6 +497,510 @@ return pdo_pgsql_transaction_cmd("ROLLBACK", dbh TSRMLS_CC); } +/* {{{ proto string PDO::pgsqlIsInTransaction() + Returns the status of a transaction according to PDO::PGSQL_TRANSACTION_* constants */ +static PHP_METHOD(PDO, pgsqlIsInTransaction) +{ + pdo_dbh_t *dbh; + pdo_pgsql_db_handle *H; + + dbh = zend_object_store_get_object(getThis() TSRMLS_CC); + PDO_CONSTRUCT_CHECK; + + H = (pdo_pgsql_db_handle *)dbh->driver_data; + + RETURN_LONG(PQtransactionStatus(H->server)); +} +/* }}} */ + +/* {{{ proto string PDO::pgsqlCopyFromArray(string $table_name , array $rows [, string $delimiter [, string $null_as ] [, string $fields]) + Returns true if the copy worked fine or false if error */ +static PHP_METHOD(PDO, pgsqlCopyFromArray) +{ + pdo_dbh_t *dbh; + pdo_pgsql_db_handle *H; + + zval *pg_rows; + zval **tmp; + char *table_name, *pg_delim = NULL, *pg_null_as = NULL, *pg_fields = NULL; + int table_name_len, pg_delim_len, pg_null_as_len, pg_fields_len; + char *query, *fields; + HashPosition pos; + int id = -1; + PGresult *pgsql_result; + ExecStatusType status; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s/a|sss", + &table_name, &table_name_len, &pg_rows, + &pg_delim, &pg_delim_len, &pg_null_as, &pg_null_as_len, &pg_fields, &pg_fields_len) == FAILURE) { + return; + } + + if (!pg_delim) { + pg_delim = "\t"; + } + if (pg_null_as_len<=0) { + pg_null_as = safe_estrdup("\\\\N"); + } + + if(pg_fields_len>0) { + spprintf(&query, 0, "COPY %s (%s) FROM STDIN DELIMITERS E'%c' WITH NULL AS E'%s'", table_name, pg_fields, *pg_delim, pg_null_as); + } + else { + spprintf(&query, 0, "COPY %s FROM STDIN DELIMITERS E'%c' WITH NULL AS E'%s'", table_name, *pg_delim, pg_null_as); + } + + // Obtain db Handler + dbh = zend_object_store_get_object(getThis() TSRMLS_CC); + PDO_CONSTRUCT_CHECK; + + H = (pdo_pgsql_db_handle *)dbh->driver_data; + // H->server is the db handle for libPQ + + + while ((pgsql_result = PQgetResult(H->server))) { + PQclear(pgsql_result); + } + pgsql_result = PQexec(H->server, query); + + if (pg_null_as_len<=0) { + efree(pg_null_as); + } + efree(query); + + if (pgsql_result) { + status = PQresultStatus(pgsql_result); + } else { + status = (ExecStatusType) PQstatus(H->server); + } + + switch (status) { + case PGRES_COPY_IN: + if (pgsql_result) { + int command_failed = 0; + PQclear(pgsql_result); + zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(pg_rows), &pos); + while (zend_hash_get_current_data_ex(Z_ARRVAL_P(pg_rows), (void **) &tmp, &pos) == SUCCESS) { + convert_to_string_ex(tmp); + query = (char *)emalloc(Z_STRLEN_PP(tmp) + 2); + strlcpy(query, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp) + 2); + if(Z_STRLEN_PP(tmp) > 0 && *(query + Z_STRLEN_PP(tmp) - 1) != '\n') { + strlcat(query, "\n", Z_STRLEN_PP(tmp) + 2); + } + if (PQputCopyData(H->server, query, strlen(query)) != 1) { + efree(query); + pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "copy failed"); + RETURN_FALSE; + } + efree(query); + zend_hash_move_forward_ex(Z_ARRVAL_P(pg_rows), &pos); + } + if (PQputCopyEnd(H->server, NULL) != 1) { + pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "putcopyend failed"); + RETURN_FALSE; + } + while ((pgsql_result = PQgetResult(H->server))) { + if (PGRES_COMMAND_OK != PQresultStatus(pgsql_result)) { + pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Copy command failed"); + command_failed = 1; + } + PQclear(pgsql_result); + } + if (command_failed) { + RETURN_FALSE; + } + } else { + PQclear(pgsql_result); + RETURN_FALSE; + } + RETURN_TRUE; + break; + default: + PQclear(pgsql_result); + pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Copy command failed"); + RETURN_FALSE; + break; + } +} +/* }}} */ + +/* {{{ proto string PDO::pgsqlCopyFromFile(string $table_name , string $filename [, string $delimiter [, string $null_as ] [, string $fields]) + Returns true if the copy worked fine or false if error */ +static PHP_METHOD(PDO, pgsqlCopyFromFile) +{ + pdo_dbh_t *dbh; + pdo_pgsql_db_handle *H; + + char *table_name, *filename, *pg_delim = NULL, *pg_null_as = NULL, *pg_fields = NULL; + int table_name_len, filename_len, pg_delim_len, pg_null_as_len, pg_fields_len; + char *query, *fields; + PGresult *pgsql_result; + ExecStatusType status; + zval *zcontext = NULL; + + php_stream_context *context = NULL; + + + size_t line_len = 0; + php_stream *stream; + char *buf = NULL; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|sss", + &table_name, &table_name_len, &filename, &filename_len, + &pg_delim, &pg_delim_len, &pg_null_as, &pg_null_as_len, &pg_fields, &pg_fields_len) == FAILURE) { + return; + } + + if (!pg_delim) { + pg_delim = "\t"; + } + if (pg_null_as_len<=0) { + pg_null_as = safe_estrdup("\\\\N"); + } + + if(pg_fields_len>0) { + spprintf(&query, 0, "COPY %s (%s) FROM STDIN DELIMITERS E'%c' WITH NULL AS E'%s'", table_name, pg_fields, *pg_delim, pg_null_as); + } + else { + spprintf(&query, 0, "COPY %s FROM STDIN DELIMITERS E'%c' WITH NULL AS E'%s'", table_name, *pg_delim, pg_null_as); + } + + // Obtain db Handler + dbh = zend_object_store_get_object(getThis() TSRMLS_CC); + PDO_CONSTRUCT_CHECK; + + H = (pdo_pgsql_db_handle *)dbh->driver_data; + // H->server is the db handle for libPQ + + + // Check filename + context = php_stream_context_from_zval(zcontext, 0); + + stream = php_stream_open_wrapper_ex(filename, "rb", ENFORCE_SAFE_MODE | REPORT_ERRORS, NULL, context); + if (!stream) { + pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Unable to open the file"); + RETURN_FALSE; + } + + + + while ((pgsql_result = PQgetResult(H->server))) { + PQclear(pgsql_result); + } + pgsql_result = PQexec(H->server, query); + + if (pg_null_as_len<=0) { + efree(pg_null_as); + } + efree(query); + + if (pgsql_result) { + status = PQresultStatus(pgsql_result); + } else { + status = (ExecStatusType) PQstatus(H->server); + } + + switch (status) { + case PGRES_COPY_IN: + if (pgsql_result) { + int command_failed = 0; + PQclear(pgsql_result); + buf = php_stream_get_line(stream, NULL, 0, &line_len); + while(buf != NULL) { + if (PQputCopyData(H->server, buf, strlen(buf)) != 1) { + efree(buf); + pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "copy failed"); + php_stream_close(stream); + RETURN_FALSE; + } + efree(buf); + buf = php_stream_get_line(stream, NULL, 0, &line_len); + } + + efree(buf); + + php_stream_close(stream); + + if (PQputCopyEnd(H->server, NULL) != 1) { + pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "putcopyend failed"); + RETURN_FALSE; + } + while ((pgsql_result = PQgetResult(H->server))) { + if (PGRES_COMMAND_OK != PQresultStatus(pgsql_result)) { + pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Copy command failed"); + command_failed = 1; + } + PQclear(pgsql_result); + } + if (command_failed) { + RETURN_FALSE; + } + } else { + PQclear(pgsql_result); + RETURN_FALSE; + } + RETURN_TRUE; + break; + default: + PQclear(pgsql_result); + pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Copy command failed"); + php_stream_close(stream); + RETURN_FALSE; + break; + } +} +/* }}} */ + + +/* {{{ proto string PDO::pgsqlCopyToFile(string $table_name , $filename, [string $delimiter [, string $null_as [, string $fields]]]) + Returns true if the copy worked fine or false if error */ +static PHP_METHOD(PDO, pgsqlCopyToFile) +{ + pdo_dbh_t *dbh; + pdo_pgsql_db_handle *H; + + char *table_name, *pg_delim = NULL, *pg_null_as = NULL, *pg_fields = NULL, *filename = NULL; + int table_name_len, pg_delim_len, pg_null_as_len, pg_fields_len, filename_len; + char *query; + int id = -1; + + PGresult *pgsql_result; + ExecStatusType status; + int copydone = 0; + char *csv = (char *)NULL; + int ret, bytes_written; + + zval *zcontext = NULL; + php_stream *stream; + + php_stream_context *context = NULL; + + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|sss", + &table_name, &table_name_len, &filename, &filename_len, + &pg_delim, &pg_delim_len, &pg_null_as, &pg_null_as_len, &pg_fields, &pg_fields_len) == FAILURE) { + return; + } + + + if (!pg_delim) { + pg_delim = "\t"; + } + + if (pg_null_as_len <= 0) { + pg_null_as = safe_estrdup("\\\\N"); + } + + if(pg_fields_len>0) { + spprintf(&query, 0, "COPY %s (%s) TO STDOUT DELIMITERS '%c' WITH NULL AS '%s'", table_name, pg_fields, *pg_delim, pg_null_as); + } + else { + spprintf(&query, 0, "COPY %s TO STDOUT DELIMITERS '%c' WITH NULL AS '%s'", table_name, *pg_delim, pg_null_as); + } + + // Obtain db Handler + dbh = zend_object_store_get_object(getThis() TSRMLS_CC); + PDO_CONSTRUCT_CHECK; + + H = (pdo_pgsql_db_handle *)dbh->driver_data; + // H->server is the db handle for libPQ + + // Check and open filename for writing + context = php_stream_context_from_zval(zcontext, 0); + + stream = php_stream_open_wrapper_ex(filename, "wb", ENFORCE_SAFE_MODE | REPORT_ERRORS, NULL, context); + if (!stream) { + pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Unable to open the file for writing"); + RETURN_FALSE; + } + + + while ((pgsql_result = PQgetResult(H->server))) { + PQclear(pgsql_result); + } + pgsql_result = PQexec(H->server, query); + + + + if (pg_null_as_len <= 0) { + efree(pg_null_as); + } + + efree(query); + + if (pgsql_result) { + status = PQresultStatus(pgsql_result); + } else { + status = (ExecStatusType) PQstatus(H->server); + } + + + switch (status) { + case PGRES_COPY_OUT: + if (pgsql_result) { + PQclear(pgsql_result); + array_init(return_value); + + while (!copydone) + { + ret = PQgetCopyData(H->server, &csv, 0); + switch (ret) { + case -1: + copydone = 1; + break; + case 0: + case -2: + pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Copy command failed: getline failed"); + php_stream_close(stream); + RETURN_FALSE; + break; + default: + bytes_written = php_stream_write(stream, csv, ret); + if(bytes_written != ret) { + pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Unable to write to file"); + PQfreemem(csv); + php_stream_close(stream); + RETURN_FALSE; + } + PQfreemem(csv); + break; + } + } + php_stream_close(stream); + + while ((pgsql_result = PQgetResult(H->server))) { + PQclear(pgsql_result); + } + RETURN_TRUE; + } else { + php_stream_close(stream); + PQclear(pgsql_result); + RETURN_FALSE; + } + break; + default: + PQclear(pgsql_result); + php_stream_close(stream); + pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Copy command failed"); + RETURN_FALSE; + break; + } +} +/* }}} */ + + + +/* {{{ proto string PDO::pgsqlCopyToArray(string $table_name , [string $delimiter [, string $null_as [, string $fields]]]) + Returns true if the copy worked fine or false if error */ +static PHP_METHOD(PDO, pgsqlCopyToArray) +{ + pdo_dbh_t *dbh; + pdo_pgsql_db_handle *H; + + char *table_name, *pg_delim = NULL, *pg_null_as = NULL, *pg_fields = NULL; + int table_name_len, pg_delim_len, pg_null_as_len, pg_fields_len; + char *query; + int id = -1; + + PGresult *pgsql_result; + ExecStatusType status; + int copydone = 0; + char *csv = (char *)NULL; + int ret; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|sss", + &table_name, &table_name_len, + &pg_delim, &pg_delim_len, &pg_null_as, &pg_null_as_len, &pg_fields, &pg_fields_len) == FAILURE) { + return; + } + + + if (!pg_delim) { + pg_delim = "\t"; + } + + if (pg_null_as_len <= 0) { + pg_null_as = safe_estrdup("\\\\N"); + } + + if(pg_fields_len>0) { + spprintf(&query, 0, "COPY %s (%s) TO STDOUT DELIMITERS '%c' WITH NULL AS '%s'", table_name, pg_fields, *pg_delim, pg_null_as); + } + else { + spprintf(&query, 0, "COPY %s TO STDOUT DELIMITERS '%c' WITH NULL AS '%s'", table_name, *pg_delim, pg_null_as); + } + + // Obtain db Handler + dbh = zend_object_store_get_object(getThis() TSRMLS_CC); + PDO_CONSTRUCT_CHECK; + + H = (pdo_pgsql_db_handle *)dbh->driver_data; + // H->server is the db handle for libPQ + + + + while ((pgsql_result = PQgetResult(H->server))) { + PQclear(pgsql_result); + } + pgsql_result = PQexec(H->server, query); + + + + if (pg_null_as_len <= 0) { + efree(pg_null_as); + } + + efree(query); + + if (pgsql_result) { + status = PQresultStatus(pgsql_result); + } else { + status = (ExecStatusType) PQstatus(H->server); + } + + + switch (status) { + case PGRES_COPY_OUT: + if (pgsql_result) { + PQclear(pgsql_result); + array_init(return_value); + + while (!copydone) + { + ret = PQgetCopyData(H->server, &csv, 0); + switch (ret) { + case -1: + copydone = 1; + break; + case 0: + case -2: + pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Copy command failed: getline failed"); + RETURN_FALSE; + break; + default: + add_next_index_string(return_value, csv, 1); + PQfreemem(csv); + break; + } + } + while ((pgsql_result = PQgetResult(H->server))) { + PQclear(pgsql_result); + } + } else { + PQclear(pgsql_result); + RETURN_FALSE; + } + break; + default: + PQclear(pgsql_result); + pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Copy command failed"); + RETURN_FALSE; + break; + } +} +/* }}} */ + + /* {{{ proto string PDO::pgsqlLOBCreate() Creates a new large object, returning its identifier. Must be called inside a transaction. */ static PHP_METHOD(PDO, pgsqlLOBCreate) @@ -608,6 +1113,11 @@ PHP_ME(PDO, pgsqlLOBCreate, NULL, ZEND_ACC_PUBLIC) PHP_ME(PDO, pgsqlLOBOpen, NULL, ZEND_ACC_PUBLIC) PHP_ME(PDO, pgsqlLOBUnlink, NULL, ZEND_ACC_PUBLIC) + PHP_ME(PDO, pgsqlIsInTransaction, NULL, ZEND_ACC_PUBLIC) + PHP_ME(PDO, pgsqlCopyFromArray, NULL, ZEND_ACC_PUBLIC) + PHP_ME(PDO, pgsqlCopyFromFile, NULL, ZEND_ACC_PUBLIC) + PHP_ME(PDO, pgsqlCopyToArray, NULL, ZEND_ACC_PUBLIC) + PHP_ME(PDO, pgsqlCopyToFile, NULL, ZEND_ACC_PUBLIC) {NULL, NULL, NULL} }; diff -u php-src-5.3/ext/pdo_pgsql/pgsql_statement.c php-src-5.3.patched/ext/pdo_pgsql/pgsql_statement.c --- php-src-5.3/ext/pdo_pgsql/pgsql_statement.c 2010-05-24 22:22:27.843522641 +0200 +++ php-src-5.3.patched/ext/pdo_pgsql/pgsql_statement.c 2010-05-24 10:20:41.464582224 +0200 @@ -556,47 +556,9 @@ return 1; } -static int pgsql_stmt_get_column_meta(pdo_stmt_t *stmt, long colno, zval *return_value TSRMLS_DC) -{ - pdo_pgsql_stmt *S = (pdo_pgsql_stmt*)stmt->driver_data; - PGresult *res; - char *q=NULL; - ExecStatusType status; - - if (!S->result) { - return FAILURE; - } - - if (colno >= stmt->column_count) { - return FAILURE; - } - - 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=%d", 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; - } - /* We want exactly one row returned */ - if (1 != PQntuples(res)) { - goto done; - } - - add_assoc_string(return_value, "native_type", PQgetvalue(res, 0, 0), 1); -done: - PQclear(res); - return 1; +static int pgsql_stmt_get_column_meta(pdo_stmt_t *stmt, long colno, zval *return_value TSRMLS_DC) { + return _pgsql_stmt_get_column_meta(stmt, colno, return_value ); } static int pdo_pgsql_stmt_cursor_closer(pdo_stmt_t *stmt TSRMLS_DC) diff -u php-src-5.3/ext/pdo_pgsql/php_pdo_pgsql.h php-src-5.3.patched/ext/pdo_pgsql/php_pdo_pgsql.h --- php-src-5.3/ext/pdo_pgsql/php_pdo_pgsql.h 2010-05-24 22:22:27.833522150 +0200 +++ php-src-5.3.patched/ext/pdo_pgsql/php_pdo_pgsql.h 2010-05-24 10:20:38.404427954 +0200 @@ -30,6 +30,8 @@ #include "TSRM.h" #endif +#define PHP_PDO_PGSQL_RES_NAME "PHP PDO RES NAME" + PHP_MINIT_FUNCTION(pdo_pgsql); PHP_MSHUTDOWN_FUNCTION(pdo_pgsql); PHP_RINIT_FUNCTION(pdo_pgsql); diff -u php-src-5.3/ext/pdo_pgsql/php_pdo_pgsql_int.h php-src-5.3.patched/ext/pdo_pgsql/php_pdo_pgsql_int.h --- php-src-5.3/ext/pdo_pgsql/php_pdo_pgsql_int.h 2010-05-24 22:22:27.833522150 +0200 +++ php-src-5.3.patched/ext/pdo_pgsql/php_pdo_pgsql_int.h 2010-05-24 10:20:34.674239905 +0200 @@ -87,6 +87,8 @@ #define pdo_pgsql_error(d,e,z) _pdo_pgsql_error(d, NULL, e, z, __FILE__, __LINE__ TSRMLS_CC) #define pdo_pgsql_error_stmt(s,e,z) _pdo_pgsql_error(s->dbh, s, e, z, __FILE__, __LINE__ TSRMLS_CC) +extern int _pgsql_stmt_get_column_meta(pdo_stmt_t *stmt, long colno, zval *return_value TSRMLS_DC); + extern struct pdo_stmt_methods pgsql_stmt_methods; #define pdo_pgsql_sqlstate(r) PQresultErrorField(r, PG_DIAG_SQLSTATE) @@ -95,6 +97,14 @@ PDO_PGSQL_ATTR_DISABLE_NATIVE_PREPARED_STATEMENT = PDO_ATTR_DRIVER_SPECIFIC, }; +enum pdo_pgsql_specific_constants { + PGSQL_TRANSACTION_IDLE = PQTRANS_IDLE, + PGSQL_TRANSACTION_ACTIVE = PQTRANS_ACTIVE, + PGSQL_TRANSACTION_INTRANS = PQTRANS_INTRANS, + PGSQL_TRANSACTION_INERROR = PQTRANS_INERROR, + PGSQL_TRANSACTION_UNKNOWN = PQTRANS_UNKNOWN +}; + struct pdo_pgsql_lob_self { pdo_dbh_t *dbh; PGconn *conn;
-- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php