"abstract": "Database partitioning implemented as procedural language",
"file": "sql/plproxy.sql",
"docfile": "doc/tutorial.txt",
- "version": "2.5.0"
+ "version": "2.5.1"
}
},
"prereqs": {
# sync with NEWS, META.json, plproxy.control, debian/changelog
DISTVERSION = 2.5
-EXTVERSION = 2.5.0
-UPGRADE_VERS = 2.3.0 2.4.0
+EXTVERSION = 2.5.1
+UPGRADE_VERS = 2.3.0 2.4.0 2.5.0
# set to 1 to disallow functions containing SELECT
NO_SELECT = 0
echo "create extension plproxy;" > sql/plproxy.sql
cat $^ > $@
-$(foreach v,$(UPGRADE_VERS),sql/plproxy--$(v)--$(EXTVERSION).sql):
- touch $@
+$(foreach v,$(UPGRADE_VERS),sql/plproxy--$(v)--$(EXTVERSION).sql): sql/ext_update_validator.sql
+ @mkdir -p sql
+ cat $< >$@
sql/plproxy--unpackaged--$(EXTVERSION).sql: sql/ext_unpackaged.sql
@mkdir -p sql
# plproxy extension
comment = 'Database partitioning implemented as procedural language'
-default_version = '2.5.0'
+default_version = '2.5.1'
module_pathname = '$libdir/plproxy'
relocatable = false
# schema = pg_catalog
--- /dev/null
+CREATE FUNCTION plproxy_validator (oid)
+RETURNS void AS 'plproxy' LANGUAGE C;
+
+CREATE OR REPLACE LANGUAGE plproxy HANDLER plproxy_call_handler VALIDATOR plproxy_validator;
CREATE FUNCTION plproxy_call_handler ()
RETURNS language_handler AS 'plproxy' LANGUAGE C;
+-- validator function
+CREATE FUNCTION plproxy_validator (oid)
+RETURNS void AS 'plproxy' LANGUAGE C;
+
-- language
-CREATE LANGUAGE plproxy HANDLER plproxy_call_handler;
+CREATE LANGUAGE plproxy HANDLER plproxy_call_handler VALIDATOR plproxy_validator;
* where everything is allocated.
*/
static ProxyFunction *
-fn_new(FunctionCallInfo fcinfo, HeapTuple proc_tuple)
+fn_new(HeapTuple proc_tuple)
{
ProxyFunction *f;
MemoryContext f_ctx,
f = palloc0(sizeof(*f));
f->ctx = f_ctx;
- f->oid = fcinfo->flinfo->fn_oid;
+ f->oid = HeapTupleGetOid(proc_tuple);
plproxy_set_stamp(&f->stamp, proc_tuple);
if (fn_returns_dynamic_record(proc_tuple))
*/
static void
fn_get_arguments(ProxyFunction *func,
- FunctionCallInfo fcinfo,
HeapTuple proc_tuple)
{
Oid *types;
func->remote_sql = plproxy_standard_query(func, true);
}
-/* Show part of compilation -- get source and parse */
-static ProxyFunction *
-fn_compile(FunctionCallInfo fcinfo,
+/*
+ * Show part of compilation -- get source and parse
+ *
+ * When called from the validator, validate_only is true, but there is no
+ * fcinfo.
+ */
+ProxyFunction *
+plproxy_compile(FunctionCallInfo fcinfo,
HeapTuple proc_tuple,
- bool validate)
+ bool validate_only)
{
ProxyFunction *f;
Form_pg_proc proc_struct;
+ Assert(fcinfo || validate_only);
+
proc_struct = (Form_pg_proc) GETSTRUCT(proc_tuple);
if (proc_struct->provolatile != PROVOLATILE_VOLATILE)
elog(ERROR, "PL/Proxy functions must be volatile");
- f = fn_new(fcinfo, proc_tuple);
+ f = fn_new(proc_tuple);
/* keep reference in case of error half-way */
- partial_func = f;
+ if (!validate_only)
+ partial_func = f;
/* info from system tables */
fn_set_name(f, proc_tuple);
- fn_get_return_type(f, fcinfo, proc_tuple);
- fn_get_arguments(f, fcinfo, proc_tuple);
+ /*
+ * Cannot check return type in validator, because there is no call info to
+ * resolve polymorphic types against.
+ */
+ if (!validate_only)
+ fn_get_return_type(f, fcinfo, proc_tuple);
+ fn_get_arguments(f, proc_tuple);
/* parse body */
fn_parse(f, proc_tuple);
if (f->dynamic_record && f->remote_sql)
plproxy_error(f, "SELECT statement not allowed for dynamic RECORD functions");
- /* create SELECT stmt if not specified */
- if (f->remote_sql == NULL)
- f->remote_sql = plproxy_standard_query(f, true);
-
- /* prepare local queries */
- if (f->cluster_sql)
- plproxy_query_prepare(f, fcinfo, f->cluster_sql, false);
- if (f->hash_sql)
- plproxy_query_prepare(f, fcinfo, f->hash_sql, true);
- if (f->connect_sql)
- plproxy_query_prepare(f, fcinfo, f->connect_sql, false);
-
/* sanity check */
- if (f->run_type == R_ALL && !fcinfo->flinfo->fn_retset)
+ if (f->run_type == R_ALL && (fcinfo
+ ? !fcinfo->flinfo->fn_retset
+ : !get_func_retset(HeapTupleGetOid(proc_tuple))))
plproxy_error(f, "RUN ON ALL requires set-returning function");
return f;
* Compile and cache PL/Proxy function.
*/
ProxyFunction *
-plproxy_compile(FunctionCallInfo fcinfo, bool validate)
+plproxy_compile_and_cache(FunctionCallInfo fcinfo)
{
ProxyFunction *f;
HeapTuple proc_tuple;
if (!f)
{
- f = fn_compile(fcinfo, proc_tuple, validate);
+ f = plproxy_compile(fcinfo, proc_tuple, false);
+
+ /* create SELECT stmt if not specified */
+ if (f->remote_sql == NULL)
+ f->remote_sql = plproxy_standard_query(f, true);
+
+ /* prepare local queries */
+ if (f->cluster_sql)
+ plproxy_query_prepare(f, fcinfo, f->cluster_sql, false);
+ if (f->hash_sql)
+ plproxy_query_prepare(f, fcinfo, f->hash_sql, true);
+ if (f->connect_sql)
+ plproxy_query_prepare(f, fcinfo, f->connect_sql, false);
fn_cache_insert(f);
#endif
PG_FUNCTION_INFO_V1(plproxy_call_handler);
+PG_FUNCTION_INFO_V1(plproxy_validator);
/*
* Centralised error reporting.
plproxy_startup_init();
/* compile code */
- func = plproxy_compile(fcinfo, false);
+ func = plproxy_compile_and_cache(fcinfo);
/* get actual cluster to run on */
cluster = plproxy_find_cluster(func, fcinfo);
}
return ret;
}
+
+/*
+ * This function is called when a PL/Proxy function is created to
+ * check the syntax.
+ */
+Datum
+plproxy_validator(PG_FUNCTION_ARGS)
+{
+ Oid oid = PG_GETARG_OID(0);
+ HeapTuple proc_tuple;
+
+ proc_tuple = SearchSysCache(PROCOID, ObjectIdGetDatum(oid), 0, 0, 0);
+ if (!HeapTupleIsValid(proc_tuple))
+ elog(ERROR, "cache lookup failed for function %u", oid);
+
+ plproxy_compile(NULL, proc_tuple, true);
+
+ ReleaseSysCache(proc_tuple);
+
+ PG_RETURN_VOID();
+}
/* main.c */
Datum plproxy_call_handler(PG_FUNCTION_ARGS);
+Datum plproxy_validator(PG_FUNCTION_ARGS);
void plproxy_error(ProxyFunction *func, const char *fmt, ...)
__attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 3)));
void plproxy_remote_error(ProxyFunction *func, ProxyConnection *conn, const PGresult *res, bool iserr);
int plproxy_get_parameter_index(ProxyFunction *func, const char *ident);
bool plproxy_split_add_ident(ProxyFunction *func, const char *ident);
void plproxy_split_all_arrays(ProxyFunction *func);
-ProxyFunction *plproxy_compile(FunctionCallInfo fcinfo, bool validate);
+ProxyFunction *plproxy_compile_and_cache(FunctionCallInfo fcinfo);
+ProxyFunction *plproxy_compile(FunctionCallInfo fcinfo, HeapTuple proc_tuple, bool validate_only);
/* execute.c */
void plproxy_exec(ProxyFunction *func, FunctionCallInfo fcinfo);
run on all;
select id, username from dynamic_query_test;
$x$ language plproxy;
-select * from dynamic_query_select() as (id integer, username text);
ERROR: PL/Proxy function public.dynamic_query_select(0): SELECT statement not allowed for dynamic RECORD functions
+select * from dynamic_query_select() as (id integer, username text);
+ERROR: function dynamic_query_select() does not exist
+LINE 1: select * from dynamic_query_select() as (id integer, usernam...
+ ^
+HINT: No function matches the given name and argument types. You might need to add explicit type casts.
cluster 'testcluster';
run on hashtext($2);
$$ language plproxy;
-select * from test_err2('dat');
ERROR: PL/Proxy function public.test_err2(1): Compile error at line 3: invalid argument reference: $2
+select * from test_err2('dat');
+ERROR: function test_err2(unknown) does not exist
+LINE 1: select * from test_err2('dat');
+ ^
+HINT: No function matches the given name and argument types. You might need to add explicit type casts.
create function test_err3(dat text)
returns text as $$
cluster 'nonexists';
run on hashtext(dat);
select dat as res2, 'foo' as res1;
$$ language plproxy;
-select * from test_map_err4('dat');
ERROR: PL/Proxy function public.test_map_err4(1): Compile error at line 5: CLUSTER statement missing
+select * from test_map_err4('dat');
+ERROR: function test_map_err4(unknown) does not exist
+LINE 1: select * from test_map_err4('dat');
+ ^
+HINT: No function matches the given name and argument types. You might need to add explicit type casts.
create function test_variadic_err(first text, rest variadic text[])
returns text as $$
cluster 'testcluster';
$$ language plproxy;
-select * from test_variadic_err('dat', 'dat', 'dat');
ERROR: PL/Proxy does not support variadic args
+select * from test_variadic_err('dat', 'dat', 'dat');
+ERROR: function test_variadic_err(unknown, unknown, unknown) does not exist
+LINE 1: select * from test_variadic_err('dat', 'dat', 'dat');
+ ^
+HINT: No function matches the given name and argument types. You might need to add explicit type casts.
create function test_volatile_err(dat text)
returns text
stable
as $$
cluster 'testcluster';
$$ language plproxy;
-select * from test_volatile_err('dat');
ERROR: PL/Proxy functions must be volatile
+select * from test_volatile_err('dat');
+ERROR: function test_volatile_err(unknown) does not exist
+LINE 1: select * from test_volatile_err('dat');
+ ^
+HINT: No function matches the given name and argument types. You might need to add explicit type casts.
create function test_pseudo_arg_err(dat cstring)
returns text
as $$
cluster 'testcluster';
$$ language plproxy;
-select * from test_pseudo_arg_err(textout('dat'));
ERROR: PL/Proxy function public.test_pseudo_arg_err(0): unsupported pseudo type: cstring (2275)
+select * from test_pseudo_arg_err(textout('dat'));
+ERROR: function test_pseudo_arg_err(cstring) does not exist
+LINE 1: select * from test_pseudo_arg_err(textout('dat'));
+ ^
+HINT: No function matches the given name and argument types. You might need to add explicit type casts.
create function test_pseudo_ret_err(dat text)
returns cstring
as $$
cluster 'testcluster';
$$ language plproxy;
+-- not detected in validator
select * from test_pseudo_ret_err('dat');
ERROR: PL/Proxy function public.test_pseudo_ret_err(0): unsupported pseudo type: cstring (2275)
create function test_runonall_err(dat text)
cluster 'testcluster';
run on all;
$$ language plproxy;
-select * from test_runonall_err('dat');
ERROR: PL/Proxy function public.test_runonall_err(1): RUN ON ALL requires set-returning function
+select * from test_runonall_err('dat');
+ERROR: function test_runonall_err(unknown) does not exist
+LINE 1: select * from test_runonall_err('dat');
+ ^
+HINT: No function matches the given name and argument types. You might need to add explicit type casts.
select id from sel_test where username = xuser;
select id from sel_test where username = xuser;
$$ language plproxy;
-select * from test_select_err('user', true);
ERROR: PL/Proxy function public.test_select_err(2): Compile error at line 5: Only one SELECT statement allowed
+select * from test_select_err('user', true);
+ERROR: function test_select_err(unknown, boolean) does not exist
+LINE 1: select * from test_select_err('user', true);
+ ^
+HINT: No function matches the given name and argument types. You might need to add explicit type casts.
create function get_zero()
returns setof integer as $x$
cluster 'testcluster';
-- invalid arg reference
create or replace function test_array(a text[], b text[], c text) returns setof text as
$$ split $4; cluster 'testcluster'; run on 0;$$ language plproxy;
-select * from test_array(array['a'], array['g'], 'foo');
ERROR: PL/Proxy function public.test_array(3): Compile error at line 1: invalid argument reference: $4
+select * from test_array(array['a'], array['g'], 'foo');
+ERROR: function test_array(text[], text[], unknown) does not exist
+LINE 1: select * from test_array(array['a'], array['g'], 'foo');
+ ^
+HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-- invalid arg name
create or replace function test_array(a text[], b text[], c text) returns setof text as
$$ split x; cluster 'testcluster'; run on 0; $$ language plproxy;
-select * from test_array(array['a'], array['b', 'c'], 'foo');
ERROR: PL/Proxy function public.test_array(3): Compile error at line 1: invalid argument reference: x
+select * from test_array(array['a'], array['b', 'c'], 'foo');
+ERROR: function test_array(text[], text[], unknown) does not exist
+LINE 1: select * from test_array(array['a'], array['b', 'c'], 'foo')...
+ ^
+HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-- cannot split more than once
create or replace function test_array(a text[], b text[], c text) returns setof text as
$$ split a, b, b; cluster 'testcluster'; run on 0; $$ language plproxy;
-select * from test_array(array['a'], array['b', 'c'], 'foo');
ERROR: PL/Proxy function public.test_array(3): SPLIT parameter specified more than once: b
+select * from test_array(array['a'], array['b', 'c'], 'foo');
+ERROR: function test_array(text[], text[], unknown) does not exist
+LINE 1: select * from test_array(array['a'], array['b', 'c'], 'foo')...
+ ^
+HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-- attempt to split non-array
create or replace function test_array(a text[], b text[], c text) returns setof text as
$$ split $3; cluster 'testcluster'; run on 0;$$ language plproxy;
-select * from test_array(array['a'], array['g'], 'foo');
ERROR: PL/Proxy function public.test_array(3): SPLIT parameter is not an array: $3
+select * from test_array(array['a'], array['g'], 'foo');
+ERROR: function test_array(text[], text[], unknown) does not exist
+LINE 1: select * from test_array(array['a'], array['g'], 'foo');
+ ^
+HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-- array size/dimensions mismatch
create or replace function test_array(a text[], b text[], c text) returns setof text as
$$ split a, b; cluster 'testcluster'; run on 0; $$ language plproxy;
target test_target_dst;
target test_target_dst;
$$ language plproxy;
-select * from test_target_err1('asd');
ERROR: PL/Proxy function public.test_target_err1(1): Compile error at line 5: Only one TARGET statement allowed
+select * from test_target_err1('asd');
+ERROR: function test_target_err1(unknown) does not exist
+LINE 1: select * from test_target_err1('asd');
+ ^
+HINT: No function matches the given name and argument types. You might need to add explicit type casts.
create function test_target_err2(xuser text)
returns text as $$
cluster 'testcluster';
target test_target_dst;
select 1;
$$ language plproxy;
-select * from test_target_err2('asd');
ERROR: PL/Proxy function public.test_target_err2(1): Compile error at line 6: TARGET cannot be used with SELECT
+select * from test_target_err2('asd');
+ERROR: function test_target_err2(unknown) does not exist
+LINE 1: select * from test_target_err2('asd');
+ ^
+HINT: No function matches the given name and argument types. You might need to add explicit type casts.
as $$
cluster 'testcluster';
$$ language plproxy;
+-- not detected in validator
select * from test_pseudo_ret_err('dat');
create function test_runonall_err(dat text)