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 <Zend/zend_smart_str.h>
20 #include <libpq-events.h>
23 #include "php_pq_misc.h"
24 #include "php_pq_object.h"
25 #include "php_pqexc.h"
26 #include "php_pqres.h"
27 #include "php_pqconn.h"
28 #include "php_pqcopy.h"
30 zend_class_entry
*php_pqcopy_class_entry
;
31 static zend_object_handlers php_pqcopy_object_handlers
;
32 static HashTable php_pqcopy_object_prophandlers
;
34 static void php_pqcopy_object_free(zend_object
*o
)
36 php_pqcopy_object_t
*obj
= PHP_PQ_OBJ(NULL
, o
);
38 fprintf(stderr
, "FREE copy(#%d) %p (conn(#%d): %p)\n", obj
->zv
.handle
, obj
, obj
->intern
->conn
->zv
.handle
, obj
->intern
->conn
);
41 efree(obj
->intern
->expression
);
42 efree(obj
->intern
->options
);
43 php_pq_object_delref(obj
->intern
->conn
);
47 zend_object_std_dtor(o
);
51 php_pqcopy_object_t
*php_pqcopy_create_object_ex(zend_class_entry
*ce
, php_pqcopy_t
*intern
)
53 php_pqcopy_object_t
*o
;
55 o
= ecalloc(1, sizeof(*o
) + zend_object_properties_size(ce
));
56 zend_object_std_init(&o
->zo
, ce
);
57 object_properties_init(&o
->zo
, ce
);
58 o
->prophandler
= &php_pqcopy_object_prophandlers
;
64 o
->zo
.handlers
= &php_pqcopy_object_handlers
;
69 static zend_object
*php_pqcopy_create_object(zend_class_entry
*class_type
)
71 return &php_pqcopy_create_object_ex(class_type
, NULL
)->zo
;
74 static void php_pqcopy_object_read_connection(zval
*object
, void *o
, zval
*return_value
)
76 php_pqcopy_object_t
*obj
= o
;
78 php_pq_object_to_zval(obj
->intern
->conn
, return_value
);
81 static void php_pqcopy_object_read_direction(zval
*object
, void *o
, zval
*return_value
)
83 php_pqcopy_object_t
*obj
= o
;
85 RETVAL_LONG(obj
->intern
->direction
);
88 static void php_pqcopy_object_read_expression(zval
*object
, void *o
, zval
*return_value
)
90 php_pqcopy_object_t
*obj
= o
;
92 RETURN_STRING(obj
->intern
->expression
);
95 static void php_pqcopy_object_read_options(zval
*object
, void *o
, zval
*return_value
)
97 php_pqcopy_object_t
*obj
= o
;
99 RETURN_STRING(obj
->intern
->options
);
102 ZEND_BEGIN_ARG_INFO_EX(ai_pqcopy_construct
, 0, 0, 3)
103 ZEND_ARG_OBJ_INFO(0, connection
, pq
\\Connection
, 0)
104 ZEND_ARG_INFO(0, expression
)
105 ZEND_ARG_INFO(0, direction
)
106 ZEND_ARG_INFO(0, options
)
108 static PHP_METHOD(pqcopy
, __construct
) {
109 zend_error_handling zeh
;
111 char *expr_str
, *opt_str
= "";
112 size_t expr_len
, opt_len
= 0;
116 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
117 rv
= zend_parse_parameters(ZEND_NUM_ARGS(), "Osl|s", &zconn
, php_pqconn_class_entry
, &expr_str
, &expr_len
, &direction
, &opt_str
, &opt_len
);
118 zend_restore_error_handling(&zeh
);
121 php_pqconn_object_t
*conn_obj
= PHP_PQ_OBJ(zconn
, NULL
);
123 if (!conn_obj
->intern
) {
124 throw_exce(EX_UNINITIALIZED
, "pq\\Connection not initialized");
126 php_pqcopy_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
130 smart_str_appends(&cmd
, "COPY ");
131 smart_str_appendl(&cmd
, expr_str
, expr_len
);
134 case PHP_PQCOPY_FROM_STDIN
:
135 smart_str_appends(&cmd
, " FROM STDIN ");
137 case PHP_PQCOPY_TO_STDOUT
:
138 smart_str_appends(&cmd
, " TO STDOUT ");
141 throw_exce(EX_RUNTIME
, "Invalid COPY direction, expected one of FROM_STDIN (%d) TO_STDOUT (%d), got %ld", PHP_PQCOPY_FROM_STDIN
, PHP_PQCOPY_TO_STDOUT
, direction
);
142 smart_str_free(&cmd
);
145 smart_str_appendl(&cmd
, opt_str
, opt_len
);
148 res
= PQexec(conn_obj
->intern
->conn
, smart_str_v(&cmd
));
151 throw_exce(EX_RUNTIME
, "Failed to start %s (%s)", smart_str_v(&cmd
), PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
153 if (SUCCESS
== php_pqres_success(res
)) {
154 obj
->intern
= ecalloc(1, sizeof(*obj
->intern
));
155 obj
->intern
->direction
= direction
;
156 obj
->intern
->expression
= estrdup(expr_str
);
157 obj
->intern
->options
= estrdup(opt_str
);
158 obj
->intern
->conn
= conn_obj
;
159 php_pq_object_addref(conn_obj
);
165 smart_str_free(&cmd
);
166 php_pqconn_notify_listeners(obj
->intern
->conn
);
171 ZEND_BEGIN_ARG_INFO_EX(ai_pqcopy_put
, 0, 0, 1)
172 ZEND_ARG_INFO(0, data
)
174 static PHP_METHOD(pqcopy
, put
) {
175 zend_error_handling zeh
;
180 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
181 rv
= zend_parse_parameters(ZEND_NUM_ARGS(), "s", &data_str
, &data_len
);
182 zend_restore_error_handling(&zeh
);
185 php_pqcopy_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
188 throw_exce(EX_UNINITIALIZED
, "pq\\COPY not initialized");
189 } else if (obj
->intern
->direction
!= PHP_PQCOPY_FROM_STDIN
) {
190 throw_exce(EX_BAD_METHODCALL
, "pq\\COPY was not initialized with FROM_STDIN");
192 if (1 != PQputCopyData(obj
->intern
->conn
->intern
->conn
, data_str
, data_len
)) {
193 throw_exce(EX_RUNTIME
, "Failed to put COPY data (%s)", PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
195 php_pqconn_notify_listeners(obj
->intern
->conn
);
200 ZEND_BEGIN_ARG_INFO_EX(ai_pqcopy_end
, 0, 0, 0)
201 ZEND_ARG_INFO(0, error
)
203 static PHP_METHOD(pqcopy
, end
) {
204 zend_error_handling zeh
;
205 char *error_str
= NULL
;
206 size_t error_len
= 0;
209 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
210 rv
= zend_parse_parameters(ZEND_NUM_ARGS(), "|s!", &error_str
, &error_len
);
211 zend_restore_error_handling(&zeh
);
214 php_pqcopy_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
217 throw_exce(EX_UNINITIALIZED
, "pq\\COPY not intitialized");
218 } else if (obj
->intern
->direction
!= PHP_PQCOPY_FROM_STDIN
) {
219 throw_exce(EX_BAD_METHODCALL
, "pq\\COPY was not intitialized with FROM_STDIN");
221 if (1 != PQputCopyEnd(obj
->intern
->conn
->intern
->conn
, error_str
)) {
222 throw_exce(EX_RUNTIME
, "Failed to end COPY (%s)", PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
224 PGresult
*res
= PQgetResult(obj
->intern
->conn
->intern
->conn
);
227 throw_exce(EX_RUNTIME
, "Failed to fetch COPY result (%s)", PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
229 php_pqres_success(res
);
234 php_pqconn_notify_listeners(obj
->intern
->conn
);
239 ZEND_BEGIN_ARG_INFO_EX(ai_pqcopy_get
, 0, 0, 1)
240 ZEND_ARG_INFO(1, data
)
242 static PHP_METHOD(pqcopy
, get
) {
243 zend_error_handling zeh
;
247 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh
);
248 rv
= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "z", &zdata
);
249 zend_restore_error_handling(&zeh
);
252 php_pqcopy_object_t
*obj
= PHP_PQ_OBJ(getThis(), NULL
);
255 throw_exce(EX_UNINITIALIZED
, "pq\\COPY not initialized");
256 } else if (obj
->intern
->direction
!= PHP_PQCOPY_TO_STDOUT
) {
257 throw_exce(EX_RUNTIME
, "pq\\COPY was not intialized with TO_STDOUT");
261 int bytes
= PQgetCopyData(obj
->intern
->conn
->intern
->conn
, &buffer
, 0);
265 throw_exce(EX_RUNTIME
, "Failed to fetch COPY data (%s)", PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
269 res
= PQgetResult(obj
->intern
->conn
->intern
->conn
);
272 throw_exce(EX_RUNTIME
, "Failed to fetch COPY result (%s)", PHP_PQerrorMessage(obj
->intern
->conn
->intern
->conn
));
274 php_pqres_success(res
);
284 ZVAL_STRINGL(zdata
, buffer
, bytes
);
286 ZVAL_EMPTY_STRING(zdata
);
299 static zend_function_entry php_pqcopy_methods
[] = {
300 PHP_ME(pqcopy
, __construct
, ai_pqcopy_construct
, ZEND_ACC_PUBLIC
|ZEND_ACC_CTOR
)
301 PHP_ME(pqcopy
, put
, ai_pqcopy_put
, ZEND_ACC_PUBLIC
)
302 PHP_ME(pqcopy
, end
, ai_pqcopy_end
, ZEND_ACC_PUBLIC
)
303 PHP_ME(pqcopy
, get
, ai_pqcopy_get
, ZEND_ACC_PUBLIC
)
307 PHP_MSHUTDOWN_FUNCTION(pqcopy
)
309 zend_hash_destroy(&php_pqcopy_object_prophandlers
);
313 PHP_MINIT_FUNCTION(pqcopy
)
315 zend_class_entry ce
= {0};
316 php_pq_object_prophandler_t ph
= {0};
318 INIT_NS_CLASS_ENTRY(ce
, "pq", "COPY", php_pqcopy_methods
);
319 php_pqcopy_class_entry
= zend_register_internal_class_ex(&ce
, NULL
);
320 php_pqcopy_class_entry
->create_object
= php_pqcopy_create_object
;
322 memcpy(&php_pqcopy_object_handlers
, zend_get_std_object_handlers(), sizeof(zend_object_handlers
));
323 php_pqcopy_object_handlers
.offset
= XtOffsetOf(php_pqcopy_object_t
, zo
);
324 php_pqcopy_object_handlers
.free_obj
= php_pqcopy_object_free
;
325 php_pqcopy_object_handlers
.read_property
= php_pq_object_read_prop
;
326 php_pqcopy_object_handlers
.write_property
= php_pq_object_write_prop
;
327 php_pqcopy_object_handlers
.clone_obj
= NULL
;
328 php_pqcopy_object_handlers
.get_property_ptr_ptr
= NULL
;
329 php_pqcopy_object_handlers
.get_gc
= NULL
;
330 php_pqcopy_object_handlers
.get_properties
= php_pq_object_properties
;
331 php_pqcopy_object_handlers
.get_debug_info
= php_pq_object_debug_info
;
333 zend_hash_init(&php_pqcopy_object_prophandlers
, 4, NULL
, NULL
, 1);
335 zend_declare_property_null(php_pqcopy_class_entry
, ZEND_STRL("connection"), ZEND_ACC_PUBLIC
);
336 ph
.read
= php_pqcopy_object_read_connection
;
337 zend_hash_str_add_mem(&php_pqcopy_object_prophandlers
, "connection", sizeof("connection")-1, (void *) &ph
, sizeof(ph
));
339 zend_declare_property_null(php_pqcopy_class_entry
, ZEND_STRL("expression"), ZEND_ACC_PUBLIC
);
340 ph
.read
= php_pqcopy_object_read_expression
;
341 zend_hash_str_add_mem(&php_pqcopy_object_prophandlers
, "expression", sizeof("expression")-1, (void *) &ph
, sizeof(ph
));
343 zend_declare_property_null(php_pqcopy_class_entry
, ZEND_STRL("direction"), ZEND_ACC_PUBLIC
);
344 ph
.read
= php_pqcopy_object_read_direction
;
345 zend_hash_str_add_mem(&php_pqcopy_object_prophandlers
, "direction", sizeof("direction")-1, (void *) &ph
, sizeof(ph
));
347 zend_declare_property_null(php_pqcopy_class_entry
, ZEND_STRL("options"), ZEND_ACC_PUBLIC
);
348 ph
.read
= php_pqcopy_object_read_options
;
349 zend_hash_str_add_mem(&php_pqcopy_object_prophandlers
, "options", sizeof("options")-1, (void *) &ph
, sizeof(ph
));
351 zend_declare_class_constant_long(php_pqcopy_class_entry
, ZEND_STRL("FROM_STDIN"), PHP_PQCOPY_FROM_STDIN
);
352 zend_declare_class_constant_long(php_pqcopy_class_entry
, ZEND_STRL("TO_STDOUT"), PHP_PQCOPY_TO_STDOUT
);
361 * vim600: noet sw=4 ts=4 fdm=marker
362 * vim<600: noet sw=4 ts=4