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
2848dc5f
Commit
2848dc5f
authored
Sep 25, 2003
by
Tom Lane
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Make the world safe (more or less) for dropped columns in plpgsql rowtypes.
parent
a039148c
Changes
7
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
263 additions
and
200 deletions
+263
-200
src/backend/executor/execQual.c
src/backend/executor/execQual.c
+35
-23
src/backend/executor/nodeFunctionscan.c
src/backend/executor/nodeFunctionscan.c
+27
-18
src/pl/plpgsql/src/gram.y
src/pl/plpgsql/src/gram.y
+8
-39
src/pl/plpgsql/src/pl_comp.c
src/pl/plpgsql/src/pl_comp.c
+83
-70
src/pl/plpgsql/src/pl_exec.c
src/pl/plpgsql/src/pl_exec.c
+90
-38
src/pl/plpgsql/src/pl_funcs.c
src/pl/plpgsql/src/pl_funcs.c
+10
-10
src/pl/plpgsql/src/plpgsql.h
src/pl/plpgsql/src/plpgsql.h
+10
-2
No files found.
src/backend/executor/execQual.c
View file @
2848dc5f
...
...
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.14
5 2003/09/25 06:57:59 petere
Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.14
6 2003/09/25 23:02:11 tgl
Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -315,23 +315,6 @@ ExecEvalAggref(AggrefExprState *aggref, ExprContext *econtext, bool *isNull)
*
* Returns a Datum whose value is the value of a range
* variable with respect to given expression context.
*
*
* As an entry condition, we expect that the datatype the
* plan expects to get (as told by our "variable" argument) is in
* fact the datatype of the attribute the plan says to fetch (as
* seen in the current context, identified by our "econtext"
* argument).
*
* If we fetch a Type A attribute and Caller treats it as if it
* were Type B, there will be undefined results (e.g. crash).
* One way these might mismatch now is that we're accessing a
* catalog class and the type information in the pg_attribute
* class does not match the hardcoded pg_attribute information
* (in pg_attribute.h) for the class in question.
*
* We have an Assert to make sure this entry condition is met.
*
* ---------------------------------------------------------------- */
static
Datum
ExecEvalVar
(
Var
*
variable
,
ExprContext
*
econtext
,
bool
*
isNull
)
...
...
@@ -369,11 +352,40 @@ ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull)
attnum
=
variable
->
varattno
;
/* (See prolog for explanation of this Assert) */
Assert
(
attnum
<=
0
||
(
attnum
-
1
<=
tuple_type
->
natts
-
1
&&
tuple_type
->
attrs
[
attnum
-
1
]
!=
NULL
&&
variable
->
vartype
==
tuple_type
->
attrs
[
attnum
-
1
]
->
atttypid
));
/*
* Some checks that are only applied for user attribute numbers
* (bogus system attnums will be caught inside heap_getattr).
*/
if
(
attnum
>
0
)
{
/*
* This assert checks that the attnum is valid.
*/
Assert
(
attnum
<=
tuple_type
->
natts
&&
tuple_type
->
attrs
[
attnum
-
1
]
!=
NULL
);
/*
* If the attribute's column has been dropped, we force a NULL result.
* This case should not happen in normal use, but it could happen if
* we are executing a plan cached before the column was dropped.
*/
if
(
tuple_type
->
attrs
[
attnum
-
1
]
->
attisdropped
)
{
*
isNull
=
true
;
return
(
Datum
)
0
;
}
/*
* This assert checks that the datatype the plan expects to get (as
* told by our "variable" argument) is in fact the datatype of the
* attribute being fetched (as seen in the current context, identified
* by our "econtext" argument). Otherwise crashes are likely.
*
* Note that we can't check dropped columns, since their atttypid
* has been zeroed.
*/
Assert
(
variable
->
vartype
==
tuple_type
->
attrs
[
attnum
-
1
]
->
atttypid
);
}
/*
* If the attribute number is invalid, then we are supposed to return
...
...
src/backend/executor/nodeFunctionscan.c
View file @
2848dc5f
...
...
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeFunctionscan.c,v 1.2
1 2003/09/25 06:57:59 petere
Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeFunctionscan.c,v 1.2
2 2003/09/25 23:02:12 tgl
Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -35,7 +35,7 @@
static
TupleTableSlot
*
FunctionNext
(
FunctionScanState
*
node
);
static
bool
tupledesc_m
ismatch
(
TupleDesc
tupdesc1
,
TupleDesc
tupdesc2
);
static
bool
tupledesc_m
atch
(
TupleDesc
dst_tupdesc
,
TupleDesc
src_tupdesc
);
/* ----------------------------------------------------------------
* Scan Support
...
...
@@ -86,8 +86,7 @@ FunctionNext(FunctionScanState *node)
* need to do this for functions returning RECORD, but might as
* well do it always.
*/
if
(
funcTupdesc
&&
tupledesc_mismatch
(
node
->
tupdesc
,
funcTupdesc
))
if
(
funcTupdesc
&&
!
tupledesc_match
(
node
->
tupdesc
,
funcTupdesc
))
ereport
(
ERROR
,
(
errcode
(
ERRCODE_DATATYPE_MISMATCH
),
errmsg
(
"query-specified return row and actual function return row do not match"
)));
...
...
@@ -364,26 +363,36 @@ ExecFunctionReScan(FunctionScanState *node, ExprContext *exprCtxt)
tuplestore_rescan
(
node
->
tuplestorestate
);
}
/*
* Check that function result tuple type (src_tupdesc) matches or can be
* considered to match what the query expects (dst_tupdesc).
*
* We really only care about number of attributes and data type.
* Also, we can ignore type mismatch on columns that are dropped in the
* destination type, so long as the physical storage matches. This is
* helpful in some cases involving out-of-date cached plans.
*/
static
bool
tupledesc_m
ismatch
(
TupleDesc
tupdesc1
,
TupleDesc
tupdesc2
)
tupledesc_m
atch
(
TupleDesc
dst_tupdesc
,
TupleDesc
src_tupdesc
)
{
int
i
;
if
(
tupdesc1
->
natts
!=
tupdesc2
->
natts
)
return
tru
e
;
if
(
dst_tupdesc
->
natts
!=
src_tupdesc
->
natts
)
return
fals
e
;
for
(
i
=
0
;
i
<
tupdesc1
->
natts
;
i
++
)
for
(
i
=
0
;
i
<
dst_tupdesc
->
natts
;
i
++
)
{
Form_pg_attribute
attr1
=
tupdesc1
->
attrs
[
i
];
Form_pg_attribute
attr2
=
tupdesc2
->
attrs
[
i
];
Form_pg_attribute
dattr
=
dst_tupdesc
->
attrs
[
i
];
Form_pg_attribute
sattr
=
src_tupdesc
->
attrs
[
i
];
/*
* We really only care about number of attributes and data type
*/
if
(
attr1
->
atttypid
!=
attr2
->
atttypid
)
return
true
;
if
(
dattr
->
atttypid
==
sattr
->
atttypid
)
continue
;
/* no worries */
if
(
!
dattr
->
attisdropped
)
return
false
;
if
(
dattr
->
attlen
!=
sattr
->
attlen
||
dattr
->
attalign
!=
sattr
->
attalign
)
return
false
;
}
return
fals
e
;
return
tru
e
;
}
src/pl/plpgsql/src/gram.y
View file @
2848dc5f
...
...
@@ -4,7 +4,7 @@
* procedural language
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/gram.y,v 1.4
6 2003/07/27 21:49:54
tgl Exp $
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/gram.y,v 1.4
7 2003/09/25 23:02:12
tgl Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
...
...
@@ -47,7 +47,6 @@ static PLpgSQL_expr *read_sql_stmt(const char *sqlstart);
static PLpgSQL_type *read_datatype(int tok);
static PLpgSQL_stmt *make_select_stmt(void);
static PLpgSQL_stmt *make_fetch_stmt(void);
static PLpgSQL_expr *make_tupret_expr(PLpgSQL_row *row);
static void check_assignable(PLpgSQL_datum *datum);
%}
...
...
@@ -493,7 +492,7 @@ decl_cursor_arglist : decl_cursor_arg
new->dtype = PLPGSQL_DTYPE_ROW;
new->refname = strdup("*internal*");
new->lineno = plpgsql_scanner_lineno();
new->rowt
ypeclass = InvalidOid
;
new->rowt
updesc = NULL
;
/*
* We make temporary fieldnames/varnos arrays that
* are much bigger than necessary. We will resize
...
...
@@ -1176,24 +1175,24 @@ stmt_return : K_RETURN lno
new = malloc(sizeof(PLpgSQL_stmt_return));
memset(new, 0, sizeof(PLpgSQL_stmt_return));
new->expr = NULL;
new->retrecno = -1;
new->retrowno = -1;
if (plpgsql_curr_compile->fn_retistuple &&
!plpgsql_curr_compile->fn_retset)
{
new->retrecno = -1;
switch (yylex())
{
case K_NULL:
new->expr = NULL;
break;
case T_ROW:
new->
expr = make_tupret_expr(yylval.row)
;
new->
retrowno = yylval.row->rowno
;
break;
case T_RECORD:
new->retrecno = yylval.rec->recno;
new->expr = NULL;
break;
default:
...
...
@@ -1874,7 +1873,7 @@ make_select_stmt(void)
row->dtype = PLPGSQL_DTYPE_ROW;
row->refname = strdup("*internal*");
row->lineno = plpgsql_scanner_lineno();
row->rowt
ypeclass = InvalidOid
;
row->rowt
updesc = NULL
;
row->nfields = nfields;
row->fieldnames = malloc(sizeof(char *) * nfields);
row->varnos = malloc(sizeof(int) * nfields);
...
...
@@ -2007,7 +2006,7 @@ make_fetch_stmt(void)
row->dtype = PLPGSQL_DTYPE_ROW;
row->refname = strdup("*internal*");
row->lineno = plpgsql_scanner_lineno();
row->rowt
ypeclass = InvalidOid
;
row->rowt
updesc = NULL
;
row->nfields = nfields;
row->fieldnames = malloc(sizeof(char *) * nfields);
row->varnos = malloc(sizeof(int) * nfields);
...
...
@@ -2041,36 +2040,6 @@ make_fetch_stmt(void)
}
static PLpgSQL_expr *
make_tupret_expr(PLpgSQL_row *row)
{
PLpgSQL_dstring ds;
PLpgSQL_expr *expr;
int i;
char buf[16];
expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * (row->nfields - 1));
expr->dtype = PLPGSQL_DTYPE_EXPR;
plpgsql_dstring_init(&ds);
plpgsql_dstring_append(&ds, "SELECT ");
for (i = 0; i < row->nfields; i++)
{
sprintf(buf, "%s$%d", (i > 0) ? "," : "", i + 1);
plpgsql_dstring_append(&ds, buf);
expr->params[i] = row->varnos[i];
}
expr->query = strdup(plpgsql_dstring_get(&ds));
expr->plan = NULL;
expr->plan_argtypes = NULL;
expr->nparams = row->nfields;
plpgsql_dstring_free(&ds);
return expr;
}
static void
check_assignable(PLpgSQL_datum *datum)
{
...
...
src/pl/plpgsql/src/pl_comp.c
View file @
2848dc5f
...
...
@@ -3,7 +3,7 @@
* procedural language
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.6
7 2003/08/18 19:16:0
2 tgl Exp $
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.6
8 2003/09/25 23:02:1
2 tgl Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
...
...
@@ -899,7 +899,8 @@ plpgsql_parse_dblword(char *word)
row
=
(
PLpgSQL_row
*
)
(
plpgsql_Datums
[
ns
->
itemno
]);
for
(
i
=
0
;
i
<
row
->
nfields
;
i
++
)
{
if
(
strcmp
(
row
->
fieldnames
[
i
],
cp
[
1
])
==
0
)
if
(
row
->
fieldnames
[
i
]
&&
strcmp
(
row
->
fieldnames
[
i
],
cp
[
1
])
==
0
)
{
plpgsql_yylval
.
var
=
(
PLpgSQL_var
*
)
(
plpgsql_Datums
[
row
->
varnos
[
i
]]);
pfree
(
cp
[
0
]);
...
...
@@ -1005,7 +1006,8 @@ plpgsql_parse_tripword(char *word)
row
=
(
PLpgSQL_row
*
)
(
plpgsql_Datums
[
ns
->
itemno
]);
for
(
i
=
0
;
i
<
row
->
nfields
;
i
++
)
{
if
(
strcmp
(
row
->
fieldnames
[
i
],
cp
[
2
])
==
0
)
if
(
row
->
fieldnames
[
i
]
&&
strcmp
(
row
->
fieldnames
[
i
],
cp
[
2
])
==
0
)
{
plpgsql_yylval
.
var
=
(
PLpgSQL_var
*
)
(
plpgsql_Datums
[
row
->
varnos
[
i
]]);
pfree
(
cp
[
0
]);
...
...
@@ -1396,6 +1398,8 @@ plpgsql_parse_wordrowtype(char *word)
*/
plpgsql_yylval
.
row
=
plpgsql_build_rowtype
(
classOid
);
plpgsql_adddatum
((
PLpgSQL_datum
*
)
plpgsql_yylval
.
row
);
pfree
(
cp
[
0
]);
pfree
(
cp
[
1
]);
...
...
@@ -1439,6 +1443,8 @@ plpgsql_parse_dblwordrowtype(char *word)
*/
plpgsql_yylval
.
row
=
plpgsql_build_rowtype
(
classOid
);
plpgsql_adddatum
((
PLpgSQL_datum
*
)
plpgsql_yylval
.
row
);
pfree
(
cp
);
return
T_ROW
;
...
...
@@ -1451,23 +1457,20 @@ PLpgSQL_row *
plpgsql_build_rowtype
(
Oid
classOid
)
{
PLpgSQL_row
*
row
;
HeapTuple
classtup
;
Relation
rel
;
Form_pg_class
classStruct
;
const
char
*
relname
;
int
i
;
MemoryContext
oldcxt
;
/*
*
Fetch the pg_class tuple
.
*
Open the relation to get info
.
*/
classtup
=
SearchSysCache
(
RELOID
,
ObjectIdGetDatum
(
classOid
),
0
,
0
,
0
);
if
(
!
HeapTupleIsValid
(
classtup
))
elog
(
ERROR
,
"cache lookup failed for relation %u"
,
classOid
);
classStruct
=
(
Form_pg_class
)
GETSTRUCT
(
classtup
);
relname
=
NameStr
(
classStruct
->
relname
);
rel
=
heap_open
(
classOid
,
AccessShareLock
);
classStruct
=
RelationGetForm
(
rel
);
relname
=
RelationGetRelationName
(
rel
);
/* accept relation, sequence, view, or
type pg_class
entries */
/* accept relation, sequence, view, or
composite type
entries */
if
(
classStruct
->
relkind
!=
RELKIND_RELATION
&&
classStruct
->
relkind
!=
RELKIND_SEQUENCE
&&
classStruct
->
relkind
!=
RELKIND_VIEW
&&
...
...
@@ -1484,30 +1487,34 @@ plpgsql_build_rowtype(Oid classOid)
memset
(
row
,
0
,
sizeof
(
PLpgSQL_row
));
row
->
dtype
=
PLPGSQL_DTYPE_ROW
;
/*
* This is a bit ugly --- need a permanent copy of the rel's tupdesc.
* Someday all these mallocs should go away in favor of a per-function
* memory context ...
*/
oldcxt
=
MemoryContextSwitchTo
(
TopMemoryContext
);
row
->
rowtupdesc
=
CreateTupleDescCopy
(
RelationGetDescr
(
rel
));
MemoryContextSwitchTo
(
oldcxt
);
row
->
nfields
=
classStruct
->
relnatts
;
row
->
rowtypeclass
=
classStruct
->
reltype
;
row
->
fieldnames
=
malloc
(
sizeof
(
char
*
)
*
row
->
nfields
);
row
->
varnos
=
malloc
(
sizeof
(
int
)
*
row
->
nfields
);
for
(
i
=
0
;
i
<
row
->
nfields
;
i
++
)
{
HeapTuple
attrtup
;
Form_pg_attribute
attrStruct
;
HeapTuple
typetup
;
const
char
*
attname
;
PLpgSQL_var
*
var
;
/*
* Get the attribute and
it's type
* Get the attribute and
check for dropped column
*/
attrtup
=
SearchSysCache
(
ATTNUM
,
ObjectIdGetDatum
(
classOid
),
Int16GetDatum
(
i
+
1
),
0
,
0
);
if
(
!
HeapTupleIsValid
(
attrtup
))
elog
(
ERROR
,
"cache lookup failed for attribute %d of relation %u"
,
i
+
1
,
classOid
);
attrStruct
=
(
Form_pg_attribute
)
GETSTRUCT
(
attrtup
);
attrStruct
=
RelationGetDescr
(
rel
)
->
attrs
[
i
];
if
(
!
attrStruct
->
attisdropped
)
{
const
char
*
attname
;
HeapTuple
typetup
;
PLpgSQL_var
*
var
;
attname
=
NameStr
(
attrStruct
->
attname
);
...
...
@@ -1519,17 +1526,17 @@ plpgsql_build_rowtype(Oid classOid)
attrStruct
->
atttypid
);
/*
* Create the internal variable
* Create the internal variable for the field
*
* We know if the table definitions contain a default value or if the
* field is declared in the table as NOT NULL. But it's possible
* to create a table field as NOT NULL without a default value and
* that would lead to problems later when initializing the
* variables due to entering a block at execution time. Thus we
*
ignore this information for now.
* We know if the table definitions contain a default value or if
* the field is declared in the table as NOT NULL. But it's
* possible to create a table field as NOT NULL without a default
* value and that would lead to problems later when initializing
* the variables due to entering a block at execution time. Thus
* we
ignore this information for now.
*/
var
=
malloc
(
sizeof
(
PLpgSQL_var
));
mems
et
(
var
,
0
,
sizeof
(
PLpgSQL_var
));
MemS
et
(
var
,
0
,
sizeof
(
PLpgSQL_var
));
var
->
dtype
=
PLPGSQL_DTYPE_VAR
;
var
->
refname
=
malloc
(
strlen
(
relname
)
+
strlen
(
attname
)
+
2
);
strcpy
(
var
->
refname
,
relname
);
...
...
@@ -1552,10 +1559,16 @@ plpgsql_build_rowtype(Oid classOid)
row
->
varnos
[
i
]
=
var
->
varno
;
ReleaseSysCache
(
typetup
);
ReleaseSysCache
(
attrtup
);
}
else
{
/* Leave a hole in the row structure for the dropped col */
row
->
fieldnames
[
i
]
=
NULL
;
row
->
varnos
[
i
]
=
-
1
;
}
}
ReleaseSysCache
(
classtup
);
heap_close
(
rel
,
AccessShareLock
);
return
row
;
}
...
...
src/pl/plpgsql/src/pl_exec.c
View file @
2848dc5f
...
...
@@ -3,7 +3,7 @@
* procedural language
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.9
0 2003/08/04 00:43:33 momjian
Exp $
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.9
1 2003/09/25 23:02:12 tgl
Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
...
...
@@ -148,6 +148,9 @@ static void exec_move_row(PLpgSQL_execstate * estate,
PLpgSQL_rec
*
rec
,
PLpgSQL_row
*
row
,
HeapTuple
tup
,
TupleDesc
tupdesc
);
static
HeapTuple
make_tuple_from_row
(
PLpgSQL_execstate
*
estate
,
PLpgSQL_row
*
row
,
TupleDesc
tupdesc
);
static
Datum
exec_cast_value
(
Datum
value
,
Oid
valtype
,
Oid
reqtype
,
FmgrInfo
*
reqinput
,
...
...
@@ -1574,6 +1577,22 @@ exec_stmt_return(PLpgSQL_execstate * estate, PLpgSQL_stmt_return * stmt)
return
PLPGSQL_RC_RETURN
;
}
if
(
stmt
->
retrowno
>=
0
)
{
PLpgSQL_row
*
row
=
(
PLpgSQL_row
*
)
(
estate
->
datums
[
stmt
->
retrowno
]);
if
(
row
->
rowtupdesc
)
/* should always be true here */
{
estate
->
retval
=
(
Datum
)
make_tuple_from_row
(
estate
,
row
,
row
->
rowtupdesc
);
if
(
estate
->
retval
==
(
Datum
)
NULL
)
/* should not happen */
elog
(
ERROR
,
"row not compatible with its own tupdesc"
);
estate
->
rettupdesc
=
row
->
rowtupdesc
;
estate
->
retisnull
=
false
;
}
return
PLPGSQL_RC_RETURN
;
}
if
(
stmt
->
expr
!=
NULL
)
{
exec_run_select
(
estate
,
stmt
->
expr
,
1
,
NULL
);
...
...
@@ -1650,37 +1669,11 @@ exec_stmt_return_next(PLpgSQL_execstate * estate,
}
else
if
(
stmt
->
row
)
{
Datum
*
dvalues
;
char
*
nulls
;
int
i
;
if
(
natts
!=
stmt
->
row
->
nfields
)
tuple
=
make_tuple_from_row
(
estate
,
stmt
->
row
,
tupdesc
);
if
(
tuple
==
NULL
)
ereport
(
ERROR
,
(
errcode
(
ERRCODE_DATATYPE_MISMATCH
),
errmsg
(
"wrong record type supplied in RETURN NEXT"
)));
dvalues
=
(
Datum
*
)
palloc0
(
natts
*
sizeof
(
Datum
));
nulls
=
(
char
*
)
palloc
(
natts
*
sizeof
(
char
));
MemSet
(
nulls
,
'n'
,
natts
);
for
(
i
=
0
;
i
<
natts
;
i
++
)
{
PLpgSQL_var
*
var
;
var
=
(
PLpgSQL_var
*
)
(
estate
->
datums
[
stmt
->
row
->
varnos
[
i
]]);
if
(
var
->
datatype
->
typoid
!=
tupdesc
->
attrs
[
i
]
->
atttypid
)
ereport
(
ERROR
,
(
errcode
(
ERRCODE_DATATYPE_MISMATCH
),
errmsg
(
"wrong record type supplied in RETURN NEXT"
)));
dvalues
[
i
]
=
var
->
value
;
if
(
!
var
->
isnull
)
nulls
[
i
]
=
' '
;
}
tuple
=
heap_formtuple
(
tupdesc
,
dvalues
,
nulls
);
pfree
(
dvalues
);
pfree
(
nulls
);
free_tuple
=
true
;
}
else
if
(
stmt
->
expr
)
...
...
@@ -3412,7 +3405,8 @@ exec_move_row(PLpgSQL_execstate * estate,
* expected if it's from an inheritance-child table of the current
* table, or it might have fewer if the table has had columns added by
* ALTER TABLE. Ignore extra columns and assume NULL for missing
* columns, the same as heap_getattr would do.
* columns, the same as heap_getattr would do. We also have to skip
* over dropped columns in either the source or destination.
*
* If we have no tuple data at all, we'll assign NULL to all columns of
* the row variable.
...
...
@@ -3420,25 +3414,35 @@ exec_move_row(PLpgSQL_execstate * estate,
if
(
row
!=
NULL
)
{
int
t_natts
;
int
i
;
int
fnum
;
int
anum
;
if
(
HeapTupleIsValid
(
tup
))
t_natts
=
tup
->
t_data
->
t_natts
;
else
t_natts
=
0
;
for
(
i
=
0
;
i
<
row
->
nfields
;
i
++
)
anum
=
0
;
for
(
fnum
=
0
;
fnum
<
row
->
nfields
;
fnum
++
)
{
PLpgSQL_var
*
var
;
Datum
value
;
bool
isnull
;
Oid
valtype
;
var
=
(
PLpgSQL_var
*
)
(
estate
->
datums
[
row
->
varnos
[
i
]]);
if
(
i
<
t_natts
)
if
(
row
->
varnos
[
fnum
]
<
0
)
continue
;
/* skip dropped column in row struct */
var
=
(
PLpgSQL_var
*
)
(
estate
->
datums
[
row
->
varnos
[
fnum
]]);
while
(
anum
<
t_natts
&&
tupdesc
->
attrs
[
anum
]
->
attisdropped
)
anum
++
;
/* skip dropped column in tuple */
if
(
anum
<
t_natts
)
{
value
=
SPI_getbinval
(
tup
,
tupdesc
,
i
+
1
,
&
isnull
);
valtype
=
SPI_gettypeid
(
tupdesc
,
i
+
1
);
value
=
SPI_getbinval
(
tup
,
tupdesc
,
anum
+
1
,
&
isnull
);
valtype
=
SPI_gettypeid
(
tupdesc
,
anum
+
1
);
anum
++
;
}
else
{
...
...
@@ -3447,7 +3451,7 @@ exec_move_row(PLpgSQL_execstate * estate,
valtype
=
InvalidOid
;
}
exec_assign_value
(
estate
,
estate
->
datums
[
row
->
varnos
[
i
]]
,
exec_assign_value
(
estate
,
(
PLpgSQL_datum
*
)
var
,
value
,
valtype
,
&
isnull
);
}
...
...
@@ -3457,6 +3461,54 @@ exec_move_row(PLpgSQL_execstate * estate,
elog
(
ERROR
,
"unsupported target"
);
}
/* ----------
* make_tuple_from_row Make a tuple from the values of a row object
*
* A NULL return indicates rowtype mismatch; caller must raise suitable error
* ----------
*/
static
HeapTuple
make_tuple_from_row
(
PLpgSQL_execstate
*
estate
,
PLpgSQL_row
*
row
,
TupleDesc
tupdesc
)
{
int
natts
=
tupdesc
->
natts
;
HeapTuple
tuple
;
Datum
*
dvalues
;
char
*
nulls
;
int
i
;
if
(
natts
!=
row
->
nfields
)
return
NULL
;
dvalues
=
(
Datum
*
)
palloc0
(
natts
*
sizeof
(
Datum
));
nulls
=
(
char
*
)
palloc
(
natts
*
sizeof
(
char
));
MemSet
(
nulls
,
'n'
,
natts
);
for
(
i
=
0
;
i
<
natts
;
i
++
)
{
PLpgSQL_var
*
var
;
if
(
tupdesc
->
attrs
[
i
]
->
attisdropped
)
continue
;
/* leave the column as null */
if
(
row
->
varnos
[
i
]
<
0
)
/* should not happen */
elog
(
ERROR
,
"dropped rowtype entry for non-dropped column"
);
var
=
(
PLpgSQL_var
*
)
(
estate
->
datums
[
row
->
varnos
[
i
]]);
if
(
var
->
datatype
->
typoid
!=
tupdesc
->
attrs
[
i
]
->
atttypid
)
return
NULL
;
dvalues
[
i
]
=
var
->
value
;
if
(
!
var
->
isnull
)
nulls
[
i
]
=
' '
;
}
tuple
=
heap_formtuple
(
tupdesc
,
dvalues
,
nulls
);
pfree
(
dvalues
);
pfree
(
nulls
);
return
tuple
;
}
/* ----------
* exec_cast_value Cast a value if required
...
...
src/pl/plpgsql/src/pl_funcs.c
View file @
2848dc5f
...
...
@@ -3,7 +3,7 @@
* procedural language
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.
29 2003/08/04 00:43:33 momjian
Exp $
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.
30 2003/09/25 23:02:12 tgl
Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
...
...
@@ -848,15 +848,14 @@ dump_return(PLpgSQL_stmt_return * stmt)
{
dump_ind
();
printf
(
"RETURN "
);
if
(
stmt
->
retrecno
>
0
)
if
(
stmt
->
retrecno
>
=
0
)
printf
(
"record %d"
,
stmt
->
retrecno
);
else
{
if
(
stmt
->
expr
==
NULL
)
else
if
(
stmt
->
retrowno
>=
0
)
printf
(
"row %d"
,
stmt
->
retrowno
);
else
if
(
stmt
->
expr
==
NULL
)
printf
(
"NULL"
);
else
dump_expr
(
stmt
->
expr
);
}
printf
(
"
\n
"
);
}
...
...
@@ -1031,6 +1030,7 @@ plpgsql_dumptree(PLpgSQL_function * func)
printf
(
"ROW %-16s fields"
,
row
->
refname
);
for
(
i
=
0
;
i
<
row
->
nfields
;
i
++
)
{
if
(
row
->
fieldnames
[
i
])
printf
(
" %s=var %d"
,
row
->
fieldnames
[
i
],
row
->
varnos
[
i
]);
}
...
...
src/pl/plpgsql/src/plpgsql.h
View file @
2848dc5f
...
...
@@ -3,7 +3,7 @@
* procedural language
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.4
0 2003/08/18 19:16:0
2 tgl Exp $
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.4
1 2003/09/25 23:02:1
2 tgl Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
...
...
@@ -207,8 +207,15 @@ typedef struct
int
rowno
;
char
*
refname
;
int
lineno
;
Oid
rowtypeclass
;
TupleDesc
rowtupdesc
;
/*
* Note: TupleDesc is only set up for named rowtypes, else it is NULL.
*
* Note: if the underlying rowtype contains a dropped column, the
* corresponding fieldnames[] entry will be NULL, and there is no
* corresponding var (varnos[] will be -1).
*/
int
nfields
;
char
**
fieldnames
;
int
*
varnos
;
...
...
@@ -449,6 +456,7 @@ typedef struct
int
lineno
;
PLpgSQL_expr
*
expr
;
int
retrecno
;
int
retrowno
;
}
PLpgSQL_stmt_return
;
typedef
struct
...
...
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