mirror of
https://github.com/postgres/postgres.git
synced 2025-09-02 04:21:28 +03:00
This patch makes a minor cleanup to the implementation of PERFORM in
PL/PgSQL. Previously, it had been bundled together with the assign statement implementation, for some reason that wasn't clear to me (they certainly don't share any code with one another). So I separated them and made PERFORM a statement like any other. No changes in functionality. Along the way, I added some regression tests for PERFORM, added a bunch more SGML tags to the PL/PgSQL docs, and removed an obsolete comment relating to the implementation of RETURN NEXT. Neil Conway
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
* procedural language
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/gram.y,v 1.39 2002/11/01 22:52:34 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/gram.y,v 1.40 2002/11/10 00:35:58 momjian Exp $
|
||||
*
|
||||
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||
*
|
||||
@@ -728,14 +728,13 @@ proc_stmt : pl_block ';'
|
||||
|
||||
stmt_perform : K_PERFORM lno expr_until_semi
|
||||
{
|
||||
PLpgSQL_stmt_assign *new;
|
||||
PLpgSQL_stmt_perform *new;
|
||||
|
||||
new = malloc(sizeof(PLpgSQL_stmt_assign));
|
||||
memset(new, 0, sizeof(PLpgSQL_stmt_assign));
|
||||
new = malloc(sizeof(PLpgSQL_stmt_perform));
|
||||
memset(new, 0, sizeof(PLpgSQL_stmt_perform));
|
||||
|
||||
new->cmd_type = PLPGSQL_STMT_ASSIGN;
|
||||
new->cmd_type = PLPGSQL_STMT_PERFORM;
|
||||
new->lineno = $2;
|
||||
new->varno = -1;
|
||||
new->expr = $3;
|
||||
|
||||
$$ = (PLpgSQL_stmt *)new;
|
||||
|
@@ -3,7 +3,7 @@
|
||||
* procedural language
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.65 2002/10/19 22:10:58 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.66 2002/11/10 00:35:58 momjian Exp $
|
||||
*
|
||||
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||
*
|
||||
@@ -73,6 +73,8 @@ static int exec_stmt(PLpgSQL_execstate * estate,
|
||||
PLpgSQL_stmt * stmt);
|
||||
static int exec_stmt_assign(PLpgSQL_execstate * estate,
|
||||
PLpgSQL_stmt_assign * stmt);
|
||||
static int exec_stmt_perform(PLpgSQL_execstate * estate,
|
||||
PLpgSQL_stmt_perform * stmt);
|
||||
static int exec_stmt_getdiag(PLpgSQL_execstate * estate,
|
||||
PLpgSQL_stmt_getdiag * stmt);
|
||||
static int exec_stmt_if(PLpgSQL_execstate * estate,
|
||||
@@ -890,6 +892,10 @@ exec_stmt(PLpgSQL_execstate * estate, PLpgSQL_stmt * stmt)
|
||||
rc = exec_stmt_assign(estate, (PLpgSQL_stmt_assign *) stmt);
|
||||
break;
|
||||
|
||||
case PLPGSQL_STMT_PERFORM:
|
||||
rc = exec_stmt_perform(estate, (PLpgSQL_stmt_perform *) stmt);
|
||||
break;
|
||||
|
||||
case PLPGSQL_STMT_GETDIAG:
|
||||
rc = exec_stmt_getdiag(estate, (PLpgSQL_stmt_getdiag *) stmt);
|
||||
break;
|
||||
@@ -973,43 +979,43 @@ exec_stmt(PLpgSQL_execstate * estate, PLpgSQL_stmt * stmt)
|
||||
/* ----------
|
||||
* exec_stmt_assign Evaluate an expression and
|
||||
* put the result into a variable.
|
||||
*
|
||||
* For no very good reason, this is also used for PERFORM statements.
|
||||
* ----------
|
||||
*/
|
||||
static int
|
||||
exec_stmt_assign(PLpgSQL_execstate * estate, PLpgSQL_stmt_assign * stmt)
|
||||
{
|
||||
Assert(stmt->varno >= 0);
|
||||
|
||||
exec_assign_expr(estate, estate->datums[stmt->varno], stmt->expr);
|
||||
|
||||
return PLPGSQL_RC_OK;
|
||||
}
|
||||
|
||||
/* ----------
|
||||
* exec_stmt_perform Evaluate query and discard result (but set
|
||||
* FOUND depending on whether at least one row
|
||||
* was returned).
|
||||
* ----------
|
||||
*/
|
||||
static int
|
||||
exec_stmt_perform(PLpgSQL_execstate * estate, PLpgSQL_stmt_perform * stmt)
|
||||
{
|
||||
PLpgSQL_expr *expr = stmt->expr;
|
||||
int rc;
|
||||
|
||||
if (stmt->varno >= 0)
|
||||
exec_assign_expr(estate, estate->datums[stmt->varno], expr);
|
||||
else
|
||||
{
|
||||
/*
|
||||
* PERFORM: evaluate query and discard result (but set FOUND
|
||||
* depending on whether at least one row was returned).
|
||||
*
|
||||
* This cannot share code with the assignment case since we do not
|
||||
* wish to constrain the discarded result to be only one
|
||||
* row/column.
|
||||
*/
|
||||
int rc;
|
||||
/*
|
||||
* If not already done create a plan for this expression
|
||||
*/
|
||||
if (expr->plan == NULL)
|
||||
exec_prepare_plan(estate, expr);
|
||||
|
||||
rc = exec_run_select(estate, expr, 0, NULL);
|
||||
if (rc != SPI_OK_SELECT)
|
||||
elog(ERROR, "query \"%s\" didn't return data", expr->query);
|
||||
|
||||
/*
|
||||
* If not already done create a plan for this expression
|
||||
*/
|
||||
if (expr->plan == NULL)
|
||||
exec_prepare_plan(estate, expr);
|
||||
exec_set_found(estate, (estate->eval_processed != 0));
|
||||
|
||||
rc = exec_run_select(estate, expr, 0, NULL);
|
||||
if (rc != SPI_OK_SELECT)
|
||||
elog(ERROR, "query \"%s\" didn't return data", expr->query);
|
||||
|
||||
exec_set_found(estate, (estate->eval_processed != 0));
|
||||
|
||||
exec_eval_cleanup(estate);
|
||||
}
|
||||
exec_eval_cleanup(estate);
|
||||
|
||||
return PLPGSQL_RC_OK;
|
||||
}
|
||||
@@ -1579,12 +1585,11 @@ exec_stmt_return(PLpgSQL_execstate * estate, PLpgSQL_stmt_return * stmt)
|
||||
return PLPGSQL_RC_RETURN;
|
||||
}
|
||||
|
||||
/*
|
||||
* Notes:
|
||||
* - the tuple store must be created in a sufficiently long-lived
|
||||
* memory context, as the same store must be used within the executor
|
||||
* after the PL/PgSQL call returns. At present, the code uses
|
||||
* TopTransactionContext.
|
||||
/* ----------
|
||||
* exec_stmt_return_next Evaluate an expression and add it to the
|
||||
* list of tuples returned by the current
|
||||
* SRF.
|
||||
* ----------
|
||||
*/
|
||||
static int
|
||||
exec_stmt_return_next(PLpgSQL_execstate * estate,
|
||||
@@ -1732,7 +1737,6 @@ exec_init_tuple_store(PLpgSQL_execstate * estate)
|
||||
estate->rettupdesc = rsi->expectedDesc;
|
||||
}
|
||||
|
||||
|
||||
/* ----------
|
||||
* exec_stmt_raise Build a message and throw it with
|
||||
* elog()
|
||||
|
@@ -3,7 +3,7 @@
|
||||
* procedural language
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.28 2002/09/12 00:24:09 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.29 2002/11/10 00:35:58 momjian Exp $
|
||||
*
|
||||
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||
*
|
||||
@@ -100,7 +100,8 @@ enum
|
||||
PLPGSQL_STMT_GETDIAG,
|
||||
PLPGSQL_STMT_OPEN,
|
||||
PLPGSQL_STMT_FETCH,
|
||||
PLPGSQL_STMT_CLOSE
|
||||
PLPGSQL_STMT_CLOSE,
|
||||
PLPGSQL_STMT_PERFORM
|
||||
};
|
||||
|
||||
|
||||
@@ -288,6 +289,12 @@ typedef struct
|
||||
PLpgSQL_expr *expr;
|
||||
} PLpgSQL_stmt_assign;
|
||||
|
||||
typedef struct
|
||||
{ /* PERFORM statement */
|
||||
int cmd_type;
|
||||
int lineno;
|
||||
PLpgSQL_expr *expr;
|
||||
} PLpgSQL_stmt_perform;
|
||||
|
||||
typedef struct
|
||||
{ /* Get Diagnostics item */
|
||||
|
@@ -1733,3 +1733,54 @@ SELECT * FROM test_ret_rec_dyn(5) AS (a int, b numeric, c text);
|
||||
50 | 5 | xxx
|
||||
(1 row)
|
||||
|
||||
--
|
||||
-- test PERFORM
|
||||
--
|
||||
create table perform_test (
|
||||
a INT,
|
||||
b INT
|
||||
);
|
||||
create function simple_func(int) returns boolean as '
|
||||
BEGIN
|
||||
IF $1 < 20 THEN
|
||||
INSERT INTO perform_test VALUES ($1, $1 + 10);
|
||||
RETURN TRUE;
|
||||
ELSE
|
||||
RETURN FALSE;
|
||||
END IF;
|
||||
END;' language 'plpgsql';
|
||||
create function perform_test_func() returns void as '
|
||||
BEGIN
|
||||
IF FOUND then
|
||||
INSERT INTO perform_test VALUES (100, 100);
|
||||
END IF;
|
||||
|
||||
PERFORM simple_func(5);
|
||||
|
||||
IF FOUND then
|
||||
INSERT INTO perform_test VALUES (100, 100);
|
||||
END IF;
|
||||
|
||||
PERFORM simple_func(50);
|
||||
|
||||
IF FOUND then
|
||||
INSERT INTO perform_test VALUES (100, 100);
|
||||
END IF;
|
||||
|
||||
RETURN;
|
||||
END;' language 'plpgsql';
|
||||
SELECT perform_test_func();
|
||||
perform_test_func
|
||||
-------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT * FROM perform_test;
|
||||
a | b
|
||||
-----+-----
|
||||
5 | 15
|
||||
100 | 100
|
||||
100 | 100
|
||||
(3 rows)
|
||||
|
||||
drop table perform_test;
|
||||
|
@@ -1559,3 +1559,48 @@ END;' language 'plpgsql';
|
||||
|
||||
SELECT * FROM test_ret_rec_dyn(1500) AS (a int, b int, c int);
|
||||
SELECT * FROM test_ret_rec_dyn(5) AS (a int, b numeric, c text);
|
||||
|
||||
--
|
||||
-- test PERFORM
|
||||
--
|
||||
|
||||
create table perform_test (
|
||||
a INT,
|
||||
b INT
|
||||
);
|
||||
|
||||
create function simple_func(int) returns boolean as '
|
||||
BEGIN
|
||||
IF $1 < 20 THEN
|
||||
INSERT INTO perform_test VALUES ($1, $1 + 10);
|
||||
RETURN TRUE;
|
||||
ELSE
|
||||
RETURN FALSE;
|
||||
END IF;
|
||||
END;' language 'plpgsql';
|
||||
|
||||
create function perform_test_func() returns void as '
|
||||
BEGIN
|
||||
IF FOUND then
|
||||
INSERT INTO perform_test VALUES (100, 100);
|
||||
END IF;
|
||||
|
||||
PERFORM simple_func(5);
|
||||
|
||||
IF FOUND then
|
||||
INSERT INTO perform_test VALUES (100, 100);
|
||||
END IF;
|
||||
|
||||
PERFORM simple_func(50);
|
||||
|
||||
IF FOUND then
|
||||
INSERT INTO perform_test VALUES (100, 100);
|
||||
END IF;
|
||||
|
||||
RETURN;
|
||||
END;' language 'plpgsql';
|
||||
|
||||
SELECT perform_test_func();
|
||||
SELECT * FROM perform_test;
|
||||
|
||||
drop table perform_test;
|
Reference in New Issue
Block a user