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
88ba64d3
Commit
88ba64d3
authored
May 30, 2006
by
Bruce Momjian
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Back out patch, wrong previous commit message.
parent
b6477c62
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
38 additions
and
472 deletions
+38
-472
doc/src/sgml/plpgsql.sgml
doc/src/sgml/plpgsql.sgml
+1
-50
src/pl/plpgsql/src/pl_comp.c
src/pl/plpgsql/src/pl_comp.c
+3
-131
src/pl/plpgsql/src/pl_exec.c
src/pl/plpgsql/src/pl_exec.c
+26
-185
src/pl/plpgsql/src/pl_funcs.c
src/pl/plpgsql/src/pl_funcs.c
+4
-8
src/pl/plpgsql/src/plpgsql.h
src/pl/plpgsql/src/plpgsql.h
+3
-21
src/pl/plpgsql/src/scan.l
src/pl/plpgsql/src/scan.l
+1
-7
src/test/regress/expected/plpgsql.out
src/test/regress/expected/plpgsql.out
+0
-38
src/test/regress/sql/plpgsql.sql
src/test/regress/sql/plpgsql.sql
+0
-32
No files found.
doc/src/sgml/plpgsql.sgml
View file @
88ba64d3
<!-- $PostgreSQL: pgsql/doc/src/sgml/plpgsql.sgml,v 1.9
1 2006/05/30 11:54:51
momjian Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/plpgsql.sgml,v 1.9
2 2006/05/30 11:58:05
momjian Exp $ -->
<chapter id="plpgsql">
<chapter id="plpgsql">
<title><application>PL/pgSQL</application> - <acronym>SQL</acronym> Procedural Language</title>
<title><application>PL/pgSQL</application> - <acronym>SQL</acronym> Procedural Language</title>
...
@@ -879,55 +879,6 @@ SELECT merge_fields(t.*) FROM table1 t WHERE ... ;
...
@@ -879,55 +879,6 @@ SELECT merge_fields(t.*) FROM table1 t WHERE ... ;
field in it will draw a run-time error.
field in it will draw a run-time error.
</para>
</para>
<para>
To obtain the values of the fields the record is made up of,
the record variable can be qualified with the column or field
name. This can be done either by literally using the column name
or the column name for indexing the record can be taken out of a scalar
variable. The syntax for this notation is Record_variable.(IndexVariable).
To get information about the column field names of the record,
a special expression exists that returns all column names as an array:
RecordVariable.(*) .
Thus, the RECORD can be viewed
as an associative array that allows for introspection of it's contents.
This feature is especially useful for writing generic triggers that
operate on records with unknown structure.
Here is an example procedure that shows column names and values
of the predefined record NEW in a trigger procedure:
<programlisting>
CREATE OR REPLACE FUNCTION show_associative_records() RETURNS TRIGGER AS $$
DECLARE
colname TEXT;
colcontent TEXT;
colnames TEXT[];
coln INT4;
coli INT4;
BEGIN
-- obtain an array with all field names of the record
colnames := NEW.(*);
RAISE NOTICE 'All column names of test record: %', colnames;
-- show field names and contents of record
coli := 1;
coln := array_upper(colnames,1);
RAISE NOTICE 'Number of columns in NEW: %', coln;
FOR coli IN 1 .. coln LOOP
colname := colnames[coli];
colcontent := NEW.(colname);
RAISE NOTICE 'column % of NEW: %', quote_ident(colname), quote_literal(colcontent);
END LOOP;
-- Do it with a fixed field name:
-- will have to know the column name
RAISE NOTICE 'column someint of NEW: %', quote_literal(NEW.someint);
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
--CREATE TABLE test_records (someint INT8, somestring TEXT);
--CREATE TRIGGER tr_test_record BEFORE INSERT ON test_records FOR EACH ROW EXECUTE PROCEDURE show_associative_records();
</programlisting>
</para>
<para>
<para>
Note that <literal>RECORD</> is not a true data type, only a placeholder.
Note that <literal>RECORD</> is not a true data type, only a placeholder.
One should also realize that when a <application>PL/pgSQL</application>
One should also realize that when a <application>PL/pgSQL</application>
...
...
src/pl/plpgsql/src/pl_comp.c
View file @
88ba64d3
...
@@ -8,7 +8,7 @@
...
@@ -8,7 +8,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.10
3 2006/05/30 11:54:51
momjian Exp $
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.10
4 2006/05/30 11:58:05
momjian Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -884,8 +884,7 @@ plpgsql_parse_dblword(char *word)
...
@@ -884,8 +884,7 @@ plpgsql_parse_dblword(char *word)
new
=
palloc
(
sizeof
(
PLpgSQL_recfield
));
new
=
palloc
(
sizeof
(
PLpgSQL_recfield
));
new
->
dtype
=
PLPGSQL_DTYPE_RECFIELD
;
new
->
dtype
=
PLPGSQL_DTYPE_RECFIELD
;
new
->
fieldindex
.
fieldname
=
pstrdup
(
cp
[
1
]);
new
->
fieldname
=
pstrdup
(
cp
[
1
]);
new
->
fieldindex_flag
=
RECFIELD_USE_FIELDNAME
;
new
->
recparentno
=
ns
->
itemno
;
new
->
recparentno
=
ns
->
itemno
;
plpgsql_adddatum
((
PLpgSQL_datum
*
)
new
);
plpgsql_adddatum
((
PLpgSQL_datum
*
)
new
);
...
@@ -991,8 +990,7 @@ plpgsql_parse_tripword(char *word)
...
@@ -991,8 +990,7 @@ plpgsql_parse_tripword(char *word)
new
=
palloc
(
sizeof
(
PLpgSQL_recfield
));
new
=
palloc
(
sizeof
(
PLpgSQL_recfield
));
new
->
dtype
=
PLPGSQL_DTYPE_RECFIELD
;
new
->
dtype
=
PLPGSQL_DTYPE_RECFIELD
;
new
->
fieldindex
.
fieldname
=
pstrdup
(
cp
[
2
]);
new
->
fieldname
=
pstrdup
(
cp
[
2
]);
new
->
fieldindex_flag
=
RECFIELD_USE_FIELDNAME
;
new
->
recparentno
=
ns
->
itemno
;
new
->
recparentno
=
ns
->
itemno
;
plpgsql_adddatum
((
PLpgSQL_datum
*
)
new
);
plpgsql_adddatum
((
PLpgSQL_datum
*
)
new
);
...
@@ -1440,132 +1438,6 @@ plpgsql_parse_dblwordrowtype(char *word)
...
@@ -1440,132 +1438,6 @@ plpgsql_parse_dblwordrowtype(char *word)
return
T_DTYPE
;
return
T_DTYPE
;
}
}
/* ----------
* plpgsql_parse_recindex
* lookup associative index into record
* ----------
*/
int
plpgsql_parse_recindex
(
char
*
word
)
{
PLpgSQL_nsitem
*
ns1
,
*
ns2
;
char
*
cp
[
2
];
int
ret
=
T_ERROR
;
char
*
fieldvar
;
int
fl
;
/* Do case conversion and word separation */
plpgsql_convert_ident
(
word
,
cp
,
2
);
Assert
(
cp
[
1
]
!=
NULL
);
/* cleanup the "(identifier)" string to "identifier" */
fieldvar
=
cp
[
1
];
Assert
(
*
fieldvar
==
'('
);
++
fieldvar
;
/* get rid of ( */
fl
=
strlen
(
fieldvar
);
Assert
(
fieldvar
[
fl
-
1
]
==
')'
);
fieldvar
[
fl
-
1
]
=
0
;
/* get rid of ) */
/*
* Lookup the first word
*/
ns1
=
plpgsql_ns_lookup
(
cp
[
0
],
NULL
);
if
(
ns1
==
NULL
)
{
pfree
(
cp
[
0
]);
pfree
(
cp
[
1
]);
return
T_ERROR
;
}
ns2
=
plpgsql_ns_lookup
(
fieldvar
,
NULL
);
pfree
(
cp
[
0
]);
pfree
(
cp
[
1
]);
if
(
ns2
==
NULL
)
/* name lookup failed */
return
T_ERROR
;
switch
(
ns1
->
itemtype
)
{
case
PLPGSQL_NSTYPE_REC
:
{
/*
* First word is a record name, so second word must be an
* variable holding the field name in this record.
*/
if
(
ns2
->
itemtype
==
PLPGSQL_NSTYPE_VAR
)
{
PLpgSQL_recfield
*
new
;
new
=
palloc
(
sizeof
(
PLpgSQL_recfield
));
new
->
dtype
=
PLPGSQL_DTYPE_RECFIELD
;
new
->
fieldindex
.
indexvar_no
=
ns2
->
itemno
;
new
->
fieldindex_flag
=
RECFIELD_USE_INDEX_VAR
;
new
->
recparentno
=
ns1
->
itemno
;
plpgsql_adddatum
((
PLpgSQL_datum
*
)
new
);
plpgsql_yylval
.
scalar
=
(
PLpgSQL_datum
*
)
new
;
ret
=
T_SCALAR
;
}
break
;
}
default:
break
;
}
return
ret
;
}
/* ----------
* plpgsql_parse_recfieldnames
* create fieldnames of a record
* ----------
*/
int
plpgsql_parse_recfieldnames
(
char
*
word
)
{
PLpgSQL_nsitem
*
ns1
;
char
*
cp
[
2
];
int
ret
=
T_ERROR
;
/* Do case conversion and word separation */
plpgsql_convert_ident
(
word
,
cp
,
2
);
/*
* Lookup the first word
*/
ns1
=
plpgsql_ns_lookup
(
cp
[
0
],
NULL
);
if
(
ns1
==
NULL
)
{
pfree
(
cp
[
0
]);
pfree
(
cp
[
1
]);
return
T_ERROR
;
}
pfree
(
cp
[
0
]);
pfree
(
cp
[
1
]);
switch
(
ns1
->
itemtype
)
{
case
PLPGSQL_NSTYPE_REC
:
{
PLpgSQL_recfieldproperties
*
new
;
new
=
palloc
(
sizeof
(
PLpgSQL_recfieldproperties
));
new
->
dtype
=
PLPGSQL_DTYPE_RECFIELDNAMES
;
new
->
recparentno
=
ns1
->
itemno
;
new
->
save_fieldnames
=
NULL
;
plpgsql_adddatum
((
PLpgSQL_datum
*
)
new
);
plpgsql_yylval
.
scalar
=
(
PLpgSQL_datum
*
)
new
;
ret
=
T_SCALAR
;
/* ??? */
break
;
}
default:
break
;
}
return
ret
;
}
/*
/*
* plpgsql_build_variable - build a datum-array entry of a given
* plpgsql_build_variable - build a datum-array entry of a given
* datatype
* datatype
...
...
src/pl/plpgsql/src/pl_exec.c
View file @
88ba64d3
...
@@ -8,7 +8,7 @@
...
@@ -8,7 +8,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.16
6 2006/05/30 11:54:51
momjian Exp $
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.16
7 2006/05/30 11:58:05
momjian Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -741,7 +741,7 @@ copy_plpgsql_datum(PLpgSQL_datum *datum)
...
@@ -741,7 +741,7 @@ copy_plpgsql_datum(PLpgSQL_datum *datum)
case
PLPGSQL_DTYPE_RECFIELD
:
case
PLPGSQL_DTYPE_RECFIELD
:
case
PLPGSQL_DTYPE_ARRAYELEM
:
case
PLPGSQL_DTYPE_ARRAYELEM
:
case
PLPGSQL_DTYPE_TRIGARG
:
case
PLPGSQL_DTYPE_TRIGARG
:
case
PLPGSQL_DTYPE_RECFIELDNAMES
:
/*
/*
* These datum records are read-only at runtime, so no need to
* These datum records are read-only at runtime, so no need to
* copy them
* copy them
...
@@ -851,7 +851,6 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
...
@@ -851,7 +851,6 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
case
PLPGSQL_DTYPE_RECFIELD
:
case
PLPGSQL_DTYPE_RECFIELD
:
case
PLPGSQL_DTYPE_ARRAYELEM
:
case
PLPGSQL_DTYPE_ARRAYELEM
:
case
PLPGSQL_DTYPE_RECFIELDNAMES
:
break
;
break
;
default:
default:
...
@@ -2180,8 +2179,6 @@ plpgsql_estate_setup(PLpgSQL_execstate *estate,
...
@@ -2180,8 +2179,6 @@ plpgsql_estate_setup(PLpgSQL_execstate *estate,
static
void
static
void
exec_eval_cleanup
(
PLpgSQL_execstate
*
estate
)
exec_eval_cleanup
(
PLpgSQL_execstate
*
estate
)
{
{
int
i
;
ArrayType
*
a
;
/* Clear result of a full SPI_execute */
/* Clear result of a full SPI_execute */
if
(
estate
->
eval_tuptable
!=
NULL
)
if
(
estate
->
eval_tuptable
!=
NULL
)
SPI_freetuptable
(
estate
->
eval_tuptable
);
SPI_freetuptable
(
estate
->
eval_tuptable
);
...
@@ -2190,14 +2187,6 @@ exec_eval_cleanup(PLpgSQL_execstate *estate)
...
@@ -2190,14 +2187,6 @@ exec_eval_cleanup(PLpgSQL_execstate *estate)
/* Clear result of exec_eval_simple_expr (but keep the econtext) */
/* Clear result of exec_eval_simple_expr (but keep the econtext) */
if
(
estate
->
eval_econtext
!=
NULL
)
if
(
estate
->
eval_econtext
!=
NULL
)
ResetExprContext
(
estate
->
eval_econtext
);
ResetExprContext
(
estate
->
eval_econtext
);
for
(
i
=
0
;
i
<
estate
->
ndatums
;
++
i
)
{
if
(
estate
->
datums
[
i
]
->
dtype
==
PLPGSQL_DTYPE_RECFIELDNAMES
)
{
a
=
((
PLpgSQL_recfieldproperties
*
)(
estate
->
datums
[
i
]))
->
save_fieldnames
;
if
(
a
)
pfree
(
a
);
((
PLpgSQL_recfieldproperties
*
)(
estate
->
datums
[
i
]))
->
save_fieldnames
=
NULL
;
}
}
}
}
...
@@ -3167,7 +3156,7 @@ exec_assign_value(PLpgSQL_execstate *estate,
...
@@ -3167,7 +3156,7 @@ exec_assign_value(PLpgSQL_execstate *estate,
*/
*/
PLpgSQL_recfield
*
recfield
=
(
PLpgSQL_recfield
*
)
target
;
PLpgSQL_recfield
*
recfield
=
(
PLpgSQL_recfield
*
)
target
;
PLpgSQL_rec
*
rec
;
PLpgSQL_rec
*
rec
;
int
fno
=
0
;
int
fno
;
HeapTuple
newtup
;
HeapTuple
newtup
;
int
natts
;
int
natts
;
int
i
;
int
i
;
...
@@ -3196,35 +3185,12 @@ exec_assign_value(PLpgSQL_execstate *estate,
...
@@ -3196,35 +3185,12 @@ exec_assign_value(PLpgSQL_execstate *estate,
* Get the number of the records field to change and the
* Get the number of the records field to change and the
* number of attributes in the tuple.
* number of attributes in the tuple.
*/
*/
if
(
recfield
->
fieldindex_flag
==
RECFIELD_USE_FIELDNAME
)
{
fno
=
SPI_fnumber
(
rec
->
tupdesc
,
recfield
->
fieldname
);
fno
=
SPI_fnumber
(
rec
->
tupdesc
,
recfield
->
fieldindex
.
fieldname
);
if
(
fno
==
SPI_ERROR_NOATTRIBUTE
)
if
(
fno
==
SPI_ERROR_NOATTRIBUTE
)
ereport
(
ERROR
,
(
errcode
(
ERRCODE_UNDEFINED_COLUMN
),
errmsg
(
"record
\"
%s
\"
has no field
\"
%s
\"
"
,
rec
->
refname
,
recfield
->
fieldindex
.
fieldname
)));
}
else
if
(
recfield
->
fieldindex_flag
==
RECFIELD_USE_INDEX_VAR
)
{
PLpgSQL_var
*
idxvar
=
(
PLpgSQL_var
*
)
(
estate
->
datums
[
recfield
->
fieldindex
.
indexvar_no
]);
char
*
fname
=
convert_value_to_string
(
idxvar
->
value
,
idxvar
->
datatype
->
typoid
);
if
(
fname
==
NULL
)
ereport
(
ERROR
,
(
errcode
(
ERRCODE_UNDEFINED_COLUMN
),
errmsg
(
"record
\"
%s
\"
: cannot evaluate variable to record index string"
,
rec
->
refname
)));
fno
=
SPI_fnumber
(
rec
->
tupdesc
,
fname
);
pfree
(
fname
);
if
(
fno
==
SPI_ERROR_NOATTRIBUTE
)
ereport
(
ERROR
,
(
errcode
(
ERRCODE_UNDEFINED_COLUMN
),
errmsg
(
"record
\"
%s
\"
has no field
\"
%s
\"
"
,
rec
->
refname
,
fname
)));
}
else
ereport
(
ERROR
,
ereport
(
ERROR
,
(
errcode
(
ERRCODE_UNDEFINED_COLUMN
),
(
errcode
(
ERRCODE_UNDEFINED_COLUMN
),
errmsg
(
"record
\"
%s
\"
: internal error
"
,
errmsg
(
"record
\"
%s
\"
has no field
\"
%s
\"
"
,
rec
->
refname
)));
rec
->
refname
,
recfield
->
fieldname
)));
fno
--
;
fno
--
;
natts
=
rec
->
tupdesc
->
natts
;
natts
=
rec
->
tupdesc
->
natts
;
...
@@ -3544,7 +3510,7 @@ exec_eval_datum(PLpgSQL_execstate *estate,
...
@@ -3544,7 +3510,7 @@ exec_eval_datum(PLpgSQL_execstate *estate,
{
{
PLpgSQL_recfield
*
recfield
=
(
PLpgSQL_recfield
*
)
datum
;
PLpgSQL_recfield
*
recfield
=
(
PLpgSQL_recfield
*
)
datum
;
PLpgSQL_rec
*
rec
;
PLpgSQL_rec
*
rec
;
int
fno
=
0
;
int
fno
;
rec
=
(
PLpgSQL_rec
*
)
(
estate
->
datums
[
recfield
->
recparentno
]);
rec
=
(
PLpgSQL_rec
*
)
(
estate
->
datums
[
recfield
->
recparentno
]);
if
(
!
HeapTupleIsValid
(
rec
->
tup
))
if
(
!
HeapTupleIsValid
(
rec
->
tup
))
...
@@ -3553,125 +3519,22 @@ exec_eval_datum(PLpgSQL_execstate *estate,
...
@@ -3553,125 +3519,22 @@ exec_eval_datum(PLpgSQL_execstate *estate,
errmsg
(
"record
\"
%s
\"
is not assigned yet"
,
errmsg
(
"record
\"
%s
\"
is not assigned yet"
,
rec
->
refname
),
rec
->
refname
),
errdetail
(
"The tuple structure of a not-yet-assigned record is indeterminate."
)));
errdetail
(
"The tuple structure of a not-yet-assigned record is indeterminate."
)));
if
(
recfield
->
fieldindex_flag
==
RECFIELD_USE_FIELDNAME
)
{
fno
=
SPI_fnumber
(
rec
->
tupdesc
,
recfield
->
fieldname
);
fno
=
SPI_fnumber
(
rec
->
tupdesc
,
recfield
->
fieldindex
.
fieldname
);
if
(
fno
==
SPI_ERROR_NOATTRIBUTE
)
if
(
fno
==
SPI_ERROR_NOATTRIBUTE
)
ereport
(
ERROR
,
ereport
(
ERROR
,
(
errcode
(
ERRCODE_UNDEFINED_COLUMN
),
(
errcode
(
ERRCODE_UNDEFINED_COLUMN
),
errmsg
(
"record
\"
%s
\"
has no field
\"
%s
\"
"
,
errmsg
(
"record
\"
%s
\"
has no field
\"
%s
\"
"
,
rec
->
refname
,
recfield
->
fieldname
)));
rec
->
refname
,
recfield
->
fieldindex
.
fieldname
)));
*
typeid
=
SPI_gettypeid
(
rec
->
tupdesc
,
fno
);
}
*
value
=
SPI_getbinval
(
rec
->
tup
,
rec
->
tupdesc
,
fno
,
isnull
);
else
if
(
recfield
->
fieldindex_flag
==
RECFIELD_USE_INDEX_VAR
)
{
if
(
expectedtypeid
!=
InvalidOid
&&
expectedtypeid
!=
*
typeid
)
PLpgSQL_var
*
idxvar
=
(
PLpgSQL_var
*
)
(
estate
->
datums
[
recfield
->
fieldindex
.
indexvar_no
]);
ereport
(
ERROR
,
char
*
fname
=
convert_value_to_string
(
idxvar
->
value
,
idxvar
->
datatype
->
typoid
);
(
errcode
(
ERRCODE_DATATYPE_MISMATCH
),
if
(
fname
==
NULL
)
errmsg
(
"type of
\"
%s.%s
\"
does not match that when preparing the plan"
,
ereport
(
ERROR
,
rec
->
refname
,
recfield
->
fieldname
)));
(
errcode
(
ERRCODE_UNDEFINED_COLUMN
),
break
;
errmsg
(
"record
\"
%s
\"
: cannot evaluate variable to record index string"
,
}
rec
->
refname
)));
fno
=
SPI_fnumber
(
rec
->
tupdesc
,
fname
);
pfree
(
fname
);
if
(
fno
==
SPI_ERROR_NOATTRIBUTE
)
ereport
(
ERROR
,
(
errcode
(
ERRCODE_UNDEFINED_COLUMN
),
errmsg
(
"record
\"
%s
\"
has no field
\"
%s
\"
"
,
rec
->
refname
,
fname
)));
}
else
ereport
(
ERROR
,
(
errcode
(
ERRCODE_UNDEFINED_COLUMN
),
errmsg
(
"record
\"
%s
\"
: internal error"
,
rec
->
refname
)));
/* Do not allow typeids to become "narrowed" by InvalidOids
causing specialized typeids from the tuple restricting the destination */
if
(
expectedtypeid
!=
InvalidOid
&&
expectedtypeid
!=
SPI_gettypeid
(
rec
->
tupdesc
,
fno
)
)
{
Datum
cval
=
SPI_getbinval
(
rec
->
tup
,
rec
->
tupdesc
,
fno
,
isnull
);
cval
=
exec_simple_cast_value
(
cval
,
SPI_gettypeid
(
rec
->
tupdesc
,
fno
),
expectedtypeid
,
-
1
,
*
isnull
);
*
value
=
cval
;
*
typeid
=
expectedtypeid
;
/* ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("type of \"%s\" does not match that when preparing the plan",
rec->refname)));
*/
}
else
{
/* expected typeid matches */
*
value
=
SPI_getbinval
(
rec
->
tup
,
rec
->
tupdesc
,
fno
,
isnull
);
*
typeid
=
SPI_gettypeid
(
rec
->
tupdesc
,
fno
);
}
break
;
}
case
PLPGSQL_DTYPE_RECFIELDNAMES
:
/* Construct array datum from record field names */
{
Oid
arraytypeid
,
arrayelemtypeid
=
TEXTOID
;
int16
arraytyplen
,
elemtyplen
;
bool
elemtypbyval
;
char
elemtypalign
;
ArrayType
*
arrayval
;
PLpgSQL_recfieldproperties
*
recfp
=
(
PLpgSQL_recfieldproperties
*
)
datum
;
PLpgSQL_rec
*
rec
=
(
PLpgSQL_rec
*
)
(
estate
->
datums
[
recfp
->
recparentno
]);
int
fc
,
tfc
=
0
;
Datum
*
arrayelems
;
char
*
fieldname
;
if
(
!
HeapTupleIsValid
(
rec
->
tup
))
ereport
(
ERROR
,
(
errcode
(
ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE
),
errmsg
(
"record
\"
%s
\"
is not assigned yet"
,
rec
->
refname
),
errdetail
(
"The tuple structure of a not-yet-assigned record is indeterminate."
)));
arrayelems
=
palloc
(
sizeof
(
Datum
)
*
rec
->
tupdesc
->
natts
);
arraytypeid
=
get_array_type
(
arrayelemtypeid
);
arraytyplen
=
get_typlen
(
arraytypeid
);
get_typlenbyvalalign
(
arrayelemtypeid
,
&
elemtyplen
,
&
elemtypbyval
,
&
elemtypalign
);
if
(
expectedtypeid
!=
InvalidOid
&&
expectedtypeid
!=
arraytypeid
)
ereport
(
ERROR
,
(
errcode
(
ERRCODE_DATATYPE_MISMATCH
),
errmsg
(
"type of
\"
%s
\"
does not match array type when preparing the plan"
,
rec
->
refname
)));
for
(
fc
=
0
;
fc
<
rec
->
tupdesc
->
natts
;
++
fc
)
{
fieldname
=
SPI_fname
(
rec
->
tupdesc
,
fc
+
1
);
if
(
fieldname
)
{
arrayelems
[
fc
]
=
DirectFunctionCall1
(
textin
,
CStringGetDatum
(
fieldname
));
pfree
(
fieldname
);
++
tfc
;
}
}
arrayval
=
construct_array
(
arrayelems
,
tfc
,
arrayelemtypeid
,
elemtyplen
,
elemtypbyval
,
elemtypalign
);
/* construct_array copies data; free temp elem array */
for
(
fc
=
0
;
fc
<
tfc
;
++
fc
)
pfree
(
DatumGetPointer
(
arrayelems
[
fc
]));
pfree
(
arrayelems
);
*
value
=
PointerGetDatum
(
arrayval
);
*
typeid
=
arraytypeid
;
*
isnull
=
false
;
/* need to save the pointer because otherwise it does not get freed */
if
(
recfp
->
save_fieldnames
)
pfree
(
recfp
->
save_fieldnames
);
recfp
->
save_fieldnames
=
arrayval
;
break
;
}
case
PLPGSQL_DTYPE_TRIGARG
:
case
PLPGSQL_DTYPE_TRIGARG
:
{
{
PLpgSQL_trigarg
*
trigarg
=
(
PLpgSQL_trigarg
*
)
datum
;
PLpgSQL_trigarg
*
trigarg
=
(
PLpgSQL_trigarg
*
)
datum
;
...
@@ -3769,29 +3632,7 @@ exec_eval_expr(PLpgSQL_execstate *estate,
...
@@ -3769,29 +3632,7 @@ exec_eval_expr(PLpgSQL_execstate *estate,
*/
*/
if
(
expr
->
plan
==
NULL
)
if
(
expr
->
plan
==
NULL
)
exec_prepare_plan
(
estate
,
expr
);
exec_prepare_plan
(
estate
,
expr
);
else
{
/*
* check for any subexpressions with varying type in the expression
* currently (July 05), this is a record field of a record indexed by a variable
*/
int
i
;
PLpgSQL_datum
*
d
;
PLpgSQL_recfield
*
rf
;
for
(
i
=
0
;
i
<
expr
->
nparams
;
++
i
)
{
d
=
estate
->
datums
[
expr
->
params
[
i
]];
if
(
d
->
dtype
==
PLPGSQL_DTYPE_RECFIELD
)
{
rf
=
(
PLpgSQL_recfield
*
)
d
;
if
(
rf
->
fieldindex_flag
==
RECFIELD_USE_INDEX_VAR
)
break
;
}
}
if
(
i
<
expr
->
nparams
)
{
/* expr may change it's type */
/* now discard the plan and get new one */
SPI_freeplan
(
expr
->
plan
);
expr
->
plan
=
NULL
;
exec_prepare_plan
(
estate
,
expr
);
}
}
/*
/*
* If this is a simple expression, bypass SPI and use the executor
* If this is a simple expression, bypass SPI and use the executor
* directly
* directly
...
...
src/pl/plpgsql/src/pl_funcs.c
View file @
88ba64d3
...
@@ -8,7 +8,7 @@
...
@@ -8,7 +8,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.
49 2006/05/30 11:54:51
momjian Exp $
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.
50 2006/05/30 11:58:05
momjian Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -1044,13 +1044,9 @@ plpgsql_dumptree(PLpgSQL_function *func)
...
@@ -1044,13 +1044,9 @@ plpgsql_dumptree(PLpgSQL_function *func)
printf
(
"REC %s
\n
"
,
((
PLpgSQL_rec
*
)
d
)
->
refname
);
printf
(
"REC %s
\n
"
,
((
PLpgSQL_rec
*
)
d
)
->
refname
);
break
;
break
;
case
PLPGSQL_DTYPE_RECFIELD
:
case
PLPGSQL_DTYPE_RECFIELD
:
if
(
((
PLpgSQL_recfield
*
)
d
)
->
fieldindex_flag
==
RECFIELD_USE_FIELDNAME
)
printf
(
"RECFIELD %-16s of REC %d
\n
"
,
printf
(
"RECFIELD %-16s of REC %d
\n
"
,
((
PLpgSQL_recfield
*
)
d
)
->
fieldname
,
((
PLpgSQL_recfield
*
)
d
)
->
fieldindex
.
fieldname
,
((
PLpgSQL_recfield
*
)
d
)
->
recparentno
);
((
PLpgSQL_recfield
*
)
d
)
->
recparentno
);
else
printf
(
"RECFIELD Variable of REC %d
\n
"
,
((
PLpgSQL_recfield
*
)
d
)
->
recparentno
);
break
;
break
;
case
PLPGSQL_DTYPE_ARRAYELEM
:
case
PLPGSQL_DTYPE_ARRAYELEM
:
printf
(
"ARRAYELEM of VAR %d subscript "
,
printf
(
"ARRAYELEM of VAR %d subscript "
,
...
...
src/pl/plpgsql/src/plpgsql.h
View file @
88ba64d3
...
@@ -8,7 +8,7 @@
...
@@ -8,7 +8,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.7
1 2006/05/30 11:54:51
momjian Exp $
* $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.7
2 2006/05/30 11:58:05
momjian Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -52,8 +52,7 @@ enum
...
@@ -52,8 +52,7 @@ enum
PLPGSQL_DTYPE_RECFIELD
,
PLPGSQL_DTYPE_RECFIELD
,
PLPGSQL_DTYPE_ARRAYELEM
,
PLPGSQL_DTYPE_ARRAYELEM
,
PLPGSQL_DTYPE_EXPR
,
PLPGSQL_DTYPE_EXPR
,
PLPGSQL_DTYPE_TRIGARG
,
PLPGSQL_DTYPE_TRIGARG
PLPGSQL_DTYPE_RECFIELDNAMES
};
};
/* ----------
/* ----------
...
@@ -252,25 +251,10 @@ typedef struct
...
@@ -252,25 +251,10 @@ typedef struct
{
/* Field in record */
{
/* Field in record */
int
dtype
;
int
dtype
;
int
rfno
;
int
rfno
;
union
{
char
*
fieldname
;
char
*
fieldname
;
int
indexvar_no
;
/* dno of variable holding index string */
}
fieldindex
;
enum
{
RECFIELD_USE_FIELDNAME
,
RECFIELD_USE_INDEX_VAR
,
}
fieldindex_flag
;
int
recparentno
;
/* dno of parent record */
int
recparentno
;
/* dno of parent record */
}
PLpgSQL_recfield
;
}
PLpgSQL_recfield
;
typedef
struct
{
/* Field in record */
int
dtype
;
int
rfno
;
int
recparentno
;
/* dno of parent record */
ArrayType
*
save_fieldnames
;
}
PLpgSQL_recfieldproperties
;
typedef
struct
typedef
struct
{
/* Element of array variable */
{
/* Element of array variable */
...
@@ -677,8 +661,6 @@ extern int plpgsql_parse_dblwordtype(char *word);
...
@@ -677,8 +661,6 @@ extern int plpgsql_parse_dblwordtype(char *word);
extern
int
plpgsql_parse_tripwordtype
(
char
*
word
);
extern
int
plpgsql_parse_tripwordtype
(
char
*
word
);
extern
int
plpgsql_parse_wordrowtype
(
char
*
word
);
extern
int
plpgsql_parse_wordrowtype
(
char
*
word
);
extern
int
plpgsql_parse_dblwordrowtype
(
char
*
word
);
extern
int
plpgsql_parse_dblwordrowtype
(
char
*
word
);
extern
int
plpgsql_parse_recfieldnames
(
char
*
word
);
extern
int
plpgsql_parse_recindex
(
char
*
word
);
extern
PLpgSQL_type
*
plpgsql_parse_datatype
(
const
char
*
string
);
extern
PLpgSQL_type
*
plpgsql_parse_datatype
(
const
char
*
string
);
extern
PLpgSQL_type
*
plpgsql_build_datatype
(
Oid
typeOid
,
int32
typmod
);
extern
PLpgSQL_type
*
plpgsql_build_datatype
(
Oid
typeOid
,
int32
typmod
);
extern
PLpgSQL_variable
*
plpgsql_build_variable
(
const
char
*
refname
,
int
lineno
,
extern
PLpgSQL_variable
*
plpgsql_build_variable
(
const
char
*
refname
,
int
lineno
,
...
...
src/pl/plpgsql/src/scan.l
View file @
88ba64d3
...
@@ -9,7 +9,7 @@
...
@@ -9,7 +9,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $PostgreSQL: pgsql/src/pl/plpgsql/src/scan.l,v 1.4
6 2006/05/30 11:54:51
momjian Exp $
* $PostgreSQL: pgsql/src/pl/plpgsql/src/scan.l,v 1.4
7 2006/05/30 11:58:05
momjian Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -222,12 +222,6 @@ dump { return O_DUMP; }
...
@@ -222,12 +222,6 @@ dump { return O_DUMP; }
{param}{space}*\.{space}*{identifier}{space}*%ROWTYPE {
{param}{space}*\.{space}*{identifier}{space}*%ROWTYPE {
plpgsql_error_lineno = plpgsql_scanner_lineno();
plpgsql_error_lineno = plpgsql_scanner_lineno();
return plpgsql_parse_dblwordrowtype(yytext); }
return plpgsql_parse_dblwordrowtype(yytext); }
{identifier}{space}*\.\(\*\) {
plpgsql_error_lineno = plpgsql_scanner_lineno();
return plpgsql_parse_recfieldnames(yytext); }
{identifier}{space}*\.\({identifier}\) {
plpgsql_error_lineno = plpgsql_scanner_lineno();
return plpgsql_parse_recindex(yytext); }
{digit}+ { return T_NUMBER; }
{digit}+ { return T_NUMBER; }
...
...
src/test/regress/expected/plpgsql.out
View file @
88ba64d3
...
@@ -2725,44 +2725,6 @@ end;
...
@@ -2725,44 +2725,6 @@ end;
$$ language plpgsql;
$$ language plpgsql;
ERROR: end label "outer_label" specified for unlabelled block
ERROR: end label "outer_label" specified for unlabelled block
CONTEXT: compile of PL/pgSQL function "end_label4" near line 5
CONTEXT: compile of PL/pgSQL function "end_label4" near line 5
-- check introspective records
create table ritest (i INT4, t TEXT);
insert into ritest (i, t) VALUES (1, 'sometext');
create function test_record() returns void as $$
declare
cname text;
tval text;
ival int4;
tval2 text;
ival2 int4;
columns text[];
r RECORD;
begin
SELECT INTO r * FROM ritest WHERE i = 1;
ival := r.i;
tval := r.t;
RAISE NOTICE 'ival=%, tval=%', ival, tval;
cname := 'i';
ival2 := r.(cname);
cname :='t';
tval2 := r.(cname);
RAISE NOTICE 'ival2=%, tval2=%', ival2, tval2;
columns := r.(*);
RAISE NOTICE 'fieldnames=%', columns;
RETURN;
end;
$$ language plpgsql;
select test_record();
NOTICE: ival=1, tval=sometext
NOTICE: ival2=1, tval2=sometext
NOTICE: fieldnames={i,t}
test_record
-------------
(1 row)
drop table ritest;
drop function test_record();
-- using list of scalars in fori and fore stmts
-- using list of scalars in fori and fore stmts
create function for_vect() returns void as $proc$
create function for_vect() returns void as $proc$
<<lbl>>declare a integer; b varchar; c varchar; r record;
<<lbl>>declare a integer; b varchar; c varchar; r record;
...
...
src/test/regress/sql/plpgsql.sql
View file @
88ba64d3
...
@@ -2281,38 +2281,6 @@ begin
...
@@ -2281,38 +2281,6 @@ begin
end
;
end
;
$$
language
plpgsql
;
$$
language
plpgsql
;
-- check introspective records
create
table
ritest
(
i
INT4
,
t
TEXT
);
insert
into
ritest
(
i
,
t
)
VALUES
(
1
,
'sometext'
);
create
function
test_record
()
returns
void
as
$$
declare
cname
text
;
tval
text
;
ival
int4
;
tval2
text
;
ival2
int4
;
columns
text
[];
r
RECORD
;
begin
SELECT
INTO
r
*
FROM
ritest
WHERE
i
=
1
;
ival
:
=
r
.
i
;
tval
:
=
r
.
t
;
RAISE
NOTICE
'ival=%, tval=%'
,
ival
,
tval
;
cname
:
=
'i'
;
ival2
:
=
r
.(
cname
);
cname
:
=
't'
;
tval2
:
=
r
.(
cname
);
RAISE
NOTICE
'ival2=%, tval2=%'
,
ival2
,
tval2
;
columns
:
=
r
.(
*
);
RAISE
NOTICE
'fieldnames=%'
,
columns
;
RETURN
;
end
;
$$
language
plpgsql
;
select
test_record
();
drop
table
ritest
;
drop
function
test_record
();
-- using list of scalars in fori and fore stmts
-- using list of scalars in fori and fore stmts
create
function
for_vect
()
returns
void
as
$
proc
$
create
function
for_vect
()
returns
void
as
$
proc
$
<<
lbl
>>
declare
a
integer
;
b
varchar
;
c
varchar
;
r
record
;
<<
lbl
>>
declare
a
integer
;
b
varchar
;
c
varchar
;
r
record
;
...
...
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