Skip to content

Commit 1310333

Browse files
committed
Added PDO::pgsqlLOBCreate(), PDO::pgsqlLOBOpen() and PDO::pgsqlLOBUnlink().
1 parent 2ad81f4 commit 1310333

9 files changed

+361
-22
lines changed

ext/pdo_pgsql/package.xml

+5-3
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@
3030
<license>PHP</license>
3131
<release>
3232
<state>stable</state>
33-
<version>1.0</version>
34-
<date>2005-11-26</date>
33+
<version>1.0.1</version>
34+
<date>2005-11-28</date>
3535

3636
<notes>
3737
Now features native prepared statements and numerous other improvements.
@@ -42,6 +42,8 @@ intend to build and/or use it.
4242

4343
If you are running on windows, you can download the binary from here:
4444
http://pecl4win.php.net/ext.php/php_pdo_pgsql.dll
45+
46+
Added PDO::pgsqlLOBCreate(), PDO::pgsqlLOBOpen() and PDO::pgsqlLOBUnlink().
4547
</notes>
4648

4749
<filelist>
@@ -57,7 +59,7 @@ http://pecl4win.php.net/ext.php/php_pdo_pgsql.dll
5759
</filelist>
5860
<deps>
5961
<dep type="php" rel="ge" version="5.0.3"/>
60-
<dep type="ext" rel="ge" name="pdo" version="1.0"/>
62+
<dep type="ext" rel="ge" name="pdo" version="1.0.2"/>
6163
</deps>
6264
</release>
6365
</package>

ext/pdo_pgsql/pdo_pgsql.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ zend_module_entry pdo_pgsql_module_entry = {
6161
PHP_RINIT(pdo_pgsql),
6262
PHP_RSHUTDOWN(pdo_pgsql),
6363
PHP_MINFO(pdo_pgsql),
64-
"1.0",
64+
"1.0.1",
6565
STANDARD_MODULE_PROPERTIES
6666
};
6767
/* }}} */

ext/pdo_pgsql/pgsql_driver.c

+198-3
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@
1212
| obtain it through the world-wide-web, please send a note to |
1313
| license@php.net so we can mail you a copy immediately. |
1414
+----------------------------------------------------------------------+
15-
| Author: Edin Kadribasic <edink@emini.dk> |
15+
| Authors: Edin Kadribasic <edink@emini.dk> |
16+
| Ilia Alshanestsky <ilia@prohost.org> |
17+
| Wez Furlong <wez@php.net> |
1618
+----------------------------------------------------------------------+
1719
*/
1820

@@ -108,6 +110,81 @@ static int pdo_pgsql_fetch_error_func(pdo_dbh_t *dbh, pdo_stmt_t *stmt, zval *in
108110
}
109111
/* }}} */
110112

