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>
20 #if defined(HAVE_JSON) && !defined(COMPILE_DL_JSON)
21 # include <ext/json/php_json.h>
24 #include <Zend/zend_interfaces.h>
26 #include <libpq/libpq-fs.h>
29 #include "php_pq_misc.h"
35 while (l
-- > 0 && e
[l
] == '\n') {
41 const char *strmode(long mode
)
43 switch (mode
& (INV_READ
|INV_WRITE
)) {
44 case INV_READ
|INV_WRITE
:
55 int compare_index(const void *lptr
, const void *rptr TSRMLS_DC
)
57 const Bucket
*l
= *(const Bucket
**) lptr
;
58 const Bucket
*r
= *(const Bucket
**) rptr
;
69 static int apply_to_oid(void *p
, void *arg TSRMLS_DC
)
74 if (Z_TYPE_PP(ztype
) != IS_LONG
) {
75 convert_to_long_ex(ztype
);
78 **types
= Z_LVAL_PP(ztype
);
81 if (*ztype
!= *(zval
**)p
) {
84 return ZEND_HASH_APPLY_KEEP
;
87 static int apply_to_param_from_array(void *p TSRMLS_DC
, int argc
, va_list argv
, zend_hash_key
*key
)
90 unsigned j
, *i
= va_arg(argv
, unsigned *);
91 smart_str
*s
= va_arg(argv
, smart_str
*);
97 smart_str_appendc(s
, ',');
100 switch (Z_TYPE_PP(zparam
)) {
102 smart_str_appends(s
, "NULL");
106 smart_str_appends(s
, Z_BVAL_PP(zparam
) ? "t" : "f");
110 smart_str_append_long(s
, Z_LVAL_PP(zparam
));
114 len
= spprintf(&tmp
, 0, "%F", Z_DVAL_PP(zparam
));
115 smart_str_appendl(s
, tmp
, len
);
121 smart_str_appendc(s
, '{');
122 zend_hash_apply_with_arguments(Z_ARRVAL_PP(zparam
) TSRMLS_CC
, apply_to_param_from_array
, 2, &j
, s
);
123 smart_str_appendc(s
, '}');
128 SEPARATE_ZVAL(zparam
);
129 if (Z_TYPE_PP(zparam
) != IS_STRING
) {
130 convert_to_string(*zparam
);
133 tmp
= php_addslashes(Z_STRVAL_PP(zparam
), Z_STRLEN_PP(zparam
), &tmp_len
, 0 TSRMLS_CC
);
134 smart_str_appendc(s
, '"');
135 smart_str_appendl(s
, tmp
, tmp_len
);
136 smart_str_appendc(s
, '"');
138 if (*zparam
!= *((zval
**) p
)) {
139 zval_ptr_dtor(zparam
);
146 return ZEND_HASH_APPLY_KEEP
;
149 static void array_param_to_string(HashTable
*ht
, char **str
, int *len TSRMLS_DC
)
154 smart_str_appendc(&s
, '{');
155 zend_hash_apply_with_arguments(ht TSRMLS_CC
, apply_to_param_from_array
, 2, &i
, &s
);
156 smart_str_appendc(&s
, '}');
163 static int apply_to_param(void *p TSRMLS_DC
, int argc
, va_list argv
, zend_hash_key
*key
)
169 params
= (char ***) va_arg(argv
, char ***);
170 zdtor
= (HashTable
*) va_arg(argv
, HashTable
*);
172 switch (Z_TYPE_PP(zparam
)) {
176 return ZEND_HASH_APPLY_KEEP
;
179 **params
= Z_BVAL_PP(zparam
) ? "t" : "f";
181 return ZEND_HASH_APPLY_KEEP
;
184 SEPARATE_ZVAL(zparam
);
185 Z_TYPE_PP(zparam
) = IS_STRING
;
186 Z_STRLEN_PP(zparam
) = spprintf(&Z_STRVAL_PP(zparam
), 0, "%F", Z_DVAL_PP((zval
**)p
));
193 Z_TYPE_P(tmp
) = IS_STRING
;
194 array_param_to_string(Z_ARRVAL_PP(zparam
), &Z_STRVAL_P(tmp
), &Z_STRLEN_P(tmp
) TSRMLS_CC
);
200 convert_to_string_ex(zparam
);
204 **params
= Z_STRVAL_PP(zparam
);
207 if (*zparam
!= *(zval
**)p
) {
208 zend_hash_next_index_insert(zdtor
, zparam
, sizeof(zval
*), NULL
);
210 return ZEND_HASH_APPLY_KEEP
;
213 int php_pq_types_to_array(HashTable
*ht
, Oid
**types TSRMLS_DC
)
215 int count
= zend_hash_num_elements(ht
);
222 /* +1 for when less types than params are specified */
223 *types
= tmp
= ecalloc(count
+ 1, sizeof(**types
));
224 zend_hash_apply_with_argument(ht
, apply_to_oid
, &tmp TSRMLS_CC
);
230 int php_pq_params_to_array(HashTable
*ht
, char ***params
, HashTable
*zdtor TSRMLS_DC
)
232 int count
= zend_hash_num_elements(ht
);
239 *params
= tmp
= ecalloc(count
, sizeof(char *));
240 zend_hash_apply_with_arguments(ht TSRMLS_CC
, apply_to_param
, 2, &tmp
, zdtor
);
247 Oid *php_pq_ntypes_to_array(zend_bool fill, int argc, ...)
250 Oid *oids = ecalloc(argc + 1, sizeof(*oids));
253 va_start(argv, argc);
254 for (i = 0; i < argc; ++i) {
256 oids[i] = va_arg(argv, Oid);
267 zend_class_entry
*php_pqdt_class_entry
;
269 ZEND_BEGIN_ARG_INFO_EX(ai_pqdt_to_string
, 0, 0, 0)
271 static PHP_METHOD(pqdt
, __toString
)
275 zend_call_method_with_1_params(&getThis(), php_pqdt_class_entry
, NULL
, "format", &rv
,
276 zend_read_property(php_pqdt_class_entry
, getThis(), ZEND_STRL("format"), 0 TSRMLS_CC
));
277 RETVAL_ZVAL(rv
, 1, 1);
280 static zend_function_entry php_pqdt_methods
[] = {
281 PHP_ME(pqdt
, __toString
, ai_pqdt_to_string
, ZEND_ACC_PUBLIC
)
282 PHP_MALIAS(pqdt
, jsonSerialize
, __toString
, ai_pqdt_to_string
, ZEND_ACC_PUBLIC
)
286 zval
*php_pqdt_from_string(char *dt_str
, size_t dt_len
, char *fmt
, zval
*zv TSRMLS_DC
)
294 php_date_instantiate(php_pqdt_class_entry
, zv TSRMLS_CC
);
295 dobj
= zend_object_store_get_object(zv TSRMLS_CC
);
296 if (!php_date_initialize(dobj
, dt_str
, dt_len
, NULL
, NULL
, 1 TSRMLS_CC
)) {
300 zend_update_property_string(php_pqdt_class_entry
, zv
, ZEND_STRL("format"), fmt TSRMLS_CC
);
306 PHP_MINIT_FUNCTION(pq_misc
)
308 zend_class_entry
**json
, ce
= {0};
310 INIT_NS_CLASS_ENTRY(ce
,"pq", "DateTime", php_pqdt_methods
);
311 php_pqdt_class_entry
= zend_register_internal_class_ex(&ce
, php_date_get_date_ce(), "DateTime" TSRMLS_CC
);
313 zend_declare_property_stringl(php_pqdt_class_entry
, ZEND_STRL("format"), ZEND_STRL("Y-m-d H:i:s.u"), ZEND_ACC_PUBLIC TSRMLS_CC
);
315 /* stop reading this file right here! */
316 if (SUCCESS
== zend_hash_find(CG(class_table
), ZEND_STRS("jsonserializable"), (void *) &json
)) {
317 zend_class_implements(php_pqdt_class_entry TSRMLS_CC
, 1, *json
);
323 typedef struct _HashTableList
{
325 struct _HashTableList
*parent
;
328 typedef struct _ArrayParserState
{
329 const char *ptr
, *end
;
339 static char caa(ArrayParserState
*a
, const char *any
, unsigned advance
)
342 TSRMLS_FETCH_FROM_CTX(a
->ts
);
351 php_error_docref(NULL TSRMLS_CC
, E_WARNING
, "Failed to parse array: expected one of '%s', got '%c'", any
, *a
->ptr
); \
355 static STATUS
add_element(ArrayParserState
*a
, const char *start
)
358 size_t el_len
= a
->ptr
- start
;
359 char *el_str
= estrndup(start
, el_len
);
360 TSRMLS_FETCH_FROM_CTX(a
->ts
);
363 int tmp_len
= el_len
;
365 php_stripslashes(el_str
, &tmp_len TSRMLS_CC
);
367 } else if ((a
->ptr
- start
== 4) && !strncmp(start
, "NULL", 4)) {
374 MAKE_STD_ZVAL(zelem
);
377 zelem
= php_pq_typed_zval(el_str
, el_len
, a
->typ TSRMLS_CC
);
382 return zend_hash_next_index_insert(&a
->list
->ht
, &zelem
, sizeof(zval
*), NULL
);
385 static STATUS
parse_array(ArrayParserState
*a
);
387 static STATUS
parse_element(ArrayParserState
*a
)
390 TSRMLS_FETCH_FROM_CTX(a
->ts
);
394 return parse_array(a
);
402 for (el
= a
->ptr
; a
->ptr
< a
->end
; ++a
->ptr
) {
407 } else if (a
->quotes
) {
408 if (SUCCESS
!= add_element(a
, el
)) {
415 php_error_docref(NULL TSRMLS_CC
, E_WARNING
, "Failed to parse element, unexpected quote: '%.*s'", (int) (a
->ptr
- el
), el
);
423 return add_element(a
, el
);
428 a
->escaped
= !a
->escaped
;
437 php_error_docref(NULL TSRMLS_CC
, E_WARNING
, "Failed to parse element, reached end of input");
441 static STATUS
parse_elements(ArrayParserState
*a
)
443 TSRMLS_FETCH_FROM_CTX(a
->ts
);
445 while (SUCCESS
== parse_element(a
)) {
446 switch (caa(a
, ",}", 0)) {
455 php_error_docref(NULL TSRMLS_CC
, E_WARNING
, "Failed to parse elements, reached end of input");
465 static STATUS
parse_array(ArrayParserState
*a
)
469 if (!caa(a
, "{", 1)) {
473 list
= ecalloc(1, sizeof(*list
));
474 ZEND_INIT_SYMTABLE(&list
->ht
);
480 Z_TYPE_P(zcur
) = IS_ARRAY
;
481 Z_ARRVAL_P(zcur
) = &list
->ht
;
483 zend_hash_next_index_insert(&a
->list
->ht
, &zcur
, sizeof(zval
*), NULL
);
485 list
->parent
= a
->list
;
489 if (SUCCESS
!= parse_elements(a
)) {
493 if (!caa(a
, "}", 1)) {
497 if (a
->list
->parent
) {
498 a
->list
= a
->list
->parent
;
504 HashTable
*php_pq_parse_array(const char *val_str
, size_t val_len
, Oid typ TSRMLS_DC
)
506 HashTable
*ht
= NULL
;
507 ArrayParserState a
= {0};
508 TSRMLS_SET_CTX(a
.ts
);
512 a
.end
= val_str
+ val_len
;
514 if (SUCCESS
!= parse_array(&a
)) {
516 HashTableList
*l
= a
.list
->parent
;
518 zend_hash_destroy(&a
.list
->ht
);
526 php_error_docref(NULL TSRMLS_CC
, E_NOTICE
, "Trailing input: '%s'", a
.ptr
);
531 } while ((a
.list
= a
.list
->parent
));
536 zval
*php_pq_typed_zval(char *val
, size_t len
, Oid typ TSRMLS_DC
)
543 #ifdef HAVE_PHP_PQ_TYPE_H
545 # include "php_pq_type.h"
546 case PHP_PQ_OID_BOOL
:
547 ZVAL_BOOL(zv
, *val
== 't');
550 case PHP_PQ_OID_INT8
:
553 case PHP_PQ_OID_INT4
:
554 case PHP_PQ_OID_INT2
:
557 ZVAL_LONG(zv
, zend_atol(val
, len
));
560 case PHP_PQ_OID_FLOAT4
:
561 case PHP_PQ_OID_FLOAT8
:
562 ZVAL_DOUBLE(zv
, zend_strtod(val
, NULL
));
565 case PHP_PQ_OID_DATE
:
566 php_pqdt_from_string(val
, len
, "Y-m-d", zv TSRMLS_CC
);
569 case PHP_PQ_OID_ABSTIME
:
570 php_pqdt_from_string(val
, len
, "Y-m-d H:i:s", zv TSRMLS_CC
);
573 case PHP_PQ_OID_TIMESTAMP
:
574 php_pqdt_from_string(val
, len
, "Y-m-d H:i:s.u", zv TSRMLS_CC
);
577 case PHP_PQ_OID_TIMESTAMPTZ
:
578 php_pqdt_from_string(val
, len
, "Y-m-d H:i:s.uO", zv TSRMLS_CC
);
582 if (PHP_PQ_TYPE_IS_ARRAY(typ
) && (Z_ARRVAL_P(zv
) = php_pq_parse_array(val
, len
, PHP_PQ_TYPE_OF_ARRAY(typ
) TSRMLS_CC
))) {
583 Z_TYPE_P(zv
) = IS_ARRAY
;
585 ZVAL_STRINGL(zv
, val
, len
, 1);
590 ZVAL_BOOL(zv
, *val
== 't');
594 ZVAL_STRINGL(zv
, val
, len
, 1);
606 * vim600: noet sw=4 ts=4 fdm=marker
607 * vim<600: noet sw=4 ts=4