plpgsql can assign to subscripted variables now, e.g.
x[42] := whatever; The facility is pretty primitive because it doesn't do array slicing and it has the same semantics as array update in SQL (array must already be non-null, etc). But it's a start.
This commit is contained in:
parent
9e29b32e78
commit
2c19928301
|
@ -4,7 +4,7 @@
|
||||||
* procedural language
|
* procedural language
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/gram.y,v 1.40 2002/11/10 00:35:58 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/gram.y,v 1.41 2003/03/25 03:16:40 tgl Exp $
|
||||||
*
|
*
|
||||||
* This software is copyrighted by Jan Wieck - Hamburg.
|
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||||
*
|
*
|
||||||
|
@ -105,7 +105,8 @@ static void check_assignable(PLpgSQL_datum *datum);
|
||||||
%type <nsitem> decl_aliasitem
|
%type <nsitem> decl_aliasitem
|
||||||
%type <str> decl_stmts decl_stmt
|
%type <str> decl_stmts decl_stmt
|
||||||
|
|
||||||
%type <expr> expr_until_semi expr_until_then expr_until_loop
|
%type <expr> expr_until_semi expr_until_rightbracket
|
||||||
|
%type <expr> expr_until_then expr_until_loop
|
||||||
%type <expr> opt_exitcond
|
%type <expr> opt_exitcond
|
||||||
|
|
||||||
%type <ival> assign_var cursor_variable
|
%type <ival> assign_var cursor_variable
|
||||||
|
@ -822,6 +823,21 @@ assign_var : T_VARIABLE
|
||||||
check_assignable(yylval.variable);
|
check_assignable(yylval.variable);
|
||||||
$$ = yylval.variable->dno;
|
$$ = yylval.variable->dno;
|
||||||
}
|
}
|
||||||
|
| assign_var '[' expr_until_rightbracket
|
||||||
|
{
|
||||||
|
PLpgSQL_arrayelem *new;
|
||||||
|
|
||||||
|
new = malloc(sizeof(PLpgSQL_arrayelem));
|
||||||
|
memset(new, 0, sizeof(PLpgSQL_arrayelem));
|
||||||
|
|
||||||
|
new->dtype = PLPGSQL_DTYPE_ARRAYELEM;
|
||||||
|
new->subscript = $3;
|
||||||
|
new->arrayparentno = $1;
|
||||||
|
|
||||||
|
plpgsql_adddatum((PLpgSQL_datum *)new);
|
||||||
|
|
||||||
|
$$ = new->dno;
|
||||||
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
stmt_if : K_IF lno expr_until_then proc_sect stmt_else K_END K_IF ';'
|
stmt_if : K_IF lno expr_until_then proc_sect stmt_else K_END K_IF ';'
|
||||||
|
@ -1491,6 +1507,10 @@ expr_until_semi :
|
||||||
{ $$ = plpgsql_read_expression(';', ";"); }
|
{ $$ = plpgsql_read_expression(';', ";"); }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
expr_until_rightbracket :
|
||||||
|
{ $$ = plpgsql_read_expression(']', "]"); }
|
||||||
|
;
|
||||||
|
|
||||||
expr_until_then :
|
expr_until_then :
|
||||||
{ $$ = plpgsql_read_expression(K_THEN, "THEN"); }
|
{ $$ = plpgsql_read_expression(K_THEN, "THEN"); }
|
||||||
;
|
;
|
||||||
|
@ -1577,16 +1597,16 @@ read_sql_construct(int until,
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
tok = yylex();
|
tok = yylex();
|
||||||
if (tok == '(')
|
if (tok == until && parenlevel == 0)
|
||||||
|
break;
|
||||||
|
if (tok == '(' || tok == '[')
|
||||||
parenlevel++;
|
parenlevel++;
|
||||||
else if (tok == ')')
|
else if (tok == ')' || tok == ']')
|
||||||
{
|
{
|
||||||
parenlevel--;
|
parenlevel--;
|
||||||
if (parenlevel < 0)
|
if (parenlevel < 0)
|
||||||
elog(ERROR, "mismatched parentheses");
|
elog(ERROR, "mismatched parentheses");
|
||||||
}
|
}
|
||||||
else if (parenlevel == 0 && tok == until)
|
|
||||||
break;
|
|
||||||
/*
|
/*
|
||||||
* End of function definition is an error, and we don't expect to
|
* End of function definition is an error, and we don't expect to
|
||||||
* hit a semicolon either (unless it's the until symbol, in which
|
* hit a semicolon either (unless it's the until symbol, in which
|
||||||
|
@ -1988,6 +2008,9 @@ check_assignable(PLpgSQL_datum *datum)
|
||||||
case PLPGSQL_DTYPE_RECFIELD:
|
case PLPGSQL_DTYPE_RECFIELD:
|
||||||
/* always assignable? */
|
/* always assignable? */
|
||||||
break;
|
break;
|
||||||
|
case PLPGSQL_DTYPE_ARRAYELEM:
|
||||||
|
/* always assignable? */
|
||||||
|
break;
|
||||||
case PLPGSQL_DTYPE_TRIGARG:
|
case PLPGSQL_DTYPE_TRIGARG:
|
||||||
yyerror("cannot assign to tg_argv");
|
yyerror("cannot assign to tg_argv");
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
* procedural language
|
* procedural language
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.82 2003/03/25 00:34:23 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.83 2003/03/25 03:16:40 tgl Exp $
|
||||||
*
|
*
|
||||||
* This software is copyrighted by Jan Wieck - Hamburg.
|
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||||
*
|
*
|
||||||
|
@ -49,6 +49,7 @@
|
||||||
#include "optimizer/clauses.h"
|
#include "optimizer/clauses.h"
|
||||||
#include "parser/parse_expr.h"
|
#include "parser/parse_expr.h"
|
||||||
#include "tcop/tcopprot.h"
|
#include "tcop/tcopprot.h"
|
||||||
|
#include "utils/array.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "utils/lsyscache.h"
|
#include "utils/lsyscache.h"
|
||||||
#include "utils/syscache.h"
|
#include "utils/syscache.h"
|
||||||
|
@ -136,6 +137,9 @@ static void exec_eval_datum(PLpgSQL_execstate *estate,
|
||||||
Oid *typeid,
|
Oid *typeid,
|
||||||
Datum *value,
|
Datum *value,
|
||||||
bool *isnull);
|
bool *isnull);
|
||||||
|
static int exec_eval_subscript(PLpgSQL_execstate * estate,
|
||||||
|
PLpgSQL_expr * expr,
|
||||||
|
bool *isNull);
|
||||||
static Datum exec_eval_expr(PLpgSQL_execstate * estate,
|
static Datum exec_eval_expr(PLpgSQL_execstate * estate,
|
||||||
PLpgSQL_expr * expr,
|
PLpgSQL_expr * expr,
|
||||||
bool *isNull,
|
bool *isNull,
|
||||||
|
@ -152,6 +156,9 @@ static Datum exec_cast_value(Datum value, Oid valtype,
|
||||||
Oid reqtypelem,
|
Oid reqtypelem,
|
||||||
int32 reqtypmod,
|
int32 reqtypmod,
|
||||||
bool *isnull);
|
bool *isnull);
|
||||||
|
static Datum exec_simple_cast_value(Datum value, Oid valtype,
|
||||||
|
Oid reqtype, int32 reqtypmod,
|
||||||
|
bool *isnull);
|
||||||
static void exec_init_tuple_store(PLpgSQL_execstate * estate);
|
static void exec_init_tuple_store(PLpgSQL_execstate * estate);
|
||||||
static bool compatible_tupdesc(TupleDesc td1, TupleDesc td2);
|
static bool compatible_tupdesc(TupleDesc td1, TupleDesc td2);
|
||||||
static void exec_set_found(PLpgSQL_execstate * estate, bool state);
|
static void exec_set_found(PLpgSQL_execstate * estate, bool state);
|
||||||
|
@ -237,6 +244,7 @@ plpgsql_exec_function(PLpgSQL_function * func, FunctionCallInfo fcinfo)
|
||||||
|
|
||||||
case PLPGSQL_DTYPE_ROW:
|
case PLPGSQL_DTYPE_ROW:
|
||||||
case PLPGSQL_DTYPE_RECFIELD:
|
case PLPGSQL_DTYPE_RECFIELD:
|
||||||
|
case PLPGSQL_DTYPE_ARRAYELEM:
|
||||||
estate.datums[i] = func->datums[i];
|
estate.datums[i] = func->datums[i];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -308,6 +316,7 @@ plpgsql_exec_function(PLpgSQL_function * func, FunctionCallInfo fcinfo)
|
||||||
case PLPGSQL_DTYPE_ROW:
|
case PLPGSQL_DTYPE_ROW:
|
||||||
case PLPGSQL_DTYPE_REC:
|
case PLPGSQL_DTYPE_REC:
|
||||||
case PLPGSQL_DTYPE_RECFIELD:
|
case PLPGSQL_DTYPE_RECFIELD:
|
||||||
|
case PLPGSQL_DTYPE_ARRAYELEM:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -507,6 +516,7 @@ plpgsql_exec_trigger(PLpgSQL_function * func,
|
||||||
|
|
||||||
case PLPGSQL_DTYPE_ROW:
|
case PLPGSQL_DTYPE_ROW:
|
||||||
case PLPGSQL_DTYPE_RECFIELD:
|
case PLPGSQL_DTYPE_RECFIELD:
|
||||||
|
case PLPGSQL_DTYPE_ARRAYELEM:
|
||||||
case PLPGSQL_DTYPE_TRIGARG:
|
case PLPGSQL_DTYPE_TRIGARG:
|
||||||
estate.datums[i] = func->datums[i];
|
estate.datums[i] = func->datums[i];
|
||||||
break;
|
break;
|
||||||
|
@ -658,6 +668,7 @@ plpgsql_exec_trigger(PLpgSQL_function * func,
|
||||||
case PLPGSQL_DTYPE_ROW:
|
case PLPGSQL_DTYPE_ROW:
|
||||||
case PLPGSQL_DTYPE_REC:
|
case PLPGSQL_DTYPE_REC:
|
||||||
case PLPGSQL_DTYPE_RECFIELD:
|
case PLPGSQL_DTYPE_RECFIELD:
|
||||||
|
case PLPGSQL_DTYPE_ARRAYELEM:
|
||||||
case PLPGSQL_DTYPE_TRIGARG:
|
case PLPGSQL_DTYPE_TRIGARG:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -822,6 +833,7 @@ exec_stmt_block(PLpgSQL_execstate * estate, PLpgSQL_stmt_block * block)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PLPGSQL_DTYPE_RECFIELD:
|
case PLPGSQL_DTYPE_RECFIELD:
|
||||||
|
case PLPGSQL_DTYPE_ARRAYELEM:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -1693,24 +1705,11 @@ exec_stmt_return_next(PLpgSQL_execstate * estate,
|
||||||
&rettype);
|
&rettype);
|
||||||
|
|
||||||
/* coerce type if needed */
|
/* coerce type if needed */
|
||||||
if (!isNull && rettype != tupdesc->attrs[0]->atttypid)
|
retval = exec_simple_cast_value(retval,
|
||||||
{
|
|
||||||
Oid targType = tupdesc->attrs[0]->atttypid;
|
|
||||||
Oid typInput;
|
|
||||||
Oid typElem;
|
|
||||||
FmgrInfo finfo_input;
|
|
||||||
|
|
||||||
getTypeInputInfo(targType, &typInput, &typElem);
|
|
||||||
fmgr_info(typInput, &finfo_input);
|
|
||||||
|
|
||||||
retval = exec_cast_value(retval,
|
|
||||||
rettype,
|
rettype,
|
||||||
targType,
|
tupdesc->attrs[0]->atttypid,
|
||||||
&finfo_input,
|
|
||||||
typElem,
|
|
||||||
tupdesc->attrs[0]->atttypmod,
|
tupdesc->attrs[0]->atttypmod,
|
||||||
&isNull);
|
&isNull);
|
||||||
}
|
|
||||||
|
|
||||||
nullflag = isNull ? 'n' : ' ';
|
nullflag = isNull ? 'n' : ' ';
|
||||||
|
|
||||||
|
@ -2709,10 +2708,21 @@ exec_assign_value(PLpgSQL_execstate * estate,
|
||||||
bool attisnull;
|
bool attisnull;
|
||||||
Oid atttype;
|
Oid atttype;
|
||||||
int32 atttypmod;
|
int32 atttypmod;
|
||||||
|
int nsubscripts;
|
||||||
|
PLpgSQL_expr *subscripts[MAXDIM];
|
||||||
|
int subscriptvals[MAXDIM];
|
||||||
|
bool havenullsubscript,
|
||||||
|
oldarrayisnull;
|
||||||
|
Oid arraytypeid,
|
||||||
|
arrayelemtypeid,
|
||||||
|
arrayInputFn;
|
||||||
|
int16 elemtyplen;
|
||||||
|
bool elemtypbyval;
|
||||||
|
char elemtypalign;
|
||||||
|
Datum oldarrayval,
|
||||||
|
coerced_value;
|
||||||
|
ArrayType *newarrayval;
|
||||||
HeapTuple newtup;
|
HeapTuple newtup;
|
||||||
Oid typInput;
|
|
||||||
Oid typElem;
|
|
||||||
FmgrInfo finfo_input;
|
|
||||||
|
|
||||||
switch (target->dtype)
|
switch (target->dtype)
|
||||||
{
|
{
|
||||||
|
@ -2812,15 +2822,10 @@ exec_assign_value(PLpgSQL_execstate * estate,
|
||||||
*/
|
*/
|
||||||
atttype = SPI_gettypeid(rec->tupdesc, fno + 1);
|
atttype = SPI_gettypeid(rec->tupdesc, fno + 1);
|
||||||
atttypmod = rec->tupdesc->attrs[fno]->atttypmod;
|
atttypmod = rec->tupdesc->attrs[fno]->atttypmod;
|
||||||
getTypeInputInfo(atttype, &typInput, &typElem);
|
|
||||||
fmgr_info(typInput, &finfo_input);
|
|
||||||
|
|
||||||
attisnull = *isNull;
|
attisnull = *isNull;
|
||||||
values[fno] = exec_cast_value(value,
|
values[fno] = exec_simple_cast_value(value,
|
||||||
valtype,
|
valtype,
|
||||||
atttype,
|
atttype,
|
||||||
&finfo_input,
|
|
||||||
typElem,
|
|
||||||
atttypmod,
|
atttypmod,
|
||||||
&attisnull);
|
&attisnull);
|
||||||
if (attisnull)
|
if (attisnull)
|
||||||
|
@ -2829,7 +2834,7 @@ exec_assign_value(PLpgSQL_execstate * estate,
|
||||||
nulls[fno] = ' ';
|
nulls[fno] = ' ';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Avoid leaking the result of exec_cast_value, if it
|
* Avoid leaking the result of exec_simple_cast_value, if it
|
||||||
* performed a conversion to a pass-by-ref type.
|
* performed a conversion to a pass-by-ref type.
|
||||||
*/
|
*/
|
||||||
if (!attisnull && values[fno] != value && !get_typbyval(atttype))
|
if (!attisnull && values[fno] != value && !get_typbyval(atttype))
|
||||||
|
@ -2856,6 +2861,103 @@ exec_assign_value(PLpgSQL_execstate * estate,
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PLPGSQL_DTYPE_ARRAYELEM:
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Target is an element of an array
|
||||||
|
*
|
||||||
|
* To handle constructs like x[1][2] := something, we have to
|
||||||
|
* be prepared to deal with a chain of arrayelem datums.
|
||||||
|
* Chase back to find the base array datum, and save the
|
||||||
|
* subscript expressions as we go. (We are scanning right to
|
||||||
|
* left here, but want to evaluate the subscripts left-to-right
|
||||||
|
* to minimize surprises.)
|
||||||
|
*/
|
||||||
|
nsubscripts = 0;
|
||||||
|
do {
|
||||||
|
PLpgSQL_arrayelem *arrayelem = (PLpgSQL_arrayelem *) target;
|
||||||
|
|
||||||
|
if (nsubscripts >= MAXDIM)
|
||||||
|
elog(ERROR, "Too many subscripts");
|
||||||
|
subscripts[nsubscripts++] = arrayelem->subscript;
|
||||||
|
target = estate->datums[arrayelem->arrayparentno];
|
||||||
|
} while (target->dtype == PLPGSQL_DTYPE_ARRAYELEM);
|
||||||
|
|
||||||
|
/* Fetch current value of array datum */
|
||||||
|
exec_eval_datum(estate, target, InvalidOid,
|
||||||
|
&arraytypeid, &oldarrayval, &oldarrayisnull);
|
||||||
|
|
||||||
|
getTypeInputInfo(arraytypeid, &arrayInputFn, &arrayelemtypeid);
|
||||||
|
if (!OidIsValid(arrayelemtypeid))
|
||||||
|
elog(ERROR, "Subscripted item is not an array");
|
||||||
|
|
||||||
|
/* Evaluate the subscripts, switch into left-to-right order */
|
||||||
|
havenullsubscript = false;
|
||||||
|
for (i = 0; i < nsubscripts; i++)
|
||||||
|
{
|
||||||
|
bool subisnull;
|
||||||
|
|
||||||
|
subscriptvals[i] =
|
||||||
|
exec_eval_subscript(estate,
|
||||||
|
subscripts[nsubscripts-1-i],
|
||||||
|
&subisnull);
|
||||||
|
havenullsubscript |= subisnull;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Skip the assignment if we have any nulls, either in the
|
||||||
|
* original array value, the subscripts, or the righthand side.
|
||||||
|
* This is pretty bogus but it corresponds to the current
|
||||||
|
* behavior of ExecEvalArrayRef().
|
||||||
|
*/
|
||||||
|
if (oldarrayisnull || havenullsubscript || *isNull)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Coerce source value to match array element type. */
|
||||||
|
coerced_value = exec_simple_cast_value(value,
|
||||||
|
valtype,
|
||||||
|
arrayelemtypeid,
|
||||||
|
-1,
|
||||||
|
isNull);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Build the modified array value.
|
||||||
|
*/
|
||||||
|
get_typlenbyvalalign(arrayelemtypeid,
|
||||||
|
&elemtyplen,
|
||||||
|
&elemtypbyval,
|
||||||
|
&elemtypalign);
|
||||||
|
|
||||||
|
newarrayval = array_set((ArrayType *) DatumGetPointer(oldarrayval),
|
||||||
|
nsubscripts,
|
||||||
|
subscriptvals,
|
||||||
|
coerced_value,
|
||||||
|
get_typlen(arraytypeid),
|
||||||
|
elemtyplen,
|
||||||
|
elemtypbyval,
|
||||||
|
elemtypalign,
|
||||||
|
isNull);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Assign it to the base variable.
|
||||||
|
*/
|
||||||
|
exec_assign_value(estate, target,
|
||||||
|
PointerGetDatum(newarrayval),
|
||||||
|
arraytypeid, isNull);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Avoid leaking the result of exec_simple_cast_value, if it
|
||||||
|
* performed a conversion to a pass-by-ref type.
|
||||||
|
*/
|
||||||
|
if (!*isNull && coerced_value != value && !elemtypbyval)
|
||||||
|
pfree(DatumGetPointer(coerced_value));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Avoid leaking the modified array value, too.
|
||||||
|
*/
|
||||||
|
pfree(newarrayval);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
elog(ERROR, "unknown dtype %d in exec_assign_value()",
|
elog(ERROR, "unknown dtype %d in exec_assign_value()",
|
||||||
target->dtype);
|
target->dtype);
|
||||||
|
@ -2888,7 +2990,6 @@ exec_eval_datum(PLpgSQL_execstate *estate,
|
||||||
PLpgSQL_recfield *recfield;
|
PLpgSQL_recfield *recfield;
|
||||||
PLpgSQL_trigarg *trigarg;
|
PLpgSQL_trigarg *trigarg;
|
||||||
int tgargno;
|
int tgargno;
|
||||||
Oid tgargoid;
|
|
||||||
int fno;
|
int fno;
|
||||||
|
|
||||||
switch (datum->dtype)
|
switch (datum->dtype)
|
||||||
|
@ -2922,9 +3023,7 @@ exec_eval_datum(PLpgSQL_execstate *estate,
|
||||||
case PLPGSQL_DTYPE_TRIGARG:
|
case PLPGSQL_DTYPE_TRIGARG:
|
||||||
trigarg = (PLpgSQL_trigarg *) datum;
|
trigarg = (PLpgSQL_trigarg *) datum;
|
||||||
*typeid = TEXTOID;
|
*typeid = TEXTOID;
|
||||||
tgargno = (int) exec_eval_expr(estate, trigarg->argnum,
|
tgargno = exec_eval_subscript(estate, trigarg->argnum, isnull);
|
||||||
isnull, &tgargoid);
|
|
||||||
exec_eval_cleanup(estate);
|
|
||||||
if (*isnull || tgargno < 0 || tgargno >= estate->trig_nargs)
|
if (*isnull || tgargno < 0 || tgargno >= estate->trig_nargs)
|
||||||
{
|
{
|
||||||
*value = (Datum) 0;
|
*value = (Datum) 0;
|
||||||
|
@ -2946,6 +3045,36 @@ exec_eval_datum(PLpgSQL_execstate *estate,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ----------
|
||||||
|
* exec_eval_subscript Hack to allow subscripting of result variables.
|
||||||
|
*
|
||||||
|
* The caller may already have an open eval_econtext, which we have to
|
||||||
|
* save and restore around the call of exec_eval_expr.
|
||||||
|
* ----------
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
exec_eval_subscript(PLpgSQL_execstate * estate,
|
||||||
|
PLpgSQL_expr * expr,
|
||||||
|
bool *isNull)
|
||||||
|
{
|
||||||
|
ExprContext *save_econtext;
|
||||||
|
Datum subscriptdatum;
|
||||||
|
Oid subscripttypeid;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
save_econtext = estate->eval_econtext;
|
||||||
|
estate->eval_econtext = NULL;
|
||||||
|
subscriptdatum = exec_eval_expr(estate, expr, isNull, &subscripttypeid);
|
||||||
|
subscriptdatum = exec_simple_cast_value(subscriptdatum,
|
||||||
|
subscripttypeid,
|
||||||
|
INT4OID, -1,
|
||||||
|
isNull);
|
||||||
|
result = DatumGetInt32(subscriptdatum);
|
||||||
|
exec_eval_cleanup(estate);
|
||||||
|
estate->eval_econtext = save_econtext;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* exec_eval_expr Evaluate an expression and return
|
* exec_eval_expr Evaluate an expression and return
|
||||||
* the result Datum.
|
* the result Datum.
|
||||||
|
@ -3323,6 +3452,43 @@ exec_cast_value(Datum value, Oid valtype,
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ----------
|
||||||
|
* exec_simple_cast_value Cast a value if required
|
||||||
|
*
|
||||||
|
* As above, but need not supply details about target type. Note that this
|
||||||
|
* is slower than exec_cast_value with cached type info, and so should be
|
||||||
|
* avoided in heavily used code paths.
|
||||||
|
* ----------
|
||||||
|
*/
|
||||||
|
static Datum
|
||||||
|
exec_simple_cast_value(Datum value, Oid valtype,
|
||||||
|
Oid reqtype, int32 reqtypmod,
|
||||||
|
bool *isnull)
|
||||||
|
{
|
||||||
|
if (!*isnull)
|
||||||
|
{
|
||||||
|
if (valtype != reqtype || reqtypmod != -1)
|
||||||
|
{
|
||||||
|
Oid typInput;
|
||||||
|
Oid typElem;
|
||||||
|
FmgrInfo finfo_input;
|
||||||
|
|
||||||
|
getTypeInputInfo(reqtype, &typInput, &typElem);
|
||||||
|
fmgr_info(typInput, &finfo_input);
|
||||||
|
|
||||||
|
value = exec_cast_value(value,
|
||||||
|
valtype,
|
||||||
|
reqtype,
|
||||||
|
&finfo_input,
|
||||||
|
typElem,
|
||||||
|
reqtypmod,
|
||||||
|
isnull);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* exec_simple_check_node - Recursively check if an expression
|
* exec_simple_check_node - Recursively check if an expression
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
* procedural language
|
* procedural language
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.24 2003/03/25 00:34:23 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.25 2003/03/25 03:16:41 tgl Exp $
|
||||||
*
|
*
|
||||||
* This software is copyrighted by Jan Wieck - Hamburg.
|
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||||
*
|
*
|
||||||
|
@ -1023,6 +1023,12 @@ plpgsql_dumptree(PLpgSQL_function * func)
|
||||||
((PLpgSQL_recfield *) d)->fieldname,
|
((PLpgSQL_recfield *) d)->fieldname,
|
||||||
((PLpgSQL_recfield *) d)->recparentno);
|
((PLpgSQL_recfield *) d)->recparentno);
|
||||||
break;
|
break;
|
||||||
|
case PLPGSQL_DTYPE_ARRAYELEM:
|
||||||
|
printf("ARRAYELEM of VAR %d subscript ",
|
||||||
|
((PLpgSQL_arrayelem *) d)->arrayparentno);
|
||||||
|
dump_expr(((PLpgSQL_arrayelem *) d)->subscript);
|
||||||
|
printf("\n");
|
||||||
|
break;
|
||||||
case PLPGSQL_DTYPE_TRIGARG:
|
case PLPGSQL_DTYPE_TRIGARG:
|
||||||
printf("TRIGARG ");
|
printf("TRIGARG ");
|
||||||
dump_expr(((PLpgSQL_trigarg *) d)->argnum);
|
dump_expr(((PLpgSQL_trigarg *) d)->argnum);
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
* procedural language
|
* procedural language
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.32 2003/03/25 00:34:24 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.33 2003/03/25 03:16:41 tgl Exp $
|
||||||
*
|
*
|
||||||
* This software is copyrighted by Jan Wieck - Hamburg.
|
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||||
*
|
*
|
||||||
|
@ -72,6 +72,7 @@ enum
|
||||||
PLPGSQL_DTYPE_ROW,
|
PLPGSQL_DTYPE_ROW,
|
||||||
PLPGSQL_DTYPE_REC,
|
PLPGSQL_DTYPE_REC,
|
||||||
PLPGSQL_DTYPE_RECFIELD,
|
PLPGSQL_DTYPE_RECFIELD,
|
||||||
|
PLPGSQL_DTYPE_ARRAYELEM,
|
||||||
PLPGSQL_DTYPE_EXPR,
|
PLPGSQL_DTYPE_EXPR,
|
||||||
PLPGSQL_DTYPE_TRIGARG
|
PLPGSQL_DTYPE_TRIGARG
|
||||||
};
|
};
|
||||||
|
@ -154,7 +155,8 @@ typedef struct
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* PLpgSQL_datum is the common supertype for PLpgSQL_expr, PLpgSQL_var,
|
* PLpgSQL_datum is the common supertype for PLpgSQL_expr, PLpgSQL_var,
|
||||||
* PLpgSQL_row, PLpgSQL_rec, PLpgSQL_recfield, PLpgSQL_trigarg
|
* PLpgSQL_row, PLpgSQL_rec, PLpgSQL_recfield, PLpgSQL_arrayelem, and
|
||||||
|
* PLpgSQL_trigarg
|
||||||
*/
|
*/
|
||||||
typedef struct
|
typedef struct
|
||||||
{ /* Generic datum array item */
|
{ /* Generic datum array item */
|
||||||
|
@ -231,10 +233,19 @@ typedef struct
|
||||||
int dtype;
|
int dtype;
|
||||||
int rfno;
|
int rfno;
|
||||||
char *fieldname;
|
char *fieldname;
|
||||||
int recparentno; /* recno of parent record */
|
int recparentno; /* dno of parent record */
|
||||||
} PLpgSQL_recfield;
|
} PLpgSQL_recfield;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{ /* Element of array variable */
|
||||||
|
int dtype;
|
||||||
|
int dno;
|
||||||
|
PLpgSQL_expr *subscript;
|
||||||
|
int arrayparentno; /* dno of parent array variable */
|
||||||
|
} PLpgSQL_arrayelem;
|
||||||
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{ /* Positional argument to trigger */
|
{ /* Positional argument to trigger */
|
||||||
int dtype;
|
int dtype;
|
||||||
|
|
Loading…
Reference in New Issue