113+
/* {{{ pdo_pgsql_create_lob_stream */
114+
static size_t pgsql_lob_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC)
115+
{
116+
struct pdo_pgsql_lob_self *self = (struct pdo_pgsql_lob_self*)stream->abstract;
117+
return lo_write(self->conn, self->lfd, (char*)buf, count);
118+
}
119+
120+
static size_t pgsql_lob_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
121+
{
122+
struct pdo_pgsql_lob_self *self = (struct pdo_pgsql_lob_self*)stream->abstract;
123+
return lo_read(self->conn, self->lfd, buf, count);
124+
}
125+
126+
static int pgsql_lob_close(php_stream *stream, int close_handle TSRMLS_DC)
127+
{
128+
struct pdo_pgsql_lob_self *self = (struct pdo_pgsql_lob_self*)stream->abstract;
129+
pdo_dbh_t *dbh = self->dbh;
130+
131+
if (close_handle) {
132+
lo_close(self->conn, self->lfd);
133+
}
134+
efree(self);
135+
php_pdo_dbh_delref(dbh TSRMLS_DC);
136+
return 0;
137+
}
138+
139+
static int pgsql_lob_flush(php_stream *stream TSRMLS_DC)
140+
{
141+
return 0;
142+
}
143+
144+
static int pgsql_lob_seek(php_stream *stream, off_t offset, int whence,
145+
off_t *newoffset TSRMLS_DC)
146+
{
147+
struct pdo_pgsql_lob_self *self = (struct pdo_pgsql_lob_self*)stream->abstract;
148+
int pos = lo_lseek(self->conn, self->lfd, offset, whence);
149+
*newoffset = pos;
150+
return pos >= 0 ? 0 : -1;
151+
}
152+
153+
php_stream_ops pdo_pgsql_lob_stream_ops = {
154+
pgsql_lob_write,
155+
pgsql_lob_read,
156+
pgsql_lob_close,
157+
pgsql_lob_flush,
158+
"pdo_pgsql lob stream",
159+
pgsql_lob_seek,
160+
NULL,
161+
NULL,
162+
NULL
163+
};
164+
165+
php_stream *pdo_pgsql_create_lob_stream(pdo_dbh_t *dbh, int lfd, Oid oid TSRMLS_DC)
166+
{
167+
php_stream *stm;
168+
struct pdo_pgsql_lob_self *self = ecalloc(1, sizeof(*self));
169+
pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data;
170+
171+
self->dbh = dbh;
172+
self->lfd = lfd;
173+
self->oid = oid;
174+
self->conn = H->server;
175+
176+
stm = php_stream_alloc(&pdo_pgsql_lob_stream_ops, self, 0, "r+b");
177+
178+
if (stm) {
179+
php_pdo_dbh_addref(dbh TSRMLS_CC);
180+
return stm;
181+
}
182+
183+
efree(self);
184+
return NULL;
185+
}
186+
/* }}} */
187+
111188
static int pgsql_handle_closer(pdo_dbh_t *dbh TSRMLS_DC) /* {{{ */
112189
{
113190
pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data;
@@ -397,6 +474,124 @@ static int pgsql_handle_rollback(pdo_dbh_t *dbh TSRMLS_DC)
397474
return pdo_pgsql_transaction_cmd("ROLLBACK", dbh TSRMLS_CC);
398475
}
399476

477+
/* {{{ string pgSQL::pgsqlLOBCreate()
478+
Creates a new large object, returning its identifier. Must be called inside a transaction. */
479+
static PHP_METHOD(pgSQL, pgsqlLOBCreate)
480+
{
481+
pdo_dbh_t *dbh;
482+
pdo_pgsql_db_handle *H;
483+
Oid lfd;
484+
485+
dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
486+
PDO_CONSTRUCT_CHECK;
487+
488+
H = (pdo_pgsql_db_handle *)dbh->driver_data;
489+
lfd = lo_creat(H->server, INV_READ|INV_WRITE);
490+
491+
if (lfd != InvalidOid) {
492+
char *buf;
493+
spprintf(&buf, 0, "%lu", lfd);
494+
RETURN_STRING(buf, 0);
495+
}
496+
497+
pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "HY000");
498+
RETURN_FALSE;
499+
}
500+
/* }}} */
501+
502+
/* {{{ resource pgSQL::pgsqlLOBOpen(string oid [, string mode = 'rb'])
503+
Opens an existing large object stream. Must be called inside a transaction. */
504+
static PHP_METHOD(pgSQL, pgsqlLOBOpen)
505+
{
506+
pdo_dbh_t *dbh;
507+
pdo_pgsql_db_handle *H;
508+
Oid oid;
509+
int lfd;
510+
char *oidstr;
511+
int oidstrlen;
512+
char *modestr = "rb";
513+
int modestrlen;
514+
int mode = INV_READ;
515+
char *end_ptr;
516+
517+
if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s",
518+
&oidstr, &oidstrlen, &modestr, &modestrlen)) {
519+
RETURN_FALSE;
520+
}
521+
522+
oid = (Oid)strtoul(oidstr, &end_ptr, 10);
523+
if (oid == 0 && (errno == ERANGE || errno == EINVAL)) {
524+
RETURN_FALSE;
525+
}
526+
527+
if (strpbrk(modestr, "+w")) {
528+
mode = INV_READ|INV_WRITE;
529+
}
530+
531+
dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
532+
PDO_CONSTRUCT_CHECK;
533+
534+
H = (pdo_pgsql_db_handle *)dbh->driver_data;
535+
536+
lfd = lo_open(H->server, oid, mode);
537+
538+
if (lfd >= 0) {
539+
php_stream *stream = pdo_pgsql_create_lob_stream(dbh, lfd, oid TSRMLS_CC);
540+
if (stream) {
541+
php_stream_to_zval(stream, return_value);
542+
return;
543+
}
544+
} else {
545+
pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "HY000");
546+
}
547+
RETURN_FALSE;
548+
}
549+
/* }}} */
550+
551+
/* {{{ bool pgSQL::pgsqlLOBUnlink(int oid)
552+
Deletes the large object identified by oid. Must be called inside a transaction. */
553+
static PHP_METHOD(pgSQL, pgsqlLOBUnlink)
554+
{
555+
pdo_dbh_t *dbh;
556+
pdo_pgsql_db_handle *H;
557+
long lfd;
558+
559+
if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l",
560+
&lfd)) {
561+
RETURN_FALSE;
562+
}
563+
564+
dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
565+
PDO_CONSTRUCT_CHECK;
566+
567+
H = (pdo_pgsql_db_handle *)dbh->driver_data;
568+
569+
if (1 == lo_unlink(H->server, lfd)) {
570+
RETURN_TRUE;
571+
}
572+
pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "HY000");
573+
RETURN_FALSE;
574+
}
575+
576+
577+
578+
static function_entry dbh_methods[] = {
579+
PHP_ME(pgSQL, pgsqlLOBCreate, NULL, ZEND_ACC_PUBLIC)
580+
PHP_ME(pgSQL, pgsqlLOBOpen, NULL, ZEND_ACC_PUBLIC)
581+
PHP_ME(pgSQL, pgsqlLOBUnlink, NULL, ZEND_ACC_PUBLIC)
582+
{NULL, NULL, NULL}
583+
};
584+
585+
static function_entry *pdo_pgsql_get_driver_methods(pdo_dbh_t *dbh, int kind TSRMLS_DC)
586+
{
587+
switch (kind) {
588+
case PDO_DBH_DRIVER_METHOD_KIND_DBH:
589+
return dbh_methods;
590+
default:
591+
return NULL;
592+
}
593+
}
594+
400595
static struct pdo_dbh_methods pgsql_methods = {
401596
pgsql_handle_closer,
402597
pgsql_handle_preparer,
@@ -410,7 +605,7 @@ static struct pdo_dbh_methods pgsql_methods = {
410605
pdo_pgsql_fetch_error_func,
411606
pdo_pgsql_get_attribute,
412607
NULL, /* check_liveness */
413-
NULL /* get_driver_methods */
608+
pdo_pgsql_get_driver_methods /* get_driver_methods */
414609
};
415610

416611
static int pdo_pgsql_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_DC) /* {{{ */
@@ -462,7 +657,7 @@ static int pdo_pgsql_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_
462657
H->pgoid = -1;
463658

