1
0
mirror of https://github.com/danog/ext-pq.git synced 2024-11-30 04:19:49 +01:00

Merge branch 'v1.1.x'

This commit is contained in:
Michael Wallner 2016-05-17 16:33:37 +02:00
commit b600ed678d
No known key found for this signature in database
GPG Key ID: 480E3E14B0A4C7C7
6 changed files with 176 additions and 1 deletions

View File

@ -86,6 +86,7 @@ static void php_pqconn_object_free(zend_object *o)
php_resource_factory_handle_dtor(&obj->intern->factory, obj->intern->conn);
php_resource_factory_dtor(&obj->intern->factory);
zend_hash_destroy(&obj->intern->listeners);
zend_hash_destroy(&obj->intern->statements);
zend_hash_destroy(&obj->intern->converters);
zend_hash_destroy(&obj->intern->eventhandlers);
efree(obj->intern);
@ -668,6 +669,7 @@ static PHP_METHOD(pqconn, __construct) {
obj->intern->default_auto_convert = PHP_PQRES_CONV_ALL;
zend_hash_init(&obj->intern->listeners, 0, NULL, ZVAL_PTR_DTOR, 0);
zend_hash_init(&obj->intern->statements, 0, NULL, NULL, 0);
zend_hash_init(&obj->intern->converters, 0, NULL, ZVAL_PTR_DTOR, 0);
zend_hash_init(&obj->intern->eventhandlers, 0, NULL, ZVAL_PTR_DTOR, 0);

View File

@ -28,6 +28,7 @@ typedef struct php_pqconn {
int (*poller)(PGconn *);
php_resource_factory_t factory;
HashTable listeners;
HashTable statements;
HashTable converters;
HashTable eventhandlers;
php_pq_callback_t onevent;

View File

@ -16,12 +16,15 @@
#include <php.h>
#include <Zend/zend_smart_str.h>
#include <libpq-events.h>
#include "php_pq.h"
#include "php_pq_misc.h"
#include "php_pq_object.h"
#include "php_pqconn_event.h"
#include "php_pqstm.h"
#include "php_pqres.h"
static int apply_event(zval *p, void *a)
@ -39,6 +42,50 @@ static int apply_event(zval *p, void *a)
return ZEND_HASH_APPLY_KEEP;
}
static inline PGresult *relisten(PGconn *conn, const char *channel_str, size_t channel_len)
{
char *quoted_channel = PQescapeIdentifier(conn, channel_str, channel_len);
PGresult *res = NULL;
if (quoted_channel) {
smart_str cmd = {0};
smart_str_appends(&cmd, "LISTEN ");
smart_str_appends(&cmd, quoted_channel);
smart_str_0(&cmd);
res = PQexec(conn, smart_str_v(&cmd));
smart_str_free(&cmd);
PQfreemem(quoted_channel);
}
return res;
}
static int apply_relisten(zval *p, int argc, va_list argv, zend_hash_key *key)
{
php_pqconn_object_t *obj = va_arg(argv, php_pqconn_object_t *);
PGresult *res = relisten(obj->intern->conn, key->key->val, key->key->len);
if (res) {
php_pqres_clear(res);
}
return ZEND_HASH_APPLY_KEEP;
}
static int apply_reprepare(zval *p, int argc, va_list argv, zend_hash_key *key)
{
php_pqconn_object_t *obj = va_arg(argv, php_pqconn_object_t *);
php_pqstm_t *stm = Z_PTR_P(p);
php_pqconn_prepare(NULL, obj, stm->name, stm->query, stm->params);
return ZEND_HASH_APPLY_KEEP;
}
static void php_pqconn_event_connreset(PGEventConnReset *event)
{
php_pqconn_event_data_t *data = PQinstanceData(event->conn, php_pqconn_event);
@ -46,6 +93,13 @@ static void php_pqconn_event_connreset(PGEventConnReset *event)
if (data) {
zval *zevhs;
/* restore listeners */
zend_hash_apply_with_arguments(&data->obj->intern->listeners, apply_relisten, 1, data->obj);
/* restore statements */
zend_hash_apply_with_arguments(&data->obj->intern->statements, apply_reprepare, 1, data->obj);
/* eventhandler */
if ((zevhs = zend_hash_str_find(&data->obj->intern->eventhandlers, ZEND_STRL("reset")))) {
zval args, connection;

View File

@ -63,6 +63,7 @@ static void php_pqstm_deallocate(php_pqstm_object_t *obj, zend_bool async, zend_
}
obj->intern->allocated = 0;
zend_hash_str_del(&obj->intern->conn->intern->statements, obj->intern->name, strlen(obj->intern->name));
}
}
@ -155,6 +156,8 @@ php_pqstm_t *php_pqstm_init(php_pqconn_object_t *conn, const char *name, const c
ZEND_INIT_SYMTABLE(&stm->bound);
zend_hash_str_add_ptr(&conn->intern->statements, name, strlen(name), stm);
return stm;
}
@ -410,7 +413,7 @@ static PHP_METHOD(pqstm, deallocateAsync)
php_pqstm_deallocate_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
}
static zend_always_inline void php_pqstm_prepare_handler(INTERNAL_FUNCTION_PARAMETERS, zend_bool async)
static inline void php_pqstm_prepare_handler(INTERNAL_FUNCTION_PARAMETERS, zend_bool async)
{
zend_error_handling zeh;
ZEND_RESULT_CODE rv;
@ -433,6 +436,9 @@ static zend_always_inline void php_pqstm_prepare_handler(INTERNAL_FUNCTION_PARAM
if (SUCCESS == rv) {
obj->intern->allocated = 1;
zend_hash_str_add_ptr(&obj->intern->conn->intern->statements,
obj->intern->name, strlen(obj->intern->name), obj->intern);
}
}
}

View File

@ -0,0 +1,70 @@
--TEST--
restore listeners on reset
--SKIPIF--
<?php
include "_skipif.inc";
?>
--INI--
date.timezone=UTC
--FILE--
<?php
echo "Test\n";
include "_setup.inc";
$c = new pq\Connection(PQ_DSN);
$c->listen("notify", function($channel, $message) {
printf("%s: %s\n", $channel, $message);
});
$c->on(pq\Connection::EVENT_RESET, function($conn) {
printf("Connection was reset\n");
});
$c->notify("notify", "Gotcha!");
$c->resetAsync();
// wait until the stream becomes writable
$w = array($c->socket);
$r = $e = null;
if (stream_select($r, $w, $e, null)) {
// loop until the connection is established
while (true) {
switch ($c->poll()) {
case pq\Connection::POLLING_READING:
// we should wait for the stream to be read-ready
$r = array($c->socket);
stream_select($r, $w, $e, NULL);
break;
case pq\Connection::POLLING_WRITING:
// we should wait for the stream to be write-ready
$w = array($c->socket);
$r = $e = null;
stream_select($r, $w, $e, null);
break;
case pq\Connection::POLLING_FAILED:
printf("Connection failed: %s\n", $c->errorMessage);
break 2;
case pq\Connection::POLLING_OK:
printf("Connection completed\n");
break 2;
}
}
}
$c->notify("notify", "Do you miss me?");
$c->exec("");
?>
===DONE===
--EXPECT--
Test
notify: Gotcha!
Connection was reset
Connection completed
notify: Do you miss me?
===DONE===

View File

@ -0,0 +1,42 @@
--TEST--
restore statements on reset
--SKIPIF--
<?php
include "_skipif.inc";
?>
--INI--
date.timezone=UTC
--FILE--
<?php
echo "Test\n";
include "_setup.inc";
$c = new pq\Connection(PQ_DSN);
$s = $c->prepare("test", "SELECT 1");
$c->on(pq\Connection::EVENT_RESET, function($conn) {
printf("Connection was reset\n");
});
var_dump($s->exec()->fetchRow());
$c->reset();
// Fatal error: Uncaught exception 'pq\Exception\DomainException' with message 'ERROR: prepared statement "test" does not exist'
var_dump($s->exec()->fetchRow());
?>
===DONE===
--EXPECT--
Test
array(1) {
[0]=>
int(1)
}
Connection was reset
array(1) {
[0]=>
int(1)
}
===DONE===