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:
commit
b600ed678d
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
70
tests/gh-issue015_listeners.phpt
Normal file
70
tests/gh-issue015_listeners.phpt
Normal 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===
|
42
tests/gh-issue015_statements.phpt
Normal file
42
tests/gh-issue015_statements.phpt
Normal 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===
|
Loading…
Reference in New Issue
Block a user