mirror of https://github.com/citusdata/citus.git
Merge pull request #770 from citusdata/fix/insert_query_inside_plpgsql
Pass text oid instead of invalid oid for null valuespull/812/head
commit
1a04cd123d
|
@ -25,6 +25,7 @@
|
||||||
#include "access/transam.h"
|
#include "access/transam.h"
|
||||||
#include "access/tupdesc.h"
|
#include "access/tupdesc.h"
|
||||||
#include "access/xact.h"
|
#include "access/xact.h"
|
||||||
|
#include "catalog/pg_type.h"
|
||||||
#include "distributed/citus_clauses.h"
|
#include "distributed/citus_clauses.h"
|
||||||
#include "distributed/citus_ruleutils.h"
|
#include "distributed/citus_ruleutils.h"
|
||||||
#include "distributed/connection_cache.h"
|
#include "distributed/connection_cache.h"
|
||||||
|
@ -840,11 +841,14 @@ ExtractParametersFromParamListInfo(ParamListInfo paramListInfo, Oid **parameterT
|
||||||
/*
|
/*
|
||||||
* If the parameter is NULL, or is not referenced / used (ptype == 0
|
* If the parameter is NULL, or is not referenced / used (ptype == 0
|
||||||
* would otherwise have errored out inside standard_planner()),
|
* would otherwise have errored out inside standard_planner()),
|
||||||
* don't pass a value to the remote side.
|
* don't pass a value to the remote side, and pass text oid to prevent
|
||||||
|
* undetermined data type errors on workers.
|
||||||
*/
|
*/
|
||||||
if (parameterData->isnull || parameterData->ptype == 0)
|
if (parameterData->isnull || parameterData->ptype == 0)
|
||||||
{
|
{
|
||||||
(*parameterValues)[parameterIndex] = NULL;
|
(*parameterValues)[parameterIndex] = NULL;
|
||||||
|
(*parameterTypes)[parameterIndex] = TEXTOID;
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -350,6 +350,272 @@ SELECT plpgsql_test_2();
|
||||||
-- FIXME: temporarily disabled, waiting for proper parametrized query support
|
-- FIXME: temporarily disabled, waiting for proper parametrized query support
|
||||||
-- SELECT plpgsql_test_6(155);
|
-- SELECT plpgsql_test_6(155);
|
||||||
-- SELECT plpgsql_test_6(1555);
|
-- SELECT plpgsql_test_6(1555);
|
||||||
|
-- test router executor parameterized PL/pgsql functions
|
||||||
|
CREATE TABLE temp_table (
|
||||||
|
key int,
|
||||||
|
value int
|
||||||
|
);
|
||||||
|
SELECT master_create_distributed_table('temp_table','key','hash');
|
||||||
|
master_create_distributed_table
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT master_create_worker_shards('temp_table',4,1);
|
||||||
|
master_create_worker_shards
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION no_parameter_insert() RETURNS void as $$
|
||||||
|
BEGIN
|
||||||
|
INSERT INTO temp_table (key) VALUES (0);
|
||||||
|
END;
|
||||||
|
$$ LANGUAGE plpgsql;
|
||||||
|
-- execute 6 times to trigger prepared statement usage
|
||||||
|
SELECT no_parameter_insert();
|
||||||
|
no_parameter_insert
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT no_parameter_insert();
|
||||||
|
no_parameter_insert
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT no_parameter_insert();
|
||||||
|
no_parameter_insert
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT no_parameter_insert();
|
||||||
|
no_parameter_insert
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT no_parameter_insert();
|
||||||
|
no_parameter_insert
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT no_parameter_insert();
|
||||||
|
no_parameter_insert
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION single_parameter_insert(key_arg int) RETURNS void as $$
|
||||||
|
BEGIN
|
||||||
|
INSERT INTO temp_table (key) VALUES (key_arg);
|
||||||
|
END;
|
||||||
|
$$ LANGUAGE plpgsql;
|
||||||
|
-- execute 6 times to trigger prepared statement usage
|
||||||
|
SELECT single_parameter_insert(1);
|
||||||
|
single_parameter_insert
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT single_parameter_insert(2);
|
||||||
|
single_parameter_insert
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT single_parameter_insert(3);
|
||||||
|
single_parameter_insert
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT single_parameter_insert(4);
|
||||||
|
single_parameter_insert
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT single_parameter_insert(5);
|
||||||
|
single_parameter_insert
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT single_parameter_insert(6);
|
||||||
|
ERROR: values given for the partition column must be constants or constant expressions
|
||||||
|
CONTEXT: SQL statement "INSERT INTO temp_table (key) VALUES (key_arg)"
|
||||||
|
PL/pgSQL function single_parameter_insert(integer) line 3 at SQL statement
|
||||||
|
CREATE OR REPLACE FUNCTION double_parameter_insert(key_arg int, value_arg int) RETURNS void as $$
|
||||||
|
BEGIN
|
||||||
|
INSERT INTO temp_table (key, value) VALUES (key_arg, value_arg);
|
||||||
|
END;
|
||||||
|
$$ LANGUAGE plpgsql;
|
||||||
|
-- execute 6 times to trigger prepared statement usage
|
||||||
|
SELECT double_parameter_insert(1, 10);
|
||||||
|
double_parameter_insert
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT double_parameter_insert(2, 20);
|
||||||
|
double_parameter_insert
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT double_parameter_insert(3, 30);
|
||||||
|
double_parameter_insert
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT double_parameter_insert(4, 40);
|
||||||
|
double_parameter_insert
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT double_parameter_insert(5, 50);
|
||||||
|
double_parameter_insert
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT double_parameter_insert(6, 60);
|
||||||
|
ERROR: values given for the partition column must be constants or constant expressions
|
||||||
|
CONTEXT: SQL statement "INSERT INTO temp_table (key, value) VALUES (key_arg, value_arg)"
|
||||||
|
PL/pgSQL function double_parameter_insert(integer,integer) line 3 at SQL statement
|
||||||
|
-- check inserted values
|
||||||
|
SELECT * FROM temp_table ORDER BY key, value;
|
||||||
|
key | value
|
||||||
|
-----+-------
|
||||||
|
0 |
|
||||||
|
0 |
|
||||||
|
0 |
|
||||||
|
0 |
|
||||||
|
0 |
|
||||||
|
0 |
|
||||||
|
1 | 10
|
||||||
|
1 |
|
||||||
|
2 | 20
|
||||||
|
2 |
|
||||||
|
3 | 30
|
||||||
|
3 |
|
||||||
|
4 | 40
|
||||||
|
4 |
|
||||||
|
5 | 50
|
||||||
|
5 |
|
||||||
|
(16 rows)
|
||||||
|
|
||||||
|
-- check router executor select
|
||||||
|
CREATE OR REPLACE FUNCTION partition_column_select(key_arg int) RETURNS TABLE(key int, value int) AS $$
|
||||||
|
DECLARE
|
||||||
|
BEGIN
|
||||||
|
RETURN QUERY
|
||||||
|
SELECT
|
||||||
|
temp_table.key,
|
||||||
|
temp_table.value
|
||||||
|
FROM
|
||||||
|
temp_table
|
||||||
|
WHERE
|
||||||
|
temp_table.key = key_arg
|
||||||
|
ORDER BY
|
||||||
|
key,
|
||||||
|
value;
|
||||||
|
END;
|
||||||
|
$$ LANGUAGE plpgsql;
|
||||||
|
SELECT partition_column_select(1);
|
||||||
|
partition_column_select
|
||||||
|
-------------------------
|
||||||
|
(1,10)
|
||||||
|
(1,)
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
SELECT partition_column_select(2);
|
||||||
|
partition_column_select
|
||||||
|
-------------------------
|
||||||
|
(2,20)
|
||||||
|
(2,)
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
SELECT partition_column_select(3);
|
||||||
|
partition_column_select
|
||||||
|
-------------------------
|
||||||
|
(3,30)
|
||||||
|
(3,)
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
SELECT partition_column_select(4);
|
||||||
|
partition_column_select
|
||||||
|
-------------------------
|
||||||
|
(4,40)
|
||||||
|
(4,)
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
SELECT partition_column_select(5);
|
||||||
|
partition_column_select
|
||||||
|
-------------------------
|
||||||
|
(5,50)
|
||||||
|
(5,)
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
-- 6th execution is failing. We don't want to run the failing test because of
|
||||||
|
-- changing output. After implementing this feature, uncomment this.
|
||||||
|
-- SELECT partition_column_select(6);
|
||||||
|
-- check real-time executor
|
||||||
|
CREATE OR REPLACE FUNCTION non_partition_column_select(value_arg int) RETURNS TABLE(key int, value int) AS $$
|
||||||
|
DECLARE
|
||||||
|
BEGIN
|
||||||
|
RETURN QUERY
|
||||||
|
SELECT
|
||||||
|
temp_table.key,
|
||||||
|
temp_table.value
|
||||||
|
FROM
|
||||||
|
temp_table
|
||||||
|
WHERE
|
||||||
|
temp_table.value = value_arg
|
||||||
|
ORDER BY
|
||||||
|
key,
|
||||||
|
value;
|
||||||
|
END;
|
||||||
|
$$ LANGUAGE plpgsql;
|
||||||
|
SELECT non_partition_column_select(10);
|
||||||
|
non_partition_column_select
|
||||||
|
-----------------------------
|
||||||
|
(1,10)
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT non_partition_column_select(20);
|
||||||
|
non_partition_column_select
|
||||||
|
-----------------------------
|
||||||
|
(2,20)
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT non_partition_column_select(30);
|
||||||
|
non_partition_column_select
|
||||||
|
-----------------------------
|
||||||
|
(3,30)
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT non_partition_column_select(40);
|
||||||
|
non_partition_column_select
|
||||||
|
-----------------------------
|
||||||
|
(4,40)
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT non_partition_column_select(50);
|
||||||
|
non_partition_column_select
|
||||||
|
-----------------------------
|
||||||
|
(5,50)
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- 6th execution is failing. We don't want to run the failing test because of
|
||||||
|
-- changing output. After implementing this feature, uncomment this.
|
||||||
|
-- SELECT partition_column_select(6);
|
||||||
-- clean-up functions
|
-- clean-up functions
|
||||||
DROP FUNCTION sql_test_no_1();
|
DROP FUNCTION sql_test_no_1();
|
||||||
DROP FUNCTION sql_test_no_2();
|
DROP FUNCTION sql_test_no_2();
|
||||||
|
@ -363,3 +629,8 @@ DROP FUNCTION plpgsql_test_4();
|
||||||
DROP FUNCTION plpgsql_test_5();
|
DROP FUNCTION plpgsql_test_5();
|
||||||
DROP FUNCTION plpgsql_test_6(int);
|
DROP FUNCTION plpgsql_test_6(int);
|
||||||
DROP FUNCTION plpgsql_test_7(text, text);
|
DROP FUNCTION plpgsql_test_7(text, text);
|
||||||
|
DROP FUNCTION no_parameter_insert();
|
||||||
|
DROP FUNCTION single_parameter_insert(int);
|
||||||
|
DROP FUNCTION double_parameter_insert(int, int);
|
||||||
|
DROP FUNCTION partition_column_select(int);
|
||||||
|
DROP FUNCTION non_partition_column_select(int);
|
||||||
|
|
|
@ -247,6 +247,115 @@ SELECT plpgsql_test_2();
|
||||||
-- SELECT plpgsql_test_6(155);
|
-- SELECT plpgsql_test_6(155);
|
||||||
-- SELECT plpgsql_test_6(1555);
|
-- SELECT plpgsql_test_6(1555);
|
||||||
|
|
||||||
|
-- test router executor parameterized PL/pgsql functions
|
||||||
|
CREATE TABLE temp_table (
|
||||||
|
key int,
|
||||||
|
value int
|
||||||
|
);
|
||||||
|
SELECT master_create_distributed_table('temp_table','key','hash');
|
||||||
|
SELECT master_create_worker_shards('temp_table',4,1);
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION no_parameter_insert() RETURNS void as $$
|
||||||
|
BEGIN
|
||||||
|
INSERT INTO temp_table (key) VALUES (0);
|
||||||
|
END;
|
||||||
|
$$ LANGUAGE plpgsql;
|
||||||
|
|
||||||
|
-- execute 6 times to trigger prepared statement usage
|
||||||
|
SELECT no_parameter_insert();
|
||||||
|
SELECT no_parameter_insert();
|
||||||
|
SELECT no_parameter_insert();
|
||||||
|
SELECT no_parameter_insert();
|
||||||
|
SELECT no_parameter_insert();
|
||||||
|
SELECT no_parameter_insert();
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION single_parameter_insert(key_arg int) RETURNS void as $$
|
||||||
|
BEGIN
|
||||||
|
INSERT INTO temp_table (key) VALUES (key_arg);
|
||||||
|
END;
|
||||||
|
$$ LANGUAGE plpgsql;
|
||||||
|
|
||||||
|
-- execute 6 times to trigger prepared statement usage
|
||||||
|
SELECT single_parameter_insert(1);
|
||||||
|
SELECT single_parameter_insert(2);
|
||||||
|
SELECT single_parameter_insert(3);
|
||||||
|
SELECT single_parameter_insert(4);
|
||||||
|
SELECT single_parameter_insert(5);
|
||||||
|
SELECT single_parameter_insert(6);
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION double_parameter_insert(key_arg int, value_arg int) RETURNS void as $$
|
||||||
|
BEGIN
|
||||||
|
INSERT INTO temp_table (key, value) VALUES (key_arg, value_arg);
|
||||||
|
END;
|
||||||
|
$$ LANGUAGE plpgsql;
|
||||||
|
|
||||||
|
-- execute 6 times to trigger prepared statement usage
|
||||||
|
SELECT double_parameter_insert(1, 10);
|
||||||
|
SELECT double_parameter_insert(2, 20);
|
||||||
|
SELECT double_parameter_insert(3, 30);
|
||||||
|
SELECT double_parameter_insert(4, 40);
|
||||||
|
SELECT double_parameter_insert(5, 50);
|
||||||
|
SELECT double_parameter_insert(6, 60);
|
||||||
|
|
||||||
|
-- check inserted values
|
||||||
|
SELECT * FROM temp_table ORDER BY key, value;
|
||||||
|
|
||||||
|
-- check router executor select
|
||||||
|
CREATE OR REPLACE FUNCTION partition_column_select(key_arg int) RETURNS TABLE(key int, value int) AS $$
|
||||||
|
DECLARE
|
||||||
|
BEGIN
|
||||||
|
RETURN QUERY
|
||||||
|
SELECT
|
||||||
|
temp_table.key,
|
||||||
|
temp_table.value
|
||||||
|
FROM
|
||||||
|
temp_table
|
||||||
|
WHERE
|
||||||
|
temp_table.key = key_arg
|
||||||
|
ORDER BY
|
||||||
|
key,
|
||||||
|
value;
|
||||||
|
END;
|
||||||
|
$$ LANGUAGE plpgsql;
|
||||||
|
|
||||||
|
SELECT partition_column_select(1);
|
||||||
|
SELECT partition_column_select(2);
|
||||||
|
SELECT partition_column_select(3);
|
||||||
|
SELECT partition_column_select(4);
|
||||||
|
SELECT partition_column_select(5);
|
||||||
|
|
||||||
|
-- 6th execution is failing. We don't want to run the failing test because of
|
||||||
|
-- changing output. After implementing this feature, uncomment this.
|
||||||
|
-- SELECT partition_column_select(6);
|
||||||
|
|
||||||
|
-- check real-time executor
|
||||||
|
CREATE OR REPLACE FUNCTION non_partition_column_select(value_arg int) RETURNS TABLE(key int, value int) AS $$
|
||||||
|
DECLARE
|
||||||
|
BEGIN
|
||||||
|
RETURN QUERY
|
||||||
|
SELECT
|
||||||
|
temp_table.key,
|
||||||
|
temp_table.value
|
||||||
|
FROM
|
||||||
|
temp_table
|
||||||
|
WHERE
|
||||||
|
temp_table.value = value_arg
|
||||||
|
ORDER BY
|
||||||
|
key,
|
||||||
|
value;
|
||||||
|
END;
|
||||||
|
$$ LANGUAGE plpgsql;
|
||||||
|
|
||||||
|
SELECT non_partition_column_select(10);
|
||||||
|
SELECT non_partition_column_select(20);
|
||||||
|
SELECT non_partition_column_select(30);
|
||||||
|
SELECT non_partition_column_select(40);
|
||||||
|
SELECT non_partition_column_select(50);
|
||||||
|
|
||||||
|
-- 6th execution is failing. We don't want to run the failing test because of
|
||||||
|
-- changing output. After implementing this feature, uncomment this.
|
||||||
|
-- SELECT partition_column_select(6);
|
||||||
|
|
||||||
-- clean-up functions
|
-- clean-up functions
|
||||||
DROP FUNCTION sql_test_no_1();
|
DROP FUNCTION sql_test_no_1();
|
||||||
DROP FUNCTION sql_test_no_2();
|
DROP FUNCTION sql_test_no_2();
|
||||||
|
@ -260,3 +369,8 @@ DROP FUNCTION plpgsql_test_4();
|
||||||
DROP FUNCTION plpgsql_test_5();
|
DROP FUNCTION plpgsql_test_5();
|
||||||
DROP FUNCTION plpgsql_test_6(int);
|
DROP FUNCTION plpgsql_test_6(int);
|
||||||
DROP FUNCTION plpgsql_test_7(text, text);
|
DROP FUNCTION plpgsql_test_7(text, text);
|
||||||
|
DROP FUNCTION no_parameter_insert();
|
||||||
|
DROP FUNCTION single_parameter_insert(int);
|
||||||
|
DROP FUNCTION double_parameter_insert(int, int);
|
||||||
|
DROP FUNCTION partition_column_select(int);
|
||||||
|
DROP FUNCTION non_partition_column_select(int);
|
||||||
|
|
Loading…
Reference in New Issue