ext/pgsql: adding pg_put_copy_data/pg_put_copy_end.

pg_put_copy_data allows to send COPY commands to the server.
pg_put_copy_end signals the end of the n commands.

Both return 3 states ; 1, 0 and -1 when 1 is success, 0 the buffer queue
is full then -1 for errors.

Close GH-14325
This commit is contained in:
David Carlier 2024-05-25 16:58:06 +01:00
parent cc6d9523d9
commit 162a311cc8
No known key found for this signature in database
GPG key ID: CEF290BB40D2086B
6 changed files with 153 additions and 1 deletions

2
NEWS
View file

@ -195,6 +195,8 @@ PHP NEWS
. Added pg_result_memory_size to get the query result memory usage.
(KentarouTakeda)
. Added pg_change_password to alter an user's password. (David Carlier)
. Added pg_put_copy_data/pg_put_copy_end to send COPY commands and signal
the end of the COPY. (David Carlier)
- Phar:
. Fixed bug GH-12532 (PharData created from zip has incorrect timestamp).

View file

@ -541,6 +541,8 @@ PHP 8.4 UPGRADE NOTES
- PGSQL:
. Added pg_change_password to alter a given user's password. It handles
transparently the password encryption from the database settings.
. Added pg_put_copy_data to send COPY commands and pg_put_copy_end to send
end-of-data to the server.
- Sodium:
. Added the sodium_crypto_aead_aegis128l_*() and sodium_crypto_aead_aegis256l_*()

View file

@ -6123,3 +6123,45 @@ PHP_FUNCTION(pg_change_password)
}
#endif
PHP_FUNCTION(pg_put_copy_data)
{
zval *pgsql_link;
pgsql_link_handle *link;
zend_string *cmd;
ZEND_PARSE_PARAMETERS_START(2, 2)
Z_PARAM_OBJECT_OF_CLASS(pgsql_link, pgsql_link_ce)
Z_PARAM_STR(cmd)
ZEND_PARSE_PARAMETERS_END();
link = Z_PGSQL_LINK_P(pgsql_link);
CHECK_PGSQL_LINK(link);
// PQputCopyData accepts empty buffers as well
RETURN_LONG((zend_long)PQputCopyData(link->conn, ZSTR_VAL(cmd), ZSTR_LEN(cmd)));
}
PHP_FUNCTION(pg_put_copy_end)
{
zval *pgsql_link;
pgsql_link_handle *link;
zend_string *error;
char *err = NULL;
ZEND_PARSE_PARAMETERS_START(1, 2)
Z_PARAM_OBJECT_OF_CLASS(pgsql_link, pgsql_link_ce)
Z_PARAM_OPTIONAL
Z_PARAM_STR_OR_NULL(error)
ZEND_PARSE_PARAMETERS_END();
link = Z_PGSQL_LINK_P(pgsql_link);
CHECK_PGSQL_LINK(link);
if (error != NULL && ZSTR_LEN(error) != 0) {
err = ZSTR_VAL(error);
}
RETURN_LONG((zend_long)PQputCopyEnd(link->conn, err));
}

View file

