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"
32 /* convert version to string */
33 extern void php_pq_version_to_string(int version
, char *buffer
, int len
) {
34 if (version
< 100000) {
35 slprintf(buffer
, len
, "%d.%d.%d", version
/10000, version
/100%100, version
%100);
36 } else { /* since version 10 */
37 slprintf(buffer
, len
, "%d.%d", version
/10000, version
%100);
41 /* clear result object associated with a result handle */
42 void php_pqres_clear(PGresult
*r
) {
43 php_pq_object_t
*o
= PQresultInstanceData(r
, php_pqconn_event
);
46 php_pq_object_delref(o
);
52 /* clear any asynchronous results */
53 void php_pqconn_clear(PGconn
*conn
) {
55 php_pqconn_event_data_t
*evdata
= PQinstanceData(conn
, php_pqconn_event
);
57 while ((r
= PQgetResult(conn
))) {
61 if (evdata
&& evdata
->obj
) {
62 if (php_pq_callback_is_enabled(&evdata
->obj
->intern
->onevent
)) {
63 if (php_pq_callback_is_locked(&evdata
->obj
->intern
->onevent
)) {
64 php_pq_callback_disable(&evdata
->obj
->intern
->onevent
);
66 php_pq_callback_dtor(&evdata
->obj
->intern
->onevent
);
72 /* safe wrappers to clear any asynchronous wrappers before querying synchronously */
73 PGresult
*php_pq_exec(PGconn
*conn
, const char *query
) {
74 php_pqconn_clear(conn
);
75 return PQexec(conn
, query
);
77 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
) {
78 php_pqconn_clear(conn
);
79 return PQexecParams(conn
, command
, nParams
, paramTypes
, paramValues
, paramLengths
, paramFormats
, resultFormat
);
81 PGresult
*php_pq_prepare(PGconn
*conn
, const char *stmtName
, const char *query
, int nParams
, const Oid
*paramTypes
) {
82 php_pqconn_clear(conn
);
83 return PQprepare(conn
, stmtName
, query
, nParams
, paramTypes
);
85 PGresult
*php_pq_exec_prepared(PGconn
*conn
, const char *stmtName
, int nParams
, const char *const * paramValues
, const int *paramLengths
, const int *paramFormats
, int resultFormat
) {
86 php_pqconn_clear(conn
);
87 return PQexecPrepared(conn
, stmtName
, nParams
, paramValues
, paramLengths
, paramFormats
, resultFormat
);
90 char *php_pq_rtrim(char *e
)
94 while (l
-- > 0 && e
[l
] == '\n') {
100 const char *php_pq_strmode(long mode
)
102 switch (mode
& (INV_READ
|INV_WRITE
)) {
103 case INV_READ
|INV_WRITE
:
114 static inline int compare_index(zend_ulong l
, zend_ulong r
)
124 #if PHP_VERSION_ID >= 80000
125 int php_pq_compare_index(Bucket
*lptr
, Bucket
*rptr
)
127 return compare_index(lptr
->h
, rptr
->h
);
130 int php_pq_compare_index(const void *lptr
, const void *rptr
) {
131 return compare_index(((const Bucket
*) lptr
)->h
, ((const Bucket
*) rptr
)->h
);
135 void php_pq_hash_ptr_dtor(zval
*p
)
140 zend_class_entry
*php_pqdt_class_entry
;
142 #if PHP_VERSION_ID >= 80100
143 ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(ai_pqdt_jsonserialize
, 0, 0, IS_MIXED
, 0)
146 #define ai_pqdt_jsonserialize ai_pqdt_to_string
149 #if PHP_VERSION_ID >= 80200
150 ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(ai_pqdt_to_string
, 0, 0, IS_STRING
, 0)
152 ZEND_BEGIN_ARG_INFO_EX(ai_pqdt_to_string
, 0, 0, 0)
155 static PHP_METHOD(pqdt
, __toString
)
160 php_pq_call_method(getThis(), "format", 1, &rv
, php_pq_read_property(getThis(), "format", &tmp
));
161 RETVAL_ZVAL(&rv
, 1, 1);
164 #if PHP_VERSION_ID >= 80100
165 ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_OBJ_TYPE_MASK_EX(ai_pqdt_create_from_format
, 0, 2, DateTime
, MAY_BE_FALSE
)
167 ZEND_BEGIN_ARG_INFO_EX(ai_pqdt_create_from_format
, 0, 0, 2)
169 ZEND_ARG_INFO(0, format
)
170 ZEND_ARG_INFO(0, datetime
)
171 #if PHP_VERSION_ID >= 70200
172 ZEND_ARG_OBJ_INFO(0, object
, DateTimeZone
, 1)
174 ZEND_ARG_INFO(0, timezone
)
177 static PHP_METHOD(pqdt
, createFromFormat
)
179 zend_error_handling zeh
;
180 char *fmt_str
, *dt_str
;
181 size_t fmt_len
, dt_len
;
185 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
186 rv
= zend_parse_parameters(ZEND_NUM_ARGS(), "ss|O", &fmt_str
, &fmt_len
, &dt_str
, &dt_len
, &ztz
, php_date_get_timezone_ce());
187 zend_restore_error_handling(&zeh
);
190 php_pqdt_from_string(return_value
, fmt_str
, dt_str
, dt_len
, "Y-m-d H:i:s.uO", ztz
);
194 static zend_function_entry php_pqdt_methods
[] = {
195 PHP_ME(pqdt
, createFromFormat
, ai_pqdt_create_from_format
, ZEND_ACC_PUBLIC
|ZEND_ACC_STATIC
)
196 PHP_ME(pqdt
, __toString
, ai_pqdt_to_string
, ZEND_ACC_PUBLIC
)
197 PHP_MALIAS(pqdt
, jsonSerialize
, __toString
, ai_pqdt_jsonserialize
, ZEND_ACC_PUBLIC
)
201 zval
*php_pqdt_from_string(zval
*zv
, char *input_fmt
, char *dt_str
, size_t dt_len
, const char *output_fmt
, zval
*ztimezone
)
205 php_date_instantiate(php_pqdt_class_entry
, zv
);
206 dobj
= php_date_obj_from_obj(Z_OBJ_P(zv
));
207 if (!php_date_initialize(dobj
, dt_str
, dt_len
, input_fmt
, ztimezone
, 1)) {
210 } else if (output_fmt
) {
212 ZVAL_STRING(&fmt
, output_fmt
);
213 php_pq_update_property(zv
, "format", &fmt
);
220 zend_string
*php_pqdt_to_string(zval
*zdt
, const char *format
)
226 if (php_pq_cast_object(zdt
, IS_STRING
, &rv
)) {
228 } else if (instanceof_function(Z_OBJCE_P(zdt
), php_date_get_date_ce())) {
232 ZVAL_STRING(&zfmt
, format
);
233 php_pq_call_method(zdt
, "format", 1, &rv
, &zfmt
);
234 zval_ptr_dtor(&zfmt
);
236 if (Z_TYPE(rv
) == IS_STRING
) {
245 zend_class_entry
*php_pqconv_class_entry
;
247 ZEND_BEGIN_ARG_INFO_EX(ai_pqconv_convert_types
, 0, 0, 0)
250 ZEND_BEGIN_ARG_INFO_EX(ai_pqconv_convert_from_string
, 0, 0, 2)
251 ZEND_ARG_INFO(0, data
)
252 ZEND_ARG_INFO(0, type
)
255 ZEND_BEGIN_ARG_INFO_EX(ai_pqconv_convert_to_string
, 0, 0, 2)
256 ZEND_ARG_INFO(0, data
)
257 ZEND_ARG_INFO(0, type
)
260 zend_function_entry php_pqconv_methods
[] = {
261 PHP_ABSTRACT_ME(pqconv
, convertTypes
, ai_pqconv_convert_types
)
262 PHP_ABSTRACT_ME(pqconv
, convertFromString
, ai_pqconv_convert_from_string
)
263 PHP_ABSTRACT_ME(pqconv
, convertToString
, ai_pqconv_convert_to_string
)
268 PHP_MINIT_FUNCTION(pq_misc
)
270 zend_class_entry
*json
, ce
= {0};
272 INIT_NS_CLASS_ENTRY(ce
, "pq", "Converter", php_pqconv_methods
);
273 php_pqconv_class_entry
= zend_register_internal_interface(&ce
);
275 memset(&ce
, 0, sizeof(ce
));
276 INIT_NS_CLASS_ENTRY(ce
,"pq", "DateTime", php_pqdt_methods
);
277 php_pqdt_class_entry
= zend_register_internal_class_ex(&ce
, php_date_get_date_ce());
279 zend_declare_property_stringl(php_pqdt_class_entry
, ZEND_STRL("format"), ZEND_STRL("Y-m-d H:i:s.uO"), ZEND_ACC_PUBLIC
);
281 /* stop reading this file right here! */
282 if ((json
= zend_hash_str_find_ptr(CG(class_table
), ZEND_STRL("jsonserializable")))) {
283 zend_class_implements(php_pqdt_class_entry
, 1, json
);
289 typedef struct _HashTableList
{
291 struct _HashTableList
*parent
;
294 typedef struct _ArrayParserState
{
295 const char *ptr
, *end
;
303 static char caa(ArrayParserState
*a
, const char *any
, unsigned advance
)
314 php_error_docref(NULL
, E_WARNING
, "Failed to parse array: expected one of '%s', got '%c'", any
, *a
->ptr
); \
318 static ZEND_RESULT_CODE
add_element(ArrayParserState
*a
, const char *start
)
321 zend_string
*zstr
= zend_string_init(start
, a
->ptr
- start
, 0);
324 php_stripslashes(zstr
);
325 ZVAL_STR(&zelem
, zstr
);
326 } else if (!zend_string_equals_literal(zstr
, "NULL")) {
327 ZVAL_STR(&zelem
, zstr
);
329 zend_string_release(zstr
);
333 if (!ZVAL_IS_NULL(&zelem
)) {
334 php_pqres_typed_zval(a
->res
, a
->typ
, &zelem
);
337 add_next_index_zval(&a
->list
->arr
, &zelem
);
341 static ZEND_RESULT_CODE
parse_array(ArrayParserState
*a
);
343 static ZEND_RESULT_CODE
parse_element(ArrayParserState
*a
, char delim
)
349 return parse_array(a
);
360 for (el
= a
->ptr
; a
->ptr
< a
->end
; ++a
->ptr
) {
363 a
->escaped
= !a
->escaped
;
369 } else if (a
->quotes
) {
370 if (SUCCESS
!= add_element(a
, el
)) {
377 php_error_docref(NULL
, E_WARNING
, "Failed to parse element, unexpected quote: '%.*s'", (int) (a
->ptr
- el
), el
);
383 if (delim
!= *a
->ptr
) {
390 return add_element(a
, el
);
397 php_error_docref(NULL
, E_WARNING
, "Failed to parse element, reached end of input");
401 static ZEND_RESULT_CODE
parse_elements(ArrayParserState
*a
)
403 char delims
[] = {'}', (char) PHP_PQ_DELIM_OF_ARRAY(a
->typ
), 0};
405 while (SUCCESS
== parse_element(a
, delims
[1])) {
406 switch (caa(a
, delims
, 0)) {
415 php_error_docref(NULL
, E_WARNING
, "Failed to parse elements, reached end of input");
425 static ZEND_RESULT_CODE
parse_array(ArrayParserState
*a
)
429 if (!caa(a
, "{", 1)) {
433 list
= ecalloc(1, sizeof(*list
));
434 array_init(&list
->arr
);
437 add_next_index_zval(&a
->list
->arr
, &list
->arr
);
438 list
->parent
= a
->list
;
442 if (SUCCESS
!= parse_elements(a
)) {
446 if (!caa(a
, "}", 1)) {
450 /* step one level back up */
451 if (a
->list
->parent
) {
452 HashTableList
*l
= a
->list
->parent
;
461 HashTable
*php_pq_parse_array(php_pqres_t
*res
, const char *val_str
, size_t val_len
, Oid typ
)
463 HashTable
*ht
= NULL
;
464 ArrayParserState a
= {0};
468 a
.end
= val_str
+ val_len
;
471 if (SUCCESS
!= parse_array(&a
)) {
473 HashTableList
*l
= a
.list
->parent
;
475 zval_dtor(&a
.list
->arr
);
483 php_error_docref(NULL
, E_NOTICE
, "Trailing input: '%s'", a
.ptr
);
487 HashTableList
*l
= a
.list
->parent
;
489 ht
= Z_ARRVAL(a
.list
->arr
);
503 * vim600: noet sw=4 ts=4 fdm=marker
504 * vim<600: noet sw=4 ts=4