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