@ -949,6 +949,9 @@ namespace {
#endif
function pg_change_password(PgSql\Connection $connection, string $user, #[\SensitiveParameter] string $password): bool {}
function pg_put_copy_data(PgSql\Connection $connection, string $cmd): int {}
function pg_put_copy_end(PgSql\Connection $connection, string $error = null): int {}
}
namespace PgSql {

View file

@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: c5cb23b6536c1908d3dcc804f5fa176323f4db07 */
* Stub hash: b3645285a405c83fec3ae55195ed577cec5f5356 */
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_pg_connect, 0, 1, PgSql\\Connection, MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, connection_string, IS_STRING, 0)
@ -471,6 +471,16 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_pg_change_password, 0, 3, _IS_BO
ZEND_ARG_TYPE_INFO(0, password, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_pg_put_copy_data, 0, 2, IS_LONG, 0)
ZEND_ARG_OBJ_INFO(0, connection, PgSql\\Connection, 0)
ZEND_ARG_TYPE_INFO(0, cmd, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_pg_put_copy_end, 0, 1, IS_LONG, 0)
ZEND_ARG_OBJ_INFO(0, connection, PgSql\\Connection, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, error, IS_STRING, 0, "null")
ZEND_END_ARG_INFO()
ZEND_FUNCTION(pg_connect);
ZEND_FUNCTION(pg_pconnect);
ZEND_FUNCTION(pg_connect_poll);
@ -569,6 +579,8 @@ ZEND_FUNCTION(pg_set_error_context_visibility);
ZEND_FUNCTION(pg_result_memory_size);
#endif
ZEND_FUNCTION(pg_change_password);
ZEND_FUNCTION(pg_put_copy_data);
ZEND_FUNCTION(pg_put_copy_end);
static const zend_function_entry ext_functions[] = {
ZEND_FE(pg_connect, arginfo_pg_connect)
@ -692,6 +704,8 @@ static const zend_function_entry ext_functions[] = {
ZEND_FE(pg_result_memory_size, arginfo_pg_result_memory_size)
#endif
ZEND_FE(pg_change_password, arginfo_pg_change_password)
ZEND_FE(pg_put_copy_data, arginfo_pg_put_copy_data)
ZEND_FE(pg_put_copy_end, arginfo_pg_put_copy_end)
ZEND_FE_END
};

View file

@ -0,0 +1,89 @@
--TEST--
PostgreSQL pg_put_copy_data/pg_end_copy_end
--EXTENSIONS--
pgsql
--SKIPIF--
<?php include("inc/skipif.inc"); ?>
--FILE--
<?php
include('inc/config.inc');
$db = pg_connect($conn_str);
pg_query($db, "CREATE TABLE copystdin(id int, val text)");
pg_query($db, "COPY copystdin(id, val) FROM STDIN");
var_dump(pg_put_copy_data($db, "0\tFooBar\n"));
var_dump(pg_put_copy_data($db, "1\tBarFoo\n"));
var_dump(pg_put_copy_data($db, ""));
var_dump(pg_put_copy_end($db));
var_dump(pg_get_result($db));
var_dump(pg_fetch_all(pg_query($db, "SELECT * FROM copystdin ORDER BY id")));
var_dump(pg_put_copy_data($db, "Error\t1"));
var_dump(pg_put_copy_end($db));
var_dump(pg_last_error($db));
pg_query($db, "COPY copystdin(id, val) FROM STDIN");
var_dump(pg_put_copy_data($db, "Error\t1"));
var_dump(pg_put_copy_end($db));
var_dump(pg_get_result($db));
var_dump(pg_fetch_all(pg_query($db, "SELECT * FROM copystdin ORDER BY id")));
?>
--CLEAN--
<?php
include('inc/config.inc');
$db = pg_connect($conn_str);
pg_query($db, "DROP TABLE IF EXISTS copystdin");
?>
--EXPECT--
int(1)
int(1)
int(1)
int(1)
object(PgSql\Result)#2 (0) {
}
array(2) {
[0]=>
array(2) {
["id"]=>
string(1) "0"
["val"]=>
string(6) "FooBar"
}
[1]=>
array(2) {
["id"]=>
string(1) "1"
["val"]=>
string(6) "BarFoo"
}
}
int(-1)
int(-1)
string(39) "no COPY in progress
no COPY in progress"
int(1)
int(1)
object(PgSql\Result)#2 (0) {
}
array(2) {
[0]=>
array(2) {
["id"]=>
string(1) "0"
["val"]=>
string(6) "FooBar"
}
[1]=>
array(2) {
["id"]=>
string(1) "1"
["val"]=>
string(6) "BarFoo"
}
}