2 +--------------------------------------------------------------------+
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted provided that the conditions mentioned |
7 | in the accompanying LICENSE file are met. |
8 +--------------------------------------------------------------------+
9 | Copyright (c) 2013, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
18 #include <ext/date/php_date.h>
19 #include <ext/standard/php_string.h>
21 #include <Zend/zend_interfaces.h>
23 #include <libpq/libpq-fs.h>
26 #include "php_pqexc.h"
27 #include "php_pq_misc.h"
28 #include "php_pqconn_event.h"
30 #include "php_pq_type.h"
33 /* clear result object associated with a result handle */
34 void php_pqres_clear(PGresult
*r
) {
35 php_pq_object_t
*o
= PQresultInstanceData(r
, php_pqconn_event
);
39 php_pq_object_delref(o TSRMLS_CC
);
45 /* clear any asynchronous results */
46 void php_pqconn_clear(PGconn
*conn
) {
48 php_pqconn_event_data_t
*evdata
= PQinstanceData(conn
, php_pqconn_event
);
50 while ((r
= PQgetResult(conn
))) {
54 if (evdata
&& evdata
->obj
) {
55 if (php_pq_callback_is_enabled(&evdata
->obj
->intern
->onevent
)) {
56 TSRMLS_FETCH_FROM_CTX(evdata
->ts
);
58 if (php_pq_callback_is_locked(&evdata
->obj
->intern
->onevent TSRMLS_CC
)) {
59 php_pq_callback_disable(&evdata
->obj
->intern
->onevent TSRMLS_CC
);
61 php_pq_callback_dtor(&evdata
->obj
->intern
->onevent
);
67 /* safe wrappers to clear any asynchronous wrappers before querying synchronously */
68 PGresult
*php_pq_exec(PGconn
*conn
, const char *query
) {
69 php_pqconn_clear(conn
);
70 return PQexec(conn
, query
);
72 PGresult
*php_pq_exec_params(PGconn
*conn
, const char *command
, int nParams
, const Oid
*paramTypes
, const char *const * paramValues
, const int *paramLengths
, const int *paramFormats
, int resultFormat
) {
73 php_pqconn_clear(conn
);
74 return PQexecParams(conn
, command
, nParams
, paramTypes
, paramValues
, paramLengths
, paramFormats
, resultFormat
);
76 PGresult
*php_pq_prepare(PGconn
*conn
, const char *stmtName
, const char *query
, int nParams
, const Oid
*paramTypes
) {
77 php_pqconn_clear(conn
);
78 return PQprepare(conn
, stmtName
, query
, nParams
, paramTypes
);
80 PGresult
*php_pq_exec_prepared(PGconn
*conn
, const char *stmtName
, int nParams
, const char *const * paramValues
, const int *paramLengths
, const int *paramFormats
, int resultFormat
) {
81 php_pqconn_clear(conn
);
82 return PQexecPrepared(conn
, stmtName
, nParams
, paramValues
, paramLengths
, paramFormats
, resultFormat
);
85 char *php_pq_rtrim(char *e
)
89 while (l
-- > 0 && e
[l
] == '\n') {
95 const char *php_pq_strmode(long mode
)
97 switch (mode
& (INV_READ
|INV_WRITE
)) {
98 case INV_READ
|INV_WRITE
:
109 int php_pq_compare_index(const void *lptr
, const void *rptr TSRMLS_DC
)
111 const Bucket
*l
= *(const Bucket
**) lptr
;
112 const Bucket
*r
= *(const Bucket
**) rptr
;
123 zend_class_entry
*php_pqdt_class_entry
;
125 ZEND_BEGIN_ARG_INFO_EX(ai_pqdt_to_string
, 0, 0, 0)
127 static PHP_METHOD(pqdt
, __toString
)
131 zend_call_method_with_1_params(&getThis(), php_pqdt_class_entry
, NULL
, "format", &rv
,
132 zend_read_property(php_pqdt_class_entry
, getThis(), ZEND_STRL("format"), 0 TSRMLS_CC
));
134 RETVAL_ZVAL(rv
, 1, 1);
138 ZEND_BEGIN_ARG_INFO_EX(ai_pqdt_create_from_format
, 0, 0, 2)
139 ZEND_ARG_INFO(0, format
)
140 ZEND_ARG_INFO(0, datetime
)
141 ZEND_ARG_INFO(0, timezone
)
143 static PHP_METHOD(pqdt
, createFromFormat
)
145 zend_error_handling zeh
;
146 char *fmt_str
, *dt_str
;
151 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
152 rv
= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "ss|O", &fmt_str
, &fmt_len
, &dt_str
, &dt_len
, &ztz
, php_date_get_timezone_ce());
153 zend_restore_error_handling(&zeh TSRMLS_CC
);
156 php_pqdt_from_string(return_value
, fmt_str
, dt_str
, dt_len
, "Y-m-d H:i:s.uO", ztz TSRMLS_CC
);
160 static zend_function_entry php_pqdt_methods
[] = {
161 PHP_ME(pqdt
, createFromFormat
, ai_pqdt_create_from_format
, ZEND_ACC_PUBLIC
|ZEND_ACC_STATIC
)
162 PHP_ME(pqdt
, __toString
, ai_pqdt_to_string
, ZEND_ACC_PUBLIC
)
163 PHP_MALIAS(pqdt
, jsonSerialize
, __toString
, ai_pqdt_to_string
, ZEND_ACC_PUBLIC
)
167 zval
*php_pqdt_from_string(zval
*zv
, char *input_fmt
, char *dt_str
, size_t dt_len
, char *output_fmt
, zval
*ztimezone TSRMLS_DC
)
175 php_date_instantiate(php_pqdt_class_entry
, zv TSRMLS_CC
);
176 dobj
= zend_object_store_get_object(zv TSRMLS_CC
);
177 if (!php_date_initialize(dobj
, dt_str
, dt_len
, input_fmt
, ztimezone
, 1 TSRMLS_CC
)) {
180 } else if (output_fmt
) {
181 zend_update_property_string(php_pqdt_class_entry
, zv
, ZEND_STRL("format"), output_fmt TSRMLS_CC
);
187 void php_pqdt_to_string(zval
*zdt
, const char *format
, char **str_buf
, size_t *str_len TSRMLS_DC
)
194 if (Z_OBJ_HT_P(zdt
)->cast_object
195 && SUCCESS
== Z_OBJ_HT_P(zdt
)->cast_object(zdt
, &rv
, IS_STRING TSRMLS_CC
)
197 *str_len
= Z_STRLEN(rv
);
198 *str_buf
= Z_STRVAL(rv
);
199 } else if (instanceof_function(Z_OBJCE_P(zdt
), php_date_get_date_ce() TSRMLS_CC
)) {
200 zval
*rv
= NULL
, *zfmt
;
203 ZVAL_STRING(zfmt
, format
, 1);
204 zend_call_method_with_1_params(&zdt
, Z_OBJCE_P(zdt
), NULL
, "format", &rv
, zfmt
);
205 zval_ptr_dtor(&zfmt
);
208 if (Z_TYPE_P(rv
) == IS_STRING
) {
209 *str_len
= Z_STRLEN_P(rv
);
210 *str_buf
= estrndup(Z_STRVAL_P(rv
), *str_len
);
217 zend_class_entry
*php_pqconv_class_entry
;
219 ZEND_BEGIN_ARG_INFO_EX(ai_pqconv_convert_types
, 0, 0, 0)
222 ZEND_BEGIN_ARG_INFO_EX(ai_pqconv_convert_from_string
, 0, 0, 2)
223 ZEND_ARG_INFO(0, data
)
224 ZEND_ARG_INFO(0, type
)
227 ZEND_BEGIN_ARG_INFO_EX(ai_pqconv_convert_to_string
, 0, 0, 2)
228 ZEND_ARG_INFO(0, data
)
229 ZEND_ARG_INFO(0, type
)
232 zend_function_entry php_pqconv_methods
[] = {
233 PHP_ABSTRACT_ME(pqconv
, convertTypes
, ai_pqconv_convert_types
)
234 PHP_ABSTRACT_ME(pqconv
, convertFromString
, ai_pqconv_convert_from_string
)
235 PHP_ABSTRACT_ME(pqconv
, convertToString
, ai_pqconv_convert_to_string
)
240 PHP_MINIT_FUNCTION(pq_misc
)
242 zend_class_entry
**json
, ce
= {0};
244 INIT_NS_CLASS_ENTRY(ce
, "pq", "Converter", php_pqconv_methods
);
245 php_pqconv_class_entry
= zend_register_internal_interface(&ce TSRMLS_CC
);
247 memset(&ce
, 0, sizeof(ce
));
248 INIT_NS_CLASS_ENTRY(ce
,"pq", "DateTime", php_pqdt_methods
);
249 php_pqdt_class_entry
= zend_register_internal_class_ex(&ce
, php_date_get_date_ce(), "DateTime" TSRMLS_CC
);
251 zend_declare_property_stringl(php_pqdt_class_entry
, ZEND_STRL("format"), ZEND_STRL("Y-m-d H:i:s.uO"), ZEND_ACC_PUBLIC TSRMLS_CC
);
253 /* stop reading this file right here! */
254 if (SUCCESS
== zend_hash_find(CG(class_table
), ZEND_STRS("jsonserializable"), (void *) &json
)) {
255 zend_class_implements(php_pqdt_class_entry TSRMLS_CC
, 1, *json
);
261 typedef struct _HashTableList
{
263 struct _HashTableList
*parent
;
266 typedef struct _ArrayParserState
{
267 const char *ptr
, *end
;
278 static char caa(ArrayParserState
*a
, const char *any
, unsigned advance
)
281 TSRMLS_FETCH_FROM_CTX(a
->ts
);
290 php_error_docref(NULL TSRMLS_CC
, E_WARNING
, "Failed to parse array: expected one of '%s', got '%c'", any
, *a
->ptr
); \
294 static ZEND_RESULT_CODE
add_element(ArrayParserState
*a
, const char *start
)
297 size_t el_len
= a
->ptr
- start
;
298 char *el_str
= estrndup(start
, el_len
);
299 TSRMLS_FETCH_FROM_CTX(a
->ts
);
302 int tmp_len
= el_len
;
304 php_stripslashes(el_str
, &tmp_len TSRMLS_CC
);
306 } else if ((a
->ptr
- start
== 4) && !strncmp(start
, "NULL", 4)) {
313 MAKE_STD_ZVAL(zelem
);
316 zelem
= php_pqres_typed_zval(a
->res
, el_str
, el_len
, a
->typ TSRMLS_CC
);
321 return zend_hash_next_index_insert(&a
->list
->ht
, &zelem
, sizeof(zval
*), NULL
);
324 static ZEND_RESULT_CODE
parse_array(ArrayParserState
*a
);
326 static ZEND_RESULT_CODE
parse_element(ArrayParserState
*a
, char delim
)
329 TSRMLS_FETCH_FROM_CTX(a
->ts
);
333 return parse_array(a
);
341 for (el
= a
->ptr
; a
->ptr
< a
->end
; ++a
->ptr
) {
344 a
->escaped
= !a
->escaped
;
350 } else if (a
->quotes
) {
351 if (SUCCESS
!= add_element(a
, el
)) {
358 php_error_docref(NULL TSRMLS_CC
, E_WARNING
, "Failed to parse element, unexpected quote: '%.*s'", (int) (a
->ptr
- el
), el
);
364 if (delim
!= *a
->ptr
) {
371 return add_element(a
, el
);
378 php_error_docref(NULL TSRMLS_CC
, E_WARNING
, "Failed to parse element, reached end of input");
382 static ZEND_RESULT_CODE
parse_elements(ArrayParserState
*a
)
384 char delims
[] = {'}', PHP_PQ_DELIM_OF_ARRAY(a
->typ
), 0};
385 TSRMLS_FETCH_FROM_CTX(a
->ts
);
387 while (SUCCESS
== parse_element(a
, delims
[1])) {
388 switch (caa(a
, delims
, 0)) {
397 php_error_docref(NULL TSRMLS_CC
, E_WARNING
, "Failed to parse elements, reached end of input");
407 static ZEND_RESULT_CODE
parse_array(ArrayParserState
*a
)
411 if (!caa(a
, "{", 1)) {
415 list
= ecalloc(1, sizeof(*list
));
416 ZEND_INIT_SYMTABLE(&list
->ht
);
422 Z_TYPE_P(zcur
) = IS_ARRAY
;
423 Z_ARRVAL_P(zcur
) = &list
->ht
;
425 zend_hash_next_index_insert(&a
->list
->ht
, &zcur
, sizeof(zval
*), NULL
);
427 list
->parent
= a
->list
;
431 if (SUCCESS
!= parse_elements(a
)) {
435 if (!caa(a
, "}", 1)) {
439 if (a
->list
->parent
) {
440 a
->list
= a
->list
->parent
;
446 HashTable
*php_pq_parse_array(php_pqres_t
*res
, const char *val_str
, size_t val_len
, Oid typ TSRMLS_DC
)
448 HashTable
*ht
= NULL
;
449 ArrayParserState a
= {0};
450 TSRMLS_SET_CTX(a
.ts
);
454 a
.end
= val_str
+ val_len
;
457 if (SUCCESS
!= parse_array(&a
)) {
459 HashTableList
*l
= a
.list
->parent
;
461 zend_hash_destroy(&a
.list
->ht
);
469 php_error_docref(NULL TSRMLS_CC
, E_NOTICE
, "Trailing input: '%s'", a
.ptr
);
474 } while ((a
.list
= a
.list
->parent
));
485 * vim600: noet sw=4 ts=4 fdm=marker
486 * vim<600: noet sw=4 ts=4