Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
Postgres FD Implementation
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Abuhujair Javed
Postgres FD Implementation
Commits
47391591
Commit
47391591
authored
May 03, 2008
by
Tom Lane
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Support RETURN QUERY EXECUTE in plpgsql.
Pavel Stehule
parent
511b798c
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
185 additions
and
62 deletions
+185
-62
doc/src/sgml/plpgsql.sgml
doc/src/sgml/plpgsql.sgml
+10
-2
src/pl/plpgsql/src/gram.y
src/pl/plpgsql/src/gram.y
+28
-2
src/pl/plpgsql/src/pl_exec.c
src/pl/plpgsql/src/pl_exec.c
+79
-52
src/pl/plpgsql/src/pl_funcs.c
src/pl/plpgsql/src/pl_funcs.c
+32
-4
src/pl/plpgsql/src/plpgsql.h
src/pl/plpgsql/src/plpgsql.h
+4
-2
src/test/regress/expected/plpgsql.out
src/test/regress/expected/plpgsql.out
+18
-0
src/test/regress/sql/plpgsql.sql
src/test/regress/sql/plpgsql.sql
+14
-0
No files found.
doc/src/sgml/plpgsql.sgml
View file @
47391591
<!-- $PostgreSQL: pgsql/doc/src/sgml/plpgsql.sgml,v 1.12
7 2008/04/06 23:43:29
tgl Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/plpgsql.sgml,v 1.12
8 2008/05/03 00:11:36
tgl Exp $ -->
<chapter id="plpgsql">
<title><application>PL/pgSQL</application> - <acronym>SQL</acronym> Procedural Language</title>
...
...
@@ -1467,6 +1467,7 @@ RETURN <replaceable>expression</replaceable>;
<synopsis>
RETURN NEXT <replaceable>expression</replaceable>;
RETURN QUERY <replaceable>query</replaceable>;
RETURN QUERY EXECUTE <replaceable class="command">command-string</replaceable> <optional> USING <replaceable>expression</replaceable> <optional>, ...</optional> </optional>;
</synopsis>
<para>
...
...
@@ -1500,6 +1501,14 @@ RETURN QUERY <replaceable>query</replaceable>;
let control reach the end of the function).
</para>
<para>
<command>RETURN QUERY</command> has a variant
<command>RETURN QUERY EXECUTE</command>, which specifies the
query to be executed dynamically. Parameter expressions can
be inserted into the computed query string via <literal>USING</>,
in just the same way as in the <command>EXECUTE</> command.
</para>
<para>
If you declared the function with output parameters, write just
<command>RETURN NEXT</command> with no expression. On each
...
...
@@ -1544,7 +1553,6 @@ SELECT * FROM getallfoo();
Note that functions using <command>RETURN NEXT</command> or
<command>RETURN QUERY</command> must be called as a table source in
a <literal>FROM</literal> clause.
</para>
<note>
...
...
src/pl/plpgsql/src/gram.y
View file @
47391591
...
...
@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.11
0 2008/04/06 23:43:29
tgl Exp $
* $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.11
1 2008/05/03 00:11:36
tgl Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -2239,6 +2239,7 @@ static PLpgSQL_stmt *
make_return_query_stmt(int lineno)
{
PLpgSQL_stmt_return_query *new;
int tok;
if (!plpgsql_curr_compile->fn_retset)
yyerror("cannot use RETURN QUERY in a non-SETOF function");
...
...
@@ -2246,7 +2247,32 @@ make_return_query_stmt(int lineno)
new = palloc0(sizeof(PLpgSQL_stmt_return_query));
new->cmd_type = PLPGSQL_STMT_RETURN_QUERY;
new->lineno = lineno;
new->query = read_sql_stmt("");
/* check for RETURN QUERY EXECUTE */
if ((tok = yylex()) != K_EXECUTE)
{
/* ordinary static query */
plpgsql_push_back_token(tok);
new->query = read_sql_stmt("");
}
else
{
/* dynamic SQL */
int term;
new->dynquery = read_sql_expression2(';', K_USING, "; or USING",
&term);
if (term == K_USING)
{
do
{
PLpgSQL_expr *expr;
expr = read_sql_expression2(',', ';', ", or ;", &term);
new->params = lappend(new->params, expr);
} while (term == ',');
}
}
return (PLpgSQL_stmt *) new;
}
...
...
src/pl/plpgsql/src/pl_exec.c
View file @
47391591
...
...
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.21
0 2008/04/17 21:37:28 alvherre
Exp $
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.21
1 2008/05/03 00:11:36 tgl
Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -197,6 +197,8 @@ static void assign_text_var(PLpgSQL_var *var, const char *str);
static
PreparedParamsData
*
exec_eval_using_params
(
PLpgSQL_execstate
*
estate
,
List
*
params
);
static
void
free_params_data
(
PreparedParamsData
*
ppd
);
static
Portal
exec_dynquery_with_params
(
PLpgSQL_execstate
*
estate
,
PLpgSQL_expr
*
query
,
List
*
params
);
/* ----------
...
...
@@ -1968,7 +1970,7 @@ exec_stmt_return(PLpgSQL_execstate *estate, PLpgSQL_stmt_return *stmt)
PLpgSQL_row
*
row
=
(
PLpgSQL_row
*
)
retvar
;
Assert
(
row
->
rowtupdesc
);
estate
->
retval
=
estate
->
retval
=
PointerGetDatum
(
make_tuple_from_row
(
estate
,
row
,
row
->
rowtupdesc
));
if
(
DatumGetPointer
(
estate
->
retval
)
==
NULL
)
/* should not happen */
...
...
@@ -2189,7 +2191,18 @@ exec_stmt_return_query(PLpgSQL_execstate *estate,
if
(
estate
->
tuple_store
==
NULL
)
exec_init_tuple_store
(
estate
);
exec_run_select
(
estate
,
stmt
->
query
,
0
,
&
portal
);
if
(
stmt
->
query
!=
NULL
)
{
/* static query */
exec_run_select
(
estate
,
stmt
->
query
,
0
,
&
portal
);
}
else
{
/* RETURN QUERY EXECUTE */
Assert
(
stmt
->
dynquery
!=
NULL
);
portal
=
exec_dynquery_with_params
(
estate
,
stmt
->
dynquery
,
stmt
->
params
);
}
if
(
!
compatible_tupdesc
(
estate
->
rettupdesc
,
portal
->
tupDesc
))
ereport
(
ERROR
,
...
...
@@ -2841,58 +2854,10 @@ exec_stmt_dynexecute(PLpgSQL_execstate *estate,
static
int
exec_stmt_dynfors
(
PLpgSQL_execstate
*
estate
,
PLpgSQL_stmt_dynfors
*
stmt
)
{
Datum
query
;
bool
isnull
;
Oid
restype
;
char
*
querystr
;
Portal
portal
;
int
rc
;
/*
* Evaluate the string expression after the EXECUTE keyword. It's result
* is the querystring we have to execute.
*/
query
=
exec_eval_expr
(
estate
,
stmt
->
query
,
&
isnull
,
&
restype
);
if
(
isnull
)
ereport
(
ERROR
,
(
errcode
(
ERRCODE_NULL_VALUE_NOT_ALLOWED
),
errmsg
(
"cannot EXECUTE a null querystring"
)));
/* Get the C-String representation */
querystr
=
convert_value_to_string
(
query
,
restype
);
exec_eval_cleanup
(
estate
);
/*
* Open an implicit cursor for the query. We use SPI_cursor_open_with_args
* even when there are no params, because this avoids making and freeing
* one copy of the plan.
*/
if
(
stmt
->
params
)
{
PreparedParamsData
*
ppd
;
ppd
=
exec_eval_using_params
(
estate
,
stmt
->
params
);
portal
=
SPI_cursor_open_with_args
(
NULL
,
querystr
,
ppd
->
nargs
,
ppd
->
types
,
ppd
->
values
,
ppd
->
nulls
,
estate
->
readonly_func
,
0
);
free_params_data
(
ppd
);
}
else
{
portal
=
SPI_cursor_open_with_args
(
NULL
,
querystr
,
0
,
NULL
,
NULL
,
NULL
,
estate
->
readonly_func
,
0
);
}
if
(
portal
==
NULL
)
elog
(
ERROR
,
"could not open implicit cursor for query
\"
%s
\"
: %s"
,
querystr
,
SPI_result_code_string
(
SPI_result
));
pfree
(
querystr
);
portal
=
exec_dynquery_with_params
(
estate
,
stmt
->
query
,
stmt
->
params
);
/*
* Execute the loop
...
...
@@ -5208,3 +5173,65 @@ free_params_data(PreparedParamsData *ppd)
pfree
(
ppd
);
}
/*
* Open portal for dynamic query
*/
static
Portal
exec_dynquery_with_params
(
PLpgSQL_execstate
*
estate
,
PLpgSQL_expr
*
dynquery
,
List
*
params
)
{
Portal
portal
;
Datum
query
;
bool
isnull
;
Oid
restype
;
char
*
querystr
;
/*
* Evaluate the string expression after the EXECUTE keyword. Its result
* is the querystring we have to execute.
*/
query
=
exec_eval_expr
(
estate
,
dynquery
,
&
isnull
,
&
restype
);
if
(
isnull
)
ereport
(
ERROR
,
(
errcode
(
ERRCODE_NULL_VALUE_NOT_ALLOWED
),
errmsg
(
"cannot EXECUTE a null querystring"
)));
/* Get the C-String representation */
querystr
=
convert_value_to_string
(
query
,
restype
);
exec_eval_cleanup
(
estate
);
/*
* Open an implicit cursor for the query. We use SPI_cursor_open_with_args
* even when there are no params, because this avoids making and freeing
* one copy of the plan.
*/
if
(
params
)
{
PreparedParamsData
*
ppd
;
ppd
=
exec_eval_using_params
(
estate
,
params
);
portal
=
SPI_cursor_open_with_args
(
NULL
,
querystr
,
ppd
->
nargs
,
ppd
->
types
,
ppd
->
values
,
ppd
->
nulls
,
estate
->
readonly_func
,
0
);
free_params_data
(
ppd
);
}
else
{
portal
=
SPI_cursor_open_with_args
(
NULL
,
querystr
,
0
,
NULL
,
NULL
,
NULL
,
estate
->
readonly_func
,
0
);
}
if
(
portal
==
NULL
)
elog
(
ERROR
,
"could not open implicit cursor for query
\"
%s
\"
: %s"
,
querystr
,
SPI_result_code_string
(
SPI_result
));
pfree
(
querystr
);
return
portal
;
}
src/pl/plpgsql/src/pl_funcs.c
View file @
47391591
...
...
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.
69 2008/04/06 23:43:29
tgl Exp $
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.
70 2008/05/03 00:11:36
tgl Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -963,9 +963,37 @@ static void
dump_return_query
(
PLpgSQL_stmt_return_query
*
stmt
)
{
dump_ind
();
printf
(
"RETURN QUERY "
);
dump_expr
(
stmt
->
query
);
printf
(
"
\n
"
);
if
(
stmt
->
query
)
{
printf
(
"RETURN QUERY "
);
dump_expr
(
stmt
->
query
);
printf
(
"
\n
"
);
}
else
{
printf
(
"RETURN QUERY EXECUTE "
);
dump_expr
(
stmt
->
dynquery
);
printf
(
"
\n
"
);
if
(
stmt
->
params
!=
NIL
)
{
ListCell
*
lc
;
int
i
;
dump_indent
+=
2
;
dump_ind
();
printf
(
" USING
\n
"
);
dump_indent
+=
2
;
i
=
1
;
foreach
(
lc
,
stmt
->
params
)
{
dump_ind
();
printf
(
" parameter $%d: "
,
i
++
);
dump_expr
((
PLpgSQL_expr
*
)
lfirst
(
lc
));
printf
(
"
\n
"
);
}
dump_indent
-=
4
;
}
}
}
static
void
...
...
src/pl/plpgsql/src/plpgsql.h
View file @
47391591
...
...
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.9
7 2008/04/06 23:43:29
tgl Exp $
* $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.9
8 2008/05/03 00:11:36
tgl Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -529,7 +529,9 @@ typedef struct
{
/* RETURN QUERY statement */
int
cmd_type
;
int
lineno
;
PLpgSQL_expr
*
query
;
PLpgSQL_expr
*
query
;
/* if static query */
PLpgSQL_expr
*
dynquery
;
/* if dynamic query (RETURN QUERY EXECUTE) */
List
*
params
;
/* USING arguments for dynamic query */
}
PLpgSQL_stmt_return_query
;
typedef
struct
...
...
src/test/regress/expected/plpgsql.out
View file @
47391591
...
...
@@ -3267,3 +3267,21 @@ end;
$$ language plpgsql;
ERROR: cursor FOR loop must use a bound cursor variable
CONTEXT: compile of PL/pgSQL function "forc_bad" near line 4
-- return query execute
create or replace function return_dquery()
returns setof int as $$
begin
return query execute 'select * from (values(10),(20)) f';
return query execute 'select * from (values($1),($2)) f' using 40,50;
end;
$$ language plpgsql;
select * from return_dquery();
return_dquery
---------------
10
20
40
50
(4 rows)
drop function return_dquery();
src/test/regress/sql/plpgsql.sql
View file @
47391591
...
...
@@ -2669,3 +2669,17 @@ begin
end
loop
;
end
;
$$
language
plpgsql
;
-- return query execute
create
or
replace
function
return_dquery
()
returns
setof
int
as
$$
begin
return
query
execute
'select * from (values(10),(20)) f'
;
return
query
execute
'select * from (values($1),($2)) f'
using
40
,
50
;
end
;
$$
language
plpgsql
;
select
*
from
return_dquery
();
drop
function
return_dquery
();
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment