diff -c -r --new-file pgsql.01/doc/src/sgml/plpgsql.sgml pgsql/doc/src/sgml/plpgsql.sgml *** pgsql.01/doc/src/sgml/plpgsql.sgml 2005-06-06 20:46:00.000000000 +0200 --- pgsql/doc/src/sgml/plpgsql.sgml 2005-06-06 22:18:53.000000000 +0200 *************** *** 1251,1263 **** EXECUTE statement is provided: ! EXECUTE command-string; where command-string is an expression yielding a string (of type text) containing the command to be executed. This string is fed literally to the SQL engine. --- 1251,1265 ---- EXECUTE statement is provided: ! EXECUTE command-string [INTO record_or_row]; where command-string is an expression yielding a string (of type text) containing the command to be executed. This string is fed literally to the SQL engine. + record_or_row is any record or row variable. + INTO record_or_row clause is optional. *************** *** 1277,1291 **** The results from SELECT commands are discarded ! by EXECUTE, and SELECT INTO is not currently supported within EXECUTE. - So there is no way to extract a result from a dynamically-created - SELECT using the plain EXECUTE - command. There are two other ways to do it, however: one is to use the - FOR-IN-EXECUTE - loop form described in , - and the other is to use a cursor with OPEN-FOR-EXECUTE, as - described in . --- 1279,1287 ---- The results from SELECT commands are discarded ! by EXECUTE if don't use clause INTO. ! SELECT INTO is not currently supported within EXECUTE. diff -c -r --new-file pgsql.01/src/pl/plpgsql/src/gram.y pgsql/src/pl/plpgsql/src/gram.y *** pgsql.01/src/pl/plpgsql/src/gram.y 2005-06-06 20:30:30.000000000 +0200 --- pgsql/src/pl/plpgsql/src/gram.y 2005-06-06 21:53:20.000000000 +0200 *************** *** 1260,1277 **** } ; ! stmt_dynexecute : K_EXECUTE lno expr_until_semi { - PLpgSQL_stmt_dynexecute *new; ! new = palloc(sizeof(PLpgSQL_stmt_dynexecute)); ! new->cmd_type = PLPGSQL_STMT_DYNEXECUTE; ! new->lineno = $2; ! new->query = $3; - $$ = (PLpgSQL_stmt *)new; - } - ; stmt_open : K_OPEN lno cursor_varptr { --- 1260,1320 ---- } ; ! stmt_dynexecute : K_EXECUTE lno { ! PLpgSQL_stmt_dynexecute *new; ! PLpgSQL_expr *expr; ! int endtoken; ! ! expr = read_sql_construct(K_INTO, ';', "INTO|;", "SELECT ", true, true, &endtoken); ! ! new = palloc(sizeof(PLpgSQL_stmt_dynexecute)); ! new->cmd_type = PLPGSQL_STMT_DYNEXECUTE; ! new->lineno = $2; ! new->query = expr; ! ! new->rec = NULL; ! new->row = NULL; ! ! if (endtoken == K_INTO) ! { ! switch (yylex()) ! { ! case T_ROW: ! check_assignable((PLpgSQL_datum *) yylval.row); ! new->row = yylval.row; ! break; ! ! case T_RECORD: ! check_assignable((PLpgSQL_datum *) yylval.row); ! new->rec = yylval.rec; ! break; ! ! default: ! plpgsql_error_lineno = $2; ! ereport(ERROR, ! (errcode(ERRCODE_SYNTAX_ERROR), ! errmsg("syntax error at \"%s\"", ! yytext), ! errdetail("Expected record or row variable."))); ! } ! if (yylex() != ';') ! { ! plpgsql_error_lineno = $2; ! ereport(ERROR, ! (errcode(ERRCODE_SYNTAX_ERROR), ! errmsg("syntax error at \"%s\"", ! yytext), ! errdetail("Expected record or row variable."))); ! } ! } ! ! $$ = (PLpgSQL_stmt *)new; ! ! } ! ; stmt_open : K_OPEN lno cursor_varptr { diff -c -r --new-file pgsql.01/src/pl/plpgsql/src/pl_exec.c pgsql/src/pl/plpgsql/src/pl_exec.c *** pgsql.01/src/pl/plpgsql/src/pl_exec.c 2005-06-06 20:35:33.000000000 +0200 --- pgsql/src/pl/plpgsql/src/pl_exec.c 2005-06-06 22:08:58.000000000 +0200 *************** *** 2236,2241 **** --- 2236,2249 ---- char *querystr; int exec_res; + PLpgSQL_rec *rec = NULL; + PLpgSQL_row *row = NULL; + + if (stmt->rec != NULL) + rec = (PLpgSQL_rec *) (estate->datums[stmt->rec->recno]); + else if (stmt->row != NULL) + row = (PLpgSQL_row *) (estate->datums[stmt->row->rowno]); + /* * First we evaluate the string expression after the EXECUTE keyword. * It's result is the querystring we have to execute. *************** *** 2257,2265 **** --- 2265,2288 ---- * results will be discarded. */ exec_res = SPI_execute(querystr, estate->readonly_func, 0); + if (exec_res != SPI_OK_SELECT && (rec || row)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("EXECUTE ... INTO is only for SELECT"))); + switch (exec_res) { case SPI_OK_SELECT: + { + if (row || rec) + { + if (SPI_processed == 0) + exec_move_row(estate, rec, row, NULL, SPI_tuptable->tupdesc); + else + exec_move_row(estate, rec, row, SPI_tuptable->vals[0], SPI_tuptable->tupdesc); + } + break; + } case SPI_OK_INSERT: case SPI_OK_UPDATE: case SPI_OK_DELETE: diff -c -r --new-file pgsql.01/src/pl/plpgsql/src/plpgsql.h pgsql/src/pl/plpgsql/src/plpgsql.h *** pgsql.01/src/pl/plpgsql/src/plpgsql.h 2005-06-06 20:20:43.000000000 +0200 --- pgsql/src/pl/plpgsql/src/plpgsql.h 2005-06-06 22:03:44.000000000 +0200 *************** *** 526,531 **** --- 526,533 ---- { /* Dynamic SQL string to execute */ int cmd_type; int lineno; + PLpgSQL_rec *rec; /* INTO record or row variable */ + PLpgSQL_row *row; PLpgSQL_expr *query; } PLpgSQL_stmt_dynexecute; diff -c -r --new-file pgsql.01/src/test/regress/expected/plpgsql.out pgsql/src/test/regress/expected/plpgsql.out *** pgsql.01/src/test/regress/expected/plpgsql.out 2005-06-06 20:48:57.000000000 +0200 --- pgsql/src/test/regress/expected/plpgsql.out 2005-06-06 22:15:34.000000000 +0200 *************** *** 2415,2417 **** --- 2415,2449 ---- drop function excpt_test(); DROP FUNCTION + + -- + -- EXECUTE ... INTO test + -- + create table eifoo (i integer, y integer); + CREATE TABLE + create type eitype as (i integer, y integer); + CREATE TYPE + create or replace function execute_into_test(varchar) returns record as $$ + declare _r record; _rt eifoo%rowtype; _v eitype; + begin + execute 'insert into '||$1||' values(10,15)'; + execute 'select (row).* from (select row(10,1)::eifoo) s' INTO _r; + raise notice '% %', _r.i, _r.y; + execute 'select * from '||$1||' limit 1' into _rt; + raise notice '% %', _rt.i, _rt.y; + execute 'select 1,2' into _v; + return _v; + end; $$ language plpgsql; + CREATE FUNCTION + select execute_into_test('eifoo'); + NOTICE: 10 1 + NOTICE: 10 15 + execute_into_test + ------------------- + (1,2) + (1 row) + + drop table eifoo cascade; + DROP TABLE + drop type eitype cascade; + DROP TYPE diff -c -r --new-file pgsql.01/src/test/regress/sql/plpgsql.sql pgsql/src/test/regress/sql/plpgsql.sql *** pgsql.01/src/test/regress/sql/plpgsql.sql 2005-06-06 20:41:53.000000000 +0200 --- pgsql/src/test/regress/sql/plpgsql.sql 2005-06-06 22:14:15.000000000 +0200 *************** *** 2043,2045 **** --- 2043,2069 ---- select excpt_test(); drop function excpt_test(); + + -- + -- EXECUTE ... INTO test + -- + + create table eifoo (i integer, y integer); + create type eitype as (i integer, y integer); + + create or replace function execute_into_test(varchar) returns record as $$ + declare _r record; _rt eifoo%rowtype; _v eitype; + begin + execute 'insert into '||$1||' values(10,15)'; + execute 'select (row).* from (select row(10,1)::eifoo) s' INTO _r; + raise notice '% %', _r.i, _r.y; + execute 'select * from '||$1||' limit 1' into _rt; + raise notice '% %', _rt.i, _rt.y; + execute 'select 1,2' into _v; + return _v; + end; $$ language plpgsql; + + select execute_into_test('eifoo'); + + drop table eifoo cascade; + drop type eitype cascade;