1/* 2 +----------------------------------------------------------------------+ 3 | PHP Version 5 | 4 +----------------------------------------------------------------------+ 5 | Copyright (c) 1997-2013 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: Zeev Suraski <zeev@zend.com> | 16 | Jouni Ahto <jouni.ahto@exdec.fi> | 17 | Yasuo Ohgaki <yohgaki@php.net> | 18 | Youichi Iwakiri <yiwakiri@st.rim.or.jp> (pg_copy_*) | 19 | Chris Kings-Lynne <chriskl@php.net> (v3 protocol) | 20 +----------------------------------------------------------------------+ 21 */ 22 23/* $Id$ */ 24 25#include <stdlib.h> 26 27#define PHP_PGSQL_PRIVATE 1 28 29#ifdef HAVE_CONFIG_H 30#include "config.h" 31#endif 32 33#define SMART_STR_PREALLOC 512 34 35#include "php.h" 36#include "php_ini.h" 37#include "ext/standard/php_standard.h" 38#include "ext/standard/php_smart_str.h" 39#include "ext/ereg/php_regex.h" 40 41#undef PACKAGE_BUGREPORT 42#undef PACKAGE_NAME 43#undef PACKAGE_STRING 44#undef PACKAGE_TARNAME 45#undef PACKAGE_VERSION 46#include "php_pgsql.h" 47#include "php_globals.h" 48#include "zend_exceptions.h" 49 50#if HAVE_PGSQL 51 52#ifndef InvalidOid 53#define InvalidOid ((Oid) 0) 54#endif 55 56#define PGSQL_ASSOC 1<<0 57#define PGSQL_NUM 1<<1 58#define PGSQL_BOTH (PGSQL_ASSOC|PGSQL_NUM) 59 60#define PGSQL_STATUS_LONG 1 61#define PGSQL_STATUS_STRING 2 62 63#define PGSQL_MAX_LENGTH_OF_LONG 30 64#define PGSQL_MAX_LENGTH_OF_DOUBLE 60 65 66#define PGSQL_RETURN_OID(oid) do { \ 67 if (oid > LONG_MAX) { \ 68 smart_str s = {0}; \ 69 smart_str_append_unsigned(&s, oid); \ 70 smart_str_0(&s); \ 71 RETURN_STRINGL(s.c, s.len, 0); \ 72 } \ 73 RETURN_LONG((long)oid); \ 74} while(0) 75 76 77#if HAVE_PQSETNONBLOCKING 78#define PQ_SETNONBLOCKING(pg_link, flag) PQsetnonblocking(pg_link, flag) 79#else 80#define PQ_SETNONBLOCKING(pg_link, flag) 0 81#endif 82 83#define CHECK_DEFAULT_LINK(x) if ((x) == -1) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "No PostgreSQL link opened yet"); } 84 85#ifndef HAVE_PQFREEMEM 86#define PQfreemem free 87#endif 88 89ZEND_DECLARE_MODULE_GLOBALS(pgsql) 90static PHP_GINIT_FUNCTION(pgsql); 91 92/* {{{ arginfo */ 93ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_connect, 0, 0, 1) 94 ZEND_ARG_INFO(0, connection_string) 95 ZEND_ARG_INFO(0, connect_type) 96 ZEND_ARG_INFO(0, host) 97 ZEND_ARG_INFO(0, port) 98 ZEND_ARG_INFO(0, options) 99 ZEND_ARG_INFO(0, tty) 100 ZEND_ARG_INFO(0, database) 101ZEND_END_ARG_INFO() 102 103ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_pconnect, 0, 0, 1) 104 ZEND_ARG_INFO(0, connection_string) 105 ZEND_ARG_INFO(0, host) 106 ZEND_ARG_INFO(0, port) 107 ZEND_ARG_INFO(0, options) 108 ZEND_ARG_INFO(0, tty) 109 ZEND_ARG_INFO(0, database) 110ZEND_END_ARG_INFO() 111 112#if HAVE_PQPARAMETERSTATUS 113ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_parameter_status, 0, 0, 1) 114 ZEND_ARG_INFO(0, connection) 115 ZEND_ARG_INFO(0, param_name) 116ZEND_END_ARG_INFO() 117#endif 118 119ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_close, 0, 0, 0) 120 ZEND_ARG_INFO(0, connection) 121ZEND_END_ARG_INFO() 122 123ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_dbname, 0, 0, 0) 124 ZEND_ARG_INFO(0, connection) 125ZEND_END_ARG_INFO() 126 127ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_last_error, 0, 0, 0) 128 ZEND_ARG_INFO(0, connection) 129ZEND_END_ARG_INFO() 130 131ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_options, 0, 0, 0) 132 ZEND_ARG_INFO(0, connection) 133ZEND_END_ARG_INFO() 134 135ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_port, 0, 0, 0) 136 ZEND_ARG_INFO(0, connection) 137ZEND_END_ARG_INFO() 138 139ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_tty, 0, 0, 0) 140 ZEND_ARG_INFO(0, connection) 141ZEND_END_ARG_INFO() 142 143ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_host, 0, 0, 0) 144 ZEND_ARG_INFO(0, connection) 145ZEND_END_ARG_INFO() 146 147ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_version, 0, 0, 0) 148 ZEND_ARG_INFO(0, connection) 149ZEND_END_ARG_INFO() 150 151ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_ping, 0, 0, 0) 152 ZEND_ARG_INFO(0, connection) 153ZEND_END_ARG_INFO() 154 155ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_query, 0, 0, 0) 156 ZEND_ARG_INFO(0, connection) 157 ZEND_ARG_INFO(0, query) 158ZEND_END_ARG_INFO() 159 160#if HAVE_PQEXECPARAMS 161ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_query_params, 0, 0, 0) 162 ZEND_ARG_INFO(0, connection) 163 ZEND_ARG_INFO(0, query) 164 ZEND_ARG_INFO(0, params) 165ZEND_END_ARG_INFO() 166#endif 167 168#if HAVE_PQPREPARE 169ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_prepare, 0, 0, 0) 170 ZEND_ARG_INFO(0, connection) 171 ZEND_ARG_INFO(0, stmtname) 172 ZEND_ARG_INFO(0, query) 173ZEND_END_ARG_INFO() 174#endif 175 176#if HAVE_PQEXECPREPARED 177ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_execute, 0, 0, 0) 178 ZEND_ARG_INFO(0, connection) 179 ZEND_ARG_INFO(0, stmtname) 180 ZEND_ARG_INFO(0, params) 181ZEND_END_ARG_INFO() 182#endif 183 184ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_num_rows, 0, 0, 1) 185 ZEND_ARG_INFO(0, result) 186ZEND_END_ARG_INFO() 187 188ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_num_fields, 0, 0, 1) 189 ZEND_ARG_INFO(0, result) 190ZEND_END_ARG_INFO() 191 192#if HAVE_PQCMDTUPLES 193ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_affected_rows, 0, 0, 1) 194 ZEND_ARG_INFO(0, result) 195ZEND_END_ARG_INFO() 196#endif 197 198ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_last_notice, 0, 0, 1) 199 ZEND_ARG_INFO(0, connection) 200ZEND_END_ARG_INFO() 201 202#ifdef HAVE_PQFTABLE 203ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_table, 0, 0, 2) 204 ZEND_ARG_INFO(0, result) 205 ZEND_ARG_INFO(0, field_number) 206 ZEND_ARG_INFO(0, oid_only) 207ZEND_END_ARG_INFO() 208#endif 209 210ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_name, 0, 0, 2) 211 ZEND_ARG_INFO(0, result) 212 ZEND_ARG_INFO(0, field_number) 213ZEND_END_ARG_INFO() 214 215ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_size, 0, 0, 2) 216 ZEND_ARG_INFO(0, result) 217 ZEND_ARG_INFO(0, field_number) 218ZEND_END_ARG_INFO() 219 220ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_type, 0, 0, 2) 221 ZEND_ARG_INFO(0, result) 222 ZEND_ARG_INFO(0, field_number) 223ZEND_END_ARG_INFO() 224 225ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_type_oid, 0, 0, 2) 226 ZEND_ARG_INFO(0, result) 227 ZEND_ARG_INFO(0, field_number) 228ZEND_END_ARG_INFO() 229 230ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_num, 0, 0, 2) 231 ZEND_ARG_INFO(0, result) 232 ZEND_ARG_INFO(0, field_name) 233ZEND_END_ARG_INFO() 234 235ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_result, 0, 0, 1) 236 ZEND_ARG_INFO(0, result) 237 ZEND_ARG_INFO(0, row_number) 238 ZEND_ARG_INFO(0, field_name) 239ZEND_END_ARG_INFO() 240 241ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_row, 0, 0, 1) 242 ZEND_ARG_INFO(0, result) 243 ZEND_ARG_INFO(0, row) 244 ZEND_ARG_INFO(0, result_type) 245ZEND_END_ARG_INFO() 246 247ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_assoc, 0, 0, 1) 248 ZEND_ARG_INFO(0, result) 249 ZEND_ARG_INFO(0, row) 250ZEND_END_ARG_INFO() 251 252ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_array, 0, 0, 1) 253 ZEND_ARG_INFO(0, result) 254 ZEND_ARG_INFO(0, row) 255 ZEND_ARG_INFO(0, result_type) 256ZEND_END_ARG_INFO() 257 258ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_object, 0, 0, 1) 259 ZEND_ARG_INFO(0, result) 260 ZEND_ARG_INFO(0, row) 261 ZEND_ARG_INFO(0, class_name) 262 ZEND_ARG_INFO(0, l) 263 ZEND_ARG_INFO(0, ctor_params) 264ZEND_END_ARG_INFO() 265 266ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_all, 0, 0, 1) 267 ZEND_ARG_INFO(0, result) 268ZEND_END_ARG_INFO() 269 270ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_all_columns, 0, 0, 1) 271 ZEND_ARG_INFO(0, result) 272 ZEND_ARG_INFO(0, column_number) 273ZEND_END_ARG_INFO() 274 275ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_result_seek, 0, 0, 2) 276 ZEND_ARG_INFO(0, result) 277 ZEND_ARG_INFO(0, offset) 278ZEND_END_ARG_INFO() 279 280ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_prtlen, 0, 0, 1) 281 ZEND_ARG_INFO(0, result) 282 ZEND_ARG_INFO(0, row) 283 ZEND_ARG_INFO(0, field_name_or_number) 284ZEND_END_ARG_INFO() 285 286ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_is_null, 0, 0, 1) 287 ZEND_ARG_INFO(0, result) 288 ZEND_ARG_INFO(0, row) 289 ZEND_ARG_INFO(0, field_name_or_number) 290ZEND_END_ARG_INFO() 291 292ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_free_result, 0, 0, 1) 293 ZEND_ARG_INFO(0, result) 294ZEND_END_ARG_INFO() 295 296ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_last_oid, 0, 0, 1) 297 ZEND_ARG_INFO(0, result) 298ZEND_END_ARG_INFO() 299 300ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_trace, 0, 0, 1) 301 ZEND_ARG_INFO(0, filename) 302 ZEND_ARG_INFO(0, mode) 303 ZEND_ARG_INFO(0, connection) 304ZEND_END_ARG_INFO() 305 306ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_untrace, 0, 0, 0) 307 ZEND_ARG_INFO(0, connection) 308ZEND_END_ARG_INFO() 309 310ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_create, 0, 0, 0) 311 ZEND_ARG_INFO(0, connection) 312 ZEND_ARG_INFO(0, large_object_id) 313ZEND_END_ARG_INFO() 314 315ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_unlink, 0, 0, 0) 316 ZEND_ARG_INFO(0, connection) 317 ZEND_ARG_INFO(0, large_object_oid) 318ZEND_END_ARG_INFO() 319 320ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_open, 0, 0, 0) 321 ZEND_ARG_INFO(0, connection) 322 ZEND_ARG_INFO(0, large_object_oid) 323 ZEND_ARG_INFO(0, mode) 324ZEND_END_ARG_INFO() 325 326ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_close, 0, 0, 1) 327 ZEND_ARG_INFO(0, large_object) 328ZEND_END_ARG_INFO() 329 330ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_read, 0, 0, 1) 331 ZEND_ARG_INFO(0, large_object) 332 ZEND_ARG_INFO(0, len) 333ZEND_END_ARG_INFO() 334 335ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_write, 0, 0, 2) 336 ZEND_ARG_INFO(0, large_object) 337 ZEND_ARG_INFO(0, buf) 338 ZEND_ARG_INFO(0, len) 339ZEND_END_ARG_INFO() 340 341ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_read_all, 0, 0, 1) 342 ZEND_ARG_INFO(0, large_object) 343ZEND_END_ARG_INFO() 344 345ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_import, 0, 0, 0) 346 ZEND_ARG_INFO(0, connection) 347 ZEND_ARG_INFO(0, filename) 348 ZEND_ARG_INFO(0, large_object_oid) 349ZEND_END_ARG_INFO() 350 351ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_export, 0, 0, 0) 352 ZEND_ARG_INFO(0, connection) 353 ZEND_ARG_INFO(0, objoid) 354 ZEND_ARG_INFO(0, filename) 355ZEND_END_ARG_INFO() 356 357ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_seek, 0, 0, 2) 358 ZEND_ARG_INFO(0, large_object) 359 ZEND_ARG_INFO(0, offset) 360 ZEND_ARG_INFO(0, whence) 361ZEND_END_ARG_INFO() 362 363ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_tell, 0, 0, 1) 364 ZEND_ARG_INFO(0, large_object) 365ZEND_END_ARG_INFO() 366 367#if HAVE_PQSETERRORVERBOSITY 368ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_set_error_verbosity, 0, 0, 0) 369 ZEND_ARG_INFO(0, connection) 370 ZEND_ARG_INFO(0, verbosity) 371ZEND_END_ARG_INFO() 372#endif 373 374#if HAVE_PQCLIENTENCODING 375ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_set_client_encoding, 0, 0, 0) 376 ZEND_ARG_INFO(0, connection) 377 ZEND_ARG_INFO(0, encoding) 378ZEND_END_ARG_INFO() 379 380ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_client_encoding, 0, 0, 0) 381 ZEND_ARG_INFO(0, connection) 382ZEND_END_ARG_INFO() 383#endif 384 385ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_end_copy, 0, 0, 0) 386 ZEND_ARG_INFO(0, connection) 387ZEND_END_ARG_INFO() 388 389ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_put_line, 0, 0, 0) 390 ZEND_ARG_INFO(0, connection) 391 ZEND_ARG_INFO(0, query) 392ZEND_END_ARG_INFO() 393 394ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_copy_to, 0, 0, 2) 395 ZEND_ARG_INFO(0, connection) 396 ZEND_ARG_INFO(0, table_name) 397 ZEND_ARG_INFO(0, delimiter) 398 ZEND_ARG_INFO(0, null_as) 399ZEND_END_ARG_INFO() 400 401ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_copy_from, 0, 0, 3) 402 ZEND_ARG_INFO(0, connection) 403 ZEND_ARG_INFO(0, table_name) 404 ZEND_ARG_INFO(0, rows) 405 ZEND_ARG_INFO(0, delimiter) 406 ZEND_ARG_INFO(0, null_as) 407ZEND_END_ARG_INFO() 408 409#if HAVE_PQESCAPE 410ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_escape_string, 0, 0, 0) 411 ZEND_ARG_INFO(0, connection) 412 ZEND_ARG_INFO(0, data) 413ZEND_END_ARG_INFO() 414 415ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_escape_bytea, 0, 0, 0) 416 ZEND_ARG_INFO(0, connection) 417 ZEND_ARG_INFO(0, data) 418ZEND_END_ARG_INFO() 419 420ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_unescape_bytea, 0, 0, 1) 421 ZEND_ARG_INFO(0, data) 422ZEND_END_ARG_INFO() 423#endif 424 425#if HAVE_PQESCAPE 426ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_escape_literal, 0, 0, 0) 427 ZEND_ARG_INFO(0, connection) 428 ZEND_ARG_INFO(0, data) 429ZEND_END_ARG_INFO() 430ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_escape_identifier, 0, 0, 0) 431 ZEND_ARG_INFO(0, connection) 432 ZEND_ARG_INFO(0, data) 433ZEND_END_ARG_INFO() 434#endif 435 436ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_result_error, 0, 0, 1) 437 ZEND_ARG_INFO(0, result) 438ZEND_END_ARG_INFO() 439 440#if HAVE_PQRESULTERRORFIELD 441ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_result_error_field, 0, 0, 2) 442 ZEND_ARG_INFO(0, result) 443 ZEND_ARG_INFO(0, fieldcode) 444ZEND_END_ARG_INFO() 445#endif 446 447ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_connection_status, 0, 0, 1) 448 ZEND_ARG_INFO(0, connection) 449ZEND_END_ARG_INFO() 450 451#if HAVE_PGTRANSACTIONSTATUS 452ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_transaction_status, 0, 0, 1) 453 ZEND_ARG_INFO(0, connection) 454ZEND_END_ARG_INFO() 455#endif 456 457ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_connection_reset, 0, 0, 1) 458 ZEND_ARG_INFO(0, connection) 459ZEND_END_ARG_INFO() 460 461ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_cancel_query, 0, 0, 1) 462 ZEND_ARG_INFO(0, connection) 463ZEND_END_ARG_INFO() 464 465ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_connection_busy, 0, 0, 1) 466 ZEND_ARG_INFO(0, connection) 467ZEND_END_ARG_INFO() 468 469ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_send_query, 0, 0, 2) 470 ZEND_ARG_INFO(0, connection) 471 ZEND_ARG_INFO(0, query) 472ZEND_END_ARG_INFO() 473 474#if HAVE_PQSENDQUERYPARAMS 475ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_send_query_params, 0, 0, 3) 476 ZEND_ARG_INFO(0, connection) 477 ZEND_ARG_INFO(0, query) 478 ZEND_ARG_INFO(0, params) 479ZEND_END_ARG_INFO() 480#endif 481 482#if HAVE_PQSENDPREPARE 483ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_send_prepare, 0, 0, 3) 484 ZEND_ARG_INFO(0, connection) 485 ZEND_ARG_INFO(0, stmtname) 486 ZEND_ARG_INFO(0, query) 487ZEND_END_ARG_INFO() 488#endif 489 490#if HAVE_PQSENDQUERYPREPARED 491ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_send_execute, 0, 0, 3) 492 ZEND_ARG_INFO(0, connection) 493 ZEND_ARG_INFO(0, stmtname) 494 ZEND_ARG_INFO(0, params) 495ZEND_END_ARG_INFO() 496#endif 497 498ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_get_result, 0, 0, 1) 499 ZEND_ARG_INFO(0, connection) 500ZEND_END_ARG_INFO() 501 502ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_result_status, 0, 0, 1) 503 ZEND_ARG_INFO(0, result) 504 ZEND_ARG_INFO(0, result_type) 505ZEND_END_ARG_INFO() 506 507ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_get_notify, 0, 0, 0) 508 ZEND_ARG_INFO(0, connection) 509 ZEND_ARG_INFO(0, e) 510ZEND_END_ARG_INFO() 511 512ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_get_pid, 0, 0, 0) 513 ZEND_ARG_INFO(0, connection) 514ZEND_END_ARG_INFO() 515 516ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_meta_data, 0, 0, 2) 517 ZEND_ARG_INFO(0, db) 518 ZEND_ARG_INFO(0, table) 519ZEND_END_ARG_INFO() 520 521ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_convert, 0, 0, 3) 522 ZEND_ARG_INFO(0, db) 523 ZEND_ARG_INFO(0, table) 524 ZEND_ARG_INFO(0, values) 525 ZEND_ARG_INFO(0, options) 526ZEND_END_ARG_INFO() 527 528ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_insert, 0, 0, 3) 529 ZEND_ARG_INFO(0, db) 530 ZEND_ARG_INFO(0, table) 531 ZEND_ARG_INFO(0, values) 532 ZEND_ARG_INFO(0, options) 533ZEND_END_ARG_INFO() 534 535ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_update, 0, 0, 4) 536 ZEND_ARG_INFO(0, db) 537 ZEND_ARG_INFO(0, table) 538 ZEND_ARG_INFO(0, fields) 539 ZEND_ARG_INFO(0, ids) 540 ZEND_ARG_INFO(0, options) 541ZEND_END_ARG_INFO() 542 543ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_delete, 0, 0, 3) 544 ZEND_ARG_INFO(0, db) 545 ZEND_ARG_INFO(0, table) 546 ZEND_ARG_INFO(0, ids) 547 ZEND_ARG_INFO(0, options) 548ZEND_END_ARG_INFO() 549 550ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_select, 0, 0, 3) 551 ZEND_ARG_INFO(0, db) 552 ZEND_ARG_INFO(0, table) 553 ZEND_ARG_INFO(0, ids) 554 ZEND_ARG_INFO(0, options) 555ZEND_END_ARG_INFO() 556/* }}} */ 557 558/* {{{ pgsql_functions[] 559 */ 560const zend_function_entry pgsql_functions[] = { 561 /* connection functions */ 562 PHP_FE(pg_connect, arginfo_pg_connect) 563 PHP_FE(pg_pconnect, arginfo_pg_pconnect) 564 PHP_FE(pg_close, arginfo_pg_close) 565 PHP_FE(pg_connection_status, arginfo_pg_connection_status) 566 PHP_FE(pg_connection_busy, arginfo_pg_connection_busy) 567 PHP_FE(pg_connection_reset, arginfo_pg_connection_reset) 568 PHP_FE(pg_host, arginfo_pg_host) 569 PHP_FE(pg_dbname, arginfo_pg_dbname) 570 PHP_FE(pg_port, arginfo_pg_port) 571 PHP_FE(pg_tty, arginfo_pg_tty) 572 PHP_FE(pg_options, arginfo_pg_options) 573 PHP_FE(pg_version, arginfo_pg_version) 574 PHP_FE(pg_ping, arginfo_pg_ping) 575#if HAVE_PQPARAMETERSTATUS 576 PHP_FE(pg_parameter_status, arginfo_pg_parameter_status) 577#endif 578#if HAVE_PGTRANSACTIONSTATUS 579 PHP_FE(pg_transaction_status, arginfo_pg_transaction_status) 580#endif 581 /* query functions */ 582 PHP_FE(pg_query, arginfo_pg_query) 583#if HAVE_PQEXECPARAMS 584 PHP_FE(pg_query_params, arginfo_pg_query_params) 585#endif 586#if HAVE_PQPREPARE 587 PHP_FE(pg_prepare, arginfo_pg_prepare) 588#endif 589#if HAVE_PQEXECPREPARED 590 PHP_FE(pg_execute, arginfo_pg_execute) 591#endif 592 PHP_FE(pg_send_query, arginfo_pg_send_query) 593#if HAVE_PQSENDQUERYPARAMS 594 PHP_FE(pg_send_query_params, arginfo_pg_send_query_params) 595#endif 596#if HAVE_PQSENDPREPARE 597 PHP_FE(pg_send_prepare, arginfo_pg_send_prepare) 598#endif 599#if HAVE_PQSENDQUERYPREPARED 600 PHP_FE(pg_send_execute, arginfo_pg_send_execute) 601#endif 602 PHP_FE(pg_cancel_query, arginfo_pg_cancel_query) 603 /* result functions */ 604 PHP_FE(pg_fetch_result, arginfo_pg_fetch_result) 605 PHP_FE(pg_fetch_row, arginfo_pg_fetch_row) 606 PHP_FE(pg_fetch_assoc, arginfo_pg_fetch_assoc) 607 PHP_FE(pg_fetch_array, arginfo_pg_fetch_array) 608 PHP_FE(pg_fetch_object, arginfo_pg_fetch_object) 609 PHP_FE(pg_fetch_all, arginfo_pg_fetch_all) 610 PHP_FE(pg_fetch_all_columns, arginfo_pg_fetch_all_columns) 611#if HAVE_PQCMDTUPLES 612 PHP_FE(pg_affected_rows,arginfo_pg_affected_rows) 613#endif 614 PHP_FE(pg_get_result, arginfo_pg_get_result) 615 PHP_FE(pg_result_seek, arginfo_pg_result_seek) 616 PHP_FE(pg_result_status,arginfo_pg_result_status) 617 PHP_FE(pg_free_result, arginfo_pg_free_result) 618 PHP_FE(pg_last_oid, arginfo_pg_last_oid) 619 PHP_FE(pg_num_rows, arginfo_pg_num_rows) 620 PHP_FE(pg_num_fields, arginfo_pg_num_fields) 621 PHP_FE(pg_field_name, arginfo_pg_field_name) 622 PHP_FE(pg_field_num, arginfo_pg_field_num) 623 PHP_FE(pg_field_size, arginfo_pg_field_size) 624 PHP_FE(pg_field_type, arginfo_pg_field_type) 625 PHP_FE(pg_field_type_oid, arginfo_pg_field_type_oid) 626 PHP_FE(pg_field_prtlen, arginfo_pg_field_prtlen) 627 PHP_FE(pg_field_is_null,arginfo_pg_field_is_null) 628#ifdef HAVE_PQFTABLE 629 PHP_FE(pg_field_table, arginfo_pg_field_table) 630#endif 631 /* async message function */ 632 PHP_FE(pg_get_notify, arginfo_pg_get_notify) 633 PHP_FE(pg_get_pid, arginfo_pg_get_pid) 634 /* error message functions */ 635 PHP_FE(pg_result_error, arginfo_pg_result_error) 636#if HAVE_PQRESULTERRORFIELD 637 PHP_FE(pg_result_error_field, arginfo_pg_result_error_field) 638#endif 639 PHP_FE(pg_last_error, arginfo_pg_last_error) 640 PHP_FE(pg_last_notice, arginfo_pg_last_notice) 641 /* copy functions */ 642 PHP_FE(pg_put_line, arginfo_pg_put_line) 643 PHP_FE(pg_end_copy, arginfo_pg_end_copy) 644 PHP_FE(pg_copy_to, arginfo_pg_copy_to) 645 PHP_FE(pg_copy_from, arginfo_pg_copy_from) 646 /* debug functions */ 647 PHP_FE(pg_trace, arginfo_pg_trace) 648 PHP_FE(pg_untrace, arginfo_pg_untrace) 649 /* large object functions */ 650 PHP_FE(pg_lo_create, arginfo_pg_lo_create) 651 PHP_FE(pg_lo_unlink, arginfo_pg_lo_unlink) 652 PHP_FE(pg_lo_open, arginfo_pg_lo_open) 653 PHP_FE(pg_lo_close, arginfo_pg_lo_close) 654 PHP_FE(pg_lo_read, arginfo_pg_lo_read) 655 PHP_FE(pg_lo_write, arginfo_pg_lo_write) 656 PHP_FE(pg_lo_read_all, arginfo_pg_lo_read_all) 657 PHP_FE(pg_lo_import, arginfo_pg_lo_import) 658 PHP_FE(pg_lo_export, arginfo_pg_lo_export) 659 PHP_FE(pg_lo_seek, arginfo_pg_lo_seek) 660 PHP_FE(pg_lo_tell, arginfo_pg_lo_tell) 661 /* utility functions */ 662#if HAVE_PQESCAPE 663 PHP_FE(pg_escape_string, arginfo_pg_escape_string) 664 PHP_FE(pg_escape_bytea, arginfo_pg_escape_bytea) 665 PHP_FE(pg_unescape_bytea, arginfo_pg_unescape_bytea) 666 PHP_FE(pg_escape_literal, arginfo_pg_escape_literal) 667 PHP_FE(pg_escape_identifier, arginfo_pg_escape_identifier) 668#endif 669#if HAVE_PQSETERRORVERBOSITY 670 PHP_FE(pg_set_error_verbosity, arginfo_pg_set_error_verbosity) 671#endif 672#if HAVE_PQCLIENTENCODING 673 PHP_FE(pg_client_encoding, arginfo_pg_client_encoding) 674 PHP_FE(pg_set_client_encoding, arginfo_pg_set_client_encoding) 675#endif 676 /* misc function */ 677 PHP_FE(pg_meta_data, arginfo_pg_meta_data) 678 PHP_FE(pg_convert, arginfo_pg_convert) 679 PHP_FE(pg_insert, arginfo_pg_insert) 680 PHP_FE(pg_update, arginfo_pg_update) 681 PHP_FE(pg_delete, arginfo_pg_delete) 682 PHP_FE(pg_select, arginfo_pg_select) 683 /* aliases for downwards compatibility */ 684 PHP_FALIAS(pg_exec, pg_query, arginfo_pg_query) 685 PHP_FALIAS(pg_getlastoid, pg_last_oid, arginfo_pg_last_oid) 686#if HAVE_PQCMDTUPLES 687 PHP_FALIAS(pg_cmdtuples, pg_affected_rows, arginfo_pg_affected_rows) 688#endif 689 PHP_FALIAS(pg_errormessage, pg_last_error, arginfo_pg_last_error) 690 PHP_FALIAS(pg_numrows, pg_num_rows, arginfo_pg_num_rows) 691 PHP_FALIAS(pg_numfields, pg_num_fields, arginfo_pg_num_fields) 692 PHP_FALIAS(pg_fieldname, pg_field_name, arginfo_pg_field_name) 693 PHP_FALIAS(pg_fieldsize, pg_field_size, arginfo_pg_field_size) 694 PHP_FALIAS(pg_fieldtype, pg_field_type, arginfo_pg_field_type) 695 PHP_FALIAS(pg_fieldnum, pg_field_num, arginfo_pg_field_num) 696 PHP_FALIAS(pg_fieldprtlen, pg_field_prtlen, arginfo_pg_field_prtlen) 697 PHP_FALIAS(pg_fieldisnull, pg_field_is_null, arginfo_pg_field_is_null) 698 PHP_FALIAS(pg_freeresult, pg_free_result, arginfo_pg_free_result) 699 PHP_FALIAS(pg_result, pg_fetch_result, arginfo_pg_get_result) 700 PHP_FALIAS(pg_loreadall, pg_lo_read_all, arginfo_pg_lo_read_all) 701 PHP_FALIAS(pg_locreate, pg_lo_create, arginfo_pg_lo_create) 702 PHP_FALIAS(pg_lounlink, pg_lo_unlink, arginfo_pg_lo_unlink) 703 PHP_FALIAS(pg_loopen, pg_lo_open, arginfo_pg_lo_open) 704 PHP_FALIAS(pg_loclose, pg_lo_close, arginfo_pg_lo_close) 705 PHP_FALIAS(pg_loread, pg_lo_read, arginfo_pg_lo_read) 706 PHP_FALIAS(pg_lowrite, pg_lo_write, arginfo_pg_lo_write) 707 PHP_FALIAS(pg_loimport, pg_lo_import, arginfo_pg_lo_import) 708 PHP_FALIAS(pg_loexport, pg_lo_export, arginfo_pg_lo_export) 709#if HAVE_PQCLIENTENCODING 710 PHP_FALIAS(pg_clientencoding, pg_client_encoding, arginfo_pg_client_encoding) 711 PHP_FALIAS(pg_setclientencoding, pg_set_client_encoding, arginfo_pg_set_client_encoding) 712#endif 713 PHP_FE_END 714}; 715/* }}} */ 716 717/* {{{ pgsql_module_entry 718 */ 719zend_module_entry pgsql_module_entry = { 720 STANDARD_MODULE_HEADER, 721 "pgsql", 722 pgsql_functions, 723 PHP_MINIT(pgsql), 724 PHP_MSHUTDOWN(pgsql), 725 PHP_RINIT(pgsql), 726 PHP_RSHUTDOWN(pgsql), 727 PHP_MINFO(pgsql), 728 NO_VERSION_YET, 729 PHP_MODULE_GLOBALS(pgsql), 730 PHP_GINIT(pgsql), 731 NULL, 732 NULL, 733 STANDARD_MODULE_PROPERTIES_EX 734}; 735/* }}} */ 736 737#ifdef COMPILE_DL_PGSQL 738ZEND_GET_MODULE(pgsql) 739#endif 740 741static int le_link, le_plink, le_result, le_lofp, le_string; 742 743/* {{{ _php_pgsql_trim_message */ 744static char * _php_pgsql_trim_message(const char *message, int *len) 745{ 746 register int i = strlen(message)-1; 747 748 if (i>1 && (message[i-1] == '\r' || message[i-1] == '\n') && message[i] == '.') { 749 --i; 750 } 751 while (i>0 && (message[i] == '\r' || message[i] == '\n')) { 752 --i; 753 } 754 ++i; 755 if (len) { 756 *len = i; 757 } 758 return estrndup(message, i); 759} 760/* }}} */ 761 762/* {{{ _php_pgsql_trim_result */ 763static inline char * _php_pgsql_trim_result(PGconn * pgsql, char **buf) 764{ 765 return *buf = _php_pgsql_trim_message(PQerrorMessage(pgsql), NULL); 766} 767/* }}} */ 768 769#define PQErrorMessageTrim(pgsql, buf) _php_pgsql_trim_result(pgsql, buf) 770 771#define PHP_PQ_ERROR(text, pgsql) { \ 772 char *msgbuf = _php_pgsql_trim_message(PQerrorMessage(pgsql), NULL); \ 773 php_error_docref(NULL TSRMLS_CC, E_WARNING, text, msgbuf); \ 774 efree(msgbuf); \ 775} \ 776 777/* {{{ php_pgsql_set_default_link 778 */ 779static void php_pgsql_set_default_link(int id TSRMLS_DC) 780{ 781 zend_list_addref(id); 782 783 if (PGG(default_link) != -1) { 784 zend_list_delete(PGG(default_link)); 785 } 786 787 PGG(default_link) = id; 788} 789/* }}} */ 790 791/* {{{ _close_pgsql_link 792 */ 793static void _close_pgsql_link(zend_rsrc_list_entry *rsrc TSRMLS_DC) 794{ 795 PGconn *link = (PGconn *)rsrc->ptr; 796 PGresult *res; 797 798 while ((res = PQgetResult(link))) { 799 PQclear(res); 800 } 801 PQfinish(link); 802 PGG(num_links)--; 803} 804/* }}} */ 805 806/* {{{ _close_pgsql_plink 807 */ 808static void _close_pgsql_plink(zend_rsrc_list_entry *rsrc TSRMLS_DC) 809{ 810 PGconn *link = (PGconn *)rsrc->ptr; 811 PGresult *res; 812 813 while ((res = PQgetResult(link))) { 814 PQclear(res); 815 } 816 PQfinish(link); 817 PGG(num_persistent)--; 818 PGG(num_links)--; 819} 820/* }}} */ 821 822/* {{{ _php_pgsql_notice_handler 823 */ 824static void _php_pgsql_notice_handler(void *resource_id, const char *message) 825{ 826 php_pgsql_notice *notice; 827 828 TSRMLS_FETCH(); 829 if (! PGG(ignore_notices)) { 830 notice = (php_pgsql_notice *)emalloc(sizeof(php_pgsql_notice)); 831 notice->message = _php_pgsql_trim_message(message, (int *)¬ice->len); 832 if (PGG(log_notices)) { 833 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "%s", notice->message); 834 } 835 zend_hash_index_update(&PGG(notices), (ulong)resource_id, (void **)¬ice, sizeof(php_pgsql_notice *), NULL); 836 } 837} 838/* }}} */ 839 840#define PHP_PGSQL_NOTICE_PTR_DTOR (void (*)(void *))_php_pgsql_notice_ptr_dtor 841 842/* {{{ _php_pgsql_notice_dtor 843 */ 844static void _php_pgsql_notice_ptr_dtor(void **ptr) 845{ 846 php_pgsql_notice *notice = (php_pgsql_notice *)*ptr; 847 if (notice) { 848 efree(notice->message); 849 efree(notice); 850 notice = NULL; 851 } 852} 853/* }}} */ 854 855/* {{{ _rollback_transactions 856 */ 857static int _rollback_transactions(zend_rsrc_list_entry *rsrc TSRMLS_DC) 858{ 859 PGconn *link; 860 PGresult *res; 861 int orig; 862 863 if (Z_TYPE_P(rsrc) != le_plink) 864 return 0; 865 866 link = (PGconn *) rsrc->ptr; 867 868 if (PQ_SETNONBLOCKING(link, 0)) { 869 php_error_docref("ref.pgsql" TSRMLS_CC, E_NOTICE, "Cannot set connection to blocking mode"); 870 return -1; 871 } 872 873 while ((res = PQgetResult(link))) { 874 PQclear(res); 875 } 876#if HAVE_PGTRANSACTIONSTATUS && HAVE_PQPROTOCOLVERSION 877 if ((PQprotocolVersion(link) >= 3 && PQtransactionStatus(link) != PQTRANS_IDLE) || PQprotocolVersion(link) < 3) 878#endif 879 { 880 orig = PGG(ignore_notices); 881 PGG(ignore_notices) = 1; 882#if HAVE_PGTRANSACTIONSTATUS && HAVE_PQPROTOCOLVERSION 883 res = PQexec(link,"ROLLBACK;"); 884#else 885 res = PQexec(link,"BEGIN;"); 886 PQclear(res); 887 res = PQexec(link,"ROLLBACK;"); 888#endif 889 PQclear(res); 890 PGG(ignore_notices) = orig; 891 } 892 893 return 0; 894} 895/* }}} */ 896 897/* {{{ _free_ptr 898 */ 899static void _free_ptr(zend_rsrc_list_entry *rsrc TSRMLS_DC) 900{ 901 pgLofp *lofp = (pgLofp *)rsrc->ptr; 902 efree(lofp); 903} 904/* }}} */ 905 906/* {{{ _free_result 907 */ 908static void _free_result(zend_rsrc_list_entry *rsrc TSRMLS_DC) 909{ 910 pgsql_result_handle *pg_result = (pgsql_result_handle *)rsrc->ptr; 911 912 PQclear(pg_result->result); 913 efree(pg_result); 914} 915/* }}} */ 916 917/* {{{ PHP_INI 918 */ 919PHP_INI_BEGIN() 920STD_PHP_INI_BOOLEAN( "pgsql.allow_persistent", "1", PHP_INI_SYSTEM, OnUpdateBool, allow_persistent, zend_pgsql_globals, pgsql_globals) 921STD_PHP_INI_ENTRY_EX("pgsql.max_persistent", "-1", PHP_INI_SYSTEM, OnUpdateLong, max_persistent, zend_pgsql_globals, pgsql_globals, display_link_numbers) 922STD_PHP_INI_ENTRY_EX("pgsql.max_links", "-1", PHP_INI_SYSTEM, OnUpdateLong, max_links, zend_pgsql_globals, pgsql_globals, display_link_numbers) 923STD_PHP_INI_BOOLEAN( "pgsql.auto_reset_persistent", "0", PHP_INI_SYSTEM, OnUpdateBool, auto_reset_persistent, zend_pgsql_globals, pgsql_globals) 924STD_PHP_INI_BOOLEAN( "pgsql.ignore_notice", "0", PHP_INI_ALL, OnUpdateBool, ignore_notices, zend_pgsql_globals, pgsql_globals) 925STD_PHP_INI_BOOLEAN( "pgsql.log_notice", "0", PHP_INI_ALL, OnUpdateBool, log_notices, zend_pgsql_globals, pgsql_globals) 926PHP_INI_END() 927/* }}} */ 928 929/* {{{ PHP_GINIT_FUNCTION 930 */ 931static PHP_GINIT_FUNCTION(pgsql) 932{ 933 memset(pgsql_globals, 0, sizeof(zend_pgsql_globals)); 934 /* Initilize notice message hash at MINIT only */ 935 zend_hash_init_ex(&pgsql_globals->notices, 0, NULL, PHP_PGSQL_NOTICE_PTR_DTOR, 1, 0); 936} 937/* }}} */ 938 939/* {{{ PHP_MINIT_FUNCTION 940 */ 941PHP_MINIT_FUNCTION(pgsql) 942{ 943 REGISTER_INI_ENTRIES(); 944 945 le_link = zend_register_list_destructors_ex(_close_pgsql_link, NULL, "pgsql link", module_number); 946 le_plink = zend_register_list_destructors_ex(NULL, _close_pgsql_plink, "pgsql link persistent", module_number); 947 le_result = zend_register_list_destructors_ex(_free_result, NULL, "pgsql result", module_number); 948 le_lofp = zend_register_list_destructors_ex(_free_ptr, NULL, "pgsql large object", module_number); 949 le_string = zend_register_list_destructors_ex(_free_ptr, NULL, "pgsql string", module_number); 950#if HAVE_PG_CONFIG_H 951 /* PG_VERSION - libpq version */ 952 REGISTER_STRING_CONSTANT("PGSQL_LIBPQ_VERSION", PG_VERSION, CONST_CS | CONST_PERSISTENT); 953 REGISTER_STRING_CONSTANT("PGSQL_LIBPQ_VERSION_STR", PG_VERSION_STR, CONST_CS | CONST_PERSISTENT); 954#endif 955 /* For connection option */ 956 REGISTER_LONG_CONSTANT("PGSQL_CONNECT_FORCE_NEW", PGSQL_CONNECT_FORCE_NEW, CONST_CS | CONST_PERSISTENT); 957 /* For pg_fetch_array() */ 958 REGISTER_LONG_CONSTANT("PGSQL_ASSOC", PGSQL_ASSOC, CONST_CS | CONST_PERSISTENT); 959 REGISTER_LONG_CONSTANT("PGSQL_NUM", PGSQL_NUM, CONST_CS | CONST_PERSISTENT); 960 REGISTER_LONG_CONSTANT("PGSQL_BOTH", PGSQL_BOTH, CONST_CS | CONST_PERSISTENT); 961 /* For pg_connection_status() */ 962 REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_BAD", CONNECTION_BAD, CONST_CS | CONST_PERSISTENT); 963 REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_OK", CONNECTION_OK, CONST_CS | CONST_PERSISTENT); 964#if HAVE_PGTRANSACTIONSTATUS 965 /* For pg_transaction_status() */ 966 REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_IDLE", PQTRANS_IDLE, CONST_CS | CONST_PERSISTENT); 967 REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_ACTIVE", PQTRANS_ACTIVE, CONST_CS | CONST_PERSISTENT); 968 REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_INTRANS", PQTRANS_INTRANS, CONST_CS | CONST_PERSISTENT); 969 REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_INERROR", PQTRANS_INERROR, CONST_CS | CONST_PERSISTENT); 970 REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_UNKNOWN", PQTRANS_UNKNOWN, CONST_CS | CONST_PERSISTENT); 971#endif 972#if HAVE_PQSETERRORVERBOSITY 973 /* For pg_set_error_verbosity() */ 974 REGISTER_LONG_CONSTANT("PGSQL_ERRORS_TERSE", PQERRORS_TERSE, CONST_CS | CONST_PERSISTENT); 975 REGISTER_LONG_CONSTANT("PGSQL_ERRORS_DEFAULT", PQERRORS_DEFAULT, CONST_CS | CONST_PERSISTENT); 976 REGISTER_LONG_CONSTANT("PGSQL_ERRORS_VERBOSE", PQERRORS_VERBOSE, CONST_CS | CONST_PERSISTENT); 977#endif 978 /* For lo_seek() */ 979 REGISTER_LONG_CONSTANT("PGSQL_SEEK_SET", SEEK_SET, CONST_CS | CONST_PERSISTENT); 980 REGISTER_LONG_CONSTANT("PGSQL_SEEK_CUR", SEEK_CUR, CONST_CS | CONST_PERSISTENT); 981 REGISTER_LONG_CONSTANT("PGSQL_SEEK_END", SEEK_END, CONST_CS | CONST_PERSISTENT); 982 /* For pg_result_status() return value type */ 983 REGISTER_LONG_CONSTANT("PGSQL_STATUS_LONG", PGSQL_STATUS_LONG, CONST_CS | CONST_PERSISTENT); 984 REGISTER_LONG_CONSTANT("PGSQL_STATUS_STRING", PGSQL_STATUS_STRING, CONST_CS | CONST_PERSISTENT); 985 /* For pg_result_status() return value */ 986 REGISTER_LONG_CONSTANT("PGSQL_EMPTY_QUERY", PGRES_EMPTY_QUERY, CONST_CS | CONST_PERSISTENT); 987 REGISTER_LONG_CONSTANT("PGSQL_COMMAND_OK", PGRES_COMMAND_OK, CONST_CS | CONST_PERSISTENT); 988 REGISTER_LONG_CONSTANT("PGSQL_TUPLES_OK", PGRES_TUPLES_OK, CONST_CS | CONST_PERSISTENT); 989 REGISTER_LONG_CONSTANT("PGSQL_COPY_OUT", PGRES_COPY_OUT, CONST_CS | CONST_PERSISTENT); 990 REGISTER_LONG_CONSTANT("PGSQL_COPY_IN", PGRES_COPY_IN, CONST_CS | CONST_PERSISTENT); 991 REGISTER_LONG_CONSTANT("PGSQL_BAD_RESPONSE", PGRES_BAD_RESPONSE, CONST_CS | CONST_PERSISTENT); 992 REGISTER_LONG_CONSTANT("PGSQL_NONFATAL_ERROR", PGRES_NONFATAL_ERROR, CONST_CS | CONST_PERSISTENT); 993 REGISTER_LONG_CONSTANT("PGSQL_FATAL_ERROR", PGRES_FATAL_ERROR, CONST_CS | CONST_PERSISTENT); 994#if HAVE_PQRESULTERRORFIELD 995 /* For pg_result_error_field() field codes */ 996 REGISTER_LONG_CONSTANT("PGSQL_DIAG_SEVERITY", PG_DIAG_SEVERITY, CONST_CS | CONST_PERSISTENT); 997 REGISTER_LONG_CONSTANT("PGSQL_DIAG_SQLSTATE", PG_DIAG_SQLSTATE, CONST_CS | CONST_PERSISTENT); 998 REGISTER_LONG_CONSTANT("PGSQL_DIAG_MESSAGE_PRIMARY", PG_DIAG_MESSAGE_PRIMARY, CONST_CS | CONST_PERSISTENT); 999 REGISTER_LONG_CONSTANT("PGSQL_DIAG_MESSAGE_DETAIL", PG_DIAG_MESSAGE_DETAIL, CONST_CS | CONST_PERSISTENT); 1000 REGISTER_LONG_CONSTANT("PGSQL_DIAG_MESSAGE_HINT", PG_DIAG_MESSAGE_HINT, CONST_CS | CONST_PERSISTENT); 1001 REGISTER_LONG_CONSTANT("PGSQL_DIAG_STATEMENT_POSITION", PG_DIAG_STATEMENT_POSITION, CONST_CS | CONST_PERSISTENT); 1002#ifdef PG_DIAG_INTERNAL_POSITION 1003 REGISTER_LONG_CONSTANT("PGSQL_DIAG_INTERNAL_POSITION", PG_DIAG_INTERNAL_POSITION, CONST_CS | CONST_PERSISTENT); 1004#endif 1005#ifdef PG_DIAG_INTERNAL_QUERY 1006 REGISTER_LONG_CONSTANT("PGSQL_DIAG_INTERNAL_QUERY", PG_DIAG_INTERNAL_QUERY, CONST_CS | CONST_PERSISTENT); 1007#endif 1008 REGISTER_LONG_CONSTANT("PGSQL_DIAG_CONTEXT", PG_DIAG_CONTEXT, CONST_CS | CONST_PERSISTENT); 1009 REGISTER_LONG_CONSTANT("PGSQL_DIAG_SOURCE_FILE", PG_DIAG_SOURCE_FILE, CONST_CS | CONST_PERSISTENT); 1010 REGISTER_LONG_CONSTANT("PGSQL_DIAG_SOURCE_LINE", PG_DIAG_SOURCE_LINE, CONST_CS | CONST_PERSISTENT); 1011 REGISTER_LONG_CONSTANT("PGSQL_DIAG_SOURCE_FUNCTION", PG_DIAG_SOURCE_FUNCTION, CONST_CS | CONST_PERSISTENT); 1012#endif 1013 /* pg_convert options */ 1014 REGISTER_LONG_CONSTANT("PGSQL_CONV_IGNORE_DEFAULT", PGSQL_CONV_IGNORE_DEFAULT, CONST_CS | CONST_PERSISTENT); 1015 REGISTER_LONG_CONSTANT("PGSQL_CONV_FORCE_NULL", PGSQL_CONV_FORCE_NULL, CONST_CS | CONST_PERSISTENT); 1016 REGISTER_LONG_CONSTANT("PGSQL_CONV_IGNORE_NOT_NULL", PGSQL_CONV_IGNORE_NOT_NULL, CONST_CS | CONST_PERSISTENT); 1017 /* pg_insert/update/delete/select options */ 1018 REGISTER_LONG_CONSTANT("PGSQL_DML_NO_CONV", PGSQL_DML_NO_CONV, CONST_CS | CONST_PERSISTENT); 1019 REGISTER_LONG_CONSTANT("PGSQL_DML_EXEC", PGSQL_DML_EXEC, CONST_CS | CONST_PERSISTENT); 1020 REGISTER_LONG_CONSTANT("PGSQL_DML_ASYNC", PGSQL_DML_ASYNC, CONST_CS | CONST_PERSISTENT); 1021 REGISTER_LONG_CONSTANT("PGSQL_DML_STRING", PGSQL_DML_STRING, CONST_CS | CONST_PERSISTENT); 1022 return SUCCESS; 1023} 1024/* }}} */ 1025 1026/* {{{ PHP_MSHUTDOWN_FUNCTION 1027 */ 1028PHP_MSHUTDOWN_FUNCTION(pgsql) 1029{ 1030 UNREGISTER_INI_ENTRIES(); 1031 zend_hash_destroy(&PGG(notices)); 1032 1033 return SUCCESS; 1034} 1035/* }}} */ 1036 1037/* {{{ PHP_RINIT_FUNCTION 1038 */ 1039PHP_RINIT_FUNCTION(pgsql) 1040{ 1041 PGG(default_link)=-1; 1042 PGG(num_links) = PGG(num_persistent); 1043 return SUCCESS; 1044} 1045/* }}} */ 1046 1047/* {{{ PHP_RSHUTDOWN_FUNCTION 1048 */ 1049PHP_RSHUTDOWN_FUNCTION(pgsql) 1050{ 1051 /* clean up notice messages */ 1052 zend_hash_clean(&PGG(notices)); 1053 /* clean up persistent connection */ 1054 zend_hash_apply(&EG(persistent_list), (apply_func_t) _rollback_transactions TSRMLS_CC); 1055 return SUCCESS; 1056} 1057/* }}} */ 1058 1059/* {{{ PHP_MINFO_FUNCTION 1060 */ 1061PHP_MINFO_FUNCTION(pgsql) 1062{ 1063 char buf[256]; 1064 1065 php_info_print_table_start(); 1066 php_info_print_table_header(2, "PostgreSQL Support", "enabled"); 1067#if HAVE_PG_CONFIG_H 1068 php_info_print_table_row(2, "PostgreSQL(libpq) Version", PG_VERSION); 1069 php_info_print_table_row(2, "PostgreSQL(libpq) ", PG_VERSION_STR); 1070#ifdef HAVE_PGSQL_WITH_MULTIBYTE_SUPPORT 1071 php_info_print_table_row(2, "Multibyte character support", "enabled"); 1072#else 1073 php_info_print_table_row(2, "Multibyte character support", "disabled"); 1074#endif 1075#ifdef USE_SSL 1076 php_info_print_table_row(2, "SSL support", "enabled"); 1077#else 1078 php_info_print_table_row(2, "SSL support", "disabled"); 1079#endif 1080#endif /* HAVE_PG_CONFIG_H */ 1081 snprintf(buf, sizeof(buf), "%ld", PGG(num_persistent)); 1082 php_info_print_table_row(2, "Active Persistent Links", buf); 1083 snprintf(buf, sizeof(buf), "%ld", PGG(num_links)); 1084 php_info_print_table_row(2, "Active Links", buf); 1085 php_info_print_table_end(); 1086 1087 DISPLAY_INI_ENTRIES(); 1088} 1089/* }}} */ 1090 1091 1092/* {{{ php_pgsql_do_connect 1093 */ 1094static void php_pgsql_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) 1095{ 1096 char *host=NULL,*port=NULL,*options=NULL,*tty=NULL,*dbname=NULL,*connstring=NULL; 1097 PGconn *pgsql; 1098 smart_str str = {0}; 1099 zval **args[5]; 1100 int i, connect_type = 0; 1101 PGresult *pg_result; 1102 1103 if (ZEND_NUM_ARGS() < 1 || ZEND_NUM_ARGS() > 5 1104 || zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args) == FAILURE) { 1105 WRONG_PARAM_COUNT; 1106 } 1107 1108 smart_str_appends(&str, "pgsql"); 1109 1110 for (i = 0; i < ZEND_NUM_ARGS(); i++) { 1111 /* make sure that the PGSQL_CONNECT_FORCE_NEW bit is not part of the hash so that subsequent connections 1112 * can re-use this connection. Bug #39979 1113 */ 1114 if (i == 1 && ZEND_NUM_ARGS() == 2 && Z_TYPE_PP(args[i]) == IS_LONG) { 1115 if (Z_LVAL_PP(args[1]) == PGSQL_CONNECT_FORCE_NEW) { 1116 continue; 1117 } else if (Z_LVAL_PP(args[1]) & PGSQL_CONNECT_FORCE_NEW) { 1118 smart_str_append_long(&str, Z_LVAL_PP(args[1]) ^ PGSQL_CONNECT_FORCE_NEW); 1119 } 1120 } 1121 convert_to_string_ex(args[i]); 1122 smart_str_appendc(&str, '_'); 1123 smart_str_appendl(&str, Z_STRVAL_PP(args[i]), Z_STRLEN_PP(args[i])); 1124 } 1125 1126 smart_str_0(&str); 1127 1128 if (ZEND_NUM_ARGS() == 1) { /* new style, using connection string */ 1129 connstring = Z_STRVAL_PP(args[0]); 1130 } else if (ZEND_NUM_ARGS() == 2 ) { /* Safe to add conntype_option, since 2 args was illegal */ 1131 connstring = Z_STRVAL_PP(args[0]); 1132 convert_to_long_ex(args[1]); 1133 connect_type = Z_LVAL_PP(args[1]); 1134 } else { 1135 host = Z_STRVAL_PP(args[0]); 1136 port = Z_STRVAL_PP(args[1]); 1137 dbname = Z_STRVAL_PP(args[ZEND_NUM_ARGS()-1]); 1138 1139 switch (ZEND_NUM_ARGS()) { 1140 case 5: 1141 tty = Z_STRVAL_PP(args[3]); 1142 /* fall through */ 1143 case 4: 1144 options = Z_STRVAL_PP(args[2]); 1145 break; 1146 } 1147 } 1148 1149 if (persistent && PGG(allow_persistent)) { 1150 zend_rsrc_list_entry *le; 1151 1152 /* try to find if we already have this link in our persistent list */ 1153 if (zend_hash_find(&EG(persistent_list), str.c, str.len+1, (void **) &le)==FAILURE) { /* we don't */ 1154 zend_rsrc_list_entry new_le; 1155 1156 if (PGG(max_links)!=-1 && PGG(num_links)>=PGG(max_links)) { 1157 php_error_docref(NULL TSRMLS_CC, E_WARNING, 1158 "Cannot create new link. Too many open links (%ld)", PGG(num_links)); 1159 goto err; 1160 } 1161 if (PGG(max_persistent)!=-1 && PGG(num_persistent)>=PGG(max_persistent)) { 1162 php_error_docref(NULL TSRMLS_CC, E_WARNING, 1163 "Cannot create new link. Too many open persistent links (%ld)", PGG(num_persistent)); 1164 goto err; 1165 } 1166 1167 /* create the link */ 1168 if (connstring) { 1169 pgsql=PQconnectdb(connstring); 1170 } else { 1171 pgsql=PQsetdb(host,port,options,tty,dbname); 1172 } 1173 if (pgsql==NULL || PQstatus(pgsql)==CONNECTION_BAD) { 1174 PHP_PQ_ERROR("Unable to connect to PostgreSQL server: %s", pgsql) 1175 if (pgsql) { 1176 PQfinish(pgsql); 1177 } 1178 goto err; 1179 } 1180 1181 /* hash it up */ 1182 Z_TYPE(new_le) = le_plink; 1183 new_le.ptr = pgsql; 1184 if (zend_hash_update(&EG(persistent_list), str.c, str.len+1, (void *) &new_le, sizeof(zend_rsrc_list_entry), NULL)==FAILURE) { 1185 goto err; 1186 } 1187 PGG(num_links)++; 1188 PGG(num_persistent)++; 1189 } else { /* we do */ 1190 if (Z_TYPE_P(le) != le_plink) { 1191 RETURN_FALSE; 1192 } 1193 /* ensure that the link did not die */ 1194 if (PGG(auto_reset_persistent) & 1) { 1195 /* need to send & get something from backend to 1196 make sure we catch CONNECTION_BAD everytime */ 1197 PGresult *pg_result; 1198 pg_result = PQexec(le->ptr, "select 1"); 1199 PQclear(pg_result); 1200 } 1201 if (PQstatus(le->ptr)==CONNECTION_BAD) { /* the link died */ 1202 if (le->ptr == NULL) { 1203 if (connstring) { 1204 le->ptr=PQconnectdb(connstring); 1205 } else { 1206 le->ptr=PQsetdb(host,port,options,tty,dbname); 1207 } 1208 } 1209 else { 1210 PQreset(le->ptr); 1211 } 1212 if (le->ptr==NULL || PQstatus(le->ptr)==CONNECTION_BAD) { 1213 php_error_docref(NULL TSRMLS_CC, E_WARNING,"PostgreSQL link lost, unable to reconnect"); 1214 zend_hash_del(&EG(persistent_list),str.c,str.len+1); 1215 goto err; 1216 } 1217 } 1218 pgsql = (PGconn *) le->ptr; 1219#if HAVE_PQPROTOCOLVERSION && HAVE_PQPARAMETERSTATUS 1220 if (PQprotocolVersion(pgsql) >= 3 && atof(PQparameterStatus(pgsql, "server_version")) >= 7.2) { 1221#else 1222 if (atof(PG_VERSION) >= 7.2) { 1223#endif 1224 pg_result = PQexec(pgsql, "RESET ALL;"); 1225 PQclear(pg_result); 1226 } 1227 } 1228 ZEND_REGISTER_RESOURCE(return_value, pgsql, le_plink); 1229 } else { /* Non persistent connection */ 1230 zend_rsrc_list_entry *index_ptr,new_index_ptr; 1231 1232 /* first we check the hash for the hashed_details key. if it exists, 1233 * it should point us to the right offset where the actual pgsql link sits. 1234 * if it doesn't, open a new pgsql link, add it to the resource list, 1235 * and add a pointer to it with hashed_details as the key. 1236 */ 1237 if (!(connect_type & PGSQL_CONNECT_FORCE_NEW) 1238 && zend_hash_find(&EG(regular_list),str.c,str.len+1,(void **) &index_ptr)==SUCCESS) { 1239 int type; 1240 ulong link; 1241 void *ptr; 1242 1243 if (Z_TYPE_P(index_ptr) != le_index_ptr) { 1244 RETURN_FALSE; 1245 } 1246 link = (ulong) index_ptr->ptr; 1247 ptr = zend_list_find(link,&type); /* check if the link is still there */ 1248 if (ptr && (type==le_link || type==le_plink)) { 1249 Z_LVAL_P(return_value) = link; 1250 zend_list_addref(link); 1251 php_pgsql_set_default_link(link TSRMLS_CC); 1252 Z_TYPE_P(return_value) = IS_RESOURCE; 1253 goto cleanup; 1254 } else { 1255 zend_hash_del(&EG(regular_list),str.c,str.len+1); 1256 } 1257 } 1258 if (PGG(max_links)!=-1 && PGG(num_links)>=PGG(max_links)) { 1259 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot create new link. Too many open links (%ld)", PGG(num_links)); 1260 goto err; 1261 } 1262 if (connstring) { 1263 pgsql = PQconnectdb(connstring); 1264 } else { 1265 pgsql = PQsetdb(host,port,options,tty,dbname); 1266 } 1267 if (pgsql==NULL || PQstatus(pgsql)==CONNECTION_BAD) { 1268 PHP_PQ_ERROR("Unable to connect to PostgreSQL server: %s", pgsql); 1269 if (pgsql) { 1270 PQfinish(pgsql); 1271 } 1272 goto err; 1273 } 1274 1275 /* add it to the list */ 1276 ZEND_REGISTER_RESOURCE(return_value, pgsql, le_link); 1277 1278 /* add it to the hash */ 1279 new_index_ptr.ptr = (void *) Z_LVAL_P(return_value); 1280 Z_TYPE(new_index_ptr) = le_index_ptr; 1281 if (zend_hash_update(&EG(regular_list),str.c,str.len+1,(void *) &new_index_ptr, sizeof(zend_rsrc_list_entry), NULL)==FAILURE) { 1282 goto err; 1283 } 1284 PGG(num_links)++; 1285 } 1286 /* set notice processer */ 1287 if (! PGG(ignore_notices) && Z_TYPE_P(return_value) == IS_RESOURCE) { 1288 PQsetNoticeProcessor(pgsql, _php_pgsql_notice_handler, (void*)Z_RESVAL_P(return_value)); 1289 } 1290 php_pgsql_set_default_link(Z_LVAL_P(return_value) TSRMLS_CC); 1291 1292cleanup: 1293 smart_str_free(&str); 1294 return; 1295 1296err: 1297 smart_str_free(&str); 1298 RETURN_FALSE; 1299} 1300/* }}} */ 1301 1302#if 0 1303/* {{{ php_pgsql_get_default_link 1304 */ 1305static int php_pgsql_get_default_link(INTERNAL_FUNCTION_PARAMETERS) 1306{ 1307 if (PGG(default_link)==-1) { /* no link opened yet, implicitly open one */ 1308 ht = 0; 1309 php_pgsql_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU,0); 1310 } 1311 return PGG(default_link); 1312} 1313/* }}} */ 1314#endif 1315 1316/* {{{ proto resource pg_connect(string connection_string[, int connect_type] | [string host, string port [, string options [, string tty,]]] string database) 1317 Open a PostgreSQL connection */ 1318PHP_FUNCTION(pg_connect) 1319{ 1320 php_pgsql_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU,0); 1321} 1322/* }}} */ 1323 1324/* {{{ proto resource pg_pconnect(string connection_string | [string host, string port [, string options [, string tty,]]] string database) 1325 Open a persistent PostgreSQL connection */ 1326PHP_FUNCTION(pg_pconnect) 1327{ 1328 php_pgsql_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU,1); 1329} 1330/* }}} */ 1331 1332/* {{{ proto bool pg_close([resource connection]) 1333 Close a PostgreSQL connection */ 1334PHP_FUNCTION(pg_close) 1335{ 1336 zval *pgsql_link = NULL; 1337 int id = -1, argc = ZEND_NUM_ARGS(); 1338 PGconn *pgsql; 1339 1340 if (zend_parse_parameters(argc TSRMLS_CC, "|r", &pgsql_link) == FAILURE) { 1341 return; 1342 } 1343 1344 if (argc == 0) { 1345 id = PGG(default_link); 1346 CHECK_DEFAULT_LINK(id); 1347 } 1348 1349 if (pgsql_link == NULL && id == -1) { 1350 RETURN_FALSE; 1351 } 1352 1353 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink); 1354 1355 if (id==-1) { /* explicit resource number */ 1356 zend_list_delete(Z_RESVAL_P(pgsql_link)); 1357 } 1358 1359 if (id!=-1 1360 || (pgsql_link && Z_RESVAL_P(pgsql_link)==PGG(default_link))) { 1361 zend_list_delete(PGG(default_link)); 1362 PGG(default_link) = -1; 1363 } 1364 1365 RETURN_TRUE; 1366} 1367/* }}} */ 1368 1369 1370#define PHP_PG_DBNAME 1 1371#define PHP_PG_ERROR_MESSAGE 2 1372#define PHP_PG_OPTIONS 3 1373#define PHP_PG_PORT 4 1374#define PHP_PG_TTY 5 1375#define PHP_PG_HOST 6 1376#define PHP_PG_VERSION 7 1377 1378/* {{{ php_pgsql_get_link_info 1379 */ 1380static void php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type) 1381{ 1382 zval *pgsql_link = NULL; 1383 int id = -1, argc = ZEND_NUM_ARGS(); 1384 PGconn *pgsql; 1385 char *msgbuf; 1386 1387 if (zend_parse_parameters(argc TSRMLS_CC, "|r", &pgsql_link) == FAILURE) { 1388 return; 1389 } 1390 1391 if (argc == 0) { 1392 id = PGG(default_link); 1393 CHECK_DEFAULT_LINK(id); 1394 } 1395 1396 if (pgsql_link == NULL && id == -1) { 1397 RETURN_FALSE; 1398 } 1399 1400 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink); 1401 1402 switch(entry_type) { 1403 case PHP_PG_DBNAME: 1404 Z_STRVAL_P(return_value) = PQdb(pgsql); 1405 break; 1406 case PHP_PG_ERROR_MESSAGE: 1407 RETURN_STRING(PQErrorMessageTrim(pgsql, &msgbuf), 0); 1408 return; 1409 case PHP_PG_OPTIONS: 1410 Z_STRVAL_P(return_value) = PQoptions(pgsql); 1411 break; 1412 case PHP_PG_PORT: 1413 Z_STRVAL_P(return_value) = PQport(pgsql); 1414 break; 1415 case PHP_PG_TTY: 1416 Z_STRVAL_P(return_value) = PQtty(pgsql); 1417 break; 1418 case PHP_PG_HOST: 1419 Z_STRVAL_P(return_value) = PQhost(pgsql); 1420 break; 1421 case PHP_PG_VERSION: 1422 array_init(return_value); 1423 add_assoc_string(return_value, "client", PG_VERSION, 1); 1424#if HAVE_PQPROTOCOLVERSION 1425 add_assoc_long(return_value, "protocol", PQprotocolVersion(pgsql)); 1426#if HAVE_PQPARAMETERSTATUS 1427 if (PQprotocolVersion(pgsql) >= 3) { 1428 add_assoc_string(return_value, "server", (char*)PQparameterStatus(pgsql, "server_version"), 1); 1429 } 1430#endif 1431#endif 1432 return; 1433 default: 1434 RETURN_FALSE; 1435 } 1436 if (Z_STRVAL_P(return_value)) { 1437 Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value)); 1438 Z_STRVAL_P(return_value) = (char *) estrdup(Z_STRVAL_P(return_value)); 1439 } else { 1440 Z_STRLEN_P(return_value) = 0; 1441 Z_STRVAL_P(return_value) = (char *) estrdup(""); 1442 } 1443 Z_TYPE_P(return_value) = IS_STRING; 1444} 1445/* }}} */ 1446 1447/* {{{ proto string pg_dbname([resource connection]) 1448 Get the database name */ 1449PHP_FUNCTION(pg_dbname) 1450{ 1451 php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_DBNAME); 1452} 1453/* }}} */ 1454 1455/* {{{ proto string pg_last_error([resource connection]) 1456 Get the error message string */ 1457PHP_FUNCTION(pg_last_error) 1458{ 1459 php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_ERROR_MESSAGE); 1460} 1461/* }}} */ 1462 1463/* {{{ proto string pg_options([resource connection]) 1464 Get the options associated with the connection */ 1465PHP_FUNCTION(pg_options) 1466{ 1467 php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_OPTIONS); 1468} 1469/* }}} */ 1470 1471/* {{{ proto int pg_port([resource connection]) 1472 Return the port number associated with the connection */ 1473PHP_FUNCTION(pg_port) 1474{ 1475 php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_PORT); 1476} 1477/* }}} */ 1478 1479/* {{{ proto string pg_tty([resource connection]) 1480 Return the tty name associated with the connection */ 1481PHP_FUNCTION(pg_tty) 1482{ 1483 php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_TTY); 1484} 1485/* }}} */ 1486 1487/* {{{ proto string pg_host([resource connection]) 1488 Returns the host name associated with the connection */ 1489PHP_FUNCTION(pg_host) 1490{ 1491 php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_HOST); 1492} 1493/* }}} */ 1494 1495/* {{{ proto array pg_version([resource connection]) 1496 Returns an array with client, protocol and server version (when available) */ 1497PHP_FUNCTION(pg_version) 1498{ 1499 php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_VERSION); 1500} 1501/* }}} */ 1502 1503#if HAVE_PQPARAMETERSTATUS 1504/* {{{ proto string|false pg_parameter_status([resource connection,] string param_name) 1505 Returns the value of a server parameter */ 1506PHP_FUNCTION(pg_parameter_status) 1507{ 1508 zval *pgsql_link; 1509 int id; 1510 PGconn *pgsql; 1511 char *param; 1512 int len; 1513 1514 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "rs", &pgsql_link, ¶m, &len) == SUCCESS) { 1515 id = -1; 1516 } else if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", ¶m, &len) == SUCCESS) { 1517 pgsql_link = NULL; 1518 id = PGG(default_link); 1519 } else { 1520 RETURN_FALSE; 1521 } 1522 if (pgsql_link == NULL && id == -1) { 1523 RETURN_FALSE; 1524 } 1525 1526 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink); 1527 1528 param = (char*)PQparameterStatus(pgsql, param); 1529 if (param) { 1530 RETURN_STRING(param, 1); 1531 } else { 1532 RETURN_FALSE; 1533 } 1534} 1535/* }}} */ 1536#endif 1537 1538/* {{{ proto bool pg_ping([resource connection]) 1539 Ping database. If connection is bad, try to reconnect. */ 1540PHP_FUNCTION(pg_ping) 1541{ 1542 zval *pgsql_link; 1543 int id; 1544 PGconn *pgsql; 1545 PGresult *res; 1546 1547 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r", &pgsql_link) == SUCCESS) { 1548 id = -1; 1549 } else { 1550 pgsql_link = NULL; 1551 id = PGG(default_link); 1552 } 1553 if (pgsql_link == NULL && id == -1) { 1554 RETURN_FALSE; 1555 } 1556 1557 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink); 1558 1559 /* ping connection */ 1560 res = PQexec(pgsql, "SELECT 1;"); 1561 PQclear(res); 1562 1563 /* check status. */ 1564 if (PQstatus(pgsql) == CONNECTION_OK) 1565 RETURN_TRUE; 1566 1567 /* reset connection if it's broken */ 1568 PQreset(pgsql); 1569 if (PQstatus(pgsql) == CONNECTION_OK) { 1570 RETURN_TRUE; 1571 } 1572 RETURN_FALSE; 1573} 1574/* }}} */ 1575 1576/* {{{ proto resource pg_query([resource connection,] string query) 1577 Execute a query */ 1578PHP_FUNCTION(pg_query) 1579{ 1580 zval *pgsql_link = NULL; 1581 char *query; 1582 int id = -1, query_len, argc = ZEND_NUM_ARGS(); 1583 int leftover = 0; 1584 PGconn *pgsql; 1585 PGresult *pgsql_result; 1586 ExecStatusType status; 1587 pgsql_result_handle *pg_result; 1588 1589 if (argc == 1) { 1590 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &query, &query_len) == FAILURE) { 1591 return; 1592 } 1593 id = PGG(default_link); 1594 CHECK_DEFAULT_LINK(id); 1595 } else { 1596 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &pgsql_link, &query, &query_len) == FAILURE) { 1597 return; 1598 } 1599 } 1600 1601 if (pgsql_link == NULL && id == -1) { 1602 RETURN_FALSE; 1603 } 1604 1605 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink); 1606 1607 if (PQ_SETNONBLOCKING(pgsql, 0)) { 1608 php_error_docref(NULL TSRMLS_CC, E_NOTICE,"Cannot set connection to blocking mode"); 1609 RETURN_FALSE; 1610 } 1611 while ((pgsql_result = PQgetResult(pgsql))) { 1612 PQclear(pgsql_result); 1613 leftover = 1; 1614 } 1615 if (leftover) { 1616 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Found results on this connection. Use pg_get_result() to get these results first"); 1617 } 1618 pgsql_result = PQexec(pgsql, query); 1619 if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) { 1620 PQclear(pgsql_result); 1621 PQreset(pgsql); 1622 pgsql_result = PQexec(pgsql, query); 1623 } 1624 1625 if (pgsql_result) { 1626 status = PQresultStatus(pgsql_result); 1627 } else { 1628 status = (ExecStatusType) PQstatus(pgsql); 1629 } 1630 1631 switch (status) { 1632 case PGRES_EMPTY_QUERY: 1633 case PGRES_BAD_RESPONSE: 1634 case PGRES_NONFATAL_ERROR: 1635 case PGRES_FATAL_ERROR: 1636 PHP_PQ_ERROR("Query failed: %s", pgsql); 1637 PQclear(pgsql_result); 1638 RETURN_FALSE; 1639 break; 1640 case PGRES_COMMAND_OK: /* successful command that did not return rows */ 1641 default: 1642 if (pgsql_result) { 1643 pg_result = (pgsql_result_handle *) emalloc(sizeof(pgsql_result_handle)); 1644 pg_result->conn = pgsql; 1645 pg_result->result = pgsql_result; 1646 pg_result->row = 0; 1647 ZEND_REGISTER_RESOURCE(return_value, pg_result, le_result); 1648 } else { 1649 PQclear(pgsql_result); 1650 RETURN_FALSE; 1651 } 1652 break; 1653 } 1654} 1655/* }}} */ 1656 1657#if HAVE_PQEXECPARAMS || HAVE_PQEXECPREPARED || HAVE_PQSENDQUERYPARAMS || HAVE_PQSENDQUERYPREPARED 1658/* {{{ _php_pgsql_free_params */ 1659static void _php_pgsql_free_params(char **params, int num_params) 1660{ 1661 if (num_params > 0) { 1662 int i; 1663 for (i = 0; i < num_params; i++) { 1664 if (params[i]) { 1665 efree(params[i]); 1666 } 1667 } 1668 efree(params); 1669 } 1670} 1671/* }}} */ 1672#endif 1673 1674#if HAVE_PQEXECPARAMS 1675/* {{{ proto resource pg_query_params([resource connection,] string query, array params) 1676 Execute a query */ 1677PHP_FUNCTION(pg_query_params) 1678{ 1679 zval *pgsql_link = NULL; 1680 zval *pv_param_arr, **tmp; 1681 char *query; 1682 int query_len, id = -1, argc = ZEND_NUM_ARGS(); 1683 int leftover = 0; 1684 int num_params = 0; 1685 char **params = NULL; 1686 PGconn *pgsql; 1687 PGresult *pgsql_result; 1688 ExecStatusType status; 1689 pgsql_result_handle *pg_result; 1690 1691 if (argc == 2) { 1692 if (zend_parse_parameters(argc TSRMLS_CC, "sa", &query, &query_len, &pv_param_arr) == FAILURE) { 1693 return; 1694 } 1695 id = PGG(default_link); 1696 CHECK_DEFAULT_LINK(id); 1697 } else { 1698 if (zend_parse_parameters(argc TSRMLS_CC, "rsa", &pgsql_link, &query, &query_len, &pv_param_arr) == FAILURE) { 1699 return; 1700 } 1701 } 1702 1703 if (pgsql_link == NULL && id == -1) { 1704 RETURN_FALSE; 1705 } 1706 1707 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink); 1708 1709 if (PQ_SETNONBLOCKING(pgsql, 0)) { 1710 php_error_docref(NULL TSRMLS_CC, E_NOTICE,"Cannot set connection to blocking mode"); 1711 RETURN_FALSE; 1712 } 1713 while ((pgsql_result = PQgetResult(pgsql))) { 1714 PQclear(pgsql_result); 1715 leftover = 1; 1716 } 1717 if (leftover) { 1718 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Found results on this connection. Use pg_get_result() to get these results first"); 1719 } 1720 1721 zend_hash_internal_pointer_reset(Z_ARRVAL_P(pv_param_arr)); 1722 num_params = zend_hash_num_elements(Z_ARRVAL_P(pv_param_arr)); 1723 if (num_params > 0) { 1724 int i = 0; 1725 params = (char **)safe_emalloc(sizeof(char *), num_params, 0); 1726 1727 for(i = 0; i < num_params; i++) { 1728 if (zend_hash_get_current_data(Z_ARRVAL_P(pv_param_arr), (void **) &tmp) == FAILURE) { 1729 php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error getting parameter"); 1730 _php_pgsql_free_params(params, num_params); 1731 RETURN_FALSE; 1732 } 1733 1734 if (Z_TYPE_PP(tmp) == IS_NULL) { 1735 params[i] = NULL; 1736 } else { 1737 zval tmp_val = **tmp; 1738 zval_copy_ctor(&tmp_val); 1739 convert_to_cstring(&tmp_val); 1740 if (Z_TYPE(tmp_val) != IS_STRING) { 1741 php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error converting parameter"); 1742 zval_dtor(&tmp_val); 1743 _php_pgsql_free_params(params, num_params); 1744 RETURN_FALSE; 1745 } 1746 params[i] = estrndup(Z_STRVAL(tmp_val), Z_STRLEN(tmp_val)); 1747 zval_dtor(&tmp_val); 1748 } 1749 1750 zend_hash_move_forward(Z_ARRVAL_P(pv_param_arr)); 1751 } 1752 } 1753 1754 pgsql_result = PQexecParams(pgsql, query, num_params, 1755 NULL, (const char * const *)params, NULL, NULL, 0); 1756 if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) { 1757 PQclear(pgsql_result); 1758 PQreset(pgsql); 1759 pgsql_result = PQexecParams(pgsql, query, num_params, 1760 NULL, (const char * const *)params, NULL, NULL, 0); 1761 } 1762 1763 if (pgsql_result) { 1764 status = PQresultStatus(pgsql_result); 1765 } else { 1766 status = (ExecStatusType) PQstatus(pgsql); 1767 } 1768 1769 _php_pgsql_free_params(params, num_params); 1770 1771 switch (status) { 1772 case PGRES_EMPTY_QUERY: 1773 case PGRES_BAD_RESPONSE: 1774 case PGRES_NONFATAL_ERROR: 1775 case PGRES_FATAL_ERROR: 1776 PHP_PQ_ERROR("Query failed: %s", pgsql); 1777 PQclear(pgsql_result); 1778 RETURN_FALSE; 1779 break; 1780 case PGRES_COMMAND_OK: /* successful command that did not return rows */ 1781 default: 1782 if (pgsql_result) { 1783 pg_result = (pgsql_result_handle *) emalloc(sizeof(pgsql_result_handle)); 1784 pg_result->conn = pgsql; 1785 pg_result->result = pgsql_result; 1786 pg_result->row = 0; 1787 ZEND_REGISTER_RESOURCE(return_value, pg_result, le_result); 1788 } else { 1789 PQclear(pgsql_result); 1790 RETURN_FALSE; 1791 } 1792 break; 1793 } 1794} 1795/* }}} */ 1796#endif 1797 1798#if HAVE_PQPREPARE 1799/* {{{ proto resource pg_prepare([resource connection,] string stmtname, string query) 1800 Prepare a query for future execution */ 1801PHP_FUNCTION(pg_prepare) 1802{ 1803 zval *pgsql_link = NULL; 1804 char *query, *stmtname; 1805 int query_len, stmtname_len, id = -1, argc = ZEND_NUM_ARGS(); 1806 int leftover = 0; 1807 PGconn *pgsql; 1808 PGresult *pgsql_result; 1809 ExecStatusType status; 1810 pgsql_result_handle *pg_result; 1811 1812 if (argc == 2) { 1813 if (zend_parse_parameters(argc TSRMLS_CC, "ss", &stmtname, &stmtname_len, &query, &query_len) == FAILURE) { 1814 return; 1815 } 1816 id = PGG(default_link); 1817 CHECK_DEFAULT_LINK(id); 1818 } else { 1819 if (zend_parse_parameters(argc TSRMLS_CC, "rss", &pgsql_link, &stmtname, &stmtname_len, &query, &query_len) == FAILURE) { 1820 return; 1821 } 1822 } 1823 1824 if (pgsql_link == NULL && id == -1) { 1825 RETURN_FALSE; 1826 } 1827 1828 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink); 1829 1830 if (PQ_SETNONBLOCKING(pgsql, 0)) { 1831 php_error_docref(NULL TSRMLS_CC, E_NOTICE,"Cannot set connection to blocking mode"); 1832 RETURN_FALSE; 1833 } 1834 while ((pgsql_result = PQgetResult(pgsql))) { 1835 PQclear(pgsql_result); 1836 leftover = 1; 1837 } 1838 if (leftover) { 1839 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Found results on this connection. Use pg_get_result() to get these results first"); 1840 } 1841 pgsql_result = PQprepare(pgsql, stmtname, query, 0, NULL); 1842 if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) { 1843 PQclear(pgsql_result); 1844 PQreset(pgsql); 1845 pgsql_result = PQprepare(pgsql, stmtname, query, 0, NULL); 1846 } 1847 1848 if (pgsql_result) { 1849 status = PQresultStatus(pgsql_result); 1850 } else { 1851 status = (ExecStatusType) PQstatus(pgsql); 1852 } 1853 1854 switch (status) { 1855 case PGRES_EMPTY_QUERY: 1856 case PGRES_BAD_RESPONSE: 1857 case PGRES_NONFATAL_ERROR: 1858 case PGRES_FATAL_ERROR: 1859 PHP_PQ_ERROR("Query failed: %s", pgsql); 1860 PQclear(pgsql_result); 1861 RETURN_FALSE; 1862 break; 1863 case PGRES_COMMAND_OK: /* successful command that did not return rows */ 1864 default: 1865 if (pgsql_result) { 1866 pg_result = (pgsql_result_handle *) emalloc(sizeof(pgsql_result_handle)); 1867 pg_result->conn = pgsql; 1868 pg_result->result = pgsql_result; 1869 pg_result->row = 0; 1870 ZEND_REGISTER_RESOURCE(return_value, pg_result, le_result); 1871 } else { 1872 PQclear(pgsql_result); 1873 RETURN_FALSE; 1874 } 1875 break; 1876 } 1877} 1878/* }}} */ 1879#endif 1880 1881#if HAVE_PQEXECPREPARED 1882/* {{{ proto resource pg_execute([resource connection,] string stmtname, array params) 1883 Execute a prepared query */ 1884PHP_FUNCTION(pg_execute) 1885{ 1886 zval *pgsql_link = NULL; 1887 zval *pv_param_arr, **tmp; 1888 char *stmtname; 1889 int stmtname_len, id = -1, argc = ZEND_NUM_ARGS(); 1890 int leftover = 0; 1891 int num_params = 0; 1892 char **params = NULL; 1893 PGconn *pgsql; 1894 PGresult *pgsql_result; 1895 ExecStatusType status; 1896 pgsql_result_handle *pg_result; 1897 1898 if (argc == 2) { 1899 if (zend_parse_parameters(argc TSRMLS_CC, "sa/", &stmtname, &stmtname_len, &pv_param_arr)==FAILURE) { 1900 return; 1901 } 1902 id = PGG(default_link); 1903 CHECK_DEFAULT_LINK(id); 1904 } else { 1905 if (zend_parse_parameters(argc TSRMLS_CC, "rsa/", &pgsql_link, &stmtname, &stmtname_len, &pv_param_arr) == FAILURE) { 1906 return; 1907 } 1908 } 1909 1910 if (pgsql_link == NULL && id == -1) { 1911 RETURN_FALSE; 1912 } 1913 1914 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink); 1915 1916 if (PQ_SETNONBLOCKING(pgsql, 0)) { 1917 php_error_docref(NULL TSRMLS_CC, E_NOTICE,"Cannot set connection to blocking mode"); 1918 RETURN_FALSE; 1919 } 1920 while ((pgsql_result = PQgetResult(pgsql))) { 1921 PQclear(pgsql_result); 1922 leftover = 1; 1923 } 1924 if (leftover) { 1925 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Found results on this connection. Use pg_get_result() to get these results first"); 1926 } 1927 1928 zend_hash_internal_pointer_reset(Z_ARRVAL_P(pv_param_arr)); 1929 num_params = zend_hash_num_elements(Z_ARRVAL_P(pv_param_arr)); 1930 if (num_params > 0) { 1931 int i = 0; 1932 params = (char **)safe_emalloc(sizeof(char *), num_params, 0); 1933 1934 for(i = 0; i < num_params; i++) { 1935 if (zend_hash_get_current_data(Z_ARRVAL_P(pv_param_arr), (void **) &tmp) == FAILURE) { 1936 php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error getting parameter"); 1937 _php_pgsql_free_params(params, num_params); 1938 RETURN_FALSE; 1939 } 1940 1941 if (Z_TYPE_PP(tmp) == IS_NULL) { 1942 params[i] = NULL; 1943 } else { 1944 zval tmp_val = **tmp; 1945 zval_copy_ctor(&tmp_val); 1946 convert_to_string(&tmp_val); 1947 if (Z_TYPE(tmp_val) != IS_STRING) { 1948 php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error converting parameter"); 1949 zval_dtor(&tmp_val); 1950 _php_pgsql_free_params(params, num_params); 1951 RETURN_FALSE; 1952 } 1953 params[i] = estrndup(Z_STRVAL(tmp_val), Z_STRLEN(tmp_val)); 1954 zval_dtor(&tmp_val); 1955 } 1956 1957 zend_hash_move_forward(Z_ARRVAL_P(pv_param_arr)); 1958 } 1959 } 1960 1961 pgsql_result = PQexecPrepared(pgsql, stmtname, num_params, 1962 (const char * const *)params, NULL, NULL, 0); 1963 if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) { 1964 PQclear(pgsql_result); 1965 PQreset(pgsql); 1966 pgsql_result = PQexecPrepared(pgsql, stmtname, num_params, 1967 (const char * const *)params, NULL, NULL, 0); 1968 } 1969 1970 if (pgsql_result) { 1971 status = PQresultStatus(pgsql_result); 1972 } else { 1973 status = (ExecStatusType) PQstatus(pgsql); 1974 } 1975 1976 _php_pgsql_free_params(params, num_params); 1977 1978 switch (status) { 1979 case PGRES_EMPTY_QUERY: 1980 case PGRES_BAD_RESPONSE: 1981 case PGRES_NONFATAL_ERROR: 1982 case PGRES_FATAL_ERROR: 1983 PHP_PQ_ERROR("Query failed: %s", pgsql); 1984 PQclear(pgsql_result); 1985 RETURN_FALSE; 1986 break; 1987 case PGRES_COMMAND_OK: /* successful command that did not return rows */ 1988 default: 1989 if (pgsql_result) { 1990 pg_result = (pgsql_result_handle *) emalloc(sizeof(pgsql_result_handle)); 1991 pg_result->conn = pgsql; 1992 pg_result->result = pgsql_result; 1993 pg_result->row = 0; 1994 ZEND_REGISTER_RESOURCE(return_value, pg_result, le_result); 1995 } else { 1996 PQclear(pgsql_result); 1997 RETURN_FALSE; 1998 } 1999 break; 2000 } 2001} 2002/* }}} */ 2003#endif 2004 2005#define PHP_PG_NUM_ROWS 1 2006#define PHP_PG_NUM_FIELDS 2 2007#define PHP_PG_CMD_TUPLES 3 2008 2009/* {{{ php_pgsql_get_result_info 2010 */ 2011static void php_pgsql_get_result_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type) 2012{ 2013 zval *result; 2014 PGresult *pgsql_result; 2015 pgsql_result_handle *pg_result; 2016 2017 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &result) == FAILURE) { 2018 return; 2019 } 2020 2021 ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result); 2022 2023 pgsql_result = pg_result->result; 2024 2025 switch (entry_type) { 2026 case PHP_PG_NUM_ROWS: 2027 Z_LVAL_P(return_value) = PQntuples(pgsql_result); 2028 break; 2029 case PHP_PG_NUM_FIELDS: 2030 Z_LVAL_P(return_value) = PQnfields(pgsql_result); 2031 break; 2032 case PHP_PG_CMD_TUPLES: 2033#if HAVE_PQCMDTUPLES 2034 Z_LVAL_P(return_value) = atoi(PQcmdTuples(pgsql_result)); 2035#else 2036 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Not supported under this build"); 2037 Z_LVAL_P(return_value) = 0; 2038#endif 2039 break; 2040 default: 2041 RETURN_FALSE; 2042 } 2043 Z_TYPE_P(return_value) = IS_LONG; 2044} 2045/* }}} */ 2046 2047/* {{{ proto int pg_num_rows(resource result) 2048 Return the number of rows in the result */ 2049PHP_FUNCTION(pg_num_rows) 2050{ 2051 php_pgsql_get_result_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_NUM_ROWS); 2052} 2053/* }}} */ 2054 2055/* {{{ proto int pg_num_fields(resource result) 2056 Return the number of fields in the result */ 2057PHP_FUNCTION(pg_num_fields) 2058{ 2059 php_pgsql_get_result_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_NUM_FIELDS); 2060} 2061/* }}} */ 2062 2063#if HAVE_PQCMDTUPLES 2064/* {{{ proto int pg_affected_rows(resource result) 2065 Returns the number of affected tuples */ 2066PHP_FUNCTION(pg_affected_rows) 2067{ 2068 php_pgsql_get_result_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_CMD_TUPLES); 2069} 2070/* }}} */ 2071#endif 2072 2073/* {{{ proto string pg_last_notice(resource connection) 2074 Returns the last notice set by the backend */ 2075PHP_FUNCTION(pg_last_notice) 2076{ 2077 zval *pgsql_link; 2078 PGconn *pg_link; 2079 int id = -1; 2080 php_pgsql_notice **notice; 2081 2082 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pgsql_link) == FAILURE) { 2083 return; 2084 } 2085 /* Just to check if user passed valid resoruce */ 2086 ZEND_FETCH_RESOURCE2(pg_link, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink); 2087 2088 if (zend_hash_index_find(&PGG(notices), Z_RESVAL_P(pgsql_link), (void **)¬ice) == FAILURE) { 2089 RETURN_FALSE; 2090 } 2091 RETURN_STRINGL((*notice)->message, (*notice)->len, 1); 2092} 2093/* }}} */ 2094 2095/* {{{ get_field_name 2096 */ 2097static char *get_field_name(PGconn *pgsql, Oid oid, HashTable *list TSRMLS_DC) 2098{ 2099 PGresult *result; 2100 smart_str str = {0}; 2101 zend_rsrc_list_entry *field_type; 2102 char *ret=NULL; 2103 2104 /* try to lookup the type in the resource list */ 2105 smart_str_appends(&str, "pgsql_oid_"); 2106 smart_str_append_unsigned(&str, oid); 2107 smart_str_0(&str); 2108 2109 if (zend_hash_find(list,str.c,str.len+1,(void **) &field_type)==SUCCESS) { 2110 ret = estrdup((char *)field_type->ptr); 2111 } else { /* hash all oid's */ 2112 int i,num_rows; 2113 int oid_offset,name_offset; 2114 char *tmp_oid, *end_ptr, *tmp_name; 2115 zend_rsrc_list_entry new_oid_entry; 2116 2117 if ((result = PQexec(pgsql,"select oid,typname from pg_type")) == NULL || PQresultStatus(result) != PGRES_TUPLES_OK) { 2118 if (result) { 2119 PQclear(result); 2120 } 2121 smart_str_free(&str); 2122 return STR_EMPTY_ALLOC(); 2123 } 2124 num_rows = PQntuples(result); 2125 oid_offset = PQfnumber(result,"oid"); 2126 name_offset = PQfnumber(result,"typname"); 2127 2128 for (i=0; i<num_rows; i++) { 2129 if ((tmp_oid = PQgetvalue(result,i,oid_offset))==NULL) { 2130 continue; 2131 } 2132 2133 str.len = 0; 2134 smart_str_appends(&str, "pgsql_oid_"); 2135 smart_str_appends(&str, tmp_oid); 2136 smart_str_0(&str); 2137 2138 if ((tmp_name = PQgetvalue(result,i,name_offset))==NULL) { 2139 continue; 2140 } 2141 Z_TYPE(new_oid_entry) = le_string; 2142 new_oid_entry.ptr = estrdup(tmp_name); 2143 zend_hash_update(list,str.c,str.len+1,(void *) &new_oid_entry, sizeof(zend_rsrc_list_entry), NULL); 2144 if (!ret && strtoul(tmp_oid, &end_ptr, 10)==oid) { 2145 ret = estrdup(tmp_name); 2146 } 2147 } 2148 PQclear(result); 2149 } 2150 2151 smart_str_free(&str); 2152 return ret; 2153} 2154/* }}} */ 2155 2156#ifdef HAVE_PQFTABLE 2157/* {{{ proto mixed pg_field_table(resource result, int field_number[, bool oid_only]) 2158 Returns the name of the table field belongs to, or table's oid if oid_only is true */ 2159PHP_FUNCTION(pg_field_table) 2160{ 2161 zval *result; 2162 pgsql_result_handle *pg_result; 2163 long fnum = -1; 2164 zend_bool return_oid = 0; 2165 Oid oid; 2166 smart_str hash_key = {0}; 2167 char *table_name; 2168 zend_rsrc_list_entry *field_table; 2169 2170 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl|b", &result, &fnum, &return_oid) == FAILURE) { 2171 return; 2172 } 2173 2174 ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result); 2175 2176 if (fnum < 0 || fnum >= PQnfields(pg_result->result)) { 2177 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad field offset specified"); 2178 RETURN_FALSE; 2179 } 2180 2181 oid = PQftable(pg_result->result, fnum); 2182 2183 if (InvalidOid == oid) { 2184 RETURN_FALSE; 2185 } 2186 2187 2188 if (return_oid) { 2189#if UINT_MAX > LONG_MAX /* Oid is unsigned int, we don't need this code, where LONG is wider */ 2190 if (oid > LONG_MAX) { 2191 smart_str oidstr = {0}; 2192 smart_str_append_unsigned(&oidstr, oid); 2193 smart_str_0(&oidstr); 2194 RETURN_STRINGL(oidstr.c, oidstr.len, 0); 2195 } else 2196#endif 2197 RETURN_LONG((long)oid); 2198 } 2199 2200 /* try to lookup the table name in the resource list */ 2201 smart_str_appends(&hash_key, "pgsql_table_oid_"); 2202 smart_str_append_unsigned(&hash_key, oid); 2203 smart_str_0(&hash_key); 2204 2205 if (zend_hash_find(&EG(regular_list), hash_key.c, hash_key.len+1, (void **) &field_table) == SUCCESS) { 2206 smart_str_free(&hash_key); 2207 RETURN_STRING((char *)field_table->ptr, 1); 2208 } else { /* Not found, lookup by querying PostgreSQL system tables */ 2209 PGresult *tmp_res; 2210 smart_str querystr = {0}; 2211 zend_rsrc_list_entry new_field_table; 2212 2213 smart_str_appends(&querystr, "select relname from pg_class where oid="); 2214 smart_str_append_unsigned(&querystr, oid); 2215 smart_str_0(&querystr); 2216 2217 2218 if ((tmp_res = PQexec(pg_result->conn, querystr.c)) == NULL || PQresultStatus(tmp_res) != PGRES_TUPLES_OK) { 2219 if (tmp_res) { 2220 PQclear(tmp_res); 2221 } 2222 smart_str_free(&querystr); 2223 smart_str_free(&hash_key); 2224 RETURN_FALSE; 2225 } 2226 2227 smart_str_free(&querystr); 2228 2229 if ((table_name = PQgetvalue(tmp_res, 0, 0)) == NULL) { 2230 PQclear(tmp_res); 2231 smart_str_free(&hash_key); 2232 RETURN_FALSE; 2233 } 2234 2235 Z_TYPE(new_field_table) = le_string; 2236 new_field_table.ptr = estrdup(table_name); 2237 zend_hash_update(&EG(regular_list), hash_key.c, hash_key.len+1, (void *) &new_field_table, sizeof(zend_rsrc_list_entry), NULL); 2238 2239 smart_str_free(&hash_key); 2240 PQclear(tmp_res); 2241 RETURN_STRING(table_name, 1); 2242 } 2243 2244} 2245/* }}} */ 2246#endif 2247 2248#define PHP_PG_FIELD_NAME 1 2249#define PHP_PG_FIELD_SIZE 2 2250#define PHP_PG_FIELD_TYPE 3 2251#define PHP_PG_FIELD_TYPE_OID 4 2252 2253/* {{{ php_pgsql_get_field_info 2254 */ 2255static void php_pgsql_get_field_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type) 2256{ 2257 zval *result; 2258 long field; 2259 PGresult *pgsql_result; 2260 pgsql_result_handle *pg_result; 2261 Oid oid; 2262 2263 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &result, &field) == FAILURE) { 2264 return; 2265 } 2266 2267 ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result); 2268 2269 pgsql_result = pg_result->result; 2270 2271 if (field < 0 || field >= PQnfields(pgsql_result)) { 2272 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad field offset specified"); 2273 RETURN_FALSE; 2274 } 2275 2276 switch (entry_type) { 2277 case PHP_PG_FIELD_NAME: 2278 Z_STRVAL_P(return_value) = PQfname(pgsql_result, field); 2279 Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value)); 2280 Z_STRVAL_P(return_value) = estrndup(Z_STRVAL_P(return_value),Z_STRLEN_P(return_value)); 2281 Z_TYPE_P(return_value) = IS_STRING; 2282 break; 2283 case PHP_PG_FIELD_SIZE: 2284 Z_LVAL_P(return_value) = PQfsize(pgsql_result, field); 2285 Z_TYPE_P(return_value) = IS_LONG; 2286 break; 2287 case PHP_PG_FIELD_TYPE: 2288 Z_STRVAL_P(return_value) = get_field_name(pg_result->conn, PQftype(pgsql_result, field), &EG(regular_list) TSRMLS_CC); 2289 Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value)); 2290 Z_TYPE_P(return_value) = IS_STRING; 2291 break; 2292 case PHP_PG_FIELD_TYPE_OID: 2293 2294 oid = PQftype(pgsql_result, field); 2295#if UINT_MAX > LONG_MAX 2296 if (oid > LONG_MAX) { 2297 smart_str s = {0}; 2298 smart_str_append_unsigned(&s, oid); 2299 smart_str_0(&s); 2300 Z_STRVAL_P(return_value) = s.c; 2301 Z_STRLEN_P(return_value) = s.len; 2302 Z_TYPE_P(return_value) = IS_STRING; 2303 } else 2304#endif 2305 { 2306 Z_LVAL_P(return_value) = (long)oid; 2307 Z_TYPE_P(return_value) = IS_LONG; 2308 } 2309 break; 2310 default: 2311 RETURN_FALSE; 2312 } 2313} 2314/* }}} */ 2315 2316/* {{{ proto string pg_field_name(resource result, int field_number) 2317 Returns the name of the field */ 2318PHP_FUNCTION(pg_field_name) 2319{ 2320 php_pgsql_get_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_FIELD_NAME); 2321} 2322/* }}} */ 2323 2324/* {{{ proto int pg_field_size(resource result, int field_number) 2325 Returns the internal size of the field */ 2326PHP_FUNCTION(pg_field_size) 2327{ 2328 php_pgsql_get_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_FIELD_SIZE); 2329} 2330/* }}} */ 2331 2332/* {{{ proto string pg_field_type(resource result, int field_number) 2333 Returns the type name for the given field */ 2334PHP_FUNCTION(pg_field_type) 2335{ 2336 php_pgsql_get_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_FIELD_TYPE); 2337} 2338/* }}} */ 2339 2340 2341/* {{{ proto string pg_field_type_oid(resource result, int field_number) 2342 Returns the type oid for the given field */ 2343PHP_FUNCTION(pg_field_type_oid) 2344{ 2345 php_pgsql_get_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_FIELD_TYPE_OID); 2346} 2347/* }}} */ 2348 2349/* {{{ proto int pg_field_num(resource result, string field_name) 2350 Returns the field number of the named field */ 2351PHP_FUNCTION(pg_field_num) 2352{ 2353 zval *result; 2354 char *field; 2355 int field_len; 2356 PGresult *pgsql_result; 2357 pgsql_result_handle *pg_result; 2358 2359 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &result, &field, &field_len) == FAILURE) { 2360 return; 2361 } 2362 2363 ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result); 2364 2365 pgsql_result = pg_result->result; 2366 2367 Z_LVAL_P(return_value) = PQfnumber(pgsql_result, field); 2368 Z_TYPE_P(return_value) = IS_LONG; 2369} 2370/* }}} */ 2371 2372/* {{{ proto mixed pg_fetch_result(resource result, [int row_number,] mixed field_name) 2373 Returns values from a result identifier */ 2374PHP_FUNCTION(pg_fetch_result) 2375{ 2376 zval *result, **field=NULL; 2377 long row; 2378 PGresult *pgsql_result; 2379 pgsql_result_handle *pg_result; 2380 int field_offset, pgsql_row, argc = ZEND_NUM_ARGS(); 2381 2382 if (argc == 2) { 2383 if (zend_parse_parameters(argc TSRMLS_CC, "rZ", &result, &field) == FAILURE) { 2384 return; 2385 } 2386 } else { 2387 if (zend_parse_parameters(argc TSRMLS_CC, "rlZ", &result, &row, &field) == FAILURE) { 2388 return; 2389 } 2390 } 2391 2392 ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result); 2393 2394 pgsql_result = pg_result->result; 2395 if (argc == 2) { 2396 if (pg_result->row < 0) { 2397 pg_result->row = 0; 2398 } 2399 pgsql_row = pg_result->row; 2400 if (pgsql_row >= PQntuples(pgsql_result)) { 2401 RETURN_FALSE; 2402 } 2403 } else { 2404 pgsql_row = row; 2405 if (pgsql_row < 0 || pgsql_row >= PQntuples(pgsql_result)) { 2406 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to jump to row %ld on PostgreSQL result index %ld", 2407 row, Z_LVAL_P(result)); 2408 RETURN_FALSE; 2409 } 2410 } 2411 switch(Z_TYPE_PP(field)) { 2412 case IS_STRING: 2413 field_offset = PQfnumber(pgsql_result, Z_STRVAL_PP(field)); 2414 break; 2415 default: 2416 convert_to_long_ex(field); 2417 field_offset = Z_LVAL_PP(field); 2418 break; 2419 } 2420 if (field_offset<0 || field_offset>=PQnfields(pgsql_result)) { 2421 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad column offset specified"); 2422 RETURN_FALSE; 2423 } 2424 2425 if (PQgetisnull(pgsql_result, pgsql_row, field_offset)) { 2426 Z_TYPE_P(return_value) = IS_NULL; 2427 } else { 2428 char *value = PQgetvalue(pgsql_result, pgsql_row, field_offset); 2429 int value_len = PQgetlength(pgsql_result, pgsql_row, field_offset); 2430 ZVAL_STRINGL(return_value, value, value_len, 1); 2431 } 2432} 2433/* }}} */ 2434 2435/* {{{ void php_pgsql_fetch_hash */ 2436static void php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, long result_type, int into_object) 2437{ 2438 zval *result, *zrow = NULL; 2439 PGresult *pgsql_result; 2440 pgsql_result_handle *pg_result; 2441 int i, num_fields, pgsql_row, use_row; 2442 long row = -1; 2443 char *field_name; 2444 zval *ctor_params = NULL; 2445 zend_class_entry *ce = NULL; 2446 2447 if (into_object) { 2448 char *class_name = NULL; 2449 int class_name_len; 2450 2451 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|z!sz", &result, &zrow, &class_name, &class_name_len, &ctor_params) == FAILURE) { 2452 return; 2453 } 2454 if (!class_name) { 2455 ce = zend_standard_class_def; 2456 } else { 2457 ce = zend_fetch_class(class_name, class_name_len, ZEND_FETCH_CLASS_AUTO TSRMLS_CC); 2458 } 2459 if (!ce) { 2460 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not find class '%s'", class_name); 2461 return; 2462 } 2463 result_type = PGSQL_ASSOC; 2464 } else { 2465 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|z!l", &result, &zrow, &result_type) == FAILURE) { 2466 return; 2467 } 2468 } 2469 if (zrow == NULL) { 2470 row = -1; 2471 } else { 2472 convert_to_long(zrow); 2473 row = Z_LVAL_P(zrow); 2474 if (row < 0) { 2475 php_error_docref(NULL TSRMLS_CC, E_WARNING, "The row parameter must be greater or equal to zero"); 2476 RETURN_FALSE; 2477 } 2478 } 2479 use_row = ZEND_NUM_ARGS() > 1 && row != -1; 2480 2481 if (!(result_type & PGSQL_BOTH)) { 2482 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid result type"); 2483 RETURN_FALSE; 2484 } 2485 2486 ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result); 2487 2488 pgsql_result = pg_result->result; 2489 2490 if (use_row) { 2491 pgsql_row = row; 2492 pg_result->row = pgsql_row; 2493 if (pgsql_row < 0 || pgsql_row >= PQntuples(pgsql_result)) { 2494 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to jump to row %ld on PostgreSQL result index %ld", 2495 row, Z_LVAL_P(result)); 2496 RETURN_FALSE; 2497 } 2498 } else { 2499 /* If 2nd param is NULL, use internal row counter to access next row */ 2500 pgsql_row = pg_result->row; 2501 if (pgsql_row < 0 || pgsql_row >= PQntuples(pgsql_result)) { 2502 RETURN_FALSE; 2503 } 2504 pg_result->row++; 2505 } 2506 2507 array_init(return_value); 2508 for (i = 0, num_fields = PQnfields(pgsql_result); i < num_fields; i++) { 2509 if (PQgetisnull(pgsql_result, pgsql_row, i)) { 2510 if (result_type & PGSQL_NUM) { 2511 add_index_null(return_value, i); 2512 } 2513 if (result_type & PGSQL_ASSOC) { 2514 field_name = PQfname(pgsql_result, i); 2515 add_assoc_null(return_value, field_name); 2516 } 2517 } else { 2518 char *element = PQgetvalue(pgsql_result, pgsql_row, i); 2519 if (element) { 2520 char *data; 2521 int data_len; 2522 int should_copy=0; 2523 const uint element_len = strlen(element); 2524 2525 data = safe_estrndup(element, element_len); 2526 data_len = element_len; 2527 2528 if (result_type & PGSQL_NUM) { 2529 add_index_stringl(return_value, i, data, data_len, should_copy); 2530 should_copy=1; 2531 } 2532 2533 if (result_type & PGSQL_ASSOC) { 2534 field_name = PQfname(pgsql_result, i); 2535 add_assoc_stringl(return_value, field_name, data, data_len, should_copy); 2536 } 2537 } 2538 } 2539 } 2540 2541 if (into_object) { 2542 zval dataset = *return_value; 2543 zend_fcall_info fci; 2544 zend_fcall_info_cache fcc; 2545 zval *retval_ptr; 2546 2547 object_and_properties_init(return_value, ce, NULL); 2548 zend_merge_properties(return_value, Z_ARRVAL(dataset), 1 TSRMLS_CC); 2549 2550 if (ce->constructor) { 2551 fci.size = sizeof(fci); 2552 fci.function_table = &ce->function_table; 2553 fci.function_name = NULL; 2554 fci.symbol_table = NULL; 2555 fci.object_ptr = return_value; 2556 fci.retval_ptr_ptr = &retval_ptr; 2557 if (ctor_params && Z_TYPE_P(ctor_params) != IS_NULL) { 2558 if (Z_TYPE_P(ctor_params) == IS_ARRAY) { 2559 HashTable *ht = Z_ARRVAL_P(ctor_params); 2560 Bucket *p; 2561 2562 fci.param_count = 0; 2563 fci.params = safe_emalloc(sizeof(zval*), ht->nNumOfElements, 0); 2564 p = ht->pListHead; 2565 while (p != NULL) { 2566 fci.params[fci.param_count++] = (zval**)p->pData; 2567 p = p->pListNext; 2568 } 2569 } else { 2570 /* Two problems why we throw exceptions here: PHP is typeless 2571 * and hence passing one argument that's not an array could be 2572 * by mistake and the other way round is possible, too. The 2573 * single value is an array. Also we'd have to make that one 2574 * argument passed by reference. 2575 */ 2576 zend_throw_exception(zend_exception_get_default(TSRMLS_C), "Parameter ctor_params must be an array", 0 TSRMLS_CC); 2577 return; 2578 } 2579 } else { 2580 fci.param_count = 0; 2581 fci.params = NULL; 2582 } 2583 fci.no_separation = 1; 2584 2585 fcc.initialized = 1; 2586 fcc.function_handler = ce->constructor; 2587 fcc.calling_scope = EG(scope); 2588 fcc.called_scope = Z_OBJCE_P(return_value); 2589 fcc.object_ptr = return_value; 2590 2591 if (zend_call_function(&fci, &fcc TSRMLS_CC) == FAILURE) { 2592 zend_throw_exception_ex(zend_exception_get_default(TSRMLS_C), 0 TSRMLS_CC, "Could not execute %s::%s()", ce->name, ce->constructor->common.function_name); 2593 } else { 2594 if (retval_ptr) { 2595 zval_ptr_dtor(&retval_ptr); 2596 } 2597 } 2598 if (fci.params) { 2599 efree(fci.params); 2600 } 2601 } else if (ctor_params) { 2602 zend_throw_exception_ex(zend_exception_get_default(TSRMLS_C), 0 TSRMLS_CC, "Class %s does not have a constructor hence you cannot use ctor_params", ce->name); 2603 } 2604 } 2605} 2606/* }}} */ 2607 2608/* {{{ proto array pg_fetch_row(resource result [, int row [, int result_type]]) 2609 Get a row as an enumerated array */ 2610PHP_FUNCTION(pg_fetch_row) 2611{ 2612 php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, PGSQL_NUM, 0); 2613} 2614/* }}} */ 2615 2616/* {{{ proto array pg_fetch_assoc(resource result [, int row]) 2617 Fetch a row as an assoc array */ 2618PHP_FUNCTION(pg_fetch_assoc) 2619{ 2620 /* pg_fetch_assoc() is added from PHP 4.3.0. It should raise error, when 2621 there is 3rd parameter */ 2622 if (ZEND_NUM_ARGS() > 2) 2623 WRONG_PARAM_COUNT; 2624 php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, PGSQL_ASSOC, 0); 2625} 2626/* }}} */ 2627 2628/* {{{ proto array pg_fetch_array(resource result [, int row [, int result_type]]) 2629 Fetch a row as an array */ 2630PHP_FUNCTION(pg_fetch_array) 2631{ 2632 php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, PGSQL_BOTH, 0); 2633} 2634/* }}} */ 2635 2636/* {{{ proto object pg_fetch_object(resource result [, int row [, string class_name [, NULL|array ctor_params]]]) 2637 Fetch a row as an object */ 2638PHP_FUNCTION(pg_fetch_object) 2639{ 2640 /* pg_fetch_object() allowed result_type used to be. 3rd parameter 2641 must be allowed for compatibility */ 2642 php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, PGSQL_ASSOC, 1); 2643} 2644/* }}} */ 2645 2646/* {{{ proto array pg_fetch_all(resource result) 2647 Fetch all rows into array */ 2648PHP_FUNCTION(pg_fetch_all) 2649{ 2650 zval *result; 2651 PGresult *pgsql_result; 2652 pgsql_result_handle *pg_result; 2653 2654 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &result) == FAILURE) { 2655 return; 2656 } 2657 2658 ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result); 2659 2660 pgsql_result = pg_result->result; 2661 array_init(return_value); 2662 if (php_pgsql_result2array(pgsql_result, return_value TSRMLS_CC) == FAILURE) { 2663 zval_dtor(return_value); 2664 RETURN_FALSE; 2665 } 2666} 2667/* }}} */ 2668 2669/* {{{ proto array pg_fetch_all_columns(resource result [, int column_number]) 2670 Fetch all rows into array */ 2671PHP_FUNCTION(pg_fetch_all_columns) 2672{ 2673 zval *result; 2674 PGresult *pgsql_result; 2675 pgsql_result_handle *pg_result; 2676 unsigned long colno=0; 2677 int pg_numrows, pg_row; 2678 size_t num_fields; 2679 2680 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &result, &colno) == FAILURE) { 2681 RETURN_FALSE; 2682 } 2683 2684 ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result); 2685 2686 pgsql_result = pg_result->result; 2687 2688 num_fields = PQnfields(pgsql_result); 2689 if (colno >= num_fields || colno < 0) { 2690 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid column number '%ld'", colno); 2691 RETURN_FALSE; 2692 } 2693 2694 array_init(return_value); 2695 2696 if ((pg_numrows = PQntuples(pgsql_result)) <= 0) { 2697 return; 2698 } 2699 2700 for (pg_row = 0; pg_row < pg_numrows; pg_row++) { 2701 if (PQgetisnull(pgsql_result, pg_row, colno)) { 2702 add_next_index_null(return_value); 2703 } else { 2704 add_next_index_string(return_value, PQgetvalue(pgsql_result, pg_row, colno), 1); 2705 } 2706 } 2707} 2708/* }}} */ 2709 2710/* {{{ proto bool pg_result_seek(resource result, int offset) 2711 Set internal row offset */ 2712PHP_FUNCTION(pg_result_seek) 2713{ 2714 zval *result; 2715 long row; 2716 pgsql_result_handle *pg_result; 2717 2718 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &result, &row) == FAILURE) { 2719 return; 2720 } 2721 2722 ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result); 2723 2724 if (row < 0 || row >= PQntuples(pg_result->result)) { 2725 RETURN_FALSE; 2726 } 2727 2728 /* seek to offset */ 2729 pg_result->row = row; 2730 RETURN_TRUE; 2731} 2732/* }}} */ 2733 2734 2735#define PHP_PG_DATA_LENGTH 1 2736#define PHP_PG_DATA_ISNULL 2 2737 2738/* {{{ php_pgsql_data_info 2739 */ 2740static void php_pgsql_data_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type) 2741{ 2742 zval *result, **field; 2743 long row; 2744 PGresult *pgsql_result; 2745 pgsql_result_handle *pg_result; 2746 int field_offset, pgsql_row, argc = ZEND_NUM_ARGS(); 2747 2748 if (argc == 2) { 2749 if (zend_parse_parameters(argc TSRMLS_CC, "rZ", &result, &field) == FAILURE) { 2750 return; 2751 } 2752 } else { 2753 if (zend_parse_parameters(argc TSRMLS_CC, "rlZ", &result, &row, &field) == FAILURE) { 2754 return; 2755 } 2756 } 2757 2758 ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result); 2759 2760 pgsql_result = pg_result->result; 2761 if (argc == 2) { 2762 if (pg_result->row < 0) { 2763 pg_result->row = 0; 2764 } 2765 pgsql_row = pg_result->row; 2766 if (pgsql_row < 0 || pgsql_row >= PQntuples(pgsql_result)) { 2767 RETURN_FALSE; 2768 } 2769 } else { 2770 pgsql_row = row; 2771 if (pgsql_row < 0 || pgsql_row >= PQntuples(pgsql_result)) { 2772 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to jump to row %ld on PostgreSQL result index %ld", 2773 row, Z_LVAL_P(result)); 2774 RETURN_FALSE; 2775 } 2776 } 2777 2778 switch(Z_TYPE_PP(field)) { 2779 case IS_STRING: 2780 convert_to_string_ex(field); 2781 field_offset = PQfnumber(pgsql_result, Z_STRVAL_PP(field)); 2782 break; 2783 default: 2784 convert_to_long_ex(field); 2785 field_offset = Z_LVAL_PP(field); 2786 break; 2787 } 2788 if (field_offset < 0 || field_offset >= PQnfields(pgsql_result)) { 2789 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad column offset specified"); 2790 RETURN_FALSE; 2791 } 2792 2793 switch (entry_type) { 2794 case PHP_PG_DATA_LENGTH: 2795 Z_LVAL_P(return_value) = PQgetlength(pgsql_result, pgsql_row, field_offset); 2796 break; 2797 case PHP_PG_DATA_ISNULL: 2798 Z_LVAL_P(return_value) = PQgetisnull(pgsql_result, pgsql_row, field_offset); 2799 break; 2800 } 2801 Z_TYPE_P(return_value) = IS_LONG; 2802} 2803/* }}} */ 2804 2805/* {{{ proto int pg_field_prtlen(resource result, [int row,] mixed field_name_or_number) 2806 Returns the printed length */ 2807PHP_FUNCTION(pg_field_prtlen) 2808{ 2809 php_pgsql_data_info(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_PG_DATA_LENGTH); 2810} 2811/* }}} */ 2812 2813/* {{{ proto int pg_field_is_null(resource result, [int row,] mixed field_name_or_number) 2814 Test if a field is NULL */ 2815PHP_FUNCTION(pg_field_is_null) 2816{ 2817 php_pgsql_data_info(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_PG_DATA_ISNULL); 2818} 2819/* }}} */ 2820 2821/* {{{ proto bool pg_free_result(resource result) 2822 Free result memory */ 2823PHP_FUNCTION(pg_free_result) 2824{ 2825 zval *result; 2826 pgsql_result_handle *pg_result; 2827 2828 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &result) == FAILURE) { 2829 return; 2830 } 2831 2832 ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result); 2833 if (Z_LVAL_P(result) == 0) { 2834 RETURN_FALSE; 2835 } 2836 zend_list_delete(Z_RESVAL_P(result)); 2837 RETURN_TRUE; 2838} 2839/* }}} */ 2840 2841/* {{{ proto string pg_last_oid(resource result) 2842 Returns the last object identifier */ 2843PHP_FUNCTION(pg_last_oid) 2844{ 2845 zval *result; 2846 PGresult *pgsql_result; 2847 pgsql_result_handle *pg_result; 2848#ifdef HAVE_PQOIDVALUE 2849 Oid oid; 2850#endif 2851 2852 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &result) == FAILURE) { 2853 return; 2854 } 2855 2856 ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result); 2857 pgsql_result = pg_result->result; 2858#ifdef HAVE_PQOIDVALUE 2859 oid = PQoidValue(pgsql_result); 2860 if (oid == InvalidOid) { 2861 RETURN_FALSE; 2862 } 2863 PGSQL_RETURN_OID(oid); 2864#else 2865 Z_STRVAL_P(return_value) = (char *) PQoidStatus(pgsql_result); 2866 if (Z_STRVAL_P(return_value)) { 2867 RETURN_STRING(Z_STRVAL_P(return_value), 1); 2868 } 2869 RETURN_STRING("", 1); 2870#endif 2871} 2872/* }}} */ 2873 2874/* {{{ proto bool pg_trace(string filename [, string mode [, resource connection]]) 2875 Enable tracing a PostgreSQL connection */ 2876PHP_FUNCTION(pg_trace) 2877{ 2878 char *z_filename, *mode = "w"; 2879 int z_filename_len, mode_len; 2880 zval *pgsql_link = NULL; 2881 int id = -1, argc = ZEND_NUM_ARGS(); 2882 PGconn *pgsql; 2883 FILE *fp = NULL; 2884 php_stream *stream; 2885 id = PGG(default_link); 2886 2887 if (zend_parse_parameters(argc TSRMLS_CC, "s|sr", &z_filename, &z_filename_len, &mode, &mode_len, &pgsql_link) == FAILURE) { 2888 return; 2889 } 2890 2891 if (argc < 3) { 2892 CHECK_DEFAULT_LINK(id); 2893 } 2894 2895 if (pgsql_link == NULL && id == -1) { 2896 RETURN_FALSE; 2897 } 2898 2899 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink); 2900 2901 stream = php_stream_open_wrapper(z_filename, mode, REPORT_ERRORS, NULL); 2902 2903 if (!stream) { 2904 RETURN_FALSE; 2905 } 2906 2907 if (FAILURE == php_stream_cast(stream, PHP_STREAM_AS_STDIO, (void**)&fp, REPORT_ERRORS)) { 2908 php_stream_close(stream); 2909 RETURN_FALSE; 2910 } 2911 php_stream_auto_cleanup(stream); 2912 PQtrace(pgsql, fp); 2913 RETURN_TRUE; 2914} 2915/* }}} */ 2916 2917/* {{{ proto bool pg_untrace([resource connection]) 2918 Disable tracing of a PostgreSQL connection */ 2919PHP_FUNCTION(pg_untrace) 2920{ 2921 zval *pgsql_link = NULL; 2922 int id = -1, argc = ZEND_NUM_ARGS(); 2923 PGconn *pgsql; 2924 2925 if (zend_parse_parameters(argc TSRMLS_CC, "|r", &pgsql_link) == FAILURE) { 2926 return; 2927 } 2928 2929 if (argc == 0) { 2930 id = PGG(default_link); 2931 CHECK_DEFAULT_LINK(id); 2932 } 2933 2934 if (pgsql_link == NULL && id == -1) { 2935 RETURN_FALSE; 2936 } 2937 2938 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink); 2939 PQuntrace(pgsql); 2940 RETURN_TRUE; 2941} 2942/* }}} */ 2943 2944/* {{{ proto mixed pg_lo_create([resource connection],[mixed large_object_oid]) 2945 Create a large object */ 2946PHP_FUNCTION(pg_lo_create) 2947{ 2948 zval *pgsql_link = NULL, *oid = NULL; 2949 PGconn *pgsql; 2950 Oid pgsql_oid, wanted_oid = InvalidOid; 2951 int id = -1, argc = ZEND_NUM_ARGS(); 2952 2953 if (zend_parse_parameters(argc TSRMLS_CC, "|zz", &pgsql_link, &oid) == FAILURE) { 2954 return; 2955 } 2956 2957 if ((argc == 1) && (Z_TYPE_P(pgsql_link) != IS_RESOURCE)) { 2958 oid = pgsql_link; 2959 pgsql_link = NULL; 2960 } 2961 2962 if (pgsql_link == NULL) { 2963 id = PGG(default_link); 2964 CHECK_DEFAULT_LINK(id); 2965 if (id == -1) { 2966 RETURN_FALSE; 2967 } 2968 } 2969 2970 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink); 2971 2972 if (oid) { 2973#ifndef HAVE_PG_LO_CREATE 2974 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "OID value passing not supported"); 2975#else 2976 switch (Z_TYPE_P(oid)) { 2977 case IS_STRING: 2978 { 2979 char *end_ptr; 2980 wanted_oid = (Oid)strtoul(Z_STRVAL_P(oid), &end_ptr, 10); 2981 if ((Z_STRVAL_P(oid)+Z_STRLEN_P(oid)) != end_ptr) { 2982 /* wrong integer format */ 2983 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "invalid OID value passed"); 2984 RETURN_FALSE; 2985 } 2986 } 2987 break; 2988 case IS_LONG: 2989 if (Z_LVAL_P(oid) < (long)InvalidOid) { 2990 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "invalid OID value passed"); 2991 RETURN_FALSE; 2992 } 2993 wanted_oid = (Oid)Z_LVAL_P(oid); 2994 break; 2995 default: 2996 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "invalid OID value passed"); 2997 RETURN_FALSE; 2998 } 2999 if ((pgsql_oid = lo_create(pgsql, wanted_oid)) == InvalidOid) { 3000 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create PostgreSQL large object"); 3001 RETURN_FALSE; 3002 } 3003 3004 PGSQL_RETURN_OID(pgsql_oid); 3005#endif 3006 } 3007 3008 if ((pgsql_oid = lo_creat(pgsql, INV_READ|INV_WRITE)) == InvalidOid) { 3009 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create PostgreSQL large object"); 3010 RETURN_FALSE; 3011 } 3012 3013 PGSQL_RETURN_OID(pgsql_oid); 3014} 3015/* }}} */ 3016 3017/* {{{ proto bool pg_lo_unlink([resource connection,] string large_object_oid) 3018 Delete a large object */ 3019PHP_FUNCTION(pg_lo_unlink) 3020{ 3021 zval *pgsql_link = NULL; 3022 long oid_long; 3023 char *oid_string, *end_ptr; 3024 int oid_strlen; 3025 PGconn *pgsql; 3026 Oid oid; 3027 int id = -1; 3028 int argc = ZEND_NUM_ARGS(); 3029 3030 /* accept string type since Oid type is unsigned int */ 3031 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC, 3032 "rs", &pgsql_link, &oid_string, &oid_strlen) == SUCCESS) { 3033 oid = (Oid)strtoul(oid_string, &end_ptr, 10); 3034 if ((oid_string+oid_strlen) != end_ptr) { 3035 /* wrong integer format */ 3036 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Wrong OID value passed"); 3037 RETURN_FALSE; 3038 } 3039 } 3040 else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC, 3041 "rl", &pgsql_link, &oid_long) == SUCCESS) { 3042 if (oid_long <= InvalidOid) { 3043 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Invalid OID specified"); 3044 RETURN_FALSE; 3045 } 3046 oid = (Oid)oid_long; 3047 } 3048 else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC, 3049 "s", &oid_string, &oid_strlen) == SUCCESS) { 3050 oid = (Oid)strtoul(oid_string, &end_ptr, 10); 3051 if ((oid_string+oid_strlen) != end_ptr) { 3052 /* wrong integer format */ 3053 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Wrong OID value passed"); 3054 RETURN_FALSE; 3055 } 3056 id = PGG(default_link); 3057 CHECK_DEFAULT_LINK(id); 3058 } 3059 else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC, 3060 "l", &oid_long) == SUCCESS) { 3061 if (oid_long <= InvalidOid) { 3062 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Invalid OID is specified"); 3063 RETURN_FALSE; 3064 } 3065 oid = (Oid)oid_long; 3066 id = PGG(default_link); 3067 CHECK_DEFAULT_LINK(id); 3068 } 3069 else { 3070 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Requires 1 or 2 arguments"); 3071 RETURN_FALSE; 3072 } 3073 if (pgsql_link == NULL && id == -1) { 3074 RETURN_FALSE; 3075 } 3076 3077 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink); 3078 3079 if (lo_unlink(pgsql, oid) == -1) { 3080 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to delete PostgreSQL large object %u", oid); 3081 RETURN_FALSE; 3082 } 3083 RETURN_TRUE; 3084} 3085/* }}} */ 3086 3087/* {{{ proto resource pg_lo_open([resource connection,] int large_object_oid, string mode) 3088 Open a large object and return fd */ 3089PHP_FUNCTION(pg_lo_open) 3090{ 3091 zval *pgsql_link = NULL; 3092 long oid_long; 3093 char *oid_string, *end_ptr, *mode_string; 3094 int oid_strlen, mode_strlen; 3095 PGconn *pgsql; 3096 Oid oid; 3097 int id = -1, pgsql_mode=0, pgsql_lofd; 3098 int create=0; 3099 pgLofp *pgsql_lofp; 3100 int argc = ZEND_NUM_ARGS(); 3101 3102 /* accept string type since Oid is unsigned int */ 3103 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC, 3104 "rss", &pgsql_link, &oid_string, &oid_strlen, &mode_string, &mode_strlen) == SUCCESS) { 3105 oid = (Oid)strtoul(oid_string, &end_ptr, 10); 3106 if ((oid_string+oid_strlen) != end_ptr) { 3107 /* wrong integer format */ 3108 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Wrong OID value passed"); 3109 RETURN_FALSE; 3110 } 3111 } 3112 else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC, 3113 "rls", &pgsql_link, &oid_long, &mode_string, &mode_strlen) == SUCCESS) { 3114 if (oid_long <= InvalidOid) { 3115 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Invalid OID specified"); 3116 RETURN_FALSE; 3117 } 3118 oid = (Oid)oid_long; 3119 } 3120 else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC, 3121 "ss", &oid_string, &oid_strlen, &mode_string, &mode_strlen) == SUCCESS) { 3122 oid = (Oid)strtoul(oid_string, &end_ptr, 10); 3123 if ((oid_string+oid_strlen) != end_ptr) { 3124 /* wrong integer format */ 3125 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Wrong OID value passed"); 3126 RETURN_FALSE; 3127 } 3128 id = PGG(default_link); 3129 CHECK_DEFAULT_LINK(id); 3130 } 3131 else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC, 3132 "ls", &oid_long, &mode_string, &mode_strlen) == SUCCESS) { 3133 if (oid_long <= InvalidOid) { 3134 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Invalid OID specified"); 3135 RETURN_FALSE; 3136 } 3137 oid = (Oid)oid_long; 3138 id = PGG(default_link); 3139 CHECK_DEFAULT_LINK(id); 3140 } 3141 else { 3142 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Requires 1 or 2 arguments"); 3143 RETURN_FALSE; 3144 } 3145 if (pgsql_link == NULL && id == -1) { 3146 RETURN_FALSE; 3147 } 3148 3149 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink); 3150 3151 /* r/w/+ is little bit more PHP-like than INV_READ/INV_WRITE and a lot of 3152 faster to type. Unfortunately, doesn't behave the same way as fopen()... 3153 (Jouni) 3154 */ 3155 3156 if (strchr(mode_string, 'r') == mode_string) { 3157 pgsql_mode |= INV_READ; 3158 if (strchr(mode_string, '+') == mode_string+1) { 3159 pgsql_mode |= INV_WRITE; 3160 } 3161 } 3162 if (strchr(mode_string, 'w') == mode_string) { 3163 pgsql_mode |= INV_WRITE; 3164 create = 1; 3165 if (strchr(mode_string, '+') == mode_string+1) { 3166 pgsql_mode |= INV_READ; 3167 } 3168 } 3169 3170 pgsql_lofp = (pgLofp *) emalloc(sizeof(pgLofp)); 3171 3172 if ((pgsql_lofd = lo_open(pgsql, oid, pgsql_mode)) == -1) { 3173 if (create) { 3174 if ((oid = lo_creat(pgsql, INV_READ|INV_WRITE)) == 0) { 3175 efree(pgsql_lofp); 3176 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create PostgreSQL large object"); 3177 RETURN_FALSE; 3178 } else { 3179 if ((pgsql_lofd = lo_open(pgsql, oid, pgsql_mode)) == -1) { 3180 if (lo_unlink(pgsql, oid) == -1) { 3181 efree(pgsql_lofp); 3182 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Something is really messed up! Your database is badly corrupted in a way NOT related to PHP"); 3183 RETURN_FALSE; 3184 } 3185 efree(pgsql_lofp); 3186 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to open PostgreSQL large object"); 3187 RETURN_FALSE; 3188 } else { 3189 pgsql_lofp->conn = pgsql; 3190 pgsql_lofp->lofd = pgsql_lofd; 3191 Z_LVAL_P(return_value) = zend_list_insert(pgsql_lofp, le_lofp TSRMLS_CC); 3192 Z_TYPE_P(return_value) = IS_LONG; 3193 } 3194 } 3195 } else { 3196 efree(pgsql_lofp); 3197 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to open PostgreSQL large object"); 3198 RETURN_FALSE; 3199 } 3200 } else { 3201 pgsql_lofp->conn = pgsql; 3202 pgsql_lofp->lofd = pgsql_lofd; 3203 ZEND_REGISTER_RESOURCE(return_value, pgsql_lofp, le_lofp); 3204 } 3205} 3206/* }}} */ 3207 3208/* {{{ proto bool pg_lo_close(resource large_object) 3209 Close a large object */ 3210PHP_FUNCTION(pg_lo_close) 3211{ 3212 zval *pgsql_lofp; 3213 pgLofp *pgsql; 3214 3215 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pgsql_lofp) == FAILURE) { 3216 return; 3217 } 3218 3219 ZEND_FETCH_RESOURCE(pgsql, pgLofp *, &pgsql_lofp, -1, "PostgreSQL large object", le_lofp); 3220 3221 if (lo_close((PGconn *)pgsql->conn, pgsql->lofd) < 0) { 3222 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to close PostgreSQL large object descriptor %d", pgsql->lofd); 3223 RETVAL_FALSE; 3224 } else { 3225 RETVAL_TRUE; 3226 } 3227 3228 zend_list_delete(Z_RESVAL_P(pgsql_lofp)); 3229 return; 3230} 3231/* }}} */ 3232 3233#define PGSQL_LO_READ_BUF_SIZE 8192 3234 3235/* {{{ proto string pg_lo_read(resource large_object [, int len]) 3236 Read a large object */ 3237PHP_FUNCTION(pg_lo_read) 3238{ 3239 zval *pgsql_id; 3240 long len; 3241 int buf_len = PGSQL_LO_READ_BUF_SIZE, nbytes, argc = ZEND_NUM_ARGS(); 3242 char *buf; 3243 pgLofp *pgsql; 3244 3245 if (zend_parse_parameters(argc TSRMLS_CC, "r|l", &pgsql_id, &len) == FAILURE) { 3246 return; 3247 } 3248 3249 ZEND_FETCH_RESOURCE(pgsql, pgLofp *, &pgsql_id, -1, "PostgreSQL large object", le_lofp); 3250 3251 if (argc > 1) { 3252 buf_len = len; 3253 } 3254 3255 buf = (char *) safe_emalloc(sizeof(char), (buf_len+1), 0); 3256 if ((nbytes = lo_read((PGconn *)pgsql->conn, pgsql->lofd, buf, buf_len))<0) { 3257 efree(buf); 3258 RETURN_FALSE; 3259 } 3260 3261 buf[nbytes] = '\0'; 3262 RETURN_STRINGL(buf, nbytes, 0); 3263} 3264/* }}} */ 3265 3266/* {{{ proto int pg_lo_write(resource large_object, string buf [, int len]) 3267 Write a large object */ 3268PHP_FUNCTION(pg_lo_write) 3269{ 3270 zval *pgsql_id; 3271 char *str; 3272 long z_len; 3273 int str_len, nbytes; 3274 int len; 3275 pgLofp *pgsql; 3276 int argc = ZEND_NUM_ARGS(); 3277 3278 if (zend_parse_parameters(argc TSRMLS_CC, "rs|l", &pgsql_id, &str, &str_len, &z_len) == FAILURE) { 3279 return; 3280 } 3281 3282 if (argc > 2) { 3283 if (z_len > str_len) { 3284 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot write more than buffer size %d. Tried to write %ld", str_len, z_len); 3285 RETURN_FALSE; 3286 } 3287 if (z_len < 0) { 3288 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Buffer size must be larger than 0, but %ld was specified", z_len); 3289 RETURN_FALSE; 3290 } 3291 len = z_len; 3292 } 3293 else { 3294 len = str_len; 3295 } 3296 3297 ZEND_FETCH_RESOURCE(pgsql, pgLofp *, &pgsql_id, -1, "PostgreSQL large object", le_lofp); 3298 3299 if ((nbytes = lo_write((PGconn *)pgsql->conn, pgsql->lofd, str, len)) == -1) { 3300 RETURN_FALSE; 3301 } 3302 3303 RETURN_LONG(nbytes); 3304} 3305/* }}} */ 3306 3307/* {{{ proto int pg_lo_read_all(resource large_object) 3308 Read a large object and send straight to browser */ 3309PHP_FUNCTION(pg_lo_read_all) 3310{ 3311 zval *pgsql_id; 3312 int tbytes; 3313 volatile int nbytes; 3314 char buf[PGSQL_LO_READ_BUF_SIZE]; 3315 pgLofp *pgsql; 3316 3317 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pgsql_id) == FAILURE) { 3318 return; 3319 } 3320 3321 ZEND_FETCH_RESOURCE(pgsql, pgLofp *, &pgsql_id, -1, "PostgreSQL large object", le_lofp); 3322 3323 tbytes = 0; 3324 while ((nbytes = lo_read((PGconn *)pgsql->conn, pgsql->lofd, buf, PGSQL_LO_READ_BUF_SIZE))>0) { 3325 PHPWRITE(buf, nbytes); 3326 tbytes += nbytes; 3327 } 3328 RETURN_LONG(tbytes); 3329} 3330/* }}} */ 3331 3332/* {{{ proto int pg_lo_import([resource connection, ] string filename [, mixed oid]) 3333 Import large object direct from filesystem */ 3334PHP_FUNCTION(pg_lo_import) 3335{ 3336 zval *pgsql_link = NULL, *oid = NULL; 3337 char *file_in; 3338 int id = -1, name_len; 3339 int argc = ZEND_NUM_ARGS(); 3340 PGconn *pgsql; 3341 Oid returned_oid; 3342 3343 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC, 3344 "rp|z", &pgsql_link, &file_in, &name_len, &oid) == SUCCESS) { 3345 ; 3346 } 3347 else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC, 3348 "p|z", &file_in, &name_len, &oid) == SUCCESS) { 3349 id = PGG(default_link); 3350 CHECK_DEFAULT_LINK(id); 3351 } 3352 /* old calling convention, deprecated since PHP 4.2 */ 3353 else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC, 3354 "pr", &file_in, &name_len, &pgsql_link ) == SUCCESS) { 3355 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Old API is used"); 3356 } 3357 else { 3358 WRONG_PARAM_COUNT; 3359 } 3360 3361 if (php_check_open_basedir(file_in TSRMLS_CC)) { 3362 RETURN_FALSE; 3363 } 3364 3365 if (pgsql_link == NULL && id == -1) { 3366 RETURN_FALSE; 3367 } 3368 3369 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink); 3370 3371 if (oid) { 3372#ifndef HAVE_PG_LO_IMPORT_WITH_OID 3373 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "OID value passing not supported"); 3374#else 3375 Oid wanted_oid; 3376 switch (Z_TYPE_P(oid)) { 3377 case IS_STRING: 3378 { 3379 char *end_ptr; 3380 wanted_oid = (Oid)strtoul(Z_STRVAL_P(oid), &end_ptr, 10); 3381 if ((Z_STRVAL_P(oid)+Z_STRLEN_P(oid)) != end_ptr) { 3382 /* wrong integer format */ 3383 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "invalid OID value passed"); 3384 RETURN_FALSE; 3385 } 3386 } 3387 break; 3388 case IS_LONG: 3389 if (Z_LVAL_P(oid) < (long)InvalidOid) { 3390 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "invalid OID value passed"); 3391 RETURN_FALSE; 3392 } 3393 wanted_oid = (Oid)Z_LVAL_P(oid); 3394 break; 3395 default: 3396 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "invalid OID value passed"); 3397 RETURN_FALSE; 3398 } 3399 3400 returned_oid = lo_import_with_oid(pgsql, file_in, wanted_oid); 3401 3402 if (returned_oid == InvalidOid) { 3403 RETURN_FALSE; 3404 } 3405 3406 PGSQL_RETURN_OID(returned_oid); 3407#endif 3408 } 3409 3410 returned_oid = lo_import(pgsql, file_in); 3411 3412 if (returned_oid == InvalidOid) { 3413 RETURN_FALSE; 3414 } 3415 PGSQL_RETURN_OID(returned_oid); 3416} 3417/* }}} */ 3418 3419/* {{{ proto bool pg_lo_export([resource connection, ] int objoid, string filename) 3420 Export large object direct to filesystem */ 3421PHP_FUNCTION(pg_lo_export) 3422{ 3423 zval *pgsql_link = NULL; 3424 char *file_out, *oid_string, *end_ptr; 3425 int oid_strlen; 3426 int id = -1, name_len; 3427 long oid_long; 3428 Oid oid; 3429 PGconn *pgsql; 3430 int argc = ZEND_NUM_ARGS(); 3431 3432 /* allow string to handle large OID value correctly */ 3433 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC, 3434 "rlp", &pgsql_link, &oid_long, &file_out, &name_len) == SUCCESS) { 3435 if (oid_long <= InvalidOid) { 3436 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Invalid OID specified"); 3437 RETURN_FALSE; 3438 } 3439 oid = (Oid)oid_long; 3440 } 3441 else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC, 3442 "rss", &pgsql_link, &oid_string, &oid_strlen, &file_out, &name_len) == SUCCESS) { 3443 oid = (Oid)strtoul(oid_string, &end_ptr, 10); 3444 if ((oid_string+oid_strlen) != end_ptr) { 3445 /* wrong integer format */ 3446 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Wrong OID value passed"); 3447 RETURN_FALSE; 3448 } 3449 } 3450 else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC, 3451 "lp", &oid_long, &file_out, &name_len) == SUCCESS) { 3452 if (oid_long <= InvalidOid) { 3453 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Invalid OID specified"); 3454 RETURN_FALSE; 3455 } 3456 oid = (Oid)oid_long; 3457 id = PGG(default_link); 3458 CHECK_DEFAULT_LINK(id); 3459 } 3460 else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC, 3461 "sp", &oid_string, &oid_strlen, &file_out, &name_len) == SUCCESS) { 3462 oid = (Oid)strtoul(oid_string, &end_ptr, 10); 3463 if ((oid_string+oid_strlen) != end_ptr) { 3464 /* wrong integer format */ 3465 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Wrong OID value passed"); 3466 RETURN_FALSE; 3467 } 3468 id = PGG(default_link); 3469 CHECK_DEFAULT_LINK(id); 3470 } 3471 else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC, 3472 "spr", &oid_string, &oid_strlen, &file_out, &name_len, &pgsql_link) == SUCCESS) { 3473 oid = (Oid)strtoul(oid_string, &end_ptr, 10); 3474 if ((oid_string+oid_strlen) != end_ptr) { 3475 /* wrong integer format */ 3476 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Wrong OID value passed"); 3477 RETURN_FALSE; 3478 } 3479 } 3480 else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC, 3481 "lpr", &oid_long, &file_out, &name_len, &pgsql_link) == SUCCESS) { 3482 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Old API is used"); 3483 if (oid_long <= InvalidOid) { 3484 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Invalid OID specified"); 3485 RETURN_FALSE; 3486 } 3487 oid = (Oid)oid_long; 3488 } 3489 else { 3490 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Requires 2 or 3 arguments"); 3491 RETURN_FALSE; 3492 } 3493 3494 if (php_check_open_basedir(file_out TSRMLS_CC)) { 3495 RETURN_FALSE; 3496 } 3497 3498 if (pgsql_link == NULL && id == -1) { 3499 RETURN_FALSE; 3500 } 3501 3502 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink); 3503 3504 if (lo_export(pgsql, oid, file_out)) { 3505 RETURN_TRUE; 3506 } 3507 RETURN_FALSE; 3508} 3509/* }}} */ 3510 3511/* {{{ proto bool pg_lo_seek(resource large_object, int offset [, int whence]) 3512 Seeks position of large object */ 3513PHP_FUNCTION(pg_lo_seek) 3514{ 3515 zval *pgsql_id = NULL; 3516 long offset = 0, whence = SEEK_CUR; 3517 pgLofp *pgsql; 3518 int argc = ZEND_NUM_ARGS(); 3519 3520 if (zend_parse_parameters(argc TSRMLS_CC, "rl|l", &pgsql_id, &offset, &whence) == FAILURE) { 3521 return; 3522 } 3523 if (whence != SEEK_SET && whence != SEEK_CUR && whence != SEEK_END) { 3524 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid whence parameter"); 3525 return; 3526 } 3527 3528 ZEND_FETCH_RESOURCE(pgsql, pgLofp *, &pgsql_id, -1, "PostgreSQL large object", le_lofp); 3529 3530 if (lo_lseek((PGconn *)pgsql->conn, pgsql->lofd, offset, whence) > -1) { 3531 RETURN_TRUE; 3532 } else { 3533 RETURN_FALSE; 3534 } 3535} 3536/* }}} */ 3537 3538/* {{{ proto int pg_lo_tell(resource large_object) 3539 Returns current position of large object */ 3540PHP_FUNCTION(pg_lo_tell) 3541{ 3542 zval *pgsql_id = NULL; 3543 int offset = 0; 3544 pgLofp *pgsql; 3545 int argc = ZEND_NUM_ARGS(); 3546 3547 if (zend_parse_parameters(argc TSRMLS_CC, "r", &pgsql_id) == FAILURE) { 3548 return; 3549 } 3550 3551 ZEND_FETCH_RESOURCE(pgsql, pgLofp *, &pgsql_id, -1, "PostgreSQL large object", le_lofp); 3552 3553 offset = lo_tell((PGconn *)pgsql->conn, pgsql->lofd); 3554 RETURN_LONG(offset); 3555} 3556/* }}} */ 3557 3558#if HAVE_PQSETERRORVERBOSITY 3559/* {{{ proto int pg_set_error_verbosity([resource connection,] int verbosity) 3560 Set error verbosity */ 3561PHP_FUNCTION(pg_set_error_verbosity) 3562{ 3563 zval *pgsql_link = NULL; 3564 long verbosity; 3565 int id = -1, argc = ZEND_NUM_ARGS(); 3566 PGconn *pgsql; 3567 3568 if (argc == 1) { 3569 if (zend_parse_parameters(argc TSRMLS_CC, "l", &verbosity) == FAILURE) { 3570 return; 3571 } 3572 id = PGG(default_link); 3573 CHECK_DEFAULT_LINK(id); 3574 } else { 3575 if (zend_parse_parameters(argc TSRMLS_CC, "rl", &pgsql_link, &verbosity) == FAILURE) { 3576 return; 3577 } 3578 } 3579 3580 if (pgsql_link == NULL && id == -1) { 3581 RETURN_FALSE; 3582 } 3583 3584 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink); 3585 3586 if (verbosity & (PQERRORS_TERSE|PQERRORS_DEFAULT|PQERRORS_VERBOSE)) { 3587 Z_LVAL_P(return_value) = PQsetErrorVerbosity(pgsql, verbosity); 3588 Z_TYPE_P(return_value) = IS_LONG; 3589 } else { 3590 RETURN_FALSE; 3591 } 3592} 3593/* }}} */ 3594#endif 3595 3596#ifdef HAVE_PQCLIENTENCODING 3597/* {{{ proto int pg_set_client_encoding([resource connection,] string encoding) 3598 Set client encoding */ 3599PHP_FUNCTION(pg_set_client_encoding) 3600{ 3601 char *encoding; 3602 int encoding_len; 3603 zval *pgsql_link = NULL; 3604 int id = -1, argc = ZEND_NUM_ARGS(); 3605 PGconn *pgsql; 3606 3607 if (argc == 1) { 3608 if (zend_parse_parameters(argc TSRMLS_CC, "s", &encoding, &encoding_len) == FAILURE) { 3609 return; 3610 } 3611 id = PGG(default_link); 3612 CHECK_DEFAULT_LINK(id); 3613 } else { 3614 if (zend_parse_parameters(argc TSRMLS_CC, "rs", &pgsql_link, &encoding, &encoding_len) == FAILURE) { 3615 return; 3616 } 3617 } 3618 3619 if (pgsql_link == NULL && id == -1) { 3620 RETURN_FALSE; 3621 } 3622 3623 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink); 3624 3625 Z_LVAL_P(return_value) = PQsetClientEncoding(pgsql, encoding); 3626 Z_TYPE_P(return_value) = IS_LONG; 3627} 3628/* }}} */ 3629 3630/* {{{ proto string pg_client_encoding([resource connection]) 3631 Get the current client encoding */ 3632PHP_FUNCTION(pg_client_encoding) 3633{ 3634 zval *pgsql_link = NULL; 3635 int id = -1, argc = ZEND_NUM_ARGS(); 3636 PGconn *pgsql; 3637 3638 if (zend_parse_parameters(argc TSRMLS_CC, "|r", &pgsql_link) == FAILURE) { 3639 return; 3640 } 3641 3642 if (argc == 0) { 3643 id = PGG(default_link); 3644 CHECK_DEFAULT_LINK(id); 3645 } 3646 3647 if (pgsql_link == NULL && id == -1) { 3648 RETURN_FALSE; 3649 } 3650 3651 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink); 3652 3653 /* Just do the same as found in PostgreSQL sources... */ 3654 3655#ifndef HAVE_PGSQL_WITH_MULTIBYTE_SUPPORT 3656#define pg_encoding_to_char(x) "SQL_ASCII" 3657#endif 3658 3659 Z_STRVAL_P(return_value) = (char *) pg_encoding_to_char(PQclientEncoding(pgsql)); 3660 Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value)); 3661 Z_STRVAL_P(return_value) = (char *) estrdup(Z_STRVAL_P(return_value)); 3662 Z_TYPE_P(return_value) = IS_STRING; 3663} 3664/* }}} */ 3665#endif 3666 3667#if !HAVE_PQGETCOPYDATA 3668#define COPYBUFSIZ 8192 3669#endif 3670 3671/* {{{ proto bool pg_end_copy([resource connection]) 3672 Sync with backend. Completes the Copy command */ 3673PHP_FUNCTION(pg_end_copy) 3674{ 3675 zval *pgsql_link = NULL; 3676 int id = -1, argc = ZEND_NUM_ARGS(); 3677 PGconn *pgsql; 3678 int result = 0; 3679 3680 if (zend_parse_parameters(argc TSRMLS_CC, "|r", &pgsql_link) == FAILURE) { 3681 return; 3682 } 3683 3684 if (argc == 0) { 3685 id = PGG(default_link); 3686 CHECK_DEFAULT_LINK(id); 3687 } 3688 3689 if (pgsql_link == NULL && id == -1) { 3690 RETURN_FALSE; 3691 } 3692 3693 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink); 3694 3695 result = PQendcopy(pgsql); 3696 3697 if (result!=0) { 3698 PHP_PQ_ERROR("Query failed: %s", pgsql); 3699 RETURN_FALSE; 3700 } 3701 RETURN_TRUE; 3702} 3703/* }}} */ 3704 3705 3706/* {{{ proto bool pg_put_line([resource connection,] string query) 3707 Send null-terminated string to backend server*/ 3708PHP_FUNCTION(pg_put_line) 3709{ 3710 char *query; 3711 zval *pgsql_link = NULL; 3712 int query_len, id = -1; 3713 PGconn *pgsql; 3714 int result = 0, argc = ZEND_NUM_ARGS(); 3715 3716 if (argc == 1) { 3717 if (zend_parse_parameters(argc TSRMLS_CC, "s", &query, &query_len) == FAILURE) { 3718 return; 3719 } 3720 id = PGG(default_link); 3721 CHECK_DEFAULT_LINK(id); 3722 } else { 3723 if (zend_parse_parameters(argc TSRMLS_CC, "rs", &pgsql_link, &query, &query_len) == FAILURE) { 3724 return; 3725 } 3726 } 3727 3728 if (pgsql_link == NULL && id == -1) { 3729 RETURN_FALSE; 3730 } 3731 3732 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink); 3733 3734 result = PQputline(pgsql, query); 3735 if (result==EOF) { 3736 PHP_PQ_ERROR("Query failed: %s", pgsql); 3737 RETURN_FALSE; 3738 } 3739 RETURN_TRUE; 3740} 3741/* }}} */ 3742 3743/* {{{ proto array pg_copy_to(resource connection, string table_name [, string delimiter [, string null_as]]) 3744 Copy table to array */ 3745PHP_FUNCTION(pg_copy_to) 3746{ 3747 zval *pgsql_link; 3748 char *table_name, *pg_delim = NULL, *pg_null_as = NULL; 3749 int table_name_len, pg_delim_len, pg_null_as_len, free_pg_null = 0; 3750 char *query; 3751 int id = -1; 3752 PGconn *pgsql; 3753 PGresult *pgsql_result; 3754 ExecStatusType status; 3755 int copydone = 0; 3756#if !HAVE_PQGETCOPYDATA 3757 char copybuf[COPYBUFSIZ]; 3758#endif 3759 char *csv = (char *)NULL; 3760 int ret; 3761 int argc = ZEND_NUM_ARGS(); 3762 3763 if (zend_parse_parameters(argc TSRMLS_CC, "rs|ss", 3764 &pgsql_link, &table_name, &table_name_len, 3765 &pg_delim, &pg_delim_len, &pg_null_as, &pg_null_as_len) == FAILURE) { 3766 return; 3767 } 3768 if (!pg_delim) { 3769 pg_delim = "\t"; 3770 } 3771 3772 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink); 3773 3774 if (!pg_null_as) { 3775 pg_null_as = safe_estrdup("\\\\N"); 3776 free_pg_null = 1; 3777 } 3778 3779 spprintf(&query, 0, "COPY %s TO STDOUT DELIMITERS E'%c' WITH NULL AS E'%s'", table_name, *pg_delim, pg_null_as); 3780 3781 while ((pgsql_result = PQgetResult(pgsql))) { 3782 PQclear(pgsql_result); 3783 } 3784 pgsql_result = PQexec(pgsql, query); 3785 if (free_pg_null) { 3786 efree(pg_null_as); 3787 } 3788 efree(query); 3789 3790 if (pgsql_result) { 3791 status = PQresultStatus(pgsql_result); 3792 } else { 3793 status = (ExecStatusType) PQstatus(pgsql); 3794 } 3795 3796 switch (status) { 3797 case PGRES_COPY_OUT: 3798 if (pgsql_result) { 3799 PQclear(pgsql_result); 3800 array_init(return_value); 3801#if HAVE_PQGETCOPYDATA 3802 while (!copydone) 3803 { 3804 ret = PQgetCopyData(pgsql, &csv, 0); 3805 switch (ret) { 3806 case -1: 3807 copydone = 1; 3808 break; 3809 case 0: 3810 case -2: 3811 PHP_PQ_ERROR("getline failed: %s", pgsql); 3812 RETURN_FALSE; 3813 break; 3814 default: 3815 add_next_index_string(return_value, csv, 1); 3816 PQfreemem(csv); 3817 break; 3818 } 3819 } 3820#else 3821 while (!copydone) 3822 { 3823 if ((ret = PQgetline(pgsql, copybuf, COPYBUFSIZ))) { 3824 PHP_PQ_ERROR("getline failed: %s", pgsql); 3825 RETURN_FALSE; 3826 } 3827 3828 if (copybuf[0] == '\\' && 3829 copybuf[1] == '.' && 3830 copybuf[2] == '\0') 3831 { 3832 copydone = 1; 3833 } 3834 else 3835 { 3836 if (csv == (char *)NULL) { 3837 csv = estrdup(copybuf); 3838 } else { 3839 csv = (char *)erealloc(csv, strlen(csv) + sizeof(char)*(COPYBUFSIZ+1)); 3840 strcat(csv, copybuf); 3841 } 3842 3843 switch (ret) 3844 { 3845 case EOF: 3846 copydone = 1; 3847 case 0: 3848 add_next_index_string(return_value, csv, 1); 3849 efree(csv); 3850 csv = (char *)NULL; 3851 break; 3852 case 1: 3853 break; 3854 } 3855 } 3856 } 3857 if (PQendcopy(pgsql)) { 3858 PHP_PQ_ERROR("endcopy failed: %s", pgsql); 3859 RETURN_FALSE; 3860 } 3861#endif 3862 while ((pgsql_result = PQgetResult(pgsql))) { 3863 PQclear(pgsql_result); 3864 } 3865 } else { 3866 PQclear(pgsql_result); 3867 RETURN_FALSE; 3868 } 3869 break; 3870 default: 3871 PQclear(pgsql_result); 3872 PHP_PQ_ERROR("Copy command failed: %s", pgsql); 3873 RETURN_FALSE; 3874 break; 3875 } 3876} 3877/* }}} */ 3878 3879/* {{{ proto bool pg_copy_from(resource connection, string table_name , array rows [, string delimiter [, string null_as]]) 3880 Copy table from array */ 3881PHP_FUNCTION(pg_copy_from) 3882{ 3883 zval *pgsql_link = NULL, *pg_rows; 3884 zval **tmp; 3885 char *table_name, *pg_delim = NULL, *pg_null_as = NULL; 3886 int table_name_len, pg_delim_len, pg_null_as_len; 3887 int pg_null_as_free = 0; 3888 char *query; 3889 HashPosition pos; 3890 int id = -1; 3891 PGconn *pgsql; 3892 PGresult *pgsql_result; 3893 ExecStatusType status; 3894 int argc = ZEND_NUM_ARGS(); 3895 3896 if (zend_parse_parameters(argc TSRMLS_CC, "rsa|ss", 3897 &pgsql_link, &table_name, &table_name_len, &pg_rows, 3898 &pg_delim, &pg_delim_len, &pg_null_as, &pg_null_as_len) == FAILURE) { 3899 return; 3900 } 3901 if (!pg_delim) { 3902 pg_delim = "\t"; 3903 } 3904 if (!pg_null_as) { 3905 pg_null_as = safe_estrdup("\\\\N"); 3906 pg_null_as_free = 1; 3907 } 3908 3909 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink); 3910 3911 spprintf(&query, 0, "COPY %s FROM STDIN DELIMITERS E'%c' WITH NULL AS E'%s'", table_name, *pg_delim, pg_null_as); 3912 while ((pgsql_result = PQgetResult(pgsql))) { 3913 PQclear(pgsql_result); 3914 } 3915 pgsql_result = PQexec(pgsql, query); 3916 3917 if (pg_null_as_free) { 3918 efree(pg_null_as); 3919 } 3920 efree(query); 3921 3922 if (pgsql_result) { 3923 status = PQresultStatus(pgsql_result); 3924 } else { 3925 status = (ExecStatusType) PQstatus(pgsql); 3926 } 3927 3928 switch (status) { 3929 case PGRES_COPY_IN: 3930 if (pgsql_result) { 3931 int command_failed = 0; 3932 PQclear(pgsql_result); 3933 zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(pg_rows), &pos); 3934#if HAVE_PQPUTCOPYDATA 3935 while (zend_hash_get_current_data_ex(Z_ARRVAL_P(pg_rows), (void **) &tmp, &pos) == SUCCESS) { 3936 convert_to_string_ex(tmp); 3937 query = (char *)emalloc(Z_STRLEN_PP(tmp) + 2); 3938 strlcpy(query, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp) + 2); 3939 if(Z_STRLEN_PP(tmp) > 0 && *(query + Z_STRLEN_PP(tmp) - 1) != '\n') { 3940 strlcat(query, "\n", Z_STRLEN_PP(tmp) + 2); 3941 } 3942 if (PQputCopyData(pgsql, query, strlen(query)) != 1) { 3943 efree(query); 3944 PHP_PQ_ERROR("copy failed: %s", pgsql); 3945 RETURN_FALSE; 3946 } 3947 efree(query); 3948 zend_hash_move_forward_ex(Z_ARRVAL_P(pg_rows), &pos); 3949 } 3950 if (PQputCopyEnd(pgsql, NULL) != 1) { 3951 PHP_PQ_ERROR("putcopyend failed: %s", pgsql); 3952 RETURN_FALSE; 3953 } 3954#else 3955 while (zend_hash_get_current_data_ex(Z_ARRVAL_P(pg_rows), (void **) &tmp, &pos) == SUCCESS) { 3956 convert_to_string_ex(tmp); 3957 query = (char *)emalloc(Z_STRLEN_PP(tmp) + 2); 3958 strlcpy(query, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp) + 2); 3959 if(Z_STRLEN_PP(tmp) > 0 && *(query + Z_STRLEN_PP(tmp) - 1) != '\n') { 3960 strlcat(query, "\n", Z_STRLEN_PP(tmp) + 2); 3961 } 3962 if (PQputline(pgsql, query)==EOF) { 3963 efree(query); 3964 PHP_PQ_ERROR("copy failed: %s", pgsql); 3965 RETURN_FALSE; 3966 } 3967 efree(query); 3968 zend_hash_move_forward_ex(Z_ARRVAL_P(pg_rows), &pos); 3969 } 3970 if (PQputline(pgsql, "\\.\n") == EOF) { 3971 PHP_PQ_ERROR("putline failed: %s", pgsql); 3972 RETURN_FALSE; 3973 } 3974 if (PQendcopy(pgsql)) { 3975 PHP_PQ_ERROR("endcopy failed: %s", pgsql); 3976 RETURN_FALSE; 3977 } 3978#endif 3979 while ((pgsql_result = PQgetResult(pgsql))) { 3980 if (PGRES_COMMAND_OK != PQresultStatus(pgsql_result)) { 3981 PHP_PQ_ERROR("Copy command failed: %s", pgsql); 3982 command_failed = 1; 3983 } 3984 PQclear(pgsql_result); 3985 } 3986 if (command_failed) { 3987 RETURN_FALSE; 3988 } 3989 } else { 3990 PQclear(pgsql_result); 3991 RETURN_FALSE; 3992 } 3993 RETURN_TRUE; 3994 break; 3995 default: 3996 PQclear(pgsql_result); 3997 PHP_PQ_ERROR("Copy command failed: %s", pgsql); 3998 RETURN_FALSE; 3999 break; 4000 } 4001} 4002/* }}} */ 4003 4004#ifdef HAVE_PQESCAPE 4005/* {{{ proto string pg_escape_string([resource connection,] string data) 4006 Escape string for text/char type */ 4007PHP_FUNCTION(pg_escape_string) 4008{ 4009 char *from = NULL, *to = NULL; 4010 zval *pgsql_link; 4011#ifdef HAVE_PQESCAPE_CONN 4012 PGconn *pgsql; 4013#endif 4014 int to_len; 4015 int from_len; 4016 int id = -1; 4017 4018 switch (ZEND_NUM_ARGS()) { 4019 case 1: 4020 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &from, &from_len) == FAILURE) { 4021 return; 4022 } 4023 pgsql_link = NULL; 4024 id = PGG(default_link); 4025 break; 4026 4027 default: 4028 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &pgsql_link, &from, &from_len) == FAILURE) { 4029 return; 4030 } 4031 break; 4032 } 4033 4034 to = (char *) safe_emalloc(from_len, 2, 1); 4035 4036#ifdef HAVE_PQESCAPE_CONN 4037 if (pgsql_link != NULL || id != -1) { 4038 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink); 4039 to_len = (int) PQescapeStringConn(pgsql, to, from, (size_t)from_len, NULL); 4040 } else 4041#endif 4042 to_len = (int) PQescapeString(to, from, (size_t)from_len); 4043 4044 RETURN_STRINGL(to, to_len, 0); 4045} 4046/* }}} */ 4047 4048/* {{{ proto string pg_escape_bytea([resource connection,] string data) 4049 Escape binary for bytea type */ 4050PHP_FUNCTION(pg_escape_bytea) 4051{ 4052 char *from = NULL, *to = NULL; 4053 size_t to_len; 4054 int from_len, id = -1; 4055#ifdef HAVE_PQESCAPE_BYTEA_CONN 4056 PGconn *pgsql; 4057#endif 4058 zval *pgsql_link; 4059 4060 switch (ZEND_NUM_ARGS()) { 4061 case 1: 4062 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &from, &from_len) == FAILURE) { 4063 return; 4064 } 4065 pgsql_link = NULL; 4066 id = PGG(default_link); 4067 break; 4068 4069 default: 4070 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &pgsql_link, &from, &from_len) == FAILURE) { 4071 return; 4072 } 4073 break; 4074 } 4075 4076#ifdef HAVE_PQESCAPE_BYTEA_CONN 4077 if (pgsql_link != NULL || id != -1) { 4078 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink); 4079 to = (char *)PQescapeByteaConn(pgsql, from, (size_t)from_len, &to_len); 4080 } else 4081#endif 4082 to = (char *)PQescapeBytea((unsigned char*)from, from_len, &to_len); 4083 4084 RETVAL_STRINGL(to, to_len-1, 1); /* to_len includes addtional '\0' */ 4085 PQfreemem(to); 4086} 4087/* }}} */ 4088 4089#if !HAVE_PQUNESCAPEBYTEA 4090/* PQunescapeBytea() from PostgreSQL 7.3 to provide bytea unescape feature to 7.2 users. 4091 Renamed to php_pgsql_unescape_bytea() */ 4092/* 4093 * PQunescapeBytea - converts the null terminated string representation 4094 * of a bytea, strtext, into binary, filling a buffer. It returns a 4095 * pointer to the buffer which is NULL on error, and the size of the 4096 * buffer in retbuflen. The pointer may subsequently be used as an 4097 * argument to the function free(3). It is the reverse of PQescapeBytea. 4098 * 4099 * The following transformations are reversed: 4100 * '\0' == ASCII 0 == \000 4101 * '\'' == ASCII 39 == \' 4102 * '\\' == ASCII 92 == \\ 4103 * 4104 * States: 4105 * 0 normal 0->1->2->3->4 4106 * 1 \ 1->5 4107 * 2 \0 1->6 4108 * 3 \00 4109 * 4 \000 4110 * 5 \' 4111 * 6 \\ 4112 */ 4113static unsigned char * php_pgsql_unescape_bytea(unsigned char *strtext, size_t *retbuflen) 4114{ 4115 size_t buflen; 4116 unsigned char *buffer, 4117 *sp, 4118 *bp; 4119 unsigned int state = 0; 4120 4121 if (strtext == NULL) 4122 return NULL; 4123 buflen = strlen(strtext); /* will shrink, also we discover if 4124 * strtext */ 4125 buffer = (unsigned char *) emalloc(buflen); /* isn't NULL terminated */ 4126 for (bp = buffer, sp = strtext; *sp != '\0'; bp++, sp++) 4127 { 4128 switch (state) 4129 { 4130 case 0: 4131 if (*sp == '\\') 4132 state = 1; 4133 *bp = *sp; 4134 break; 4135 case 1: 4136 if (*sp == '\'') /* state=5 */ 4137 { /* replace \' with 39 */ 4138 bp--; 4139 *bp = '\''; 4140 buflen--; 4141 state = 0; 4142 } 4143 else if (*sp == '\\') /* state=6 */ 4144 { /* replace \\ with 92 */ 4145 bp--; 4146 *bp = '\\'; 4147 buflen--; 4148 state = 0; 4149 } 4150 else 4151 { 4152 if (isdigit(*sp)) 4153 state = 2; 4154 else 4155 state = 0; 4156 *bp = *sp; 4157 } 4158 break; 4159 case 2: 4160 if (isdigit(*sp)) 4161 state = 3; 4162 else 4163 state = 0; 4164 *bp = *sp; 4165 break; 4166 case 3: 4167 if (isdigit(*sp)) /* state=4 */ 4168 { 4169 unsigned char *start, *end, buf[4]; /* 000 + '\0' */ 4170 4171 bp -= 3; 4172 memcpy(buf, sp-2, 3); 4173 buf[3] = '\0'; 4174 start = buf; 4175 *bp = (unsigned char)strtoul(start, (char **)&end, 8); 4176 buflen -= 3; 4177 state = 0; 4178 } 4179 else 4180 { 4181 *bp = *sp; 4182 state = 0; 4183 } 4184 break; 4185 } 4186 } 4187 buffer = erealloc(buffer, buflen+1); 4188 buffer[buflen] = '\0'; 4189 4190 *retbuflen = buflen; 4191 return buffer; 4192} 4193#endif 4194 4195/* {{{ proto string pg_unescape_bytea(string data) 4196 Unescape binary for bytea type */ 4197PHP_FUNCTION(pg_unescape_bytea) 4198{ 4199 char *from = NULL, *to = NULL, *tmp = NULL; 4200 size_t to_len; 4201 int from_len; 4202 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", 4203 &from, &from_len) == FAILURE) { 4204 return; 4205 } 4206 4207#if HAVE_PQUNESCAPEBYTEA 4208 tmp = (char *)PQunescapeBytea((unsigned char*)from, &to_len); 4209 to = estrndup(tmp, to_len); 4210 PQfreemem(tmp); 4211#else 4212 to = (char *)php_pgsql_unescape_bytea((unsigned char*)from, &to_len); 4213#endif 4214 if (!to) { 4215 RETURN_FALSE; 4216 } 4217 RETVAL_STRINGL(to, to_len, 0); 4218} 4219/* }}} */ 4220#endif 4221 4222#ifdef HAVE_PQESCAPE 4223#if !HAVE_PQESCAPELITERAL 4224/* emulate libpq's PQescapeInternal() 9.0 or later */ 4225static char* php_pgsql_PQescapeInternal(PGconn *conn, const char *str, size_t len, int escape_literal) { 4226 char *result, *rp; 4227 const char *s; 4228 size_t tmp_len; 4229 int input_len = len; 4230 char quote_char = escape_literal ? '\'' : '"'; 4231 4232 if (!conn) { 4233 return NULL; 4234 } 4235 4236 /* 4237 * NOTE: multibyte strings that could cointain slashes should be considered. 4238 * (e.g. SJIS, BIG5) However, it cannot be done without valid PGconn and mbstring. 4239 * Therefore, this function does not support such encodings currently. 4240 * FIXME: add encoding check and skip multibyte char bytes if there is vaild PGconn. 4241 */ 4242 4243 /* allocate enough memory */ 4244 rp = result = (char *)emalloc(len*2 + 5); /* leading " E" needs extra 2 bytes + quote_chars on both end for 2 bytes + NULL */ 4245 4246 if (escape_literal) { 4247 /* check backslashes */ 4248 tmp_len = strspn(str, "\\"); 4249 if (tmp_len != len) { 4250 /* add " E" for escaping slashes */ 4251 *rp++ = ' '; 4252 *rp++ = 'E'; 4253 } 4254 } 4255 /* open quote */ 4256 *rp++ = quote_char; 4257 for (s = str; s - str < input_len; ++s) { 4258 if (*s == quote_char || (escape_literal && *s == '\\')) { 4259 *rp++ = *s; 4260 *rp++ = *s; 4261 } else { 4262 *rp++ = *s; 4263 } 4264 } 4265 *rp++ = quote_char; 4266 *rp = '\0'; 4267 4268 return result; 4269} 4270#endif 4271 4272static void php_pgsql_escape_internal(INTERNAL_FUNCTION_PARAMETERS, int escape_literal) { 4273 char *from = NULL, *to = NULL, *tmp = NULL; 4274 zval *pgsql_link = NULL; 4275 PGconn *pgsql; 4276 int to_len; 4277 int from_len; 4278 int id = -1; 4279 4280 switch (ZEND_NUM_ARGS()) { 4281 case 1: 4282 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &from, &from_len) == FAILURE) { 4283 return; 4284 } 4285 pgsql_link = NULL; 4286 id = PGG(default_link); 4287 break; 4288 4289 default: 4290 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &pgsql_link, &from, &from_len) == FAILURE) { 4291 return; 4292 } 4293 break; 4294 } 4295 4296 if (pgsql_link == NULL && id == -1) { 4297 RETURN_FALSE; 4298 } 4299 4300 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink); 4301 if (pgsql == NULL) { 4302 php_error_docref(NULL TSRMLS_CC, E_WARNING,"Cannot get default pgsql link"); 4303 RETURN_FALSE; 4304 } 4305#ifdef HAVE_PQESCAPELITERAL 4306 if (escape_literal) { 4307 tmp = PQescapeLiteral(pgsql, from, (size_t)from_len); 4308 } else { 4309 tmp = PQescapeIdentifier(pgsql, from, (size_t)from_len); 4310 } 4311 if (!tmp) { 4312 php_error_docref(NULL TSRMLS_CC, E_WARNING,"Failed to escape"); 4313 RETURN_FALSE; 4314 } 4315 to = estrdup(tmp); 4316 PQfreemem(tmp); 4317#else 4318 to = php_pgsql_PQescapeInternal(pgsql, from, (size_t)from_len, escape_literal); 4319 if (!to) { 4320 php_error_docref(NULL TSRMLS_CC, E_WARNING,"Failed to escape"); 4321 RETURN_FALSE; 4322 } 4323#endif 4324 4325 RETURN_STRING(to, 0); 4326} 4327 4328/* {{{ proto string pg_escape_literal([resource connection,] string data) 4329 Escape parameter as string literal (i.e. parameter) */ 4330PHP_FUNCTION(pg_escape_literal) 4331{ 4332 php_pgsql_escape_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); 4333} 4334/* }}} */ 4335 4336/* {{{ proto string pg_escape_identifier([resource connection,] string data) 4337 Escape identifier (i.e. table name, field name) */ 4338PHP_FUNCTION(pg_escape_identifier) 4339{ 4340 php_pgsql_escape_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); 4341} 4342/* }}} */ 4343#endif 4344 4345 4346/* {{{ proto string pg_result_error(resource result) 4347 Get error message associated with result */ 4348PHP_FUNCTION(pg_result_error) 4349{ 4350 zval *result; 4351 PGresult *pgsql_result; 4352 pgsql_result_handle *pg_result; 4353 char *err = NULL; 4354 4355 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r", 4356 &result) == FAILURE) { 4357 RETURN_FALSE; 4358 } 4359 4360 ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result); 4361 4362 pgsql_result = pg_result->result; 4363 if (!pgsql_result) { 4364 RETURN_FALSE; 4365 } 4366 err = (char *)PQresultErrorMessage(pgsql_result); 4367 RETURN_STRING(err,1); 4368} 4369/* }}} */ 4370 4371#if HAVE_PQRESULTERRORFIELD 4372/* {{{ proto string pg_result_error_field(resource result, int fieldcode) 4373 Get error message field associated with result */ 4374PHP_FUNCTION(pg_result_error_field) 4375{ 4376 zval *result; 4377 long fieldcode; 4378 PGresult *pgsql_result; 4379 pgsql_result_handle *pg_result; 4380 char *field = NULL; 4381 4382 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "rl", 4383 &result, &fieldcode) == FAILURE) { 4384 RETURN_FALSE; 4385 } 4386 4387 ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result); 4388 4389 pgsql_result = pg_result->result; 4390 if (!pgsql_result) { 4391 RETURN_FALSE; 4392 } 4393 if (fieldcode & (PG_DIAG_SEVERITY|PG_DIAG_SQLSTATE|PG_DIAG_MESSAGE_PRIMARY|PG_DIAG_MESSAGE_DETAIL 4394 |PG_DIAG_MESSAGE_HINT|PG_DIAG_STATEMENT_POSITION 4395#if PG_DIAG_INTERNAL_POSITION 4396 |PG_DIAG_INTERNAL_POSITION 4397#endif 4398#if PG_DIAG_INTERNAL_QUERY 4399 |PG_DIAG_INTERNAL_QUERY 4400#endif 4401 |PG_DIAG_CONTEXT|PG_DIAG_SOURCE_FILE|PG_DIAG_SOURCE_LINE 4402 |PG_DIAG_SOURCE_FUNCTION)) { 4403 field = (char *)PQresultErrorField(pgsql_result, fieldcode); 4404 if (field == NULL) { 4405 RETURN_NULL(); 4406 } else { 4407 RETURN_STRING(field, 1); 4408 } 4409 } else { 4410 RETURN_FALSE; 4411 } 4412} 4413/* }}} */ 4414#endif 4415 4416/* {{{ proto int pg_connection_status(resource connection) 4417 Get connection status */ 4418PHP_FUNCTION(pg_connection_status) 4419{ 4420 zval *pgsql_link = NULL; 4421 int id = -1; 4422 PGconn *pgsql; 4423 4424 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r", 4425 &pgsql_link) == FAILURE) { 4426 RETURN_FALSE; 4427 } 4428 4429 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink); 4430 4431 RETURN_LONG(PQstatus(pgsql)); 4432} 4433 4434/* }}} */ 4435 4436#if HAVE_PGTRANSACTIONSTATUS 4437/* {{{ proto int pg_transaction_status(resource connection) 4438 Get transaction status */ 4439PHP_FUNCTION(pg_transaction_status) 4440{ 4441 zval *pgsql_link = NULL; 4442 int id = -1; 4443 PGconn *pgsql; 4444 4445 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r", 4446 &pgsql_link) == FAILURE) { 4447 RETURN_FALSE; 4448 } 4449 4450 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink); 4451 4452 RETURN_LONG(PQtransactionStatus(pgsql)); 4453} 4454#endif 4455 4456/* }}} */ 4457 4458/* {{{ proto bool pg_connection_reset(resource connection) 4459 Reset connection (reconnect) */ 4460PHP_FUNCTION(pg_connection_reset) 4461{ 4462 zval *pgsql_link; 4463 int id = -1; 4464 PGconn *pgsql; 4465 4466 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r", 4467 &pgsql_link) == FAILURE) { 4468 RETURN_FALSE; 4469 } 4470 4471 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink); 4472 4473 PQreset(pgsql); 4474 if (PQstatus(pgsql) == CONNECTION_BAD) { 4475 RETURN_FALSE; 4476 } 4477 RETURN_TRUE; 4478} 4479 4480/* }}} */ 4481 4482#define PHP_PG_ASYNC_IS_BUSY 1 4483#define PHP_PG_ASYNC_REQUEST_CANCEL 2 4484 4485/* {{{ php_pgsql_flush_query 4486 */ 4487static int php_pgsql_flush_query(PGconn *pgsql TSRMLS_DC) 4488{ 4489 PGresult *res; 4490 int leftover = 0; 4491 4492 if (PQ_SETNONBLOCKING(pgsql, 1)) { 4493 php_error_docref(NULL TSRMLS_CC, E_NOTICE,"Cannot set connection to nonblocking mode"); 4494 return -1; 4495 } 4496 while ((res = PQgetResult(pgsql))) { 4497 PQclear(res); 4498 leftover++; 4499 } 4500 PQ_SETNONBLOCKING(pgsql, 0); 4501 return leftover; 4502} 4503/* }}} */ 4504 4505/* {{{ php_pgsql_do_async 4506 */ 4507static void php_pgsql_do_async(INTERNAL_FUNCTION_PARAMETERS, int entry_type) 4508{ 4509 zval *pgsql_link; 4510 int id = -1; 4511 PGconn *pgsql; 4512 PGresult *pgsql_result; 4513 4514 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r", 4515 &pgsql_link) == FAILURE) { 4516 RETURN_FALSE; 4517 } 4518 4519 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink); 4520 4521 if (PQ_SETNONBLOCKING(pgsql, 1)) { 4522 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to nonblocking mode"); 4523 RETURN_FALSE; 4524 } 4525 switch(entry_type) { 4526 case PHP_PG_ASYNC_IS_BUSY: 4527 PQconsumeInput(pgsql); 4528 Z_LVAL_P(return_value) = PQisBusy(pgsql); 4529 Z_TYPE_P(return_value) = IS_LONG; 4530 break; 4531 case PHP_PG_ASYNC_REQUEST_CANCEL: 4532 Z_LVAL_P(return_value) = PQrequestCancel(pgsql); 4533 Z_TYPE_P(return_value) = IS_LONG; 4534 while ((pgsql_result = PQgetResult(pgsql))) { 4535 PQclear(pgsql_result); 4536 } 4537 break; 4538 default: 4539 php_error_docref(NULL TSRMLS_CC, E_ERROR, "PostgreSQL module error, please report this error"); 4540 break; 4541 } 4542 if (PQ_SETNONBLOCKING(pgsql, 0)) { 4543 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to blocking mode"); 4544 } 4545 convert_to_boolean_ex(&return_value); 4546} 4547/* }}} */ 4548 4549/* {{{ proto bool pg_cancel_query(resource connection) 4550 Cancel request */ 4551PHP_FUNCTION(pg_cancel_query) 4552{ 4553 php_pgsql_do_async(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_PG_ASYNC_REQUEST_CANCEL); 4554} 4555/* }}} */ 4556 4557/* {{{ proto bool pg_connection_busy(resource connection) 4558 Get connection is busy or not */ 4559PHP_FUNCTION(pg_connection_busy) 4560{ 4561 php_pgsql_do_async(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_PG_ASYNC_IS_BUSY); 4562} 4563/* }}} */ 4564 4565/* {{{ proto bool pg_send_query(resource connection, string query) 4566 Send asynchronous query */ 4567PHP_FUNCTION(pg_send_query) 4568{ 4569 zval *pgsql_link; 4570 char *query; 4571 int len; 4572 int id = -1; 4573 PGconn *pgsql; 4574 PGresult *res; 4575 int leftover = 0; 4576 4577 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", 4578 &pgsql_link, &query, &len) == FAILURE) { 4579 return; 4580 } 4581 4582 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink); 4583 4584 if (PQ_SETNONBLOCKING(pgsql, 1)) { 4585 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to nonblocking mode"); 4586 RETURN_FALSE; 4587 } 4588 while ((res = PQgetResult(pgsql))) { 4589 PQclear(res); 4590 leftover = 1; 4591 } 4592 if (leftover) { 4593 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "There are results on this connection. Call pg_get_result() until it returns FALSE"); 4594 } 4595 if (!PQsendQuery(pgsql, query)) { 4596 if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) { 4597 PQreset(pgsql); 4598 } 4599 if (!PQsendQuery(pgsql, query)) { 4600 RETURN_FALSE; 4601 } 4602 } 4603 if (PQ_SETNONBLOCKING(pgsql, 0)) { 4604 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to blocking mode"); 4605 } 4606 RETURN_TRUE; 4607} 4608/* }}} */ 4609 4610#if HAVE_PQSENDQUERYPARAMS 4611/* {{{ proto bool pg_send_query_params(resource connection, string query, array params) 4612 Send asynchronous parameterized query */ 4613PHP_FUNCTION(pg_send_query_params) 4614{ 4615 zval *pgsql_link, *pv_param_arr, **tmp; 4616 int num_params = 0; 4617 char **params = NULL; 4618 char *query; 4619 int query_len, id = -1; 4620 PGconn *pgsql; 4621 PGresult *res; 4622 int leftover = 0; 4623 4624 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsa/", &pgsql_link, &query, &query_len, &pv_param_arr) == FAILURE) { 4625 return; 4626 } 4627 4628 if (pgsql_link == NULL && id == -1) { 4629 RETURN_FALSE; 4630 } 4631 4632 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink); 4633 4634 if (PQ_SETNONBLOCKING(pgsql, 1)) { 4635 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to nonblocking mode"); 4636 RETURN_FALSE; 4637 } 4638 while ((res = PQgetResult(pgsql))) { 4639 PQclear(res); 4640 leftover = 1; 4641 } 4642 if (leftover) { 4643 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "There are results on this connection. Call pg_get_result() until it returns FALSE"); 4644 } 4645 4646 zend_hash_internal_pointer_reset(Z_ARRVAL_P(pv_param_arr)); 4647 num_params = zend_hash_num_elements(Z_ARRVAL_P(pv_param_arr)); 4648 if (num_params > 0) { 4649 int i = 0; 4650 params = (char **)safe_emalloc(sizeof(char *), num_params, 0); 4651 4652 for(i = 0; i < num_params; i++) { 4653 if (zend_hash_get_current_data(Z_ARRVAL_P(pv_param_arr), (void **) &tmp) == FAILURE) { 4654 php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error getting parameter"); 4655 _php_pgsql_free_params(params, num_params); 4656 RETURN_FALSE; 4657 } 4658 4659 if (Z_TYPE_PP(tmp) == IS_NULL) { 4660 params[i] = NULL; 4661 } else { 4662 zval tmp_val = **tmp; 4663 zval_copy_ctor(&tmp_val); 4664 convert_to_string(&tmp_val); 4665 if (Z_TYPE(tmp_val) != IS_STRING) { 4666 php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error converting parameter"); 4667 zval_dtor(&tmp_val); 4668 _php_pgsql_free_params(params, num_params); 4669 RETURN_FALSE; 4670 } 4671 params[i] = estrndup(Z_STRVAL(tmp_val), Z_STRLEN(tmp_val)); 4672 zval_dtor(&tmp_val); 4673 } 4674 4675 zend_hash_move_forward(Z_ARRVAL_P(pv_param_arr)); 4676 } 4677 } 4678 4679 if (!PQsendQueryParams(pgsql, query, num_params, NULL, (const char * const *)params, NULL, NULL, 0)) { 4680 if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) { 4681 PQreset(pgsql); 4682 } 4683 if (!PQsendQueryParams(pgsql, query, num_params, NULL, (const char * const *)params, NULL, NULL, 0)) { 4684 _php_pgsql_free_params(params, num_params); 4685 RETURN_FALSE; 4686 } 4687 } 4688 _php_pgsql_free_params(params, num_params); 4689 if (PQ_SETNONBLOCKING(pgsql, 0)) { 4690 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to blocking mode"); 4691 } 4692 RETURN_TRUE; 4693} 4694/* }}} */ 4695#endif 4696 4697#if HAVE_PQSENDPREPARE 4698/* {{{ proto bool pg_send_prepare(resource connection, string stmtname, string query) 4699 Asynchronously prepare a query for future execution */ 4700PHP_FUNCTION(pg_send_prepare) 4701{ 4702 zval *pgsql_link; 4703 char *query, *stmtname; 4704 int stmtname_len, query_len, id = -1; 4705 PGconn *pgsql; 4706 PGresult *res; 4707 int leftover = 0; 4708 4709 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rss", &pgsql_link, &stmtname, &stmtname_len, &query, &query_len) == FAILURE) { 4710 return; 4711 } 4712 4713 if (pgsql_link == NULL && id == -1) { 4714 RETURN_FALSE; 4715 } 4716 4717 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink); 4718 4719 if (PQ_SETNONBLOCKING(pgsql, 1)) { 4720 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to nonblocking mode"); 4721 RETURN_FALSE; 4722 } 4723 while ((res = PQgetResult(pgsql))) { 4724 PQclear(res); 4725 leftover = 1; 4726 } 4727 if (leftover) { 4728 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "There are results on this connection. Call pg_get_result() until it returns FALSE"); 4729 } 4730 if (!PQsendPrepare(pgsql, stmtname, query, 0, NULL)) { 4731 if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) { 4732 PQreset(pgsql); 4733 } 4734 if (!PQsendPrepare(pgsql, stmtname, query, 0, NULL)) { 4735 RETURN_FALSE; 4736 } 4737 } 4738 if (PQ_SETNONBLOCKING(pgsql, 0)) { 4739 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to blocking mode"); 4740 } 4741 RETURN_TRUE; 4742} 4743/* }}} */ 4744#endif 4745 4746#if HAVE_PQSENDQUERYPREPARED 4747/* {{{ proto bool pg_send_execute(resource connection, string stmtname, array params) 4748 Executes prevriously prepared stmtname asynchronously */ 4749PHP_FUNCTION(pg_send_execute) 4750{ 4751 zval *pgsql_link; 4752 zval *pv_param_arr, **tmp; 4753 int num_params = 0; 4754 char **params = NULL; 4755 char *stmtname; 4756 int stmtname_len, id = -1; 4757 PGconn *pgsql; 4758 PGresult *res; 4759 int leftover = 0; 4760 4761 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsa", &pgsql_link, &stmtname, &stmtname_len, &pv_param_arr) == FAILURE) { 4762 return; 4763 } 4764 4765 if (pgsql_link == NULL && id == -1) { 4766 RETURN_FALSE; 4767 } 4768 4769 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink); 4770 4771 if (PQ_SETNONBLOCKING(pgsql, 1)) { 4772 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to nonblocking mode"); 4773 RETURN_FALSE; 4774 } 4775 while ((res = PQgetResult(pgsql))) { 4776 PQclear(res); 4777 leftover = 1; 4778 } 4779 if (leftover) { 4780 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "There are results on this connection. Call pg_get_result() until it returns FALSE"); 4781 } 4782 4783 zend_hash_internal_pointer_reset(Z_ARRVAL_P(pv_param_arr)); 4784 num_params = zend_hash_num_elements(Z_ARRVAL_P(pv_param_arr)); 4785 if (num_params > 0) { 4786 int i = 0; 4787 params = (char **)safe_emalloc(sizeof(char *), num_params, 0); 4788 4789 for(i = 0; i < num_params; i++) { 4790 if (zend_hash_get_current_data(Z_ARRVAL_P(pv_param_arr), (void **) &tmp) == FAILURE) { 4791 php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error getting parameter"); 4792 _php_pgsql_free_params(params, num_params); 4793 RETURN_FALSE; 4794 } 4795 4796 if (Z_TYPE_PP(tmp) == IS_NULL) { 4797 params[i] = NULL; 4798 } else { 4799 zval tmp_val = **tmp; 4800 zval_copy_ctor(&tmp_val); 4801 convert_to_string(&tmp_val); 4802 if (Z_TYPE(tmp_val) != IS_STRING) { 4803 php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error converting parameter"); 4804 zval_dtor(&tmp_val); 4805 _php_pgsql_free_params(params, num_params); 4806 RETURN_FALSE; 4807 } 4808 params[i] = estrndup(Z_STRVAL(tmp_val), Z_STRLEN(tmp_val)); 4809 zval_dtor(&tmp_val); 4810 } 4811 4812 zend_hash_move_forward(Z_ARRVAL_P(pv_param_arr)); 4813 } 4814 } 4815 4816 if (!PQsendQueryPrepared(pgsql, stmtname, num_params, (const char * const *)params, NULL, NULL, 0)) { 4817 if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) { 4818 PQreset(pgsql); 4819 } 4820 if (!PQsendQueryPrepared(pgsql, stmtname, num_params, (const char * const *)params, NULL, NULL, 0)) { 4821 _php_pgsql_free_params(params, num_params); 4822 RETURN_FALSE; 4823 } 4824 } 4825 _php_pgsql_free_params(params, num_params); 4826 if (PQ_SETNONBLOCKING(pgsql, 0)) { 4827 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to blocking mode"); 4828 } 4829 RETURN_TRUE; 4830} 4831/* }}} */ 4832#endif 4833 4834/* {{{ proto resource pg_get_result(resource connection) 4835 Get asynchronous query result */ 4836PHP_FUNCTION(pg_get_result) 4837{ 4838 zval *pgsql_link; 4839 int id = -1; 4840 PGconn *pgsql; 4841 PGresult *pgsql_result; 4842 pgsql_result_handle *pg_result; 4843 4844 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r", &pgsql_link) == FAILURE) { 4845 RETURN_FALSE; 4846 } 4847 4848 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink); 4849 4850 pgsql_result = PQgetResult(pgsql); 4851 if (!pgsql_result) { 4852 /* no result */ 4853 RETURN_FALSE; 4854 } 4855 pg_result = (pgsql_result_handle *) emalloc(sizeof(pgsql_result_handle)); 4856 pg_result->conn = pgsql; 4857 pg_result->result = pgsql_result; 4858 pg_result->row = 0; 4859 ZEND_REGISTER_RESOURCE(return_value, pg_result, le_result); 4860} 4861/* }}} */ 4862 4863/* {{{ proto mixed pg_result_status(resource result[, long result_type]) 4864 Get status of query result */ 4865PHP_FUNCTION(pg_result_status) 4866{ 4867 zval *result; 4868 long result_type = PGSQL_STATUS_LONG; 4869 ExecStatusType status; 4870 PGresult *pgsql_result; 4871 pgsql_result_handle *pg_result; 4872 4873 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r|l", 4874 &result, &result_type) == FAILURE) { 4875 RETURN_FALSE; 4876 } 4877 4878 ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result); 4879 4880 pgsql_result = pg_result->result; 4881 if (result_type == PGSQL_STATUS_LONG) { 4882 status = PQresultStatus(pgsql_result); 4883 RETURN_LONG((int)status); 4884 } 4885 else if (result_type == PGSQL_STATUS_STRING) { 4886 RETURN_STRING(PQcmdStatus(pgsql_result), 1); 4887 } 4888 else { 4889 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Optional 2nd parameter should be PGSQL_STATUS_LONG or PGSQL_STATUS_STRING"); 4890 RETURN_FALSE; 4891 } 4892} 4893/* }}} */ 4894 4895 4896/* {{{ proto array pg_get_notify([resource connection[, result_type]]) 4897 Get asynchronous notification */ 4898PHP_FUNCTION(pg_get_notify) 4899{ 4900 zval *pgsql_link; 4901 int id = -1; 4902 long result_type = PGSQL_ASSOC; 4903 PGconn *pgsql; 4904 PGnotify *pgsql_notify; 4905 4906 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r|l", 4907 &pgsql_link, &result_type) == FAILURE) { 4908 RETURN_FALSE; 4909 } 4910 4911 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink); 4912 4913 if (!(result_type & PGSQL_BOTH)) { 4914 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid result type"); 4915 RETURN_FALSE; 4916 } 4917 4918 PQconsumeInput(pgsql); 4919 pgsql_notify = PQnotifies(pgsql); 4920 if (!pgsql_notify) { 4921 /* no notify message */ 4922 RETURN_FALSE; 4923 } 4924 array_init(return_value); 4925 if (result_type & PGSQL_NUM) { 4926 add_index_string(return_value, 0, pgsql_notify->relname, 1); 4927 add_index_long(return_value, 1, pgsql_notify->be_pid); 4928#if HAVE_PQPROTOCOLVERSION && HAVE_PQPARAMETERSTATUS 4929 if (PQprotocolVersion(pgsql) >= 3 && atof(PQparameterStatus(pgsql, "server_version")) >= 9.0) { 4930#else 4931 if (atof(PG_VERSION) >= 9.0) { 4932#endif 4933#if HAVE_PQPARAMETERSTATUS 4934 add_index_string(return_value, 2, pgsql_notify->extra, 1); 4935#endif 4936 } 4937 } 4938 if (result_type & PGSQL_ASSOC) { 4939 add_assoc_string(return_value, "message", pgsql_notify->relname, 1); 4940 add_assoc_long(return_value, "pid", pgsql_notify->be_pid); 4941#if HAVE_PQPROTOCOLVERSION && HAVE_PQPARAMETERSTATUS 4942 if (PQprotocolVersion(pgsql) >= 3 && atof(PQparameterStatus(pgsql, "server_version")) >= 9.0) { 4943#else 4944 if (atof(PG_VERSION) >= 9.0) { 4945#endif 4946#if HAVE_PQPARAMETERSTATUS 4947 add_assoc_string(return_value, "payload", pgsql_notify->extra, 1); 4948#endif 4949 } 4950 } 4951 PQfreemem(pgsql_notify); 4952} 4953/* }}} */ 4954 4955/* {{{ proto int pg_get_pid([resource connection) 4956 Get backend(server) pid */ 4957PHP_FUNCTION(pg_get_pid) 4958{ 4959 zval *pgsql_link; 4960 int id = -1; 4961 PGconn *pgsql; 4962 4963 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r", 4964 &pgsql_link) == FAILURE) { 4965 RETURN_FALSE; 4966 } 4967 4968 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink); 4969 4970 RETURN_LONG(PQbackendPID(pgsql)); 4971} 4972/* }}} */ 4973 4974/* {{{ php_pgsql_meta_data 4975 * TODO: Add meta_data cache for better performance 4976 */ 4977PHP_PGSQL_API int php_pgsql_meta_data(PGconn *pg_link, const char *table_name, zval *meta TSRMLS_DC) 4978{ 4979 PGresult *pg_result; 4980 char *src, *tmp_name, *tmp_name2 = NULL; 4981 smart_str querystr = {0}; 4982 int new_len; 4983 int i, num_rows; 4984 zval *elem; 4985 4986 if (!*table_name) { 4987 php_error_docref(NULL TSRMLS_CC, E_WARNING, "The table name must be specified"); 4988 return FAILURE; 4989 } 4990 4991 src = estrdup(table_name); 4992 tmp_name = php_strtok_r(src, ".", &tmp_name2); 4993 4994 if (!tmp_name2 || !*tmp_name2) { 4995 /* Default schema */ 4996 tmp_name2 = tmp_name; 4997 tmp_name = "public"; 4998 } 4999 5000 smart_str_appends(&querystr, 5001 "SELECT a.attname, a.attnum, t.typname, a.attlen, a.attnotNULL, a.atthasdef, a.attndims " 5002 "FROM pg_class as c, pg_attribute a, pg_type t, pg_namespace n " 5003 "WHERE a.attnum > 0 AND a.attrelid = c.oid AND c.relname = '"); 5004 tmp_name2 = php_addslashes(tmp_name2, strlen(tmp_name2), &new_len, 0 TSRMLS_CC); 5005 smart_str_appendl(&querystr, tmp_name2, new_len); 5006 5007 smart_str_appends(&querystr, "' AND c.relnamespace = n.oid AND n.nspname = '"); 5008 tmp_name = php_addslashes(tmp_name, strlen(tmp_name), &new_len, 0 TSRMLS_CC); 5009 smart_str_appendl(&querystr, tmp_name, new_len); 5010 5011 smart_str_appends(&querystr, "' AND a.atttypid = t.oid ORDER BY a.attnum;"); 5012 smart_str_0(&querystr); 5013 5014 efree(tmp_name2); 5015 efree(tmp_name); 5016 efree(src); 5017 5018 pg_result = PQexec(pg_link, querystr.c); 5019 if (PQresultStatus(pg_result) != PGRES_TUPLES_OK || (num_rows = PQntuples(pg_result)) == 0) { 5020 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Table '%s' doesn't exists", table_name); 5021 smart_str_free(&querystr); 5022 PQclear(pg_result); 5023 return FAILURE; 5024 } 5025 smart_str_free(&querystr); 5026 5027 for (i = 0; i < num_rows; i++) { 5028 char *name; 5029 MAKE_STD_ZVAL(elem); 5030 array_init(elem); 5031 add_assoc_long(elem, "num", atoi(PQgetvalue(pg_result,i,1))); 5032 add_assoc_string(elem, "type", PQgetvalue(pg_result,i,2), 1); 5033 add_assoc_long(elem, "len", atoi(PQgetvalue(pg_result,i,3))); 5034 if (!strcmp(PQgetvalue(pg_result,i,4), "t")) { 5035 add_assoc_bool(elem, "not null", 1); 5036 } 5037 else { 5038 add_assoc_bool(elem, "not null", 0); 5039 } 5040 if (!strcmp(PQgetvalue(pg_result,i,5), "t")) { 5041 add_assoc_bool(elem, "has default", 1); 5042 } 5043 else { 5044 add_assoc_bool(elem, "has default", 0); 5045 } 5046 add_assoc_long(elem, "array dims", atoi(PQgetvalue(pg_result,i,6))); 5047 name = PQgetvalue(pg_result,i,0); 5048 add_assoc_zval(meta, name, elem); 5049 } 5050 PQclear(pg_result); 5051 5052 return SUCCESS; 5053} 5054 5055/* }}} */ 5056 5057 5058/* {{{ proto array pg_meta_data(resource db, string table) 5059 Get meta_data */ 5060PHP_FUNCTION(pg_meta_data) 5061{ 5062 zval *pgsql_link; 5063 char *table_name; 5064 uint table_name_len; 5065 PGconn *pgsql; 5066 int id = -1; 5067 5068 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", 5069 &pgsql_link, &table_name, &table_name_len) == FAILURE) { 5070 return; 5071 } 5072 5073 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink); 5074 5075 array_init(return_value); 5076 if (php_pgsql_meta_data(pgsql, table_name, return_value TSRMLS_CC) == FAILURE) { 5077 zval_dtor(return_value); /* destroy array */ 5078 RETURN_FALSE; 5079 } 5080} 5081/* }}} */ 5082 5083/* {{{ php_pgsql_get_data_type 5084 */ 5085static php_pgsql_data_type php_pgsql_get_data_type(const char *type_name, size_t len) 5086{ 5087 /* This is stupid way to do. I'll fix it when I decied how to support 5088 user defined types. (Yasuo) */ 5089 5090 /* boolean */ 5091 if (!strcmp(type_name, "bool")|| !strcmp(type_name, "boolean")) 5092 return PG_BOOL; 5093 /* object id */ 5094 if (!strcmp(type_name, "oid")) 5095 return PG_OID; 5096 /* integer */ 5097 if (!strcmp(type_name, "int2") || !strcmp(type_name, "smallint")) 5098 return PG_INT2; 5099 if (!strcmp(type_name, "int4") || !strcmp(type_name, "integer")) 5100 return PG_INT4; 5101 if (!strcmp(type_name, "int8") || !strcmp(type_name, "bigint")) 5102 return PG_INT8; 5103 /* real and other */ 5104 if (!strcmp(type_name, "float4") || !strcmp(type_name, "real")) 5105 return PG_FLOAT4; 5106 if (!strcmp(type_name, "float8") || !strcmp(type_name, "double precision")) 5107 return PG_FLOAT8; 5108 if (!strcmp(type_name, "numeric")) 5109 return PG_NUMERIC; 5110 if (!strcmp(type_name, "money")) 5111 return PG_MONEY; 5112 /* character */ 5113 if (!strcmp(type_name, "text")) 5114 return PG_TEXT; 5115 if (!strcmp(type_name, "bpchar") || !strcmp(type_name, "character")) 5116 return PG_CHAR; 5117 if (!strcmp(type_name, "varchar") || !strcmp(type_name, "character varying")) 5118 return PG_VARCHAR; 5119 /* time and interval */ 5120 if (!strcmp(type_name, "abstime")) 5121 return PG_UNIX_TIME; 5122 if (!strcmp(type_name, "reltime")) 5123 return PG_UNIX_TIME_INTERVAL; 5124 if (!strcmp(type_name, "tinterval")) 5125 return PG_UNIX_TIME_INTERVAL; 5126 if (!strcmp(type_name, "date")) 5127 return PG_DATE; 5128 if (!strcmp(type_name, "time")) 5129 return PG_TIME; 5130 if (!strcmp(type_name, "time with time zone") || !strcmp(type_name, "timetz")) 5131 return PG_TIME_WITH_TIMEZONE; 5132 if (!strcmp(type_name, "timestamp without time zone") || !strcmp(type_name, "timestamp")) 5133 return PG_TIMESTAMP; 5134 if (!strcmp(type_name, "timestamp with time zone") || !strcmp(type_name, "timestamptz")) 5135 return PG_TIMESTAMP_WITH_TIMEZONE; 5136 if (!strcmp(type_name, "interval")) 5137 return PG_INTERVAL; 5138 /* binary */ 5139 if (!strcmp(type_name, "bytea")) 5140 return PG_BYTEA; 5141 /* network */ 5142 if (!strcmp(type_name, "cidr")) 5143 return PG_CIDR; 5144 if (!strcmp(type_name, "inet")) 5145 return PG_INET; 5146 if (!strcmp(type_name, "macaddr")) 5147 return PG_MACADDR; 5148 /* bit */ 5149 if (!strcmp(type_name, "bit")) 5150 return PG_BIT; 5151 if (!strcmp(type_name, "bit varying")) 5152 return PG_VARBIT; 5153 /* geometric */ 5154 if (!strcmp(type_name, "line")) 5155 return PG_LINE; 5156 if (!strcmp(type_name, "lseg")) 5157 return PG_LSEG; 5158 if (!strcmp(type_name, "box")) 5159 return PG_BOX; 5160 if (!strcmp(type_name, "path")) 5161 return PG_PATH; 5162 if (!strcmp(type_name, "point")) 5163 return PG_POINT; 5164 if (!strcmp(type_name, "polygon")) 5165 return PG_POLYGON; 5166 if (!strcmp(type_name, "circle")) 5167 return PG_CIRCLE; 5168 5169 return PG_UNKNOWN; 5170} 5171/* }}} */ 5172 5173/* {{{ php_pgsql_convert_match 5174 * test field value with regular expression specified. 5175 */ 5176static int php_pgsql_convert_match(const char *str, const char *regex , int icase TSRMLS_DC) 5177{ 5178 regex_t re; 5179 regmatch_t *subs; 5180 int regopt = REG_EXTENDED; 5181 int regerr, ret = SUCCESS; 5182 5183 if (icase) { 5184 regopt |= REG_ICASE; 5185 } 5186 5187 regerr = regcomp(&re, regex, regopt); 5188 if (regerr) { 5189 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot compile regex"); 5190 regfree(&re); 5191 return FAILURE; 5192 } 5193 subs = (regmatch_t *)ecalloc(sizeof(regmatch_t), re.re_nsub+1); 5194 5195 regerr = regexec(&re, str, re.re_nsub+1, subs, 0); 5196 if (regerr == REG_NOMATCH) { 5197#ifdef PHP_DEBUG 5198 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "'%s' does not match with '%s'", str, regex); 5199#endif 5200 ret = FAILURE; 5201 } 5202 else if (regerr) { 5203 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot exec regex"); 5204 ret = FAILURE; 5205 } 5206 regfree(&re); 5207 efree(subs); 5208 return ret; 5209} 5210 5211/* }}} */ 5212 5213/* {{{ php_pgsql_add_quote 5214 * add quotes around string. 5215 */ 5216static int php_pgsql_add_quotes(zval *src, zend_bool should_free TSRMLS_DC) 5217{ 5218 smart_str str = {0}; 5219 5220 assert(Z_TYPE_P(src) == IS_STRING); 5221 assert(should_free == 1 || should_free == 0); 5222 5223 smart_str_appendc(&str, '\''); 5224 smart_str_appendl(&str, Z_STRVAL_P(src), Z_STRLEN_P(src)); 5225 smart_str_appendc(&str, '\''); 5226 smart_str_0(&str); 5227 5228 if (should_free) { 5229 efree(Z_STRVAL_P(src)); 5230 } 5231 Z_STRVAL_P(src) = str.c; 5232 Z_STRLEN_P(src) = str.len; 5233 5234 return SUCCESS; 5235} 5236/* }}} */ 5237 5238#define PGSQL_CONV_CHECK_IGNORE() \ 5239 if (!err && Z_TYPE_P(new_val) == IS_STRING && !strcmp(Z_STRVAL_P(new_val), "NULL")) { \ 5240 /* if new_value is string "NULL" and field has default value, remove element to use default value */ \ 5241 if (!(opt & PGSQL_CONV_IGNORE_DEFAULT) && Z_BVAL_PP(has_default)) { \ 5242 zval_dtor(new_val); \ 5243 FREE_ZVAL(new_val); \ 5244 skip_field = 1; \ 5245 } \ 5246 /* raise error if it's not null and cannot be ignored */ \ 5247 else if (!(opt & PGSQL_CONV_IGNORE_NOT_NULL) && Z_BVAL_PP(not_null)) { \ 5248 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected NULL for 'NOT NULL' field '%s'", field ); \ 5249 err = 1; \ 5250 } \ 5251 } 5252 5253/* {{{ php_pgsql_convert 5254 * check and convert array values (fieldname=>vlaue pair) for sql 5255 */ 5256PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, const zval *values, zval *result, ulong opt TSRMLS_DC) 5257{ 5258 HashPosition pos; 5259 char *field = NULL; 5260 uint field_len = -1; 5261 ulong num_idx = -1; 5262 zval *meta, **def, **type, **not_null, **has_default, **val, *new_val; 5263 int new_len, key_type, err = 0, skip_field; 5264 5265 assert(pg_link != NULL); 5266 assert(Z_TYPE_P(values) == IS_ARRAY); 5267 assert(Z_TYPE_P(result) == IS_ARRAY); 5268 assert(!(opt & ~PGSQL_CONV_OPTS)); 5269 5270 if (!table_name) { 5271 return FAILURE; 5272 } 5273 MAKE_STD_ZVAL(meta); 5274 array_init(meta); 5275 if (php_pgsql_meta_data(pg_link, table_name, meta TSRMLS_CC) == FAILURE) { 5276 zval_dtor(meta); 5277 FREE_ZVAL(meta); 5278 return FAILURE; 5279 } 5280 for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(values), &pos); 5281 zend_hash_get_current_data_ex(Z_ARRVAL_P(values), (void **)&val, &pos) == SUCCESS; 5282 zend_hash_move_forward_ex(Z_ARRVAL_P(values), &pos)) { 5283 skip_field = 0; 5284 new_val = NULL; 5285 5286 if ((key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(values), &field, &field_len, &num_idx, 0, &pos)) == HASH_KEY_NON_EXISTANT) { 5287 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to get array key type"); 5288 err = 1; 5289 } 5290 if (!err && key_type == HASH_KEY_IS_LONG) { 5291 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Accepts only string key for values"); 5292 err = 1; 5293 } 5294 if (!err && key_type == HASH_KEY_NON_EXISTANT) { 5295 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Accepts only string key for values"); 5296 err = 1; 5297 } 5298 if (!err && zend_hash_find(Z_ARRVAL_P(meta), field, field_len, (void **)&def) == FAILURE) { 5299 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Invalid field name (%s) in values", field); 5300 err = 1; 5301 } 5302 if (!err && zend_hash_find(Z_ARRVAL_PP(def), "type", sizeof("type"), (void **)&type) == FAILURE) { 5303 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected broken meta data. Missing 'type'"); 5304 err = 1; 5305 } 5306 if (!err && zend_hash_find(Z_ARRVAL_PP(def), "not null", sizeof("not null"), (void **)¬_null) == FAILURE) { 5307 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected broken meta data. Missing 'not null'"); 5308 err = 1; 5309 } 5310 if (!err && zend_hash_find(Z_ARRVAL_PP(def), "has default", sizeof("has default"), (void **)&has_default) == FAILURE) { 5311 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected broken meta data. Missing 'has default'"); 5312 err = 1; 5313 } 5314 if (!err && (Z_TYPE_PP(val) == IS_ARRAY || 5315 Z_TYPE_PP(val) == IS_OBJECT || 5316 Z_TYPE_PP(val) == IS_CONSTANT_ARRAY)) { 5317 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects scaler values as field values"); 5318 err = 1; 5319 } 5320 if (err) { 5321 break; /* break out for() */ 5322 } 5323 ALLOC_INIT_ZVAL(new_val); 5324 switch(php_pgsql_get_data_type(Z_STRVAL_PP(type), Z_STRLEN_PP(type))) 5325 { 5326 case PG_BOOL: 5327 switch (Z_TYPE_PP(val)) { 5328 case IS_STRING: 5329 if (Z_STRLEN_PP(val) == 0) { 5330 ZVAL_STRING(new_val, "NULL", 1); 5331 } 5332 else { 5333 if (!strcmp(Z_STRVAL_PP(val), "t") || !strcmp(Z_STRVAL_PP(val), "T") || 5334 !strcmp(Z_STRVAL_PP(val), "y") || !strcmp(Z_STRVAL_PP(val), "Y") || 5335 !strcmp(Z_STRVAL_PP(val), "true") || !strcmp(Z_STRVAL_PP(val), "True") || 5336 !strcmp(Z_STRVAL_PP(val), "yes") || !strcmp(Z_STRVAL_PP(val), "Yes") || 5337 !strcmp(Z_STRVAL_PP(val), "1")) { 5338 ZVAL_STRING(new_val, "'t'", 1); 5339 } 5340 else if (!strcmp(Z_STRVAL_PP(val), "f") || !strcmp(Z_STRVAL_PP(val), "F") || 5341 !strcmp(Z_STRVAL_PP(val), "n") || !strcmp(Z_STRVAL_PP(val), "N") || 5342 !strcmp(Z_STRVAL_PP(val), "false") || !strcmp(Z_STRVAL_PP(val), "False") || 5343 !strcmp(Z_STRVAL_PP(val), "no") || !strcmp(Z_STRVAL_PP(val), "No") || 5344 !strcmp(Z_STRVAL_PP(val), "0")) { 5345 ZVAL_STRING(new_val, "'f'", 1); 5346 } 5347 else { 5348 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected invalid value (%s) for PostgreSQL %s field (%s)", Z_STRVAL_PP(val), Z_STRVAL_PP(type), field); 5349 err = 1; 5350 } 5351 } 5352 break; 5353 5354 case IS_LONG: 5355 case IS_BOOL: 5356 if (Z_LVAL_PP(val)) { 5357 ZVAL_STRING(new_val, "'t'", 1); 5358 } 5359 else { 5360 ZVAL_STRING(new_val, "'f'", 1); 5361 } 5362 break; 5363 5364 case IS_NULL: 5365 ZVAL_STRING(new_val, "NULL", 1); 5366 break; 5367 5368 default: 5369 err = 1; 5370 } 5371 PGSQL_CONV_CHECK_IGNORE(); 5372 if (err) { 5373 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects string, null, long or boolelan value for PostgreSQL '%s' (%s)", Z_STRVAL_PP(type), field); 5374 } 5375 break; 5376 5377 case PG_OID: 5378 case PG_INT2: 5379 case PG_INT4: 5380 case PG_INT8: 5381 switch (Z_TYPE_PP(val)) { 5382 case IS_STRING: 5383 if (Z_STRLEN_PP(val) == 0) { 5384 ZVAL_STRING(new_val, "NULL", 1); 5385 } 5386 else { 5387 /* FIXME: better regex must be used */ 5388 if (php_pgsql_convert_match(Z_STRVAL_PP(val), "^([+-]{0,1}[0-9]+)$", 0 TSRMLS_CC) == FAILURE) { 5389 err = 1; 5390 } 5391 else { 5392 ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1); 5393 } 5394 } 5395 break; 5396 5397 case IS_DOUBLE: 5398 ZVAL_DOUBLE(new_val, Z_DVAL_PP(val)); 5399 convert_to_long_ex(&new_val); 5400 break; 5401 5402 case IS_LONG: 5403 ZVAL_LONG(new_val, Z_LVAL_PP(val)); 5404 break; 5405 5406 case IS_NULL: 5407 ZVAL_STRING(new_val, "NULL", 1); 5408 break; 5409 5410 default: 5411 err = 1; 5412 } 5413 PGSQL_CONV_CHECK_IGNORE(); 5414 if (err) { 5415 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL, string, long or double value for pgsql '%s' (%s)", Z_STRVAL_PP(type), field); 5416 } 5417 break; 5418 5419 case PG_NUMERIC: 5420 case PG_MONEY: 5421 case PG_FLOAT4: 5422 case PG_FLOAT8: 5423 switch (Z_TYPE_PP(val)) { 5424 case IS_STRING: 5425 if (Z_STRLEN_PP(val) == 0) { 5426 ZVAL_STRING(new_val, "NULL", 1); 5427 } 5428 else { 5429 /* FIXME: better regex must be used */ 5430 if (php_pgsql_convert_match(Z_STRVAL_PP(val), "^([+-]{0,1}[0-9]+)|([+-]{0,1}[0-9]*[\\.][0-9]+)|([+-]{0,1}[0-9]+[\\.][0-9]*)$", 0 TSRMLS_CC) == FAILURE) { 5431 err = 1; 5432 } 5433 else { 5434 ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1); 5435 } 5436 } 5437 break; 5438 5439 case IS_LONG: 5440 ZVAL_LONG(new_val, Z_LVAL_PP(val)); 5441 break; 5442 5443 case IS_DOUBLE: 5444 ZVAL_DOUBLE(new_val, Z_DVAL_PP(val)); 5445 break; 5446 5447 case IS_NULL: 5448 ZVAL_STRING(new_val, "NULL", 1); 5449 break; 5450 5451 default: 5452 err = 1; 5453 } 5454 PGSQL_CONV_CHECK_IGNORE(); 5455 if (err) { 5456 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL, string, long or double value for PostgreSQL '%s' (%s)", Z_STRVAL_PP(type), field); 5457 } 5458 break; 5459 5460 case PG_TEXT: 5461 case PG_CHAR: 5462 case PG_VARCHAR: 5463 switch (Z_TYPE_PP(val)) { 5464 case IS_STRING: 5465 if (Z_STRLEN_PP(val) == 0) { 5466 if (opt & PGSQL_CONV_FORCE_NULL) { 5467 ZVAL_STRING(new_val, "NULL", 1); 5468 } else { 5469 ZVAL_STRING(new_val, "''", 1); 5470 } 5471 } 5472 else { 5473 Z_TYPE_P(new_val) = IS_STRING; 5474#if HAVE_PQESCAPE 5475 { 5476 char *tmp; 5477 tmp = (char *)safe_emalloc(Z_STRLEN_PP(val), 2, 1); 5478 Z_STRLEN_P(new_val) = (int)PQescapeString(tmp, Z_STRVAL_PP(val), Z_STRLEN_PP(val)); 5479 Z_STRVAL_P(new_val) = tmp; 5480 } 5481#else 5482 Z_STRVAL_P(new_val) = php_addslashes(Z_STRVAL_PP(val), Z_STRLEN_PP(val), &Z_STRLEN_P(new_val), 0 TSRMLS_CC); 5483#endif 5484 php_pgsql_add_quotes(new_val, 1 TSRMLS_CC); 5485 } 5486 break; 5487 5488 case IS_LONG: 5489 ZVAL_LONG(new_val, Z_LVAL_PP(val)); 5490 convert_to_string_ex(&new_val); 5491 break; 5492 5493 case IS_DOUBLE: 5494 ZVAL_DOUBLE(new_val, Z_DVAL_PP(val)); 5495 convert_to_string_ex(&new_val); 5496 break; 5497 5498 case IS_NULL: 5499 ZVAL_STRING(new_val, "NULL", 1); 5500 break; 5501 5502 default: 5503 err = 1; 5504 } 5505 PGSQL_CONV_CHECK_IGNORE(); 5506 if (err) { 5507 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL, string, long or double value for PostgreSQL '%s' (%s)", Z_STRVAL_PP(type), field); 5508 } 5509 break; 5510 5511 case PG_UNIX_TIME: 5512 case PG_UNIX_TIME_INTERVAL: 5513 /* these are the actallay a integer */ 5514 switch (Z_TYPE_PP(val)) { 5515 case IS_STRING: 5516 if (Z_STRLEN_PP(val) == 0) { 5517 ZVAL_STRING(new_val, "NULL", 1); 5518 } 5519 else { 5520 /* FIXME: Better regex must be used */ 5521 if (php_pgsql_convert_match(Z_STRVAL_PP(val), "^[0-9]+$", 0 TSRMLS_CC) == FAILURE) { 5522 err = 1; 5523 } 5524 else { 5525 ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1); 5526 convert_to_long_ex(&new_val); 5527 } 5528 } 5529 break; 5530 5531 case IS_DOUBLE: 5532 ZVAL_DOUBLE(new_val, Z_DVAL_PP(val)); 5533 convert_to_long_ex(&new_val); 5534 break; 5535 5536 case IS_LONG: 5537 ZVAL_LONG(new_val, Z_LVAL_PP(val)); 5538 break; 5539 5540 case IS_NULL: 5541 ZVAL_STRING(new_val, "NULL", 1); 5542 break; 5543 5544 default: 5545 err = 1; 5546 } 5547 PGSQL_CONV_CHECK_IGNORE(); 5548 if (err) { 5549 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL, string, long or double value for '%s' (%s)", Z_STRVAL_PP(type), field); 5550 } 5551 break; 5552 5553 case PG_CIDR: 5554 case PG_INET: 5555 switch (Z_TYPE_PP(val)) { 5556 case IS_STRING: 5557 if (Z_STRLEN_PP(val) == 0) { 5558 ZVAL_STRING(new_val, "NULL", 1); 5559 } 5560 else { 5561 /* FIXME: Better regex must be used */ 5562 if (php_pgsql_convert_match(Z_STRVAL_PP(val), "^([0-9]{1,3}\\.){3}[0-9]{1,3}(/[0-9]{1,2}){0,1}$", 0 TSRMLS_CC) == FAILURE) { 5563 err = 1; 5564 } 5565 else { 5566 ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1); 5567 php_pgsql_add_quotes(new_val, 1 TSRMLS_CC); 5568 } 5569 } 5570 break; 5571 5572 case IS_NULL: 5573 ZVAL_STRING(new_val, "NULL", 1); 5574 break; 5575 5576 default: 5577 err = 1; 5578 } 5579 PGSQL_CONV_CHECK_IGNORE(); 5580 if (err) { 5581 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL or string for '%s' (%s)", Z_STRVAL_PP(type), field); 5582 } 5583 break; 5584 5585 case PG_TIME_WITH_TIMEZONE: 5586 case PG_TIMESTAMP: 5587 case PG_TIMESTAMP_WITH_TIMEZONE: 5588 switch(Z_TYPE_PP(val)) { 5589 case IS_STRING: 5590 if (Z_STRLEN_PP(val) == 0) { 5591 ZVAL_STRINGL(new_val, "NULL", sizeof("NULL")-1, 1); 5592 } else if (!strcasecmp(Z_STRVAL_PP(val), "now()")) { 5593 ZVAL_STRINGL(new_val, "NOW()", sizeof("NOW()")-1, 1); 5594 } else { 5595 /* FIXME: better regex must be used */ 5596 if (php_pgsql_convert_match(Z_STRVAL_PP(val), "^([0-9]{4}[/-][0-9]{1,2}[/-][0-9]{1,2})([ \\t]+(([0-9]{1,2}:[0-9]{1,2}){1}(:[0-9]{1,2}){0,1}(\\.[0-9]+){0,1}([ \\t]*([+-][0-9]{1,4}(:[0-9]{1,2}){0,1}|[-a-zA-Z_/+]{1,50})){0,1})){0,1}$", 1 TSRMLS_CC) == FAILURE) { 5597 err = 1; 5598 } else { 5599 ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1); 5600 php_pgsql_add_quotes(new_val, 1 TSRMLS_CC); 5601 } 5602 } 5603 break; 5604 5605 case IS_NULL: 5606 ZVAL_STRINGL(new_val, "NULL", sizeof("NULL")-1, 1); 5607 break; 5608 5609 default: 5610 err = 1; 5611 } 5612 PGSQL_CONV_CHECK_IGNORE(); 5613 if (err) { 5614 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_PP(type), field); 5615 } 5616 break; 5617 5618 case PG_DATE: 5619 switch(Z_TYPE_PP(val)) { 5620 case IS_STRING: 5621 if (Z_STRLEN_PP(val) == 0) { 5622 ZVAL_STRING(new_val, "NULL", 1); 5623 } 5624 else { 5625 /* FIXME: better regex must be used */ 5626 if (php_pgsql_convert_match(Z_STRVAL_PP(val), "^([0-9]{4}[/-][0-9]{1,2}[/-][0-9]{1,2})$", 1 TSRMLS_CC) == FAILURE) { 5627 err = 1; 5628 } 5629 else { 5630 ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1); 5631 php_pgsql_add_quotes(new_val, 1 TSRMLS_CC); 5632 } 5633 } 5634 break; 5635 5636 case IS_NULL: 5637 ZVAL_STRING(new_val, "NULL", 1); 5638 break; 5639 5640 default: 5641 err = 1; 5642 } 5643 PGSQL_CONV_CHECK_IGNORE(); 5644 if (err) { 5645 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_PP(type), field); 5646 } 5647 break; 5648 5649 case PG_TIME: 5650 switch(Z_TYPE_PP(val)) { 5651 case IS_STRING: 5652 if (Z_STRLEN_PP(val) == 0) { 5653 ZVAL_STRING(new_val, "NULL", 1); 5654 } 5655 else { 5656 /* FIXME: better regex must be used */ 5657 if (php_pgsql_convert_match(Z_STRVAL_PP(val), "^(([0-9]{1,2}:[0-9]{1,2}){1}(:[0-9]{1,2}){0,1})){0,1}$", 1 TSRMLS_CC) == FAILURE) { 5658 err = 1; 5659 } 5660 else { 5661 ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1); 5662 php_pgsql_add_quotes(new_val, 1 TSRMLS_CC); 5663 } 5664 } 5665 break; 5666 5667 case IS_NULL: 5668 ZVAL_STRING(new_val, "NULL", 1); 5669 break; 5670 5671 default: 5672 err = 1; 5673 } 5674 PGSQL_CONV_CHECK_IGNORE(); 5675 if (err) { 5676 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_PP(type), field); 5677 } 5678 break; 5679 5680 case PG_INTERVAL: 5681 switch(Z_TYPE_PP(val)) { 5682 case IS_STRING: 5683 if (Z_STRLEN_PP(val) == 0) { 5684 ZVAL_STRING(new_val, "NULL", 1); 5685 } 5686 else { 5687 5688 /* From the Postgres docs: 5689 5690 interval values can be written with the following syntax: 5691 [@] quantity unit [quantity unit...] [direction] 5692 5693 Where: quantity is a number (possibly signed); unit is second, minute, hour, 5694 day, week, month, year, decade, century, millennium, or abbreviations or 5695 plurals of these units [note not *all* abbreviations] ; direction can be 5696 ago or empty. The at sign (@) is optional noise. 5697 5698 ... 5699 5700 Quantities of days, hours, minutes, and seconds can be specified without explicit 5701 unit markings. For example, '1 12:59:10' is read the same as '1 day 12 hours 59 min 10 5702 sec'. 5703 */ 5704 if (php_pgsql_convert_match(Z_STRVAL_PP(val), 5705 "^(@?[ \\t]+)?(" 5706 5707 /* Textual time units and their abbreviations: */ 5708 "(([-+]?[ \\t]+)?" 5709 "[0-9]+(\\.[0-9]*)?[ \\t]*" 5710 "(millenniums|millennia|millennium|mil|mils|" 5711 "centuries|century|cent|c|" 5712 "decades|decade|dec|decs|" 5713 "years|year|y|" 5714 "months|month|mon|" 5715 "weeks|week|w|" 5716 "days|day|d|" 5717 "hours|hour|hr|hrs|h|" 5718 "minutes|minute|mins|min|m|" 5719 "seconds|second|secs|sec|s))+|" 5720 5721 /* Textual time units plus (dd)* hh[:mm[:ss]] */ 5722 "((([-+]?[ \\t]+)?" 5723 "[0-9]+(\\.[0-9]*)?[ \\t]*" 5724 "(millenniums|millennia|millennium|mil|mils|" 5725 "centuries|century|cent|c|" 5726 "decades|decade|dec|decs|" 5727 "years|year|y|" 5728 "months|month|mon|" 5729 "weeks|week|w|" 5730 "days|day|d))+" 5731 "([-+]?[ \\t]+" 5732 "([0-9]+[ \\t]+)+" /* dd */ 5733 "(([0-9]{1,2}:){0,2}[0-9]{0,2})" /* hh:[mm:[ss]] */ 5734 ")?))" 5735 "([ \\t]+ago)?$", 5736 1 TSRMLS_CC) == FAILURE) { 5737 err = 1; 5738 } 5739 else { 5740 ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1); 5741 php_pgsql_add_quotes(new_val, 1 TSRMLS_CC); 5742 } 5743 } 5744 break; 5745 5746 case IS_NULL: 5747 ZVAL_STRING(new_val, "NULL", 1); 5748 break; 5749 5750 default: 5751 err = 1; 5752 } 5753 PGSQL_CONV_CHECK_IGNORE(); 5754 if (err) { 5755 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_PP(type), field); 5756 } 5757 break; 5758#ifdef HAVE_PQESCAPE 5759 case PG_BYTEA: 5760 switch (Z_TYPE_PP(val)) { 5761 case IS_STRING: 5762 if (Z_STRLEN_PP(val) == 0) { 5763 ZVAL_STRING(new_val, "NULL", 1); 5764 } 5765 else { 5766 unsigned char *tmp; 5767 size_t to_len; 5768#ifdef HAVE_PQESCAPE_BYTEA_CONN 5769 tmp = PQescapeByteaConn(pg_link, Z_STRVAL_PP(val), Z_STRLEN_PP(val), &to_len); 5770#else 5771 tmp = PQescapeBytea(Z_STRVAL_PP(val), Z_STRLEN_PP(val), &to_len); 5772#endif 5773 Z_TYPE_P(new_val) = IS_STRING; 5774 Z_STRLEN_P(new_val) = to_len-1; /* PQescapeBytea's to_len includes additional '\0' */ 5775 Z_STRVAL_P(new_val) = emalloc(to_len); 5776 memcpy(Z_STRVAL_P(new_val), tmp, to_len); 5777 PQfreemem(tmp); 5778 php_pgsql_add_quotes(new_val, 1 TSRMLS_CC); 5779 5780 } 5781 break; 5782 5783 case IS_LONG: 5784 ZVAL_LONG(new_val, Z_LVAL_PP(val)); 5785 convert_to_string_ex(&new_val); 5786 break; 5787 5788 case IS_DOUBLE: 5789 ZVAL_DOUBLE(new_val, Z_DVAL_PP(val)); 5790 convert_to_string_ex(&new_val); 5791 break; 5792 5793 case IS_NULL: 5794 ZVAL_STRING(new_val, "NULL", 1); 5795 break; 5796 5797 default: 5798 err = 1; 5799 } 5800 PGSQL_CONV_CHECK_IGNORE(); 5801 if (err) { 5802 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL, string, long or double value for PostgreSQL '%s' (%s)", Z_STRVAL_PP(type), field); 5803 } 5804 break; 5805 5806#endif 5807 case PG_MACADDR: 5808 switch(Z_TYPE_PP(val)) { 5809 case IS_STRING: 5810 if (Z_STRLEN_PP(val) == 0) { 5811 ZVAL_STRING(new_val, "NULL", 1); 5812 } 5813 else { 5814 if (php_pgsql_convert_match(Z_STRVAL_PP(val), "^([0-9a-f]{2,2}:){5,5}[0-9a-f]{2,2}$", 1 TSRMLS_CC) == FAILURE) { 5815 err = 1; 5816 } 5817 else { 5818 ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1); 5819 php_pgsql_add_quotes(new_val, 1 TSRMLS_CC); 5820 } 5821 } 5822 break; 5823 5824 case IS_NULL: 5825 ZVAL_STRING(new_val, "NULL", 1); 5826 break; 5827 5828 default: 5829 err = 1; 5830 } 5831 PGSQL_CONV_CHECK_IGNORE(); 5832 if (err) { 5833 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_PP(type), field); 5834 } 5835 break; 5836 5837 /* bit */ 5838 case PG_BIT: 5839 case PG_VARBIT: 5840 /* geometric */ 5841 case PG_LINE: 5842 case PG_LSEG: 5843 case PG_POINT: 5844 case PG_BOX: 5845 case PG_PATH: 5846 case PG_POLYGON: 5847 case PG_CIRCLE: 5848 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "PostgreSQL '%s' type (%s) is not supported", Z_STRVAL_PP(type), field); 5849 err = 1; 5850 break; 5851 5852 case PG_UNKNOWN: 5853 default: 5854 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Unknown or system data type '%s' for '%s'", Z_STRVAL_PP(type), field); 5855 err = 1; 5856 break; 5857 } /* switch */ 5858 5859 if (err) { 5860 zval_dtor(new_val); 5861 FREE_ZVAL(new_val); 5862 break; /* break out for() */ 5863 } 5864 if (!skip_field) { 5865 /* If field is NULL and HAS DEFAULT, should be skipped */ 5866 field = php_addslashes(field, strlen(field), &new_len, 0 TSRMLS_CC); 5867 add_assoc_zval(result, field, new_val); 5868 efree(field); 5869 } 5870 } /* for */ 5871 zval_dtor(meta); 5872 FREE_ZVAL(meta); 5873 5874 if (err) { 5875 /* shouldn't destroy & free zval here */ 5876 return FAILURE; 5877 } 5878 return SUCCESS; 5879} 5880/* }}} */ 5881 5882 5883/* {{{ proto array pg_convert(resource db, string table, array values[, int options]) 5884 Check and convert values for PostgreSQL SQL statement */ 5885PHP_FUNCTION(pg_convert) 5886{ 5887 zval *pgsql_link, *values; 5888 char *table_name; 5889 int table_name_len; 5890 ulong option = 0; 5891 PGconn *pg_link; 5892 int id = -1; 5893 5894 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, 5895 "rsa|l", &pgsql_link, &table_name, &table_name_len, &values, &option) == FAILURE) { 5896 return; 5897 } 5898 if (option & ~PGSQL_CONV_OPTS) { 5899 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid option is specified"); 5900 RETURN_FALSE; 5901 } 5902 if (!table_name_len) { 5903 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Table name is invalid"); 5904 RETURN_FALSE; 5905 } 5906 5907 ZEND_FETCH_RESOURCE2(pg_link, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink); 5908 5909 if (php_pgsql_flush_query(pg_link TSRMLS_CC)) { 5910 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected unhandled result(s) in connection"); 5911 } 5912 array_init(return_value); 5913 if (php_pgsql_convert(pg_link, table_name, values, return_value, option TSRMLS_CC) == FAILURE) { 5914 zval_dtor(return_value); 5915 RETURN_FALSE; 5916 } 5917} 5918/* }}} */ 5919 5920static int do_exec(smart_str *querystr, int expect, PGconn *pg_link, ulong opt TSRMLS_DC) 5921{ 5922 if (opt & PGSQL_DML_ASYNC) { 5923 if (PQsendQuery(pg_link, querystr->c)) { 5924 return 0; 5925 } 5926 } 5927 else { 5928 PGresult *pg_result; 5929 5930 pg_result = PQexec(pg_link, querystr->c); 5931 if (PQresultStatus(pg_result) == expect) { 5932 PQclear(pg_result); 5933 return 0; 5934 } else { 5935 php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", PQresultErrorMessage(pg_result)); 5936 PQclear(pg_result); 5937 } 5938 } 5939 5940 return -1; 5941} 5942 5943/* {{{ php_pgsql_insert 5944 */ 5945PHP_PGSQL_API int php_pgsql_insert(PGconn *pg_link, const char *table, zval *var_array, ulong opt, char **sql TSRMLS_DC) 5946{ 5947 zval **val, *converted = NULL; 5948 char buf[256]; 5949 char *fld; 5950 smart_str querystr = {0}; 5951 int key_type, ret = FAILURE; 5952 uint fld_len; 5953 ulong num_idx; 5954 HashPosition pos; 5955 5956 assert(pg_link != NULL); 5957 assert(table != NULL); 5958 assert(Z_TYPE_P(var_array) == IS_ARRAY); 5959 5960 if (zend_hash_num_elements(Z_ARRVAL_P(var_array)) == 0) { 5961 smart_str_appends(&querystr, "INSERT INTO "); 5962 smart_str_appends(&querystr, table); 5963 smart_str_appends(&querystr, " DEFAULT VALUES"); 5964 5965 goto no_values; 5966 } 5967 5968 /* convert input array if needed */ 5969 if (!(opt & PGSQL_DML_NO_CONV)) { 5970 MAKE_STD_ZVAL(converted); 5971 array_init(converted); 5972 if (php_pgsql_convert(pg_link, table, var_array, converted, (opt & PGSQL_CONV_OPTS) TSRMLS_CC) == FAILURE) { 5973 goto cleanup; 5974 } 5975 var_array = converted; 5976 } 5977 5978 smart_str_appends(&querystr, "INSERT INTO "); 5979 smart_str_appends(&querystr, table); 5980 smart_str_appends(&querystr, " ("); 5981 5982 zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(var_array), &pos); 5983 while ((key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(var_array), &fld, 5984 &fld_len, &num_idx, 0, &pos)) != HASH_KEY_NON_EXISTANT) { 5985 if (key_type == HASH_KEY_IS_LONG) { 5986 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects associative array for values to be inserted"); 5987 goto cleanup; 5988 } 5989 smart_str_appendl(&querystr, fld, fld_len - 1); 5990 smart_str_appendc(&querystr, ','); 5991 zend_hash_move_forward_ex(Z_ARRVAL_P(var_array), &pos); 5992 } 5993 querystr.len--; 5994 smart_str_appends(&querystr, ") VALUES ("); 5995 5996 /* make values string */ 5997 for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(var_array), &pos); 5998 zend_hash_get_current_data_ex(Z_ARRVAL_P(var_array), (void **)&val, &pos) == SUCCESS; 5999 zend_hash_move_forward_ex(Z_ARRVAL_P(var_array), &pos)) { 6000 6001 /* we can avoid the key_type check here, because we tested it in the other loop */ 6002 switch(Z_TYPE_PP(val)) { 6003 case IS_STRING: 6004 smart_str_appendl(&querystr, Z_STRVAL_PP(val), Z_STRLEN_PP(val)); 6005 break; 6006 case IS_LONG: 6007 smart_str_append_long(&querystr, Z_LVAL_PP(val)); 6008 break; 6009 case IS_DOUBLE: 6010 smart_str_appendl(&querystr, buf, snprintf(buf, sizeof(buf), "%F", Z_DVAL_PP(val))); 6011 break; 6012 default: 6013 /* should not happen */ 6014 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Report this error to php-dev@lists.php.net, type = %d", Z_TYPE_PP(val)); 6015 goto cleanup; 6016 break; 6017 } 6018 smart_str_appendc(&querystr, ','); 6019 } 6020 /* Remove the trailing "," */ 6021 querystr.len--; 6022 smart_str_appends(&querystr, ");"); 6023 6024no_values: 6025 6026 smart_str_0(&querystr); 6027 6028 if ((opt & (PGSQL_DML_EXEC|PGSQL_DML_ASYNC)) && 6029 do_exec(&querystr, PGRES_COMMAND_OK, pg_link, (opt & PGSQL_CONV_OPTS) TSRMLS_CC) == 0) { 6030 ret = SUCCESS; 6031 } 6032 else if (opt & PGSQL_DML_STRING) { 6033 ret = SUCCESS; 6034 } 6035 6036cleanup: 6037 if (!(opt & PGSQL_DML_NO_CONV) && converted) { 6038 zval_dtor(converted); 6039 FREE_ZVAL(converted); 6040 } 6041 if (ret == SUCCESS && (opt & PGSQL_DML_STRING)) { 6042 *sql = querystr.c; 6043 } 6044 else { 6045 smart_str_free(&querystr); 6046 } 6047 return ret; 6048} 6049/* }}} */ 6050 6051/* {{{ proto mixed pg_insert(resource db, string table, array values[, int options]) 6052 Insert values (filed=>value) to table */ 6053PHP_FUNCTION(pg_insert) 6054{ 6055 zval *pgsql_link, *values; 6056 char *table, *sql = NULL; 6057 int table_len; 6058 ulong option = PGSQL_DML_EXEC; 6059 PGconn *pg_link; 6060 int id = -1, argc = ZEND_NUM_ARGS(); 6061 6062 if (zend_parse_parameters(argc TSRMLS_CC, "rsa|l", 6063 &pgsql_link, &table, &table_len, &values, &option) == FAILURE) { 6064 return; 6065 } 6066 if (option & ~(PGSQL_CONV_OPTS|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_ASYNC|PGSQL_DML_STRING)) { 6067 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid option is specified"); 6068 RETURN_FALSE; 6069 } 6070 6071 ZEND_FETCH_RESOURCE2(pg_link, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink); 6072 6073 if (php_pgsql_flush_query(pg_link TSRMLS_CC)) { 6074 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected unhandled result(s) in connection"); 6075 } 6076 if (php_pgsql_insert(pg_link, table, values, option, &sql TSRMLS_CC) == FAILURE) { 6077 RETURN_FALSE; 6078 } 6079 if (option & PGSQL_DML_STRING) { 6080 RETURN_STRING(sql, 0); 6081 } 6082 RETURN_TRUE; 6083} 6084/* }}} */ 6085 6086static inline int build_assignment_string(smart_str *