1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 7 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2018 The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Authors: Edin Kadribasic <edink@emini.dk> |
16 | Ilia Alshanestsky <ilia@prohost.org> |
17 | Wez Furlong <wez@php.net> |
18 +----------------------------------------------------------------------+
19 */
20
21 /* $Id$ */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include "php.h"
28 #include "php_ini.h"
29 #include "ext/standard/info.h"
30 #include "ext/standard/php_string.h"
31 #include "main/php_network.h"
32 #include "pdo/php_pdo.h"
33 #include "pdo/php_pdo_driver.h"
34 #include "pdo/php_pdo_error.h"
35 #include "ext/standard/file.h"
36
37 #undef PACKAGE_BUGREPORT
38 #undef PACKAGE_NAME
39 #undef PACKAGE_STRING
40 #undef PACKAGE_TARNAME
41 #undef PACKAGE_VERSION
42 #include "pg_config.h" /* needed for PG_VERSION */
43 #include "php_pdo_pgsql.h"
44 #include "php_pdo_pgsql_int.h"
45 #include "zend_exceptions.h"
46
_pdo_pgsql_trim_message(const char * message,int persistent)47 static char * _pdo_pgsql_trim_message(const char *message, int persistent)
48 {
49 register int i = strlen(message)-1;
50 char *tmp;
51
52 if (i>1 && (message[i-1] == '\r' || message[i-1] == '\n') && message[i] == '.') {
53 --i;
54 }
55 while (i>0 && (message[i] == '\r' || message[i] == '\n')) {
56 --i;
57 }
58 ++i;
59 tmp = pemalloc(i + 1, persistent);
60 memcpy(tmp, message, i);
61 tmp[i] = '\0';
62
63 return tmp;
64 }
65
_pdo_pgsql_escape_credentials(char * str)66 static zend_string* _pdo_pgsql_escape_credentials(char *str)
67 {
68 if (str) {
69 zend_string *tmp = zend_string_init(str, strlen(str), 0);
70
71 return php_addcslashes(tmp, 1, "\\'", sizeof("\\'"));
72 }
73
74 return NULL;
75 }
76
_pdo_pgsql_error(pdo_dbh_t * dbh,pdo_stmt_t * stmt,int errcode,const char * sqlstate,const char * msg,const char * file,int line)77 int _pdo_pgsql_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, int errcode, const char *sqlstate, const char *msg, const char *file, int line) /* {{{ */
78 {
79 pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data;
80 pdo_error_type *pdo_err = stmt ? &stmt->error_code : &dbh->error_code;
81 pdo_pgsql_error_info *einfo = &H->einfo;
82 char *errmsg = PQerrorMessage(H->server);
83
84 einfo->errcode = errcode;
85 einfo->file = file;
86 einfo->line = line;
87
88 if (einfo->errmsg) {
89 pefree(einfo->errmsg, dbh->is_persistent);
90 einfo->errmsg = NULL;
91 }
92
93 if (sqlstate == NULL || strlen(sqlstate) >= sizeof(pdo_error_type)) {
94 strcpy(*pdo_err, "HY000");
95 }
96 else {
97 strcpy(*pdo_err, sqlstate);
98 }
99
100 if (msg) {
101 einfo->errmsg = estrdup(msg);
102 }
103 else if (errmsg) {
104 einfo->errmsg = _pdo_pgsql_trim_message(errmsg, dbh->is_persistent);
105 }
106
107 if (!dbh->methods) {
108 zend_throw_exception_ex(php_pdo_get_exception(), einfo->errcode, "SQLSTATE[%s] [%d] %s",
109 *pdo_err, einfo->errcode, einfo->errmsg);
110 }
111
112 return errcode;
113 }
114 /* }}} */
115
_pdo_pgsql_notice(pdo_dbh_t * dbh,const char * message)116 static void _pdo_pgsql_notice(pdo_dbh_t *dbh, const char *message) /* {{{ */
117 {
118 /* pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data; */
119 }
120 /* }}} */
121
pdo_pgsql_fetch_error_func(pdo_dbh_t * dbh,pdo_stmt_t * stmt,zval * info)122 static int pdo_pgsql_fetch_error_func(pdo_dbh_t *dbh, pdo_stmt_t *stmt, zval *info) /* {{{ */
123 {
124 pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data;
125 pdo_pgsql_error_info *einfo = &H->einfo;
126
127 if (einfo->errcode) {
128 add_next_index_long(info, einfo->errcode);
129 add_next_index_string(info, einfo->errmsg);
130 }
131
132 return 1;
133 }
134 /* }}} */
135
136 /* {{{ pdo_pgsql_create_lob_stream */
pgsql_lob_write(php_stream * stream,const char * buf,size_t count)137 static size_t pgsql_lob_write(php_stream *stream, const char *buf, size_t count)
138 {
139 struct pdo_pgsql_lob_self *self = (struct pdo_pgsql_lob_self*)stream->abstract;
140 return lo_write(self->conn, self->lfd, (char*)buf, count);
141 }
142
pgsql_lob_read(php_stream * stream,char * buf,size_t count)143 static size_t pgsql_lob_read(php_stream *stream, char *buf, size_t count)
144 {
145 struct pdo_pgsql_lob_self *self = (struct pdo_pgsql_lob_self*)stream->abstract;
146 return lo_read(self->conn, self->lfd, buf, count);
147 }
148
pgsql_lob_close(php_stream * stream,int close_handle)149 static int pgsql_lob_close(php_stream *stream, int close_handle)
150 {
151 struct pdo_pgsql_lob_self *self = (struct pdo_pgsql_lob_self*)stream->abstract;
152
153 if (close_handle) {
154 lo_close(self->conn, self->lfd);
155 }
156 zval_ptr_dtor(&self->dbh);
157 efree(self);
158 return 0;
159 }
160
pgsql_lob_flush(php_stream * stream)161 static int pgsql_lob_flush(php_stream *stream)
162 {
163 return 0;
164 }
165
pgsql_lob_seek(php_stream * stream,zend_off_t offset,int whence,zend_off_t * newoffset)166 static int pgsql_lob_seek(php_stream *stream, zend_off_t offset, int whence,
167 zend_off_t *newoffset)
168 {
169 struct pdo_pgsql_lob_self *self = (struct pdo_pgsql_lob_self*)stream->abstract;
170 #if HAVE_PG_LO64 && ZEND_ENABLE_ZVAL_LONG64
171 zend_off_t pos = lo_lseek64(self->conn, self->lfd, offset, whence);
172 #else
173 zend_off_t pos = lo_lseek(self->conn, self->lfd, offset, whence);
174 #endif
175 *newoffset = pos;
176 return pos >= 0 ? 0 : -1;
177 }
178
179 php_stream_ops pdo_pgsql_lob_stream_ops = {
180 pgsql_lob_write,
181 pgsql_lob_read,
182 pgsql_lob_close,
183 pgsql_lob_flush,
184 "pdo_pgsql lob stream",
185 pgsql_lob_seek,
186 NULL,
187 NULL,
188 NULL
189 };
190
pdo_pgsql_create_lob_stream(zval * dbh,int lfd,Oid oid)191 php_stream *pdo_pgsql_create_lob_stream(zval *dbh, int lfd, Oid oid)
192 {
193 php_stream *stm;
194 struct pdo_pgsql_lob_self *self = ecalloc(1, sizeof(*self));
195 pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)(Z_PDO_DBH_P(dbh))->driver_data;
196
197 ZVAL_COPY_VALUE(&self->dbh, dbh);
198 self->lfd = lfd;
199 self->oid = oid;
200 self->conn = H->server;
201
202 stm = php_stream_alloc(&pdo_pgsql_lob_stream_ops, self, 0, "r+b");
203
204 if (stm) {
205 Z_ADDREF_P(dbh);
206 return stm;
207 }
208
209 efree(self);
210 return NULL;
211 }
212 /* }}} */
213
pgsql_handle_closer(pdo_dbh_t * dbh)214 static int pgsql_handle_closer(pdo_dbh_t *dbh) /* {{{ */
215 {
216 pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data;
217 if (H) {
218 if (H->server) {
219 PQfinish(H->server);
220 H->server = NULL;
221 }
222 if (H->einfo.errmsg) {
223 pefree(H->einfo.errmsg, dbh->is_persistent);
224 H->einfo.errmsg = NULL;
225 }
226 pefree(H, dbh->is_persistent);
227 dbh->driver_data = NULL;
228 }
229 return 0;
230 }
231 /* }}} */
232
pgsql_handle_preparer(pdo_dbh_t * dbh,const char * sql,size_t sql_len,pdo_stmt_t * stmt,zval * driver_options)233 static int pgsql_handle_preparer(pdo_dbh_t *dbh, const char *sql, size_t sql_len, pdo_stmt_t *stmt, zval *driver_options)
234 {
235 pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data;
236 pdo_pgsql_stmt *S = ecalloc(1, sizeof(pdo_pgsql_stmt));
237 int scrollable;
238 int ret;
239 char *nsql = NULL;
240 size_t nsql_len = 0;
241 int emulate = 0;
242 int execute_only = 0;
243
244 S->H = H;
245 stmt->driver_data = S;
246 stmt->methods = &pgsql_stmt_methods;
247
248 scrollable = pdo_attr_lval(driver_options, PDO_ATTR_CURSOR,
249 PDO_CURSOR_FWDONLY) == PDO_CURSOR_SCROLL;
250
251 if (scrollable) {
252 if (S->cursor_name) {
253 efree(S->cursor_name);
254 }
255 spprintf(&S->cursor_name, 0, "pdo_crsr_%08x", ++H->stmt_counter);
256 emulate = 1;
257 } else if (driver_options) {
258 if (pdo_attr_lval(driver_options, PDO_ATTR_EMULATE_PREPARES, H->emulate_prepares) == 1) {
259 emulate = 1;
260 }
261 if (pdo_attr_lval(driver_options, PDO_PGSQL_ATTR_DISABLE_PREPARES, H->disable_prepares) == 1) {
262 execute_only = 1;
263 }
264 } else {
265 emulate = H->disable_native_prepares || H->emulate_prepares;
266 execute_only = H->disable_prepares;
267 }
268
269 if (!emulate && PQprotocolVersion(H->server) > 2) {
270 stmt->supports_placeholders = PDO_PLACEHOLDER_NAMED;
271 stmt->named_rewrite_template = "$%d";
272 ret = pdo_parse_params(stmt, (char*)sql, sql_len, &nsql, &nsql_len);
273
274 if (ret == 1) {
275 /* query was re-written */
276 sql = nsql;
277 } else if (ret == -1) {
278 /* couldn't grok it */
279 strcpy(dbh->error_code, stmt->error_code);
280 return 0;
281 }
282
283 if (!execute_only) {
284 /* prepared query: set the query name and defer the
285 actual prepare until the first execute call */
286 spprintf(&S->stmt_name, 0, "pdo_stmt_%08x", ++H->stmt_counter);
287 }
288
289 if (nsql) {
290 S->query = nsql;
291 } else {
292 S->query = estrdup(sql);
293 }
294
295 return 1;
296 }
297
298 stmt->supports_placeholders = PDO_PLACEHOLDER_NONE;
299 return 1;
300 }
301
pgsql_handle_doer(pdo_dbh_t * dbh,const char * sql,size_t sql_len)302 static zend_long pgsql_handle_doer(pdo_dbh_t *dbh, const char *sql, size_t sql_len)
303 {
304 pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data;
305 PGresult *res;
306 zend_long ret = 1;
307 ExecStatusType qs;
308
309 if (!(res = PQexec(H->server, sql))) {
310 /* fatal error */
311 pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, NULL);
312 return -1;
313 }
314 qs = PQresultStatus(res);
315 if (qs != PGRES_COMMAND_OK && qs != PGRES_TUPLES_OK) {
316 pdo_pgsql_error(dbh, qs, pdo_pgsql_sqlstate(res));
317 PQclear(res);
318 return -1;
319 }
320 H->pgoid = PQoidValue(res);
321 if (qs == PGRES_COMMAND_OK) {
322 ZEND_ATOL(ret, PQcmdTuples(res));
323 } else {
324 ret = Z_L(0);
325 }
326 PQclear(res);
327
328 return ret;
329 }
330
pgsql_handle_quoter(pdo_dbh_t * dbh,const char * unquoted,size_t unquotedlen,char ** quoted,size_t * quotedlen,enum pdo_param_type paramtype)331 static int pgsql_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, size_t unquotedlen, char **quoted, size_t *quotedlen, enum pdo_param_type paramtype)
332 {
333 unsigned char *escaped;
334 pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data;
335 size_t tmp_len;
336
337 switch (paramtype) {
338 case PDO_PARAM_LOB:
339 /* escapedlen returned by PQescapeBytea() accounts for trailing 0 */
340 escaped = PQescapeByteaConn(H->server, (unsigned char *)unquoted, unquotedlen, &tmp_len);
341 *quotedlen = tmp_len + 1;
342 *quoted = emalloc(*quotedlen + 1);
343 memcpy((*quoted)+1, escaped, *quotedlen-2);
344 (*quoted)[0] = '\'';
345 (*quoted)[*quotedlen-1] = '\'';
346 (*quoted)[*quotedlen] = '\0';
347 PQfreemem(escaped);
348 break;
349 default:
350 *quoted = safe_emalloc(2, unquotedlen, 3);
351 (*quoted)[0] = '\'';
352 *quotedlen = PQescapeStringConn(H->server, *quoted + 1, unquoted, unquotedlen, NULL);
353 (*quoted)[*quotedlen + 1] = '\'';
354 (*quoted)[*quotedlen + 2] = '\0';
355 *quotedlen += 2;
356 }
357 return 1;
358 }
359
pdo_pgsql_last_insert_id(pdo_dbh_t * dbh,const char * name,size_t * len)360 static char *pdo_pgsql_last_insert_id(pdo_dbh_t *dbh, const char *name, size_t *len)
361 {
362 pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data;
363 char *id = NULL;
364 PGresult *res;
365 ExecStatusType status;
366
367 if (name == NULL) {
368 res = PQexec(H->server, "SELECT LASTVAL()");
369 } else {
370 const char *q[1];
371 q[0] = name;
372
373 res = PQexecParams(H->server, "SELECT CURRVAL($1)", 1, NULL, q, NULL, NULL, 0);
374 }
375 status = PQresultStatus(res);
376
377 if (res && (status == PGRES_TUPLES_OK)) {
378 id = estrdup((char *)PQgetvalue(res, 0, 0));
379 *len = PQgetlength(res, 0, 0);
380 } else {
381 pdo_pgsql_error(dbh, status, pdo_pgsql_sqlstate(res));
382 }
383
384 if (res) {
385 PQclear(res);
386 }
387
388 return id;
389 }
390
pdo_pgsql_get_attribute(pdo_dbh_t * dbh,zend_long attr,zval * return_value)391 static int pdo_pgsql_get_attribute(pdo_dbh_t *dbh, zend_long attr, zval *return_value)
392 {
393 pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data;
394
395 switch (attr) {
396 case PDO_ATTR_EMULATE_PREPARES:
397 ZVAL_BOOL(return_value, H->emulate_prepares);
398 break;
399
400 case PDO_PGSQL_ATTR_DISABLE_PREPARES:
401 ZVAL_BOOL(return_value, H->disable_prepares);
402 break;
403
404 case PDO_ATTR_CLIENT_VERSION:
405 ZVAL_STRING(return_value, PG_VERSION);
406 break;
407
408 case PDO_ATTR_SERVER_VERSION:
409 if (PQprotocolVersion(H->server) >= 3) { /* PostgreSQL 7.4 or later */
410 ZVAL_STRING(return_value, (char*)PQparameterStatus(H->server, "server_version"));
411 } else /* emulate above via a query */
412 {
413 PGresult *res = PQexec(H->server, "SELECT VERSION()");
414 if (res && PQresultStatus(res) == PGRES_TUPLES_OK) {
415 ZVAL_STRING(return_value, (char *)PQgetvalue(res, 0, 0));
416 }
417
418 if (res) {
419 PQclear(res);
420 }
421 }
422 break;
423
424 case PDO_ATTR_CONNECTION_STATUS:
425 switch (PQstatus(H->server)) {
426 case CONNECTION_STARTED:
427 ZVAL_STRINGL(return_value, "Waiting for connection to be made.", sizeof("Waiting for connection to be made.")-1);
428 break;
429
430 case CONNECTION_MADE:
431 case CONNECTION_OK:
432 ZVAL_STRINGL(return_value, "Connection OK; waiting to send.", sizeof("Connection OK; waiting to send.")-1);
433 break;
434
435 case CONNECTION_AWAITING_RESPONSE:
436 ZVAL_STRINGL(return_value, "Waiting for a response from the server.", sizeof("Waiting for a response from the server.")-1);
437 break;
438
439 case CONNECTION_AUTH_OK:
440 ZVAL_STRINGL(return_value, "Received authentication; waiting for backend start-up to finish.", sizeof("Received authentication; waiting for backend start-up to finish.")-1);
441 break;
442 #ifdef CONNECTION_SSL_STARTUP
443 case CONNECTION_SSL_STARTUP:
444 ZVAL_STRINGL(return_value, "Negotiating SSL encryption.", sizeof("Negotiating SSL encryption.")-1);
445 break;
446 #endif
447 case CONNECTION_SETENV:
448 ZVAL_STRINGL(return_value, "Negotiating environment-driven parameter settings.", sizeof("Negotiating environment-driven parameter settings.")-1);
449 break;
450
451 case CONNECTION_BAD:
452 default:
453 ZVAL_STRINGL(return_value, "Bad connection.", sizeof("Bad connection.")-1);
454 break;
455 }
456 break;
457
458 case PDO_ATTR_SERVER_INFO: {
459 int spid = PQbackendPID(H->server);
460
461
462 zend_string *str_info =
463 strpprintf(0,
464 "PID: %d; Client Encoding: %s; Is Superuser: %s; Session Authorization: %s; Date Style: %s",
465 spid,
466 (char*)PQparameterStatus(H->server, "client_encoding"),
467 (char*)PQparameterStatus(H->server, "is_superuser"),
468 (char*)PQparameterStatus(H->server, "session_authorization"),
469 (char*)PQparameterStatus(H->server, "DateStyle"));
470
471 ZVAL_STR(return_value, str_info);
472 }
473 break;
474
475 default:
476 return 0;
477 }
478
479 return 1;
480 }
481
482 /* {{{ */
pdo_pgsql_check_liveness(pdo_dbh_t * dbh)483 static int pdo_pgsql_check_liveness(pdo_dbh_t *dbh)
484 {
485 pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data;
486 if (PQstatus(H->server) == CONNECTION_BAD) {
487 PQreset(H->server);
488 }
489 return (PQstatus(H->server) == CONNECTION_OK) ? SUCCESS : FAILURE;
490 }
491 /* }}} */
492
pgsql_handle_in_transaction(pdo_dbh_t * dbh)493 static int pgsql_handle_in_transaction(pdo_dbh_t *dbh)
494 {
495 pdo_pgsql_db_handle *H;
496
497 H = (pdo_pgsql_db_handle *)dbh->driver_data;
498
499 return PQtransactionStatus(H->server) > PQTRANS_IDLE;
500 }
501
pdo_pgsql_transaction_cmd(const char * cmd,pdo_dbh_t * dbh)502 static int pdo_pgsql_transaction_cmd(const char *cmd, pdo_dbh_t *dbh)
503 {
504 pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data;
505 PGresult *res;
506 int ret = 1;
507
508 res = PQexec(H->server, cmd);
509
510 if (PQresultStatus(res) != PGRES_COMMAND_OK) {
511 pdo_pgsql_error(dbh, PQresultStatus(res), pdo_pgsql_sqlstate(res));
512 ret = 0;
513 }
514
515 PQclear(res);
516 return ret;
517 }
518
pgsql_handle_begin(pdo_dbh_t * dbh)519 static int pgsql_handle_begin(pdo_dbh_t *dbh)
520 {
521 return pdo_pgsql_transaction_cmd("BEGIN", dbh);
522 }
523
pgsql_handle_commit(pdo_dbh_t * dbh)524 static int pgsql_handle_commit(pdo_dbh_t *dbh)
525 {
526 int ret = pdo_pgsql_transaction_cmd("COMMIT", dbh);
527
528 /* When deferred constraints are used the commit could
529 fail, and a ROLLBACK implicitly ran. See bug #67462 */
530 if (!ret) {
531 dbh->in_txn = pgsql_handle_in_transaction(dbh);
532 }
533
534 return ret;
535 }
536
pgsql_handle_rollback(pdo_dbh_t * dbh)537 static int pgsql_handle_rollback(pdo_dbh_t *dbh)
538 {
539 return pdo_pgsql_transaction_cmd("ROLLBACK", dbh);
540 }
541
542 /* {{{ proto string PDO::pgsqlCopyFromArray(string $table_name , array $rows [, string $delimiter [, string $null_as ] [, string $fields])
543 Returns true if the copy worked fine or false if error */
PHP_METHOD(PDO,pgsqlCopyFromArray)544 static PHP_METHOD(PDO, pgsqlCopyFromArray)
545 {
546 pdo_dbh_t *dbh;
547 pdo_pgsql_db_handle *H;
548
549 zval *pg_rows;
550
551 char *table_name, *pg_delim = NULL, *pg_null_as = NULL, *pg_fields = NULL;
552 size_t table_name_len, pg_delim_len = 0, pg_null_as_len = 0, pg_fields_len;
553 char *query;
554
555 PGresult *pgsql_result;
556 ExecStatusType status;
557
558 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s/a|sss",
559 &table_name, &table_name_len, &pg_rows,
560 &pg_delim, &pg_delim_len, &pg_null_as, &pg_null_as_len, &pg_fields, &pg_fields_len) == FAILURE) {
561 return;
562 }
563
564 if (!zend_hash_num_elements(Z_ARRVAL_P(pg_rows))) {
565 php_error_docref(NULL, E_WARNING, "Cannot copy from an empty array");
566 RETURN_FALSE;
567 }
568
569 dbh = Z_PDO_DBH_P(getThis());
570 PDO_CONSTRUCT_CHECK;
571 PDO_DBH_CLEAR_ERR();
572
573 /* using pre-9.0 syntax as PDO_pgsql is 7.4+ compatible */
574 if (pg_fields) {
575 spprintf(&query, 0, "COPY %s (%s) FROM STDIN WITH DELIMITER E'%c' NULL AS E'%s'", table_name, pg_fields, (pg_delim_len ? *pg_delim : '\t'), (pg_null_as_len ? pg_null_as : "\\\\N"));
576 } else {
577 spprintf(&query, 0, "COPY %s FROM STDIN WITH DELIMITER E'%c' NULL AS E'%s'", table_name, (pg_delim_len ? *pg_delim : '\t'), (pg_null_as_len ? pg_null_as : "\\\\N"));
578 }
579
580 /* Obtain db Handle */
581 H = (pdo_pgsql_db_handle *)dbh->driver_data;
582
583 while ((pgsql_result = PQgetResult(H->server))) {
584 PQclear(pgsql_result);
585 }
586 pgsql_result = PQexec(H->server, query);
587
588 efree(query);
589 query = NULL;
590
591 if (pgsql_result) {
592 status = PQresultStatus(pgsql_result);
593 } else {
594 status = (ExecStatusType) PQstatus(H->server);
595 }
596
597 if (status == PGRES_COPY_IN && pgsql_result) {
598 int command_failed = 0;
599 size_t buffer_len = 0;
600 zval *tmp;
601
602 PQclear(pgsql_result);
603 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pg_rows), tmp) {
604 size_t query_len;
605 convert_to_string_ex(tmp);
606
607 if (buffer_len < Z_STRLEN_P(tmp)) {
608 buffer_len = Z_STRLEN_P(tmp);
609 query = erealloc(query, buffer_len + 2); /* room for \n\0 */
610 }
611 memcpy(query, Z_STRVAL_P(tmp), Z_STRLEN_P(tmp));
612 query_len = Z_STRLEN_P(tmp);
613 if (query[query_len - 1] != '\n') {
614 query[query_len++] = '\n';
615 }
616 query[query_len] = '\0';
617 if (PQputCopyData(H->server, query, query_len) != 1) {
618 efree(query);
619 pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, NULL);
620 PDO_HANDLE_DBH_ERR();
621 RETURN_FALSE;
622 }
623 } ZEND_HASH_FOREACH_END();
624 if (query) {
625 efree(query);
626 }
627
628 if (PQputCopyEnd(H->server, NULL) != 1) {
629 pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, NULL);
630 PDO_HANDLE_DBH_ERR();
631 RETURN_FALSE;
632 }
633
634 while ((pgsql_result = PQgetResult(H->server))) {
635 if (PGRES_COMMAND_OK != PQresultStatus(pgsql_result)) {
636 pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, pdo_pgsql_sqlstate(pgsql_result));
637 command_failed = 1;
638 }
639 PQclear(pgsql_result);
640 }
641
642 PDO_HANDLE_DBH_ERR();
643 RETURN_BOOL(!command_failed);
644 } else {
645 pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, pdo_pgsql_sqlstate(pgsql_result));
646 PQclear(pgsql_result);
647 PDO_HANDLE_DBH_ERR();
648 RETURN_FALSE;
649 }
650 }
651 /* }}} */
652
653 /* {{{ proto string PDO::pgsqlCopyFromFile(string $table_name , string $filename [, string $delimiter [, string $null_as ] [, string $fields])
654 Returns true if the copy worked fine or false if error */
PHP_METHOD(PDO,pgsqlCopyFromFile)655 static PHP_METHOD(PDO, pgsqlCopyFromFile)
656 {
657 pdo_dbh_t *dbh;
658 pdo_pgsql_db_handle *H;
659
660 char *table_name, *filename, *pg_delim = NULL, *pg_null_as = NULL, *pg_fields = NULL;
661 size_t table_name_len, filename_len, pg_delim_len = 0, pg_null_as_len = 0, pg_fields_len;
662 char *query;
663 PGresult *pgsql_result;
664 ExecStatusType status;
665 php_stream *stream;
666
667 if (zend_parse_parameters(ZEND_NUM_ARGS(), "sp|sss",
668 &table_name, &table_name_len, &filename, &filename_len,
669 &pg_delim, &pg_delim_len, &pg_null_as, &pg_null_as_len, &pg_fields, &pg_fields_len) == FAILURE) {
670 return;
671 }
672
673 /* Obtain db Handler */
674 dbh = Z_PDO_DBH_P(getThis());
675 PDO_CONSTRUCT_CHECK;
676 PDO_DBH_CLEAR_ERR();
677
678 stream = php_stream_open_wrapper_ex(filename, "rb", 0, NULL, FG(default_context));
679 if (!stream) {
680 pdo_pgsql_error_msg(dbh, PGRES_FATAL_ERROR, "Unable to open the file");
681 PDO_HANDLE_DBH_ERR();
682 RETURN_FALSE;
683 }
684
685 /* using pre-9.0 syntax as PDO_pgsql is 7.4+ compatible */
686 if (pg_fields) {
687 spprintf(&query, 0, "COPY %s (%s) FROM STDIN WITH DELIMITER E'%c' NULL AS E'%s'", table_name, pg_fields, (pg_delim_len ? *pg_delim : '\t'), (pg_null_as_len ? pg_null_as : "\\\\N"));
688 } else {
689 spprintf(&query, 0, "COPY %s FROM STDIN WITH DELIMITER E'%c' NULL AS E'%s'", table_name, (pg_delim_len ? *pg_delim : '\t'), (pg_null_as_len ? pg_null_as : "\\\\N"));
690 }
691
692 H = (pdo_pgsql_db_handle *)dbh->driver_data;
693
694 while ((pgsql_result = PQgetResult(H->server))) {
695 PQclear(pgsql_result);
696 }
697 pgsql_result = PQexec(H->server, query);
698
699 efree(query);
700
701 if (pgsql_result) {
702 status = PQresultStatus(pgsql_result);
703 } else {
704 status = (ExecStatusType) PQstatus(H->server);
705 }
706
707 if (status == PGRES_COPY_IN && pgsql_result) {
708 char *buf;
709 int command_failed = 0;
710 size_t line_len = 0;
711
712 PQclear(pgsql_result);
713 while ((buf = php_stream_get_line(stream, NULL, 0, &line_len)) != NULL) {
714 if (PQputCopyData(H->server, buf, line_len) != 1) {
715 efree(buf);
716 pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, NULL);
717 php_stream_close(stream);
718 PDO_HANDLE_DBH_ERR();
719 RETURN_FALSE;
720 }
721 efree(buf);
722 }
723 php_stream_close(stream);
724
725 if (PQputCopyEnd(H->server, NULL) != 1) {
726 pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, NULL);
727 PDO_HANDLE_DBH_ERR();
728 RETURN_FALSE;
729 }
730
731 while ((pgsql_result = PQgetResult(H->server))) {
732 if (PGRES_COMMAND_OK != PQresultStatus(pgsql_result)) {
733 pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, pdo_pgsql_sqlstate(pgsql_result));
734 command_failed = 1;
735 }
736 PQclear(pgsql_result);
737 }
738
739 PDO_HANDLE_DBH_ERR();
740 RETURN_BOOL(!command_failed);
741 } else {
742 php_stream_close(stream);
743 pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, pdo_pgsql_sqlstate(pgsql_result));
744 PQclear(pgsql_result);
745 PDO_HANDLE_DBH_ERR();
746 RETURN_FALSE;
747 }
748 }
749 /* }}} */
750
751
752 /* {{{ proto string PDO::pgsqlCopyToFile(string $table_name , string $filename, [string $delimiter [, string $null_as [, string $fields]]])
753 Returns true if the copy worked fine or false if error */
PHP_METHOD(PDO,pgsqlCopyToFile)754 static PHP_METHOD(PDO, pgsqlCopyToFile)
755 {
756 pdo_dbh_t *dbh;
757 pdo_pgsql_db_handle *H;
758
759 char *table_name, *pg_delim = NULL, *pg_null_as = NULL, *pg_fields = NULL, *filename = NULL;
760 size_t table_name_len, pg_delim_len = 0, pg_null_as_len = 0, pg_fields_len, filename_len;
761 char *query;
762
763 PGresult *pgsql_result;
764 ExecStatusType status;
765
766 php_stream *stream;
767
768 if (zend_parse_parameters(ZEND_NUM_ARGS(), "sp|sss",
769 &table_name, &table_name_len, &filename, &filename_len,
770 &pg_delim, &pg_delim_len, &pg_null_as, &pg_null_as_len, &pg_fields, &pg_fields_len) == FAILURE) {
771 return;
772 }
773
774 dbh = Z_PDO_DBH_P(getThis());
775 PDO_CONSTRUCT_CHECK;
776 PDO_DBH_CLEAR_ERR();
777
778 H = (pdo_pgsql_db_handle *)dbh->driver_data;
779
780 stream = php_stream_open_wrapper_ex(filename, "wb", 0, NULL, FG(default_context));
781 if (!stream) {
782 pdo_pgsql_error_msg(dbh, PGRES_FATAL_ERROR, "Unable to open the file for writing");
783 PDO_HANDLE_DBH_ERR();
784 RETURN_FALSE;
785 }
786
787 while ((pgsql_result = PQgetResult(H->server))) {
788 PQclear(pgsql_result);
789 }
790
791 /* using pre-9.0 syntax as PDO_pgsql is 7.4+ compatible */
792 if (pg_fields) {
793 spprintf(&query, 0, "COPY %s (%s) TO STDIN WITH DELIMITER E'%c' NULL AS E'%s'", table_name, pg_fields, (pg_delim_len ? *pg_delim : '\t'), (pg_null_as_len ? pg_null_as : "\\\\N"));
794 } else {
795 spprintf(&query, 0, "COPY %s TO STDIN WITH DELIMITER E'%c' NULL AS E'%s'", table_name, (pg_delim_len ? *pg_delim : '\t'), (pg_null_as_len ? pg_null_as : "\\\\N"));
796 }
797 pgsql_result = PQexec(H->server, query);
798 efree(query);
799
800 if (pgsql_result) {
801 status = PQresultStatus(pgsql_result);
802 } else {
803 status = (ExecStatusType) PQstatus(H->server);
804 }
805
806 if (status == PGRES_COPY_OUT && pgsql_result) {
807 PQclear(pgsql_result);
808 while (1) {
809 char *csv = NULL;
810 int ret = PQgetCopyData(H->server, &csv, 0);
811
812 if (ret == -1) {
813 break; /* done */
814 } else if (ret > 0) {
815 if (php_stream_write(stream, csv, ret) != (size_t)ret) {
816 pdo_pgsql_error_msg(dbh, PGRES_FATAL_ERROR, "Unable to write to file");
817 PQfreemem(csv);
818 php_stream_close(stream);
819 PDO_HANDLE_DBH_ERR();
820 RETURN_FALSE;
821 } else {
822 PQfreemem(csv);
823 }
824 } else {
825 pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, NULL);
826 php_stream_close(stream);
827 PDO_HANDLE_DBH_ERR();
828 RETURN_FALSE;
829 }
830 }
831 php_stream_close(stream);
832
833 while ((pgsql_result = PQgetResult(H->server))) {
834 PQclear(pgsql_result);
835 }
836 RETURN_TRUE;
837 } else {
838 php_stream_close(stream);
839 pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, pdo_pgsql_sqlstate(pgsql_result));
840 PQclear(pgsql_result);
841 PDO_HANDLE_DBH_ERR();
842 RETURN_FALSE;
843 }
844 }
845 /* }}} */
846
847 /* {{{ proto string PDO::pgsqlCopyToArray(string $table_name , [string $delimiter [, string $null_as [, string $fields]]])
848 Returns true if the copy worked fine or false if error */
PHP_METHOD(PDO,pgsqlCopyToArray)849 static PHP_METHOD(PDO, pgsqlCopyToArray)
850 {
851 pdo_dbh_t *dbh;
852 pdo_pgsql_db_handle *H;
853
854 char *table_name, *pg_delim = NULL, *pg_null_as = NULL, *pg_fields = NULL;
855 size_t table_name_len, pg_delim_len = 0, pg_null_as_len = 0, pg_fields_len;
856 char *query;
857
858 PGresult *pgsql_result;
859 ExecStatusType status;
860
861 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|sss",
862 &table_name, &table_name_len,
863 &pg_delim, &pg_delim_len, &pg_null_as, &pg_null_as_len, &pg_fields, &pg_fields_len) == FAILURE) {
864 return;
865 }
866
867 dbh = Z_PDO_DBH_P(getThis());
868 PDO_CONSTRUCT_CHECK;
869 PDO_DBH_CLEAR_ERR();
870
871 H = (pdo_pgsql_db_handle *)dbh->driver_data;
872
873 while ((pgsql_result = PQgetResult(H->server))) {
874 PQclear(pgsql_result);
875 }
876
877 /* using pre-9.0 syntax as PDO_pgsql is 7.4+ compatible */
878 if (pg_fields) {
879 spprintf(&query, 0, "COPY %s (%s) TO STDIN WITH DELIMITER E'%c' NULL AS E'%s'", table_name, pg_fields, (pg_delim_len ? *pg_delim : '\t'), (pg_null_as_len ? pg_null_as : "\\\\N"));
880 } else {
881 spprintf(&query, 0, "COPY %s TO STDIN WITH DELIMITER E'%c' NULL AS E'%s'", table_name, (pg_delim_len ? *pg_delim : '\t'), (pg_null_as_len ? pg_null_as : "\\\\N"));
882 }
883 pgsql_result = PQexec(H->server, query);
884 efree(query);
885
886 if (pgsql_result) {
887 status = PQresultStatus(pgsql_result);
888 } else {
889 status = (ExecStatusType) PQstatus(H->server);
890 }
891
892 if (status == PGRES_COPY_OUT && pgsql_result) {
893 PQclear(pgsql_result);
894 array_init(return_value);
895
896 while (1) {
897 char *csv = NULL;
898 int ret = PQgetCopyData(H->server, &csv, 0);
899 if (ret == -1) {
900 break; /* copy done */
901 } else if (ret > 0) {
902 add_next_index_stringl(return_value, csv, ret);
903 PQfreemem(csv);
904 } else {
905 pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, NULL);
906 PDO_HANDLE_DBH_ERR();
907 RETURN_FALSE;
908 }
909 }
910
911 while ((pgsql_result = PQgetResult(H->server))) {
912 PQclear(pgsql_result);
913 }
914 } else {
915 pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, pdo_pgsql_sqlstate(pgsql_result));
916 PQclear(pgsql_result);
917 PDO_HANDLE_DBH_ERR();
918 RETURN_FALSE;
919 }
920 }
921 /* }}} */
922
923
924 /* {{{ proto string PDO::pgsqlLOBCreate()
925 Creates a new large object, returning its identifier. Must be called inside a transaction. */
PHP_METHOD(PDO,pgsqlLOBCreate)926 static PHP_METHOD(PDO, pgsqlLOBCreate)
927 {
928 pdo_dbh_t *dbh;
929 pdo_pgsql_db_handle *H;
930 Oid lfd;
931
932 dbh = Z_PDO_DBH_P(getThis());
933 PDO_CONSTRUCT_CHECK;
934 PDO_DBH_CLEAR_ERR();
935
936 H = (pdo_pgsql_db_handle *)dbh->driver_data;
937 lfd = lo_creat(H->server, INV_READ|INV_WRITE);
938
939 if (lfd != InvalidOid) {
940 zend_string *buf = strpprintf(0, ZEND_ULONG_FMT, (zend_long) lfd);
941
942 RETURN_STR(buf);
943 }
944
945 pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, NULL);
946 PDO_HANDLE_DBH_ERR();
947 RETURN_FALSE;
948 }
949 /* }}} */
950
951 /* {{{ proto resource PDO::pgsqlLOBOpen(string oid [, string mode = 'rb'])
952 Opens an existing large object stream. Must be called inside a transaction. */
PHP_METHOD(PDO,pgsqlLOBOpen)953 static PHP_METHOD(PDO, pgsqlLOBOpen)
954 {
955 pdo_dbh_t *dbh;
956 pdo_pgsql_db_handle *H;
957 Oid oid;
958 int lfd;
959 char *oidstr;
960 size_t oidstrlen;
961 char *modestr = "rb";
962 size_t modestrlen;
963 int mode = INV_READ;
964 char *end_ptr;
965
966 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "s|s",
967 &oidstr, &oidstrlen, &modestr, &modestrlen)) {
968 RETURN_FALSE;
969 }
970
971 oid = (Oid)strtoul(oidstr, &end_ptr, 10);
972 if (oid == 0 && (errno == ERANGE || errno == EINVAL)) {
973 RETURN_FALSE;
974 }
975
976 if (strpbrk(modestr, "+w")) {
977 mode = INV_READ|INV_WRITE;
978 }
979
980 dbh = Z_PDO_DBH_P(getThis());
981 PDO_CONSTRUCT_CHECK;
982 PDO_DBH_CLEAR_ERR();
983
984 H = (pdo_pgsql_db_handle *)dbh->driver_data;
985
986 lfd = lo_open(H->server, oid, mode);
987
988 if (lfd >= 0) {
989 php_stream *stream = pdo_pgsql_create_lob_stream(getThis(), lfd, oid);
990 if (stream) {
991 php_stream_to_zval(stream, return_value);
992 return;
993 }
994 } else {
995 pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, NULL);
996 }
997
998 PDO_HANDLE_DBH_ERR();
999 RETURN_FALSE;
1000 }
1001 /* }}} */
1002
1003 /* {{{ proto bool PDO::pgsqlLOBUnlink(string oid)
1004 Deletes the large object identified by oid. Must be called inside a transaction. */
PHP_METHOD(PDO,pgsqlLOBUnlink)1005 static PHP_METHOD(PDO, pgsqlLOBUnlink)
1006 {
1007 pdo_dbh_t *dbh;
1008 pdo_pgsql_db_handle *H;
1009 Oid oid;
1010 char *oidstr, *end_ptr;
1011 size_t oidlen;
1012
1013 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "s",
1014 &oidstr, &oidlen)) {
1015 RETURN_FALSE;
1016 }
1017
1018 oid = (Oid)strtoul(oidstr, &end_ptr, 10);
1019 if (oid == 0 && (errno == ERANGE || errno == EINVAL)) {
1020 RETURN_FALSE;
1021 }
1022
1023 dbh = Z_PDO_DBH_P(getThis());
1024 PDO_CONSTRUCT_CHECK;
1025 PDO_DBH_CLEAR_ERR();
1026
1027 H = (pdo_pgsql_db_handle *)dbh->driver_data;
1028
1029 if (1 == lo_unlink(H->server, oid)) {
1030 RETURN_TRUE;
1031 }
1032
1033 pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, NULL);
1034 PDO_HANDLE_DBH_ERR();
1035 RETURN_FALSE;
1036 }
1037 /* }}} */
1038
1039 /* {{{ proto mixed PDO::pgsqlGetNotify([ int $result_type = PDO::FETCH_USE_DEFAULT] [, int $ms_timeout = 0 ]])
1040 Get asyncronous notification */
PHP_METHOD(PDO,pgsqlGetNotify)1041 static PHP_METHOD(PDO, pgsqlGetNotify)
1042 {
1043 pdo_dbh_t *dbh;
1044 pdo_pgsql_db_handle *H;
1045 zend_long result_type = PDO_FETCH_USE_DEFAULT;
1046 zend_long ms_timeout = 0;
1047 PGnotify *pgsql_notify;
1048
1049 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "|ll",
1050 &result_type, &ms_timeout)) {
1051 RETURN_FALSE;
1052 }
1053
1054 dbh = Z_PDO_DBH_P(getThis());
1055 PDO_CONSTRUCT_CHECK;
1056
1057 if (result_type == PDO_FETCH_USE_DEFAULT) {
1058 result_type = dbh->default_fetch_type;
1059 }
1060
1061 if (result_type != PDO_FETCH_BOTH && result_type != PDO_FETCH_ASSOC && result_type != PDO_FETCH_NUM) {
1062 php_error_docref(NULL, E_WARNING, "Invalid result type");
1063 RETURN_FALSE;
1064 }
1065
1066 if (ms_timeout < 0) {
1067 php_error_docref(NULL, E_WARNING, "Invalid timeout");
1068 RETURN_FALSE;
1069 #if ZEND_ENABLE_ZVAL_LONG64
1070 } else if (ms_timeout > INT_MAX) {
1071 php_error_docref(NULL, E_WARNING, "timeout was shrinked to %d", INT_MAX);
1072 ms_timeout = INT_MAX;
1073 #endif
1074 }
1075
1076 H = (pdo_pgsql_db_handle *)dbh->driver_data;
1077
1078 PQconsumeInput(H->server);
1079 pgsql_notify = PQnotifies(H->server);
1080
1081 if (ms_timeout && !pgsql_notify) {
1082 php_pollfd_for_ms(PQsocket(H->server), PHP_POLLREADABLE, (int)ms_timeout);
1083
1084 PQconsumeInput(H->server);
1085 pgsql_notify = PQnotifies(H->server);
1086 }
1087
1088 if (!pgsql_notify) {
1089 RETURN_FALSE;
1090 }
1091
1092 array_init(return_value);
1093 if (result_type == PDO_FETCH_NUM || result_type == PDO_FETCH_BOTH) {
1094 add_index_string(return_value, 0, pgsql_notify->relname);
1095 add_index_long(return_value, 1, pgsql_notify->be_pid);
1096 if (pgsql_notify->extra && pgsql_notify->extra[0]) {
1097 add_index_string(return_value, 2, pgsql_notify->extra);
1098 }
1099 }
1100 if (result_type == PDO_FETCH_ASSOC || result_type == PDO_FETCH_BOTH) {
1101 add_assoc_string(return_value, "message", pgsql_notify->relname);
1102 add_assoc_long(return_value, "pid", pgsql_notify->be_pid);
1103 if (pgsql_notify->extra && pgsql_notify->extra[0]) {
1104 add_assoc_string(return_value, "payload", pgsql_notify->extra);
1105 }
1106 }
1107
1108 PQfreemem(pgsql_notify);
1109 }
1110 /* }}} */
1111
1112 /* {{{ proto int PDO::pgsqlGetPid()
1113 Get backend(server) pid */
PHP_METHOD(PDO,pgsqlGetPid)1114 static PHP_METHOD(PDO, pgsqlGetPid)
1115 {
1116 pdo_dbh_t *dbh;
1117 pdo_pgsql_db_handle *H;
1118
1119 dbh = Z_PDO_DBH_P(getThis());
1120 PDO_CONSTRUCT_CHECK;
1121
1122 H = (pdo_pgsql_db_handle *)dbh->driver_data;
1123
1124 RETURN_LONG(PQbackendPID(H->server));
1125 }
1126 /* }}} */
1127
1128
1129 static const zend_function_entry dbh_methods[] = {
1130 PHP_ME(PDO, pgsqlLOBCreate, NULL, ZEND_ACC_PUBLIC)
1131 PHP_ME(PDO, pgsqlLOBOpen, NULL, ZEND_ACC_PUBLIC)
1132 PHP_ME(PDO, pgsqlLOBUnlink, NULL, ZEND_ACC_PUBLIC)
1133 PHP_ME(PDO, pgsqlCopyFromArray, NULL, ZEND_ACC_PUBLIC)
1134 PHP_ME(PDO, pgsqlCopyFromFile, NULL, ZEND_ACC_PUBLIC)
1135 PHP_ME(PDO, pgsqlCopyToArray, NULL, ZEND_ACC_PUBLIC)
1136 PHP_ME(PDO, pgsqlCopyToFile, NULL, ZEND_ACC_PUBLIC)
1137 PHP_ME(PDO, pgsqlGetNotify, NULL, ZEND_ACC_PUBLIC)
1138 PHP_ME(PDO, pgsqlGetPid, NULL, ZEND_ACC_PUBLIC)
1139 PHP_FE_END
1140 };
1141
pdo_pgsql_get_driver_methods(pdo_dbh_t * dbh,int kind)1142 static const zend_function_entry *pdo_pgsql_get_driver_methods(pdo_dbh_t *dbh, int kind)
1143 {
1144 switch (kind) {
1145 case PDO_DBH_DRIVER_METHOD_KIND_DBH:
1146 return dbh_methods;
1147 default:
1148 return NULL;
1149 }
1150 }
1151
pdo_pgsql_set_attr(pdo_dbh_t * dbh,zend_long attr,zval * val)1152 static int pdo_pgsql_set_attr(pdo_dbh_t *dbh, zend_long attr, zval *val)
1153 {
1154 zend_bool bval = zval_get_long(val)? 1 : 0;
1155 pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data;
1156
1157 switch (attr) {
1158 case PDO_ATTR_EMULATE_PREPARES:
1159 H->emulate_prepares = bval;
1160 return 1;
1161 case PDO_PGSQL_ATTR_DISABLE_PREPARES:
1162 H->disable_prepares = bval;
1163 return 1;
1164 default:
1165 return 0;
1166 }
1167 }
1168
1169 static struct pdo_dbh_methods pgsql_methods = {
1170 pgsql_handle_closer,
1171 pgsql_handle_preparer,
1172 pgsql_handle_doer,
1173 pgsql_handle_quoter,
1174 pgsql_handle_begin,
1175 pgsql_handle_commit,
1176 pgsql_handle_rollback,
1177 pdo_pgsql_set_attr,
1178 pdo_pgsql_last_insert_id,
1179 pdo_pgsql_fetch_error_func,
1180 pdo_pgsql_get_attribute,
1181 pdo_pgsql_check_liveness, /* check_liveness */
1182 pdo_pgsql_get_driver_methods, /* get_driver_methods */
1183 NULL,
1184 pgsql_handle_in_transaction,
1185 };
1186
pdo_pgsql_handle_factory(pdo_dbh_t * dbh,zval * driver_options)1187 static int pdo_pgsql_handle_factory(pdo_dbh_t *dbh, zval *driver_options) /* {{{ */
1188 {
1189 pdo_pgsql_db_handle *H;
1190 int ret = 0;
1191 char *conn_str, *p, *e;
1192 zend_string *tmp_user, *tmp_pass;
1193 zend_long connect_timeout = 30;
1194
1195 H = pecalloc(1, sizeof(pdo_pgsql_db_handle), dbh->is_persistent);
1196 dbh->driver_data = H;
1197
1198 H->einfo.errcode = 0;
1199 H->einfo.errmsg = NULL;
1200
1201 /* PostgreSQL wants params in the connect string to be separated by spaces,
1202 * if the PDO standard semicolons are used, we convert them to spaces
1203 */
1204 e = (char *) dbh->data_source + strlen(dbh->data_source);
1205 p = (char *) dbh->data_source;
1206 while ((p = memchr(p, ';', (e - p)))) {
1207 *p = ' ';
1208 }
1209
1210 if (driver_options) {
1211 connect_timeout = pdo_attr_lval(driver_options, PDO_ATTR_TIMEOUT, 30);
1212 }
1213
1214 /* escape username and password, if provided */
1215 tmp_user = _pdo_pgsql_escape_credentials(dbh->username);
1216 tmp_pass = _pdo_pgsql_escape_credentials(dbh->password);
1217
1218 /* support both full connection string & connection string + login and/or password */
1219 if (tmp_user && tmp_pass) {
1220 spprintf(&conn_str, 0, "%s user='%s' password='%s' connect_timeout=" ZEND_LONG_FMT, (char *) dbh->data_source, ZSTR_VAL(tmp_user), ZSTR_VAL(tmp_pass), connect_timeout);
1221 } else if (tmp_user) {
1222 spprintf(&conn_str, 0, "%s user='%s' connect_timeout=" ZEND_LONG_FMT, (char *) dbh->data_source, ZSTR_VAL(tmp_user), connect_timeout);
1223 } else if (tmp_pass) {
1224 spprintf(&conn_str, 0, "%s password='%s' connect_timeout=" ZEND_LONG_FMT, (char *) dbh->data_source, ZSTR_VAL(tmp_pass), connect_timeout);
1225 } else {
1226 spprintf(&conn_str, 0, "%s connect_timeout=" ZEND_LONG_FMT, (char *) dbh->data_source, connect_timeout);
1227 }
1228
1229 H->server = PQconnectdb(conn_str);
1230
1231 if (tmp_user) {
1232 zend_string_release(tmp_user);
1233 }
1234 if (tmp_pass) {
1235 zend_string_release(tmp_pass);
1236 }
1237
1238 efree(conn_str);
1239
1240 if (PQstatus(H->server) != CONNECTION_OK) {
1241 pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, PHP_PDO_PGSQL_CONNECTION_FAILURE_SQLSTATE);
1242 goto cleanup;
1243 }
1244
1245 PQsetNoticeProcessor(H->server, (void(*)(void*,const char*))_pdo_pgsql_notice, (void *)&dbh);
1246
1247 H->attached = 1;
1248 H->pgoid = -1;
1249
1250 dbh->methods = &pgsql_methods;
1251 dbh->alloc_own_columns = 1;
1252 dbh->max_escaped_char_length = 2;
1253
1254 ret = 1;
1255
1256 cleanup:
1257 dbh->methods = &pgsql_methods;
1258 if (!ret) {
1259 pgsql_handle_closer(dbh);
1260 }
1261
1262 return ret;
1263 }
1264 /* }}} */
1265
1266 pdo_driver_t pdo_pgsql_driver = {
1267 PDO_DRIVER_HEADER(pgsql),
1268 pdo_pgsql_handle_factory
1269 };
1270
1271 /*
1272 * Local variables:
1273 * tab-width: 4
1274 * c-basic-offset: 4
1275 * End:
1276 * vim600: noet sw=4 ts=4 fdm=marker
1277 * vim<600: noet sw=4 ts=4
1278 */
1279