+ZEND_BEGIN_ARG_INFO_EX(ai_pqcopy_construct, 0, 0, 3)
+ ZEND_ARG_OBJ_INFO(0, "connection", pq\\Connection, 0)
+ ZEND_ARG_INFO(0, expression)
+ ZEND_ARG_INFO(0, direction)
+ ZEND_ARG_INFO(0, options)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(pqcopy, __construct) {
+ zend_error_handling zeh;
+ zval *zconn;
+ char *expr_str, *opt_str = "";
+ int expr_len, opt_len = 0;
+ long direction;
+
+ zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Osl|s", &zconn, php_pqconn_class_entry, &expr_str, &expr_len, &direction, &opt_str, &opt_len)) {
+ php_pqconn_object_t *conn_obj = zend_object_store_get_object(zconn TSRMLS_CC);
+
+ if (conn_obj->intern) {
+ char *copy = NULL;
+
+ switch (direction) {
+ case PHP_PQCOPY_FROM_STDIN:
+ spprintf(©, 0, "COPY %s %s %s", expr_str, "FROM STDIN", opt_str);
+ break;
+
+ case PHP_PQCOPY_TO_STDOUT:
+ spprintf(©, 0, "COPY %s %s %s", expr_str, "TO STDOUT", opt_str);
+ break;
+
+ default:
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid COPY direction, expected one of FROM_STDIN (%d) TO_STDOUT (%d), got %ld",
+ PHP_PQCOPY_FROM_STDIN, PHP_PQCOPY_TO_STDOUT, direction);
+ break;
+ }
+
+ if (copy) {
+ php_pqcopy_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+ PGresult *res = PQexec(conn_obj->intern->conn, copy);
+
+ efree(copy);
+
+ if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
+ obj->intern = ecalloc(1, sizeof(*obj->intern));
+ obj->intern->direction = direction;
+ obj->intern->expression = estrdup(expr_str);
+ obj->intern->options = estrdup(opt_str);
+ obj->intern->conn = conn_obj;
+ php_pq_object_addref(conn_obj TSRMLS_CC);
+ }
+
+ PHP_PQclear(res);
+ }
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
+ }
+ }
+ zend_restore_error_handling(&zeh TSRMLS_CC);
+}
+
+ZEND_BEGIN_ARG_INFO_EX(ai_pqcopy_put, 0, 0, 1)
+ ZEND_ARG_INFO(0, data)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(pqcopy, put) {
+ zend_error_handling zeh;
+ char *data_str;
+ int data_len;
+
+ zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data_str, &data_len)) {
+ php_pqcopy_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (obj->intern) {
+ if (PHP_PQCOPY_FROM_STDIN == obj->intern->direction) {
+ if (1 == PQputCopyData(obj->intern->conn->intern->conn, data_str, data_len)) {
+ RETVAL_TRUE;
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to send COPY data (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn));
+ }
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\COPY was not initialized with FROM_STDIN");
+ }
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\COPY not initialized");
+ }
+ }
+ zend_restore_error_handling(&zeh TSRMLS_CC);
+}
+
+ZEND_BEGIN_ARG_INFO_EX(ai_pqcopy_end, 0, 0, 0)
+ ZEND_ARG_INFO(0, error)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(pqcopy, end) {
+ zend_error_handling zeh;
+ char *error_str = NULL;
+ int error_len = 0;
+
+ zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!", &error_str, &error_len)) {
+ php_pqcopy_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (obj->intern) {
+ if (PHP_PQCOPY_FROM_STDIN == obj->intern->direction) {
+ if (1 == PQputCopyEnd(obj->intern->conn->intern->conn, error_str)) {
+ PGresult *res = PQgetResult(obj->intern->conn->intern->conn);
+
+ if (res) {
+ if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
+ RETVAL_TRUE;
+ }
+
+ PHP_PQclear(res);
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to get COPY result (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn));
+ }
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to end COPY (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn));
+ }
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\COPY was not initialized with FROM_STDIN");
+ }
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\COPY not initialized");
+ }
+ }
+ zend_restore_error_handling(&zeh TSRMLS_CC);
+}
+
+ZEND_BEGIN_ARG_INFO_EX(ai_pqcopy_get, 0, 0, 1)
+ ZEND_ARG_INFO(1, data)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(pqcopy, get) {
+ zend_error_handling zeh;
+ zval *zdata;
+
+ zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zdata)) {
+ php_pqcopy_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+ char *buffer = NULL;
+
+ if (obj->intern) {
+ if (PHP_PQCOPY_TO_STDOUT == obj->intern->direction) {
+ PGresult *res;
+ int bytes = PQgetCopyData(obj->intern->conn->intern->conn, &buffer, 0);
+
+ switch (bytes) {
+ case -1:
+ res = PQgetResult(obj->intern->conn->intern->conn);
+
+ if (res) {
+ if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
+ RETVAL_FALSE;
+ }
+
+ PHP_PQclear(res);
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to get COPY result (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn));
+ }
+ break;
+
+ case -2:
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to get COPY data (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn));
+ break;
+
+ default:
+ zval_dtor(zdata);
+ if (buffer) {
+ ZVAL_STRINGL(zdata, buffer, bytes, 1);
+ } else {
+ ZVAL_EMPTY_STRING(zdata);
+ }
+ RETVAL_TRUE;
+ break;
+ }
+
+ if (buffer) {
+ PQfreemem(buffer);
+ }
+ }
+ }
+ }
+ zend_restore_error_handling(&zeh TSRMLS_CC);
+}
+
+static zend_function_entry php_pqcopy_methods[] = {
+ PHP_ME(pqcopy, __construct, ai_pqcopy_construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
+ PHP_ME(pqcopy, put, ai_pqcopy_put, ZEND_ACC_PUBLIC)
+ PHP_ME(pqcopy, end, ai_pqcopy_end, ZEND_ACC_PUBLIC)
+ PHP_ME(pqcopy, get, ai_pqcopy_get, ZEND_ACC_PUBLIC)
+ {0}
+};
+