diff options
Diffstat (limited to 'ext/pgsql/pgsql.c')
| -rw-r--r-- | ext/pgsql/pgsql.c | 1490 |
1 files changed, 1490 insertions, 0 deletions
diff --git a/ext/pgsql/pgsql.c b/ext/pgsql/pgsql.c new file mode 100644 index 0000000000..fa38715d25 --- /dev/null +++ b/ext/pgsql/pgsql.c @@ -0,0 +1,1490 @@ +/* + +----------------------------------------------------------------------+ + | PHP HTML Embedded Scripting Language Version 3.0 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997,1998 PHP Development Team (See Credits file) | + +----------------------------------------------------------------------+ + | This program is free software; you can redistribute it and/or modify | + | it under the terms of one of the following licenses: | + | | + | A) the GNU General Public License as published by the Free Software | + | Foundation; either version 2 of the License, or (at your option) | + | any later version. | + | | + | B) the PHP License as published by the PHP Development Team and | + | included in the distribution in the file: LICENSE | + | | + | This program is distributed in the hope that it will be useful, | + | but WITHOUT ANY WARRANTY; without even the implied warranty of | + | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | + | GNU General Public License for more details. | + | | + | You should have received a copy of both licenses referred to here. | + | If you did not, or have any questions about PHP licensing, please | + | contact core@php.net. | + +----------------------------------------------------------------------+ + | Authors: Zeev Suraski <zeev@zend.com> | + | Jouni Ahto <jah@cultnet.fi> (large object interface) | + +----------------------------------------------------------------------+ + */ + +/* $Id$ */ + +#include <stdlib.h> + +#ifndef MSVC5 +#include "config.h" +#endif +#include "php.h" +#include "php3_pgsql.h" +#include "ext/standard/php3_standard.h" +#include "php_globals.h" + +#if HAVE_PGSQL + + + +function_entry pgsql_functions[] = { + {"pg_connect", php3_pgsql_connect, NULL}, + {"pg_pconnect", php3_pgsql_pconnect, NULL}, + {"pg_close", php3_pgsql_close, NULL}, + {"pg_cmdtuples", php3_pgsql_cmdtuples, NULL}, + {"pg_dbname", php3_pgsql_dbname, NULL}, + {"pg_errormessage", php3_pgsql_error_message, NULL}, + {"pg_options", php3_pgsql_options, NULL}, + {"pg_port", php3_pgsql_port, NULL}, + {"pg_tty", php3_pgsql_tty, NULL}, + {"pg_host", php3_pgsql_host, NULL}, + {"pg_exec", php3_pgsql_exec, NULL}, + {"pg_numrows", php3_pgsql_num_rows, NULL}, + {"pg_numfields", php3_pgsql_num_fields, NULL}, + {"pg_fieldname", php3_pgsql_field_name, NULL}, + {"pg_fieldsize", php3_pgsql_field_size, NULL}, + {"pg_fieldtype", php3_pgsql_field_type, NULL}, + {"pg_fieldnum", php3_pgsql_field_number, NULL}, + {"pg_result", php3_pgsql_result, NULL}, + {"pg_fetch_row", php3_pgsql_fetch_row, NULL}, + {"pg_fetch_array", php3_pgsql_fetch_array, NULL}, + {"pg_fetch_object", php3_pgsql_fetch_object, NULL}, + {"pg_fieldprtlen", php3_pgsql_data_length, NULL}, + {"pg_fieldisnull", php3_pgsql_data_isnull, NULL}, + {"pg_freeresult", php3_pgsql_free_result, NULL}, + {"pg_getlastoid", php3_pgsql_last_oid, NULL}, + {"pg_locreate", php3_pgsql_lo_create, NULL}, + {"pg_lounlink", php3_pgsql_lo_unlink, NULL}, + {"pg_loopen", php3_pgsql_lo_open, NULL}, + {"pg_loclose", php3_pgsql_lo_close, NULL}, + {"pg_loread", php3_pgsql_lo_read, NULL}, + {"pg_lowrite", php3_pgsql_lo_write, NULL}, + {"pg_loreadall", php3_pgsql_lo_readall, NULL}, + {NULL, NULL, NULL} +}; + +php3_module_entry pgsql_module_entry = { + "PostgreSQL", pgsql_functions, php3_minit_pgsql, NULL, php3_rinit_pgsql, NULL, NULL, STANDARD_MODULE_PROPERTIES +}; + +#if COMPILE_DL +php3_module_entry *get_module() { return &pgsql_module_entry; } +#endif + +THREAD_LS pgsql_module php3_pgsql_module; + +static void _close_pgsql_link(PGconn *link) +{ + PQfinish(link); + php3_pgsql_module.num_links--; +} + + +static void _close_pgsql_plink(PGconn *link) +{ + PQfinish(link); + php3_pgsql_module.num_persistent--; + php3_pgsql_module.num_links--; +} + + +static void _free_ptr(pgLofp *lofp) +{ + efree(lofp); +} + + +static void _free_result(pgsql_result_handle *pg_result) +{ + PQclear(pg_result->result); + efree(pg_result); +} + + +int php3_minit_pgsql(INIT_FUNC_ARGS) +{ + if (cfg_get_long("pgsql.allow_persistent",&php3_pgsql_module.allow_persistent)==FAILURE) { + php3_pgsql_module.allow_persistent=1; + } + if (cfg_get_long("pgsql.max_persistent",&php3_pgsql_module.max_persistent)==FAILURE) { + php3_pgsql_module.max_persistent=-1; + } + if (cfg_get_long("pgsql.max_links",&php3_pgsql_module.max_links)==FAILURE) { + php3_pgsql_module.max_links=-1; + } + php3_pgsql_module.num_persistent=0; + php3_pgsql_module.le_link = register_list_destructors(_close_pgsql_link,NULL); + php3_pgsql_module.le_plink = register_list_destructors(NULL,_close_pgsql_plink); + /* php3_pgsql_module.le_result = register_list_destructors(PQclear,NULL); */ + php3_pgsql_module.le_result = register_list_destructors(_free_result,NULL); + php3_pgsql_module.le_lofp = register_list_destructors(_free_ptr,NULL); + php3_pgsql_module.le_string = register_list_destructors(_free_ptr,NULL); + return SUCCESS; +} + + +int php3_rinit_pgsql(INIT_FUNC_ARGS) +{ + php3_pgsql_module.default_link=-1; + php3_pgsql_module.num_links = php3_pgsql_module.num_persistent; + return SUCCESS; +} + + +void php3_pgsql_do_connect(INTERNAL_FUNCTION_PARAMETERS,int persistent) +{ + char *host=NULL,*port=NULL,*options=NULL,*tty=NULL,*dbname=NULL,*connstring=NULL; + char *hashed_details; + int hashed_details_length; + PGconn *pgsql; + + switch(ARG_COUNT(ht)) { + case 1: { /* new style, using connection string */ + pval *yyconnstring; + if (getParameters(ht, 1, &yyconnstring) == FAILURE) { + RETURN_FALSE; + } + convert_to_string(yyconnstring); + connstring = yyconnstring->value.str.val; + hashed_details_length = yyconnstring->value.str.len+5+1; + hashed_details = (char *) emalloc(hashed_details_length+1); + sprintf(hashed_details,"pgsql_%s",connstring); /* SAFE */ + } + break; + case 3: { /* host, port, dbname */ + pval *yyhost, *yyport, *yydbname; + + if (getParameters(ht, 3, &yyhost, &yyport, &yydbname) == FAILURE) { + RETURN_FALSE; + } + convert_to_string(yyhost); + convert_to_string(yyport); + convert_to_string(yydbname); + host = yyhost->value.str.val; + port = yyport->value.str.val; + dbname = yydbname->value.str.val; + options=tty=NULL; + hashed_details_length = yyhost->value.str.len+yyport->value.str.len+yydbname->value.str.len+5+5; + hashed_details = (char *) emalloc(hashed_details_length+1); + sprintf(hashed_details,"pgsql_%s_%s___%s",host,port,dbname); /* SAFE */ + } + break; + case 4: { /* host, port, options, dbname */ + pval *yyhost, *yyport, *yyoptions, *yydbname; + + if (getParameters(ht, 4, &yyhost, &yyport, &yyoptions, &yydbname) == FAILURE) { + RETURN_FALSE; + } + convert_to_string(yyhost); + convert_to_string(yyport); + convert_to_string(yyoptions); + convert_to_string(yydbname); + host = yyhost->value.str.val; + port = yyport->value.str.val; + options = yyoptions->value.str.val; + dbname = yydbname->value.str.val; + tty=NULL; + hashed_details_length = yyhost->value.str.len+yyport->value.str.len+yyoptions->value.str.len+yydbname->value.str.len+5+5; + hashed_details = (char *) emalloc(hashed_details_length+1); + sprintf(hashed_details,"pgsql_%s_%s_%s__%s",host,port,options,dbname); /* SAFE */ + } + break; + case 5: { /* host, port, options, tty, dbname */ + pval *yyhost, *yyport, *yyoptions, *yytty, *yydbname; + + if (getParameters(ht, 5, &yyhost, &yyport, &yyoptions, &yytty, &yydbname) == FAILURE) { + RETURN_FALSE; + } + convert_to_string(yyhost); + convert_to_string(yyport); + convert_to_string(yyoptions); + convert_to_string(yytty); + convert_to_string(yydbname); + host = yyhost->value.str.val; + port = yyport->value.str.val; + options = yyoptions->value.str.val; + tty = yytty->value.str.val; + dbname = yydbname->value.str.val; + hashed_details_length = yyhost->value.str.len+yyport->value.str.len+yyoptions->value.str.len+yytty->value.str.len+yydbname->value.str.len+5+5; + hashed_details = (char *) emalloc(hashed_details_length+1); + sprintf(hashed_details,"pgsql_%s_%s_%s_%s_%s",host,port,options,tty,dbname); /* SAFE */ + } + break; + default: + WRONG_PARAM_COUNT; + break; + } + + if (persistent) { + list_entry *le; + + /* try to find if we already have this link in our persistent list */ + if (_php3_hash_find(plist, hashed_details, hashed_details_length+1, (void **) &le)==FAILURE) { /* we don't */ + list_entry new_le; + + if (php3_pgsql_module.max_links!=-1 && php3_pgsql_module.num_links>=php3_pgsql_module.max_links) { + php3_error(E_WARNING,"PostgresSQL: Too many open links (%d)",php3_pgsql_module.num_links); + efree(hashed_details); + RETURN_FALSE; + } + if (php3_pgsql_module.max_persistent!=-1 && php3_pgsql_module.num_persistent>=php3_pgsql_module.max_persistent) { + php3_error(E_WARNING,"PostgresSQL: Too many open persistent links (%d)",php3_pgsql_module.num_persistent); + efree(hashed_details); + RETURN_FALSE; + } + + /* create the link */ + if (connstring) { + pgsql=PQconnectdb(connstring); + } else { + pgsql=PQsetdb(host,port,options,tty,dbname); + } + if (pgsql==NULL || PQstatus(pgsql)==CONNECTION_BAD) { + php3_error(E_WARNING,"Unable to connect to PostgresSQL server: %s",PQerrorMessage(pgsql)); + efree(hashed_details); + RETURN_FALSE; + } + + /* hash it up */ + new_le.type = php3_pgsql_module.le_plink; + new_le.ptr = pgsql; + if (_php3_hash_update(plist, hashed_details, hashed_details_length+1, (void *) &new_le, sizeof(list_entry), NULL)==FAILURE) { + efree(hashed_details); + RETURN_FALSE; + } + php3_pgsql_module.num_links++; + php3_pgsql_module.num_persistent++; + } else { /* we do */ + if (le->type != php3_pgsql_module.le_plink) { + RETURN_FALSE; + } + /* ensure that the link did not die */ + if (PQstatus(le->ptr)==CONNECTION_BAD) { /* the link died */ + if (connstring) { + le->ptr=PQconnectdb(connstring); + } else { + le->ptr=PQsetdb(host,port,options,tty,dbname); + } + if (le->ptr==NULL || PQstatus(le->ptr)==CONNECTION_BAD) { + php3_error(E_WARNING,"PostgresSQL link lost, unable to reconnect"); + _php3_hash_del(plist,hashed_details,hashed_details_length+1); + efree(hashed_details); + RETURN_FALSE; + } + } + pgsql = (PGconn *) le->ptr; + } + return_value->value.lval = php3_list_insert(pgsql,php3_pgsql_module.le_plink); + return_value->type = IS_LONG; + } else { + list_entry *index_ptr,new_index_ptr; + + /* first we check the hash for the hashed_details key. if it exists, + * it should point us to the right offset where the actual pgsql link sits. + * if it doesn't, open a new pgsql link, add it to the resource list, + * and add a pointer to it with hashed_details as the key. + */ + if (_php3_hash_find(list,hashed_details,hashed_details_length+1,(void **) &index_ptr)==SUCCESS) { + int type,link; + void *ptr; + + if (index_ptr->type != le_index_ptr) { + RETURN_FALSE; + } + link = (int) index_ptr->ptr; + ptr = php3_list_find(link,&type); /* check if the link is still there */ + if (ptr && (type==php3_pgsql_module.le_link || type==php3_pgsql_module.le_plink)) { + return_value->value.lval = php3_pgsql_module.default_link = link; + return_value->type = IS_LONG; + efree(hashed_details); + return; + } else { + _php3_hash_del(list,hashed_details,hashed_details_length+1); + } + } + if (php3_pgsql_module.max_links!=-1 && php3_pgsql_module.num_links>=php3_pgsql_module.max_links) { + php3_error(E_WARNING,"PostgresSQL: Too many open links (%d)",php3_pgsql_module.num_links); + efree(hashed_details); + RETURN_FALSE; + } + if (connstring) { + pgsql=PQconnectdb(connstring); + } else { + pgsql=PQsetdb(host,port,options,tty,dbname); + } + if (pgsql==NULL || PQstatus(pgsql)==CONNECTION_BAD) { + php3_error(E_WARNING,"Unable to connect to PostgresSQL server: %s",PQerrorMessage(pgsql)); + efree(hashed_details); + RETURN_FALSE; + } + + /* add it to the list */ + return_value->value.lval = php3_list_insert(pgsql,php3_pgsql_module.le_link); + return_value->type = IS_LONG; + + /* add it to the hash */ + new_index_ptr.ptr = (void *) return_value->value.lval; + new_index_ptr.type = le_index_ptr; + if (_php3_hash_update(list,hashed_details,hashed_details_length+1,(void *) &new_index_ptr, sizeof(list_entry), NULL)==FAILURE) { + efree(hashed_details); + RETURN_FALSE; + } + php3_pgsql_module.num_links++; + } + efree(hashed_details); + php3_pgsql_module.default_link=return_value->value.lval; +} + + +int php3_pgsql_get_default_link(INTERNAL_FUNCTION_PARAMETERS) +{ + if (php3_pgsql_module.default_link==-1) { /* no link opened yet, implicitly open one */ + HashTable tmp; + + _php3_hash_init(&tmp,0,NULL,NULL,0); + php3_pgsql_do_connect(&tmp,return_value,list,plist,0); + _php3_hash_destroy(&tmp); + } + return php3_pgsql_module.default_link; +} + +/* {{{ proto int pg_connect([string connection_string] | [string host, string port, [string options, [string tty,]] string database) + Open a PostgreSQL connection */ +void php3_pgsql_connect(INTERNAL_FUNCTION_PARAMETERS) +{ + php3_pgsql_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU,0); +} +/* }}} */ + +/* {{{ proto int pg_connect([string connection_string] | [string host, string port, [string options, [string tty,]] string database) + Open a persistent PostgreSQL connection */ +void php3_pgsql_pconnect(INTERNAL_FUNCTION_PARAMETERS) +{ + php3_pgsql_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU,1); +} +/* }}} */ + +/* {{{ proto bool pg_close([int connection]) + Close a PostgreSQL connection */ +void php3_pgsql_close(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *pgsql_link; + int id,type; + PGconn *pgsql; + + switch (ARG_COUNT(ht)) { + case 0: + id = php3_pgsql_module.default_link; + break; + case 1: + if (getParameters(ht, 1, &pgsql_link)==FAILURE) { + RETURN_FALSE; + } + convert_to_long(pgsql_link); + id = pgsql_link->value.lval; + break; + default: + WRONG_PARAM_COUNT; + break; + } + + pgsql = (PGconn *) php3_list_find(id,&type); + if (type!=php3_pgsql_module.le_link && type!=php3_pgsql_module.le_plink) { + php3_error(E_WARNING,"%d is not a PostgresSQL link index",id); + RETURN_FALSE; + } + + php3_list_delete(pgsql_link->value.lval); + RETURN_TRUE; +} +/* }}} */ + + +#define PHP3_PG_DBNAME 1 +#define PHP3_PG_ERROR_MESSAGE 2 +#define PHP3_PG_OPTIONS 3 +#define PHP3_PG_PORT 4 +#define PHP3_PG_TTY 5 +#define PHP3_PG_HOST 6 + +void php3_pgsql_get_link_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type) +{ + pval *pgsql_link; + int id,type; + PGconn *pgsql; + + switch(ARG_COUNT(ht)) { + case 0: + id = php3_pgsql_module.default_link; + break; + case 1: + if (getParameters(ht, 1, &pgsql_link)==FAILURE) { + RETURN_FALSE; + } + convert_to_long(pgsql_link); + id = pgsql_link->value.lval; + break; + default: + WRONG_PARAM_COUNT; + break; + } + + pgsql = (PGconn *) php3_list_find(id,&type); + if (type!=php3_pgsql_module.le_link && type!=php3_pgsql_module.le_plink) { + php3_error(E_WARNING,"%d is not a PostgresSQL link index",id); + RETURN_FALSE; + } + + switch(entry_type) { + case PHP3_PG_DBNAME: + return_value->value.str.val = PQdb(pgsql); + break; + case PHP3_PG_ERROR_MESSAGE: + return_value->value.str.val = PQerrorMessage(pgsql); + break; + case PHP3_PG_OPTIONS: + return_value->value.str.val = PQoptions(pgsql); + break; + case PHP3_PG_PORT: + return_value->value.str.val = PQport(pgsql); + break; + case PHP3_PG_TTY: + return_value->value.str.val = PQtty(pgsql); + break; + case PHP3_PG_HOST: + return_value->value.str.val = PQhost(pgsql); + break; + default: + RETURN_FALSE; + } + return_value->value.str.len = strlen(return_value->value.str.val); + return_value->value.str.val = (char *) estrdup(return_value->value.str.val); + return_value->type = IS_STRING; +} + +/* {{{ proto string pg_dbname([int connection]) + Get the database name */ +void php3_pgsql_dbname(INTERNAL_FUNCTION_PARAMETERS) +{ + php3_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP3_PG_DBNAME); +} +/* }}} */ + +/* {{{ proto string pg_errormessage([int connection]) + Get the error message string */ +void php3_pgsql_error_message(INTERNAL_FUNCTION_PARAMETERS) +{ + php3_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP3_PG_ERROR_MESSAGE); +} +/* }}} */ + +/* {{{ proto string pg_options([int connection]) + Get the options associated with the connection */ +void php3_pgsql_options(INTERNAL_FUNCTION_PARAMETERS) +{ + php3_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP3_PG_OPTIONS); +} +/* }}} */ + +/* {{{ proto int pg_port([int connection]) + Return the port number associated with the connection */ +void php3_pgsql_port(INTERNAL_FUNCTION_PARAMETERS) +{ + php3_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP3_PG_PORT); +} +/* }}} */ + +/* {{{ proto string pg_tty([int connection]) + Return the tty name associated with the connection */ +void php3_pgsql_tty(INTERNAL_FUNCTION_PARAMETERS) +{ + php3_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP3_PG_TTY); +} +/* }}} */ + +/* {{{ proto string pg_host([int connection]) + Returns the host name associated with the connection */ +void php3_pgsql_host(INTERNAL_FUNCTION_PARAMETERS) +{ + php3_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP3_PG_HOST); +} +/* }}} */ + +/* {{{ proto int pg_exec([int connection,] string query) + Execute a query */ +void php3_pgsql_exec(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *query,*pgsql_link; + int id,type; + PGconn *pgsql; + PGresult *pgsql_result; + ExecStatusType status; + pgsql_result_handle *pg_result; + + switch(ARG_COUNT(ht)) { + case 1: + if (getParameters(ht, 1, &query)==FAILURE) { + RETURN_FALSE; + } + id = php3_pgsql_module.default_link; + break; + case 2: + if (getParameters(ht, 2, &pgsql_link, &query)==FAILURE) { + RETURN_FALSE; + } + convert_to_long(pgsql_link); + id = pgsql_link->value.lval; + break; + default: + WRONG_PARAM_COUNT; + break; + } + + pgsql = (PGconn *) php3_list_find(id,&type); + if (type!=php3_pgsql_module.le_link && type!=php3_pgsql_module.le_plink) { + php3_error(E_WARNING,"%d is not a PostgresSQL link index",id); + RETURN_FALSE; + } + + convert_to_string(query); + pgsql_result=PQexec(pgsql,query->value.str.val); + + if (pgsql_result) { + status = PQresultStatus(pgsql_result); + } else { + status = (ExecStatusType) PQstatus(pgsql); + } + + + switch (status) { + case PGRES_EMPTY_QUERY: + case PGRES_BAD_RESPONSE: + case PGRES_NONFATAL_ERROR: + case PGRES_FATAL_ERROR: + php3_error(E_WARNING,"PostgresSQL query failed: %s",PQerrorMessage(pgsql)); + RETURN_FALSE; + break; + case PGRES_COMMAND_OK: /* successful command that did not return rows */ + default: + if (pgsql_result) { + pg_result = (pgsql_result_handle *) emalloc(sizeof(pgsql_result_handle)); + pg_result->conn = pgsql; + pg_result->result = pgsql_result; + return_value->value.lval = php3_list_insert(pg_result,php3_pgsql_module.le_result); + return_value->type = IS_LONG; + } else { + RETURN_FALSE; + } + break; + } +} +/* }}} */ + +#define PHP3_PG_NUM_ROWS 1 +#define PHP3_PG_NUM_FIELDS 2 +#define PHP3_PG_CMD_TUPLES 3 + +void php3_pgsql_get_result_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type) +{ + pval *result; + PGresult *pgsql_result; + pgsql_result_handle *pg_result; + int type; + + if (ARG_COUNT(ht)!=1 || getParameters(ht, 1, &result)==FAILURE) { + WRONG_PARAM_COUNT; + } + + convert_to_long(result); + pg_result = (pgsql_result_handle *) php3_list_find(result->value.lval,&type); + + if (type!=php3_pgsql_module.le_result) { + php3_error(E_WARNING,"%d is not a PostgresSQL result index",result->value.lval); + RETURN_FALSE; + } + + pgsql_result = pg_result->result; + + switch (entry_type) { + case PHP3_PG_NUM_ROWS: + return_value->value.lval = PQntuples(pgsql_result); + break; + case PHP3_PG_NUM_FIELDS: + return_value->value.lval = PQnfields(pgsql_result); + break; + case PHP3_PG_CMD_TUPLES: +#if HAVE_PQCMDTUPLES + return_value->value.lval = atoi(PQcmdTuples(pgsql_result)); +#else + php3_error(E_WARNING,"This compilation does not support pg_cmdtuples()"); + return_value->value.lval = 0; +#endif + break; + default: + RETURN_FALSE; + } + return_value->type = IS_LONG; +} + +/* {{{ proto int pg_numrows(int result) + Return the number of rows in the result */ +void php3_pgsql_num_rows(INTERNAL_FUNCTION_PARAMETERS) +{ + php3_pgsql_get_result_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP3_PG_NUM_ROWS); +} +/* }}} */ + +/* {{{ proto int pg_numfields(int result) + Return the number of fields in the result */ +void php3_pgsql_num_fields(INTERNAL_FUNCTION_PARAMETERS) +{ + php3_pgsql_get_result_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP3_PG_NUM_FIELDS); +} +/* }}} */ + +/* {{{ proto int pg_cmdtuples(int result) + Returns the number of affected tuples */ +void php3_pgsql_cmdtuples(INTERNAL_FUNCTION_PARAMETERS) +{ + php3_pgsql_get_result_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP3_PG_CMD_TUPLES); +} +/* }}} */ + + +char *get_field_name(PGconn *pgsql, Oid oid, HashTable *list) +{ + PGresult *result; + char hashed_oid_key[32]; + list_entry *field_type; + char *ret=NULL; + + /* try to lookup the type in the resource list */ + snprintf(hashed_oid_key,31,"pgsql_oid_%d",(int) oid); + hashed_oid_key[31]=0; + + if (_php3_hash_find(list,hashed_oid_key,strlen(hashed_oid_key)+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, *tmp_name; + list_entry new_oid_entry; + + if ((result=PQexec(pgsql,"select oid,typname from pg_type"))==NULL) { + return empty_string; + } + 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; + } + snprintf(hashed_oid_key,31,"pgsql_oid_%s",tmp_oid); + if ((tmp_name=PQgetvalue(result,i,name_offset))==NULL) { + continue; + } + new_oid_entry.type = php3_pgsql_module.le_string; + new_oid_entry.ptr = estrdup(tmp_name); + _php3_hash_update(list,hashed_oid_key,strlen(hashed_oid_key)+1,(void *) &new_oid_entry, sizeof(list_entry), NULL); + if (!ret && atoi(tmp_oid)==oid) { + ret = estrdup(tmp_name); + } + } + } + return ret; +} + + +#define PHP3_PG_FIELD_NAME 1 +#define PHP3_PG_FIELD_SIZE 2 +#define PHP3_PG_FIELD_TYPE 3 + +void php3_pgsql_get_field_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type) +{ + pval *result,*field; + PGresult *pgsql_result; + pgsql_result_handle *pg_result; + int type; + + if (ARG_COUNT(ht)!=2 || getParameters(ht, 2, &result, &field)==FAILURE) { + WRONG_PARAM_COUNT; + } + + convert_to_long(result); + pg_result = (pgsql_result_handle *) php3_list_find(result->value.lval,&type); + + if (type!=php3_pgsql_module.le_result) { + php3_error(E_WARNING,"%d is not a PostgresSQL result index",result->value.lval); + RETURN_FALSE; + } + + pgsql_result = pg_result->result; + convert_to_long(field); + + if (field->value.lval<0 || field->value.lval>=PQnfields(pgsql_result)) { + php3_error(E_WARNING,"Bad field offset specified"); + RETURN_FALSE; + } + + switch (entry_type) { + case PHP3_PG_FIELD_NAME: + return_value->value.str.val = PQfname(pgsql_result,field->value.lval); + return_value->value.str.len = strlen(return_value->value.str.val); + return_value->value.str.val = estrndup(return_value->value.str.val,return_value->value.str.len); + return_value->type = IS_STRING; + break; + case PHP3_PG_FIELD_SIZE: + return_value->value.lval = PQfsize(pgsql_result,field->value.lval); + return_value->type = IS_LONG; + break; + case PHP3_PG_FIELD_TYPE: + return_value->value.str.val = get_field_name(pg_result->conn,PQftype(pgsql_result,field->value.lval),list); + return_value->value.str.len = strlen(return_value->value.str.val); + return_value->type = IS_STRING; + break; + default: + RETURN_FALSE; + } +} + +/* {{{ proto string pg_fieldname(int result, int field_number) + Returns the name of the field */ +void php3_pgsql_field_name(INTERNAL_FUNCTION_PARAMETERS) +{ + php3_pgsql_get_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP3_PG_FIELD_NAME); +} +/* }}} */ + +/* {{{ proto pg_fieldsize(int result, int field_number) + Returns the internal size of the field */ +void php3_pgsql_field_size(INTERNAL_FUNCTION_PARAMETERS) +{ + php3_pgsql_get_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP3_PG_FIELD_SIZE); +} +/* }}} */ + +/* {{{ proto string pg_fieldtype(int result, int field_number) + Returns the type name for the given field */ +void php3_pgsql_field_type(INTERNAL_FUNCTION_PARAMETERS) +{ + php3_pgsql_get_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP3_PG_FIELD_TYPE); +} +/* }}} */ + +/* {{{ proto int pg_fieldnum(int result, string field_name) + Returns the field number of the named field */ +void php3_pgsql_field_number(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *result,*field; + PGresult *pgsql_result; + pgsql_result_handle *pg_result; + int type; + + if (ARG_COUNT(ht)!=2 || getParameters(ht, 2, &result, &field)==FAILURE) { + WRONG_PARAM_COUNT; + } + + convert_to_long(result); + pg_result = (pgsql_result_handle *) php3_list_find(result->value.lval,&type); + + if (type!=php3_pgsql_module.le_result) { + php3_error(E_WARNING,"%d is not a PostgresSQL result index",result->value.lval); + RETURN_FALSE; + } + pgsql_result = pg_result->result; + + convert_to_string(field); + return_value->value.lval = PQfnumber(pgsql_result,field->value.str.val); + return_value->type = IS_LONG; +} +/* }}} */ + +/* {{{ proto mixed pg_result(int result, int row_number, mixed field_name) + Returns values from a result identifier */ +void php3_pgsql_result(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *result, *row, *field=NULL; + PGresult *pgsql_result; + pgsql_result_handle *pg_result; + int type,field_offset; + + + if (ARG_COUNT(ht)!=3 || getParameters(ht, 3, &result, &row, &field)==FAILURE) { + WRONG_PARAM_COUNT; + } + + convert_to_long(result); + pg_result = (pgsql_result_handle *) php3_list_find(result->value.lval,&type); + + if (type!=php3_pgsql_module.le_result) { + php3_error(E_WARNING,"%d is not a PostgresSQL result index",result->value.lval); + RETURN_FALSE; + } + pgsql_result = pg_result->result; + + convert_to_long(row); + if (row->value.lval<0 || row->value.lval>=PQntuples(pgsql_result)) { + php3_error(E_WARNING,"Unable to jump to row %d on PostgresSQL result index %d",row->value.lval,result->value.lval); + RETURN_FALSE; + } + switch(field->type) { + case IS_STRING: + field_offset = PQfnumber(pgsql_result,field->value.str.val); + break; + default: + convert_to_long(field); + field_offset = field->value.lval; + break; + } + if (field_offset<0 || field_offset>=PQnfields(pgsql_result)) { + php3_error(E_WARNING,"Bad column offset specified"); + RETURN_FALSE; + } + + return_value->value.str.val = PQgetvalue(pgsql_result,row->value.lval,field_offset); + return_value->value.str.len = (return_value->value.str.val ? strlen(return_value->value.str.val) : 0); + return_value->value.str.val = safe_estrndup(return_value->value.str.val,return_value->value.str.len); + return_value->type = IS_STRING; +} +/* }}} */ + +/* {{{ proto array pg_fetchrow(int result, int row) + Get a row as an enumerated array */ +void php3_pgsql_fetch_row(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *result, *row; + PGresult *pgsql_result; + pgsql_result_handle *pg_result; + int type; + int i,num_fields; + char *element; + uint element_len; + PLS_FETCH(); + + + if (ARG_COUNT(ht)!=2 || getParameters(ht, 2, &result, &row)==FAILURE) { + WRONG_PARAM_COUNT; + } + + convert_to_long(result); + pg_result = (pgsql_result_handle *) php3_list_find(result->value.lval,&type); + + if (type!=php3_pgsql_module.le_result) { + php3_error(E_WARNING,"%d is not a PostgresSQL result index",result->value.lval); + RETURN_FALSE; + } + pgsql_result = pg_result->result; + + convert_to_long(row); + if (row->value.lval<0 || row->value.lval>=PQntuples(pgsql_result)) { + php3_error(E_WARNING,"Unable to jump to row %d on PostgresSQL result index %d",row->value.lval,result->value.lval); + RETURN_FALSE; + } + array_init(return_value); + for (i=0,num_fields=PQnfields(pgsql_result); i<num_fields; i++) { + element = PQgetvalue(pgsql_result,row->value.lval,i); + element_len = (element ? strlen(element) : 0); + element = safe_estrndup(element,element_len); + if (element) { + if (PG(magic_quotes_runtime)) { + char *tmp=_php3_addslashes(element,element_len,&element_len,0); + + add_index_stringl(return_value, i, tmp, element_len, 0); + } else { + add_index_stringl(return_value, i, element, element_len, 1); + } + } else { + /* NULL field, don't set it */ + /*add_index_stringl(return_value, i, empty_string, 0, 1);*/ + } + } +} +/* }}} */ + +void php3_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *result, *row, *pval_ptr; + PGresult *pgsql_result; + pgsql_result_handle *pg_result; + int type; + int i,num_fields; + char *element,*field_name; + uint element_len; + PLS_FETCH(); + + + if (ARG_COUNT(ht)!=2 || getParameters(ht, 2, &result, &row)==FAILURE) { + WRONG_PARAM_COUNT; + } + + convert_to_long(result); + pg_result = (pgsql_result_handle *) php3_list_find(result->value.lval,&type); + + if (type!=php3_pgsql_module.le_result) { + php3_error(E_WARNING,"%d is not a PostgresSQL result index",result->value.lval); + RETURN_FALSE; + } + pgsql_result = pg_result->result; + + convert_to_long(row); + if (row->value.lval<0 || row->value.lval>=PQntuples(pgsql_result)) { + php3_error(E_WARNING,"Unable to jump to row %d on PostgresSQL result index %d",row->value.lval,result->value.lval); + RETURN_FALSE; + } + array_init(return_value); + for (i=0,num_fields=PQnfields(pgsql_result); i<num_fields; i++) { + element = PQgetvalue(pgsql_result,row->value.lval,i); + element_len = (element ? strlen(element) : 0); + element = safe_estrndup(element,element_len); + if (element) { + if (PG(magic_quotes_runtime)) { + char *tmp=_php3_addslashes(element,element_len,&element_len,0); + + add_get_index_stringl(return_value, i, tmp, element_len, (void **) &pval_ptr, 0); + } else { + add_get_index_stringl(return_value, i, element, element_len, (void **) &pval_ptr, 1); + } + field_name = PQfname(pgsql_result,i); + _php3_hash_pointer_update(return_value->value.ht, field_name, strlen(field_name)+1, pval_ptr); + } else { + /* NULL field, don't set it */ + /* add_get_index_stringl(return_value, i, empty_string, 0, (void **) &pval_ptr); */ + } + } +} + +/* ?? This is a rather odd function - why not just point pg_fetcharray() directly at fetch_hash ? -RL */ +/* {{{ proto array pg_fetch_array(int result, int row) + Fetch a row as an array */ +void php3_pgsql_fetch_array(INTERNAL_FUNCTION_PARAMETERS) +{ + php3_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU); +} +/* }}} */ + +/* {{{ proto object pg_fetch_object(int result, int row) + Fetch a row as an object */ +void php3_pgsql_fetch_object(INTERNAL_FUNCTION_PARAMETERS) +{ + php3_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU); + if (return_value->type==IS_ARRAY) { + return_value->type = IS_OBJECT; + } +} +/* }}} */ + +#define PHP3_PG_DATA_LENGTH 1 +#define PHP3_PG_DATA_ISNULL 2 + +void php3_pgsql_data_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type) +{ + pval *result,*row,*field; + PGresult *pgsql_result; + pgsql_result_handle *pg_result; + int type,field_offset; + + if (ARG_COUNT(ht)!=3 || getParameters(ht, 3, &result, &row, &field)==FAILURE) { + WRONG_PARAM_COUNT; + } + + convert_to_long(result); + pg_result = (pgsql_result_handle *) php3_list_find(result->value.lval,&type); + + if (type!=php3_pgsql_module.le_result) { + php3_error(E_WARNING,"%d is not a PostgresSQL result index",result->value.lval); + RETURN_FALSE; + } + pgsql_result = pg_result->result; + + convert_to_long(row); + if (row->value.lval<0 || row->value.lval>=PQntuples(pgsql_result)) { + php3_error(E_WARNING,"Unable to jump to row %d on PostgresSQL result index %d",row->value.lval,result->value.lval); + RETURN_FALSE; + } + switch(field->type) { + case IS_STRING: + field_offset = PQfnumber(pgsql_result,field->value.str.val); + break; + default: + convert_to_long(field); + field_offset = field->value.lval; + break; + } + if (field_offset<0 || field_offset>=PQnfields(pgsql_result)) { + php3_error(E_WARNING,"Bad column offset specified"); + RETURN_FALSE; + } + + switch (entry_type) { + case PHP3_PG_DATA_LENGTH: + return_value->value.lval = PQgetlength(pgsql_result,row->value.lval,field_offset); + break; + case PHP3_PG_DATA_ISNULL: + return_value->value.lval = PQgetisnull(pgsql_result,row->value.lval,field_offset); + break; + } + return_value->type = IS_LONG; +} + +/* {{{ proto int pg_fieldprtlen(int result, int row, mixed field_name_or_number) + Returns the printed length */ +void php3_pgsql_data_length(INTERNAL_FUNCTION_PARAMETERS) +{ + php3_pgsql_data_info(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP3_PG_DATA_LENGTH); +} +/* }}} */ + +/* {{{ proto int pg_fieldisnull(int result, int row, mixed field_name_or_number) + Test if a field is NULL */ +void php3_pgsql_data_isnull(INTERNAL_FUNCTION_PARAMETERS) +{ + php3_pgsql_data_info(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP3_PG_DATA_ISNULL); +} +/* }}} */ + +/* {{{ proto int pg_freeresult(int result) + Free result memory */ +void php3_pgsql_free_result(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *result; + pgsql_result_handle *pg_result; + int type; + + if (ARG_COUNT(ht)!=1 || getParameters(ht, 1, &result)==FAILURE) { + WRONG_PARAM_COUNT; + } + + convert_to_long(result); + if (result->value.lval==0) { + RETURN_FALSE; + } + pg_result = (pgsql_result_handle *) php3_list_find(result->value.lval,&type); + + if (type!=php3_pgsql_module.le_result) { + php3_error(E_WARNING,"%d is not a PostgresSQL result index",result->value.lval); + RETURN_FALSE; + } + php3_list_delete(result->value.lval); + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto int pg_getlastoid(int result) + Returns the last object identifier */ +void php3_pgsql_last_oid(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *result; + PGresult *pgsql_result; + pgsql_result_handle *pg_result; + int type; + + if (ARG_COUNT(ht)!=1 || getParameters(ht, 1, &result)==FAILURE) { + WRONG_PARAM_COUNT; + } + + convert_to_long(result); + pg_result = (pgsql_result_handle *) php3_list_find(result->value.lval,&type); + + if (type!=php3_pgsql_module.le_result) { + php3_error(E_WARNING,"%d is not a PostgresSQL result index",result->value.lval); + RETURN_FALSE; + } + pgsql_result = pg_result->result; + return_value->value.str.val = (char *) PQoidStatus(pgsql_result); + if (return_value->value.str.val) { + return_value->value.str.len = strlen(return_value->value.str.val); + return_value->value.str.val = estrndup(return_value->value.str.val, return_value->value.str.len); + return_value->type = IS_STRING; + } else { + return_value->value.str.val = empty_string; + } +} +/* }}} */ + +/* {{{ proto int pg_locreate(int connection) + Create a large object */ +void php3_pgsql_lo_create(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *pgsql_link; + PGconn *pgsql; + Oid pgsql_oid; + int id, type; + + switch(ARG_COUNT(ht)) { + case 0: + id = php3_pgsql_module.default_link; + break; + case 1: + if (getParameters(ht, 1, &pgsql_link)==FAILURE) { + RETURN_FALSE; + } + convert_to_long(pgsql_link); + id = pgsql_link->value.lval; + break; + default: + WRONG_PARAM_COUNT; + break; + } + + pgsql = (PGconn *) php3_list_find(id,&type); + if (type!=php3_pgsql_module.le_link && type!=php3_pgsql_module.le_plink) { + php3_error(E_WARNING,"%d is not a PostgresSQL link index",id); + RETURN_FALSE; + } + + /* XXX: Archive modes not supported until I get some more data. Don't think anybody's + using it anyway. I believe it's also somehow related to the 'time travel' feature of + PostgreSQL, that's on the list of features to be removed... Create modes not supported. + What's the use of an object that can be only written to, but not read from, and vice + versa? Beats me... And the access type (r/w) must be specified again when opening + the object, probably (?) overrides this. (Jouni) + */ + + if ((pgsql_oid=lo_creat(pgsql, INV_READ|INV_WRITE))==0) { + php3_error(E_WARNING,"Unable to create PostgresSQL large object"); + RETURN_FALSE; + } + + return_value->value.lval = pgsql_oid; + return_value->type = IS_LONG; +} +/* }}} */ + +/* {{{ proto void pg_lounlink([int connection, ] int large_obj_id) + Delete a large object */ +void php3_pgsql_lo_unlink(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *pgsql_link, *oid; + PGconn *pgsql; + Oid pgsql_oid; + int id, type; + + switch(ARG_COUNT(ht)) { + case 1: + if (getParameters(ht, 1, &oid)==FAILURE) { + RETURN_FALSE; + } + convert_to_long(oid); + pgsql_oid = oid->value.lval; + id = php3_pgsql_module.default_link; + break; + case 2: + if (getParameters(ht, 2, &pgsql_link, &oid)==FAILURE) { + RETURN_FALSE; + } + convert_to_long(pgsql_link); + id = pgsql_link->value.lval; + convert_to_long(oid); + pgsql_oid = oid->value.lval; + break; + default: + WRONG_PARAM_COUNT; + break; + } + + pgsql = (PGconn *) php3_list_find(id,&type); + if (type!=php3_pgsql_module.le_link && type!=php3_pgsql_module.le_plink) { + php3_error(E_WARNING,"%d is not a PostgresSQL link index",id); + RETURN_FALSE; + } + + if (lo_unlink(pgsql, pgsql_oid)==-1) { + php3_error(E_WARNING,"Unable to delete PostgresSQL large object %d", (int) pgsql_oid); + RETURN_FALSE; + } + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto int pg_loopen([int connection,] int objoid, string mode) + Open a large object and return fd */ +void php3_pgsql_lo_open(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *pgsql_link, *oid, *mode; + PGconn *pgsql; + Oid pgsql_oid; + int id, type, pgsql_mode=0, pgsql_lofd; + int create=0; + char *mode_string=NULL; + pgLofp *pgsql_lofp; + + switch(ARG_COUNT(ht)) { + case 2: + if (getParameters(ht, 2, &oid, &mode)==FAILURE) { + RETURN_FALSE; + } + convert_to_long(oid); + pgsql_oid = oid->value.lval; + convert_to_string(mode); + mode_string = mode->value.str.val; + id = php3_pgsql_module.default_link; + break; + case 3: + if (getParameters(ht, 3, &pgsql_link, &oid, &mode)==FAILURE) { + RETURN_FALSE; + } + convert_to_long(pgsql_link); + id = pgsql_link->value.lval; + convert_to_long(oid); + pgsql_oid = oid->value.lval; + convert_to_string(mode); + mode_string = mode->value.str.val; + break; + default: + WRONG_PARAM_COUNT; + break; + } + + pgsql = (PGconn *) php3_list_find(id,&type); + if (type!=php3_pgsql_module.le_link && type!=php3_pgsql_module.le_plink) { + php3_error(E_WARNING,"%d is not a PostgresSQL link index",id); + RETURN_FALSE; + } + + /* r/w/+ is little bit more PHP-like than INV_READ/INV_WRITE and a lot of + faster to type. Unfortunately, doesn't behave the same way as fopen()... + (Jouni) + */ + + if (strchr(mode_string, 'r')==mode_string) { + pgsql_mode |= INV_READ; + if (strchr(mode_string, '+')==mode_string+1) { + pgsql_mode |= INV_WRITE; + } + } + if (strchr(mode_string, 'w')==mode_string) { + pgsql_mode |= INV_WRITE; + create = 1; + if (strchr(mode_string, '+')==mode_string+1) { + pgsql_mode |= INV_READ; + } + } + + + pgsql_lofp = (pgLofp *) emalloc(sizeof(pgLofp)); + + if ((pgsql_lofd=lo_open(pgsql, pgsql_oid, pgsql_mode))==-1) { + if (create) { + if ((pgsql_oid=lo_creat(pgsql, INV_READ|INV_WRITE))==0) { + efree(pgsql_lofp); + php3_error(E_WARNING,"Unable to create PostgresSQL large object"); + RETURN_FALSE; + } else { + if ((pgsql_lofd=lo_open(pgsql, pgsql_oid, pgsql_mode))==-1) { + if (lo_unlink(pgsql, pgsql_oid)==-1) { + efree(pgsql_lofp); + php3_error(E_WARNING,"Something's really messed up!!! Your database is badly corrupted in a way NOT related to PHP."); + RETURN_FALSE; + } + efree(pgsql_lofp); + php3_error(E_WARNING,"Unable to open PostgresSQL large object"); + RETURN_FALSE; + } else { + pgsql_lofp->conn = pgsql; + pgsql_lofp->lofd = pgsql_lofd; + return_value->value.lval = php3_list_insert(pgsql_lofp, php3_pgsql_module.le_lofp); + return_value->type = IS_LONG; + } + } + } else { + efree(pgsql_lofp); + php3_error(E_WARNING,"Unable to open PostgresSQL large object"); + RETURN_FALSE; + } + } else { + pgsql_lofp->conn = pgsql; + pgsql_lofp->lofd = pgsql_lofd; + return_value->value.lval = php3_list_insert(pgsql_lofp, php3_pgsql_module.le_lofp); + return_value->type = IS_LONG; + } +} +/* }}} */ + +/* {{{ proto void pg_loclose(int fd) + Close a large object */ +void php3_pgsql_lo_close(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *pgsql_lofp; + int id, type; + pgLofp *pgsql; + + switch(ARG_COUNT(ht)) { + case 1: + if (getParameters(ht, 1, &pgsql_lofp)==FAILURE) { + RETURN_FALSE; + } + convert_to_long(pgsql_lofp); + id = pgsql_lofp->value.lval; + break; + default: + WRONG_PARAM_COUNT; + break; + } + + pgsql = (pgLofp *) php3_list_find(id,&type); + if (type!=php3_pgsql_module.le_lofp) { + php3_error(E_WARNING,"%d is not a PostgresSQL large object index",id); + RETURN_FALSE; + } + + if (lo_close((PGconn *)pgsql->conn, pgsql->lofd)<0) { + php3_error(E_WARNING,"Unable to close PostgresSQL large object descriptor %d", pgsql->lofd); + RETVAL_FALSE; + } else { + RETVAL_TRUE; + } + php3_list_delete(id); + return; +} +/* }}} */ + +/* {{{ proto string pg_loread(int fd, int len) + Read a large object */ +void php3_pgsql_lo_read(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *pgsql_id, *len; + int id, buf_len, type, nbytes; + char *buf; + pgLofp *pgsql; + + switch(ARG_COUNT(ht)) { + case 2: + if (getParameters(ht, 2, &pgsql_id, &len)==FAILURE) { + RETURN_FALSE; + } + convert_to_long(pgsql_id); + id = pgsql_id->value.lval; + convert_to_long(len); + buf_len = len->value.lval; + break; + default: + WRONG_PARAM_COUNT; + break; + } + + pgsql = (pgLofp *) php3_list_find(id,&type); + if (type!=php3_pgsql_module.le_lofp) { + php3_error(E_WARNING,"%d is not a PostgresSQL large object index",id); + RETURN_FALSE; + } + + buf = (char *) emalloc(sizeof(char)*(buf_len+1)); + if ((nbytes = lo_read((PGconn *)pgsql->conn, pgsql->lofd, buf, buf_len))<0) { + efree(buf); + RETURN_FALSE; + } + return_value->value.str.val = buf; + return_value->value.str.len = nbytes; + return_value->value.str.val[nbytes] = 0; + return_value->type = IS_STRING; +} +/* }}} */ + +/* {{{ proto int pg_lowrite(int fd, string buf) + Write a large object */ +void php3_pgsql_lo_write(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *pgsql_id, *str; + int id, buf_len, nbytes, type; + char *buf; + pgLofp *pgsql; + + switch(ARG_COUNT(ht)) { + case 2: + if (getParameters(ht, 2, &pgsql_id, &str)==FAILURE) { + RETURN_FALSE; + } + convert_to_long(pgsql_id); + id = pgsql_id->value.lval; + convert_to_string(str); + buf = str->value.str.val; + break; + default: + WRONG_PARAM_COUNT; + break; + } + + pgsql = (pgLofp *) php3_list_find(id,&type); + if (type!=php3_pgsql_module.le_lofp) { + php3_error(E_WARNING,"%d is not a PostgresSQL large object index",id); + RETURN_FALSE; + } + + buf_len = str->value.str.len; + if ((nbytes = lo_write((PGconn *)pgsql->conn, pgsql->lofd, buf, buf_len))==-1) { + RETURN_FALSE; + } + return_value->value.lval = nbytes; + return_value->type = IS_LONG; +} +/* }}} */ + +/* {{{ proto void pg_loreadall(int fd) + Read a large object and send straight to browser */ +void php3_pgsql_lo_readall(INTERNAL_FUNCTION_PARAMETERS) +{ + pval *pgsql_id; + int i, id, tbytes, type; + volatile int nbytes; + char buf[8192]; + pgLofp *pgsql; + int output=1; + + switch(ARG_COUNT(ht)) { + case 1: + if (getParameters(ht, 1, &pgsql_id)==FAILURE) { + RETURN_FALSE; + } + convert_to_long(pgsql_id); + id = pgsql_id->value.lval; + break; + default: + WRONG_PARAM_COUNT; + break; + } + + pgsql = (pgLofp *) php3_list_find(id,&type); + if (type!=php3_pgsql_module.le_lofp) { + php3_error(E_WARNING,"%d is not a PostgresSQL large object index",id); + RETURN_FALSE; + } + + tbytes = 0; + while ((nbytes = lo_read((PGconn *)pgsql->conn, pgsql->lofd, buf, 8192))>0) { + for(i=0; i<nbytes; i++) { + if (output) PUTC(buf[i]); + } + tbytes += i; + } + return_value->value.lval = tbytes; + return_value->type = IS_LONG; +} +/* }}} */ + +#endif + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ |
