+ZEND_BEGIN_ARG_INFO_EX(ai_pqlob_construct, 0, 0, 1)
+ ZEND_ARG_OBJ_INFO(0, transaction, pq\\Transaction, 0)
+ ZEND_ARG_INFO(0, oid)
+ ZEND_ARG_INFO(0, mode)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(pqlob, __construct) {
+ zend_error_handling zeh;
+ zval *ztxn;
+ long mode = INV_WRITE|INV_READ, loid = InvalidOid;
+
+ zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|ll", &ztxn, php_pqtxn_class_entry, &loid, &mode)) {
+ php_pqtxn_object_t *txn_obj = zend_object_store_get_object(ztxn TSRMLS_CC);
+
+ if (txn_obj->intern) {
+
+ if (loid == InvalidOid) {
+ loid = lo_creat(txn_obj->intern->conn->intern->conn, mode);
+ }
+
+ if (loid != InvalidOid) {
+ int lofd = lo_open(txn_obj->intern->conn->intern->conn, loid, mode);
+
+ if (lofd >= 0) {
+ php_pqlob_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ obj->intern = ecalloc(1, sizeof(*obj->intern));
+ obj->intern->lofd = lofd;
+ obj->intern->loid = loid;
+ php_pq_object_addref(txn_obj TSRMLS_CC);
+ obj->intern->txn = txn_obj;
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to open large object with mode '%s' (%s)",
+ (mode & (INV_READ|INV_WRITE) ? "rw" :
+ (mode & INV_READ ? "r" :
+ (mode & INV_WRITE ? "w" : "-"))),
+ PHP_PQerrorMessage(txn_obj->intern->conn->intern->conn)
+ );
+ }
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to create large object with mode '%s' (%s)",
+ (mode & (INV_READ|INV_WRITE) ? "rw" :
+ (mode & INV_READ ? "r" :
+ (mode & INV_WRITE ? "w" : "-"))),
+ PHP_PQerrorMessage(txn_obj->intern->conn->intern->conn)
+ );
+ }
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Transaction not initialized");
+ }
+ }
+ zend_restore_error_handling(&zeh TSRMLS_CC);
+}
+
+ZEND_BEGIN_ARG_INFO_EX(ai_pqlob_write, 0, 0, 1)
+ ZEND_ARG_INFO(0, data)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(pqlob, write) {
+ char *data_str;
+ int data_len;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data_str, &data_len)) {
+ php_pqlob_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (obj->intern) {
+ int written = lo_write(obj->intern->txn->intern->conn->intern->conn, obj->intern->lofd, data_str, data_len);
+
+ if (written >= 0) {
+ RETVAL_LONG(written);
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to write to LOB, oid=%d (%s)", obj->intern->loid,
+ PHP_PQerrorMessage(obj->intern->txn->intern->conn->intern->conn));
+ RETVAL_FALSE;
+ }
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\LOB not initialized");
+ RETVAL_FALSE;
+ }
+ }
+}
+
+ZEND_BEGIN_ARG_INFO_EX(ai_pqlob_read, 0, 0, 0)
+ ZEND_ARG_INFO(0, length)
+ ZEND_ARG_INFO(1, read)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(pqlob, read) {
+ long length = 0x1000;
+ zval *zread = NULL;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lz!", &length, &zread)) {
+ php_pqlob_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (obj->intern) {
+ char *buffer = emalloc(length + 1);
+ int read = lo_read(obj->intern->txn->intern->conn->intern->conn, obj->intern->lofd, buffer, length);
+
+ if (read >= 0) {
+ if (zread) {
+ zval_dtor(zread);
+ ZVAL_LONG(zread, read);
+ }
+ buffer[read] = '\0';
+ RETVAL_STRINGL(buffer, read, 0);
+ } else {
+ efree(buffer);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to read from LOB, oid=%d (%s)", obj->intern->loid,
+ PHP_PQerrorMessage(obj->intern->txn->intern->conn->intern->conn));
+ RETVAL_FALSE;
+ }
+
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\LOB not initialized");
+ RETVAL_FALSE;
+ }
+ }
+}
+
+ZEND_BEGIN_ARG_INFO_EX(ai_pqlob_seek, 0, 0, 1)
+ ZEND_ARG_INFO(0, offset)
+ ZEND_ARG_INFO(0, whence)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(pqlob, seek) {
+ long offset, whence = SEEK_SET;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|l", &offset, &whence)) {
+ php_pqlob_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (obj->intern) {
+ int position = lo_lseek(obj->intern->txn->intern->conn->intern->conn, obj->intern->lofd, offset, whence);
+
+ if (position >= 0) {
+ RETVAL_LONG(position);
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to seek offset in LOB, oid=%d (%s)", obj->intern->loid,
+ PHP_PQerrorMessage(obj->intern->txn->intern->conn->intern->conn));
+ RETVAL_FALSE;
+ }
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\LOB not initialized");
+ RETVAL_FALSE;
+ }
+ }
+}
+
+ZEND_BEGIN_ARG_INFO_EX(ai_pqlob_tell, 0, 0, 0)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(pqlob, tell) {
+ if (SUCCESS == zend_parse_parameters_none()) {
+ php_pqlob_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (obj->intern) {
+ int position = lo_tell(obj->intern->txn->intern->conn->intern->conn, obj->intern->lofd);
+
+ if (position >= 0) {
+ RETVAL_LONG(position);
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to tell offset in LOB (oid=%d): %s", obj->intern->loid,
+ PHP_PQerrorMessage(obj->intern->txn->intern->conn->intern->conn));
+ RETVAL_FALSE;
+ }
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\LOB not initialized");
+ RETVAL_FALSE;
+ }
+ }
+}
+
+ZEND_BEGIN_ARG_INFO_EX(ai_pqlob_truncate, 0, 0, 0)
+ ZEND_ARG_INFO(0, length)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(pqlob, truncate) {
+ long length = 0;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &length)) {
+ php_pqlob_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (obj->intern) {
+ if (0 == lo_truncate(obj->intern->txn->intern->conn->intern->conn, obj->intern->lofd, length)) {
+ RETVAL_TRUE;
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to truncate LOB (oid=%d): %s", obj->intern->loid,
+ PHP_PQerrorMessage(obj->intern->txn->intern->conn->intern->conn));
+ RETVAL_FALSE;
+ }
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\LOB not initialized");
+ RETVAL_FALSE;
+ }
+ }
+}
+
+static zend_function_entry php_pqlob_methods[] = {
+ PHP_ME(pqlob, __construct, ai_pqlob_construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
+ PHP_ME(pqlob, write, ai_pqlob_write, ZEND_ACC_PUBLIC)
+ PHP_ME(pqlob, read, ai_pqlob_read, ZEND_ACC_PUBLIC)
+ PHP_ME(pqlob, seek, ai_pqlob_seek, ZEND_ACC_PUBLIC)
+ PHP_ME(pqlob, tell, ai_pqlob_tell, ZEND_ACC_PUBLIC)
+ PHP_ME(pqlob, truncate, ai_pqlob_truncate, ZEND_ACC_PUBLIC)
+ {0}
+};
+
+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}
+};
+