464659
dbh->methods = &pgsql_methods;
465-
dbh->alloc_own_columns = 1;
660+
dbh->alloc_own_columns = 0;
466661
dbh->max_escaped_char_length = 2;
467662

468663
ret = 1;

ext/pdo_pgsql/pgsql_statement.c

+64-10
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@
1212
| obtain it through the world-wide-web, please send a note to |
1313
| license@php.net so we can mail you a copy immediately. |
1414
+----------------------------------------------------------------------+
15-
| Author: Edin Kadribasic <edink@emini.dk> |
15+
| Authors: Edin Kadribasic <edink@emini.dk> |
16+
| Ilia Alshanestsky <ilia@prohost.org> |
17+
| Wez Furlong <wez@php.net> |
1618
+----------------------------------------------------------------------+
1719
*/
1820

@@ -39,7 +41,6 @@
3941
#define TEXTOID 25
4042
#define OIDOID 26
4143

42-
4344
static int pgsql_stmt_dtor(pdo_stmt_t *stmt TSRMLS_DC)
4445
{
4546
pdo_pgsql_stmt *S = (pdo_pgsql_stmt*)stmt->driver_data;
@@ -184,6 +185,12 @@ static int pgsql_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *
184185
#if HAVE_PQPREPARE
185186
if (S->stmt_name && param->is_param) {
186187
switch (event_type) {
188+
case PDO_PARAM_EVT_FREE:
189+
if (param->driver_data) {
190+
efree(param->driver_data);
191+
}
192+
break;
193+
187194
case PDO_PARAM_EVT_ALLOC:
188195
/* decode name from $1, $2 into 0, 1 etc. */
189196
if (param->name) {
@@ -224,10 +231,26 @@ static int pgsql_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *
224231
php_stream *stm;
225232
php_stream_from_zval_no_verify(stm, &param->parameter);
226233
if (stm) {
227-
SEPARATE_ZVAL_IF_NOT_REF(&param->parameter);
228-
Z_TYPE_P(param->parameter) = IS_STRING;
229-
Z_STRLEN_P(param->parameter) = php_stream_copy_to_mem(stm,
230-
&Z_STRVAL_P(param->parameter), PHP_STREAM_COPY_ALL, 0);
234+
if (php_stream_is(stm, &pdo_pgsql_lob_stream_ops)) {
235+
struct pdo_pgsql_lob_self *self = (struct pdo_pgsql_lob_self*)stm->abstract;
236+
pdo_pgsql_bound_param *P = param->driver_data;
237+
238+
if (P == NULL) {
239+
P = ecalloc(1, sizeof(*P));
240+
param->driver_data = P;
241+
}
242+
P->oid = htonl(self->oid);
243+
S->param_values[param->paramno] = (char*)&P->oid;
244+
S->param_lengths[param->paramno] = sizeof(P->oid);
245+
S->param_formats[param->paramno] = 1;
246+
S->param_types[param->paramno] = OIDOID;
247+
return 1;
248+
} else {
249+
SEPARATE_ZVAL_IF_NOT_REF(&param->parameter);
250+
Z_TYPE_P(param->parameter) = IS_STRING;
251+
Z_STRLEN_P(param->parameter) = php_stream_copy_to_mem(stm,
252+
&Z_STRVAL_P(param->parameter), PHP_STREAM_COPY_ALL, 0);
253+
}
231254
} else {
232255
/* expected a stream resource */
233256
pdo_pgsql_error_stmt(stmt, PGRES_FATAL_ERROR, "HY105");
@@ -308,6 +331,7 @@ static int pgsql_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC)
308331
{
309332
pdo_pgsql_stmt *S = (pdo_pgsql_stmt*)stmt->driver_data;
310333
struct pdo_column_data *cols = stmt->columns;
334+
struct pdo_bound_param_data *param;
311335

312336
if (!S->result) {
313337
return 0;
@@ -324,10 +348,25 @@ static int pgsql_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC)
324348
case BOOLOID:
325349
cols[colno].param_type = PDO_PARAM_BOOL;
326350
break;
351+
352+
case OIDOID:
353+
/* did the user bind the column as a LOB ? */
354+
if (stmt->bound_columns && (
355+
SUCCESS == zend_hash_index_find(stmt->bound_columns,
356+
colno, (void**)&param) ||
357+
SUCCESS == zend_hash_find(stmt->bound_columns,
358+
cols[colno].name, cols[colno].namelen,
359+
(void**)&param))) {
360+
if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB) {
361+
cols[colno].param_type = PDO_PARAM_LOB;
362+
break;
363+
}
364+
}
365+
cols[colno].param_type = PDO_PARAM_INT;
366+
break;
327367

328368
case INT2OID:
329369
case INT4OID:
330-
case OIDOID:
331370
cols[colno].param_type = PDO_PARAM_INT;
332371
break;
333372

@@ -487,9 +526,24 @@ static int pgsql_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, unsigned
487526
break;
488527

489528
case PDO_PARAM_LOB:
490-
*ptr = php_pdo_pgsql_unescape_bytea(*ptr, &tmp_len);
491-
*len = tmp_len;
492-
*caller_frees = 1;
529+
if (S->cols[colno].pgsql_type == OIDOID) {
530+
/* ooo, a real large object */
531+
char *end_ptr;
532+
Oid oid = (Oid)strtoul(*ptr, &end_ptr, 10);
533+
int loid = lo_open(S->H->server, oid, INV_READ);
534+
if (loid >= 0) {
535+
*ptr = (char*)pdo_pgsql_create_lob_stream(stmt->dbh, loid, oid TSRMLS_CC);
536+
*len = 0;
537+
return *ptr ? 1 : 0;
538+
}
539+
*ptr = NULL;
540+
*len = 0;
541+
return 0;
542+
} else {
543+
*ptr = php_pdo_pgsql_unescape_bytea(*ptr, &tmp_len);
544+
*len = tmp_len;
545+
*caller_frees = 1;
546+
}
493547
break;
494548
case PDO_PARAM_NULL:
495549
case PDO_PARAM_STR:

0 commit comments

Comments
 (0)