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
4a5b781d
Commit
4a5b781d
authored
Nov 25, 1997
by
Bruce Momjian
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Break parser functions into smaller files, group together.
parent
3aff4011
Changes
60
Hide whitespace changes
Inline
Side-by-side
Showing
60 changed files
with
5592 additions
and
3309 deletions
+5592
-3309
src/backend/access/common/tupdesc.c
src/backend/access/common/tupdesc.c
+9
-8
src/backend/catalog/heap.c
src/backend/catalog/heap.c
+6
-5
src/backend/catalog/index.c
src/backend/catalog/index.c
+12
-11
src/backend/catalog/pg_operator.c
src/backend/catalog/pg_operator.c
+3
-2
src/backend/catalog/pg_proc.c
src/backend/catalog/pg_proc.c
+9
-9
src/backend/catalog/pg_type.c
src/backend/catalog/pg_type.c
+3
-2
src/backend/commands/_deadcode/version.c
src/backend/commands/_deadcode/version.c
+2
-1
src/backend/commands/explain.c
src/backend/commands/explain.c
+2
-3
src/backend/commands/recipe.c
src/backend/commands/recipe.c
+3
-3
src/backend/commands/remove.c
src/backend/commands/remove.c
+3
-2
src/backend/commands/vacuum.c
src/backend/commands/vacuum.c
+2
-2
src/backend/commands/view.c
src/backend/commands/view.c
+4
-4
src/backend/executor/execTuples.c
src/backend/executor/execTuples.c
+4
-4
src/backend/executor/functions.c
src/backend/executor/functions.c
+1
-2
src/backend/executor/nodeAgg.c
src/backend/executor/nodeAgg.c
+2
-2
src/backend/executor/spi.c
src/backend/executor/spi.c
+1
-0
src/backend/nodes/copyfuncs.c
src/backend/nodes/copyfuncs.c
+1
-2
src/backend/nodes/print.c
src/backend/nodes/print.c
+3
-3
src/backend/optimizer/path/xfunc.c
src/backend/optimizer/path/xfunc.c
+6
-6
src/backend/optimizer/plan/createplan.c
src/backend/optimizer/plan/createplan.c
+1
-2
src/backend/optimizer/plan/planner.c
src/backend/optimizer/plan/planner.c
+13
-14
src/backend/optimizer/prep/preptlist.c
src/backend/optimizer/prep/preptlist.c
+4
-3
src/backend/optimizer/prep/prepunion.c
src/backend/optimizer/prep/prepunion.c
+1
-2
src/backend/optimizer/util/tlist.c
src/backend/optimizer/util/tlist.c
+1
-2
src/backend/parser/Makefile
src/backend/parser/Makefile
+4
-3
src/backend/parser/analyze.c
src/backend/parser/analyze.c
+15
-2677
src/backend/parser/gram.y
src/backend/parser/gram.y
+29
-5
src/backend/parser/keywords.c
src/backend/parser/keywords.c
+2
-2
src/backend/parser/parse_agg.c
src/backend/parser/parse_agg.c
+371
-0
src/backend/parser/parse_clause.c
src/backend/parser/parse_clause.c
+407
-0
src/backend/parser/parse_expr.c
src/backend/parser/parse_expr.c
+694
-0
src/backend/parser/parse_func.c
src/backend/parser/parse_func.c
+1264
-0
src/backend/parser/parse_node.c
src/backend/parser/parse_node.c
+77
-376
src/backend/parser/parse_oper.c
src/backend/parser/parse_oper.c
+613
-0
src/backend/parser/parse_relation.c
src/backend/parser/parse_relation.c
+480
-0
src/backend/parser/parse_target.c
src/backend/parser/parse_target.c
+679
-0
src/backend/parser/parse_type.c
src/backend/parser/parse_type.c
+319
-0
src/backend/parser/parser.c
src/backend/parser/parser.c
+19
-9
src/backend/parser/scansup.c
src/backend/parser/scansup.c
+1
-2
src/backend/rewrite/rewriteDefine.c
src/backend/rewrite/rewriteDefine.c
+6
-5
src/backend/tcop/aclchk.c
src/backend/tcop/aclchk.c
+4
-2
src/backend/tcop/postgres.c
src/backend/tcop/postgres.c
+3
-4
src/include/executor/spi.h
src/include/executor/spi.h
+0
-1
src/include/nodes/nodeFuncs.h
src/include/nodes/nodeFuncs.h
+4
-1
src/include/optimizer/planner.h
src/include/optimizer/planner.h
+3
-1
src/include/parser/analyze.h
src/include/parser/analyze.h
+19
-0
src/include/parser/catalog_utils.h
src/include/parser/catalog_utils.h
+0
-54
src/include/parser/parse_agg.h
src/include/parser/parse_agg.h
+38
-0
src/include/parser/parse_clause.h
src/include/parser/parse_clause.h
+39
-0
src/include/parser/parse_expr.h
src/include/parser/parse_expr.h
+34
-0
src/include/parser/parse_func.h
src/include/parser/parse_func.h
+97
-0
src/include/parser/parse_node.h
src/include/parser/parse_node.h
+67
-0
src/include/parser/parse_oper.h
src/include/parser/parse_oper.h
+50
-0
src/include/parser/parse_query.h
src/include/parser/parse_query.h
+0
-70
src/include/parser/parse_relation.h
src/include/parser/parse_relation.h
+56
-0
src/include/parser/parse_target.h
src/include/parser/parse_target.h
+39
-0
src/include/parser/parse_type.h
src/include/parser/parse_type.h
+37
-0
src/include/parser/parser.h
src/include/parser/parser.h
+21
-0
src/include/tcop/tcopprot.h
src/include/tcop/tcopprot.h
+2
-2
src/test/regress/checkresults
src/test/regress/checkresults
+3
-1
No files found.
src/backend/access/common/tupdesc.c
View file @
4a5b781d
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/common/tupdesc.c,v 1.2
8 1997/11/24 05:07:42
momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/access/common/tupdesc.c,v 1.2
9 1997/11/25 21:58:35
momjian Exp $
*
*
* NOTES
* NOTES
* some of the executor utility code such as "ExecTypeFromTL" should be
* some of the executor utility code such as "ExecTypeFromTL" should be
...
@@ -20,8 +20,9 @@
...
@@ -20,8 +20,9 @@
#include <postgres.h>
#include <postgres.h>
#include <
parser/catalog_utils
.h>
#include <
catalog/pg_type
.h>
#include <nodes/parsenodes.h>
#include <nodes/parsenodes.h>
#include <parser/parse_type.h>
#include <utils/builtins.h>
#include <utils/builtins.h>
#include <utils/fcache.h>
#include <utils/fcache.h>
#include <utils/syscache.h>
#include <utils/syscache.h>
...
@@ -377,10 +378,10 @@ TupleDescInitEntry(TupleDesc desc,
...
@@ -377,10 +378,10 @@ TupleDescInitEntry(TupleDesc desc,
*/
*/
if
(
attisset
)
if
(
attisset
)
{
{
Type
t
=
type
(
"oid"
);
Type
t
=
type
idType
(
OIDOID
);
att
->
attlen
=
t
l
en
(
t
);
att
->
attlen
=
t
ypeL
en
(
t
);
att
->
attbyval
=
t
byv
al
(
t
);
att
->
attbyval
=
t
ypeByV
al
(
t
);
}
}
else
else
{
{
...
@@ -410,12 +411,12 @@ TupleDescMakeSelfReference(TupleDesc desc,
...
@@ -410,12 +411,12 @@ TupleDescMakeSelfReference(TupleDesc desc,
char
*
relname
)
char
*
relname
)
{
{
AttributeTupleForm
att
;
AttributeTupleForm
att
;
Type
t
=
type
(
"oid"
);
Type
t
=
type
idType
(
OIDOID
);
att
=
desc
->
attrs
[
attnum
-
1
];
att
=
desc
->
attrs
[
attnum
-
1
];
att
->
atttypid
=
TypeShellMake
(
relname
);
att
->
atttypid
=
TypeShellMake
(
relname
);
att
->
attlen
=
t
l
en
(
t
);
att
->
attlen
=
t
ypeL
en
(
t
);
att
->
attbyval
=
t
byv
al
(
t
);
att
->
attbyval
=
t
ypeByV
al
(
t
);
att
->
attnelems
=
0
;
att
->
attnelems
=
0
;
}
}
...
...
src/backend/catalog/heap.c
View file @
4a5b781d
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.3
3 1997/11/24 05:08:07
momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.3
4 1997/11/25 21:58:40
momjian Exp $
*
*
* INTERFACE ROUTINES
* INTERFACE ROUTINES
* heap_creatr() - Create an uncataloged heap relation
* heap_creatr() - Create an uncataloged heap relation
...
@@ -42,11 +42,12 @@
...
@@ -42,11 +42,12 @@
#include <catalog/pg_attrdef.h>
#include <catalog/pg_attrdef.h>
#include <catalog/pg_relcheck.h>
#include <catalog/pg_relcheck.h>
#include <commands/trigger.h>
#include <commands/trigger.h>
#include <parser/parse_expr.h>
#include <parser/parse_node.h>
#include <parser/parse_type.h>
#include <storage/bufmgr.h>
#include <storage/bufmgr.h>
#include <storage/lmgr.h>
#include <storage/lmgr.h>
#include <storage/smgr.h>
#include <storage/smgr.h>
#include <parser/catalog_utils.h>
#include <parser/parse_query.h>
#include <rewrite/rewriteRemove.h>
#include <rewrite/rewriteRemove.h>
#include <utils/builtins.h>
#include <utils/builtins.h>
#include <utils/mcxt.h>
#include <utils/mcxt.h>
...
@@ -722,8 +723,8 @@ addNewRelationType(char *typeName, Oid new_rel_oid)
...
@@ -722,8 +723,8 @@ addNewRelationType(char *typeName, Oid new_rel_oid)
*/
*/
new_type_oid
=
TypeCreate
(
typeName
,
/* type name */
new_type_oid
=
TypeCreate
(
typeName
,
/* type name */
new_rel_oid
,
/* relation oid */
new_rel_oid
,
/* relation oid */
t
len
(
type
(
"oid"
)),
/* internal size */
t
ypeLen
(
typeidType
(
OIDOID
)),
/* internal size */
t
len
(
type
(
"oid"
)),
/* external size */
t
ypeLen
(
typeidType
(
OIDOID
)),
/* external size */
'c'
,
/* type-type (catalog) */
'c'
,
/* type-type (catalog) */
','
,
/* default array delimiter */
','
,
/* default array delimiter */
"int4in"
,
/* input procedure */
"int4in"
,
/* input procedure */
...
...
src/backend/catalog/index.c
View file @
4a5b781d
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.
29 1997/11/24 05:08:11
momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.
30 1997/11/25 21:58:43
momjian Exp $
*
*
*
*
* INTERFACE ROUTINES
* INTERFACE ROUTINES
...
@@ -30,26 +30,27 @@
...
@@ -30,26 +30,27 @@
#include <fmgr.h>
#include <fmgr.h>
#include <access/genam.h>
#include <access/genam.h>
#include <access/heapam.h>
#include <access/heapam.h>
#include <storage/lmgr.h>
#include <access/istrat.h>
#include <miscadmin.h>
#include <access/xact.h>
#include <access/xact.h>
#include <parser/catalog_utils.h>
#include <storage/smgr.h>
#include <utils/builtins.h>
#include <utils/mcxt.h>
#include <utils/relcache.h>
#include <utils/syscache.h>
#include <utils/tqual.h>
#include <bootstrap/bootstrap.h>
#include <bootstrap/bootstrap.h>
#include <catalog/catname.h>
#include <catalog/catname.h>
#include <catalog/catalog.h>
#include <catalog/catalog.h>
#include <catalog/indexing.h>
#include <catalog/indexing.h>
#include <catalog/heap.h>
#include <catalog/heap.h>
#include <catalog/index.h>
#include <catalog/index.h>
#include <catalog/pg_type.h>
#include <executor/executor.h>
#include <executor/executor.h>
#include <miscadmin.h>
#include <optimizer/clauses.h>
#include <optimizer/clauses.h>
#include <optimizer/prep.h>
#include <optimizer/prep.h>
#include <access/istrat.h>
#include <parser/parse_func.h>
#include <storage/lmgr.h>
#include <storage/smgr.h>
#include <utils/builtins.h>
#include <utils/mcxt.h>
#include <utils/relcache.h>
#include <utils/syscache.h>
#include <utils/tqual.h>
#ifndef HAVE_MEMMOVE
#ifndef HAVE_MEMMOVE
#include <regex/utils.h>
#include <regex/utils.h>
...
...
src/backend/catalog/pg_operator.c
View file @
4a5b781d
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.1
6 1997/11/24 05:08:15
momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.1
7 1997/11/25 21:58:46
momjian Exp $
*
*
* NOTES
* NOTES
* these routines moved here from commands/define.c and somewhat cleaned up.
* these routines moved here from commands/define.c and somewhat cleaned up.
...
@@ -20,9 +20,10 @@
...
@@ -20,9 +20,10 @@
#include <utils/syscache.h>
#include <utils/syscache.h>
#include <utils/tqual.h>
#include <utils/tqual.h>
#include <access/heapam.h>
#include <access/heapam.h>
#include <parser/catalog_utils.h>
#include <catalog/catname.h>
#include <catalog/catname.h>
#include <catalog/pg_operator.h>
#include <catalog/pg_operator.h>
#include <catalog/pg_type.h>
#include <parser/parse_oper.h>
#include <storage/bufmgr.h>
#include <storage/bufmgr.h>
#include <fmgr.h>
#include <fmgr.h>
#include <miscadmin.h>
#include <miscadmin.h>
...
...
src/backend/catalog/pg_proc.c
View file @
4a5b781d
...
@@ -7,28 +7,28 @@
...
@@ -7,28 +7,28 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.
9 1997/09/18 20:20:1
8 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.
10 1997/11/25 21:58:4
8 momjian Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
#include <postgres.h>
#include <postgres.h>
#include <fmgr.h>
#include <miscadmin.h>
#include <utils/syscache.h>
#include <utils/syscache.h>
#include <catalog/pg_proc.h>
#include <catalog/pg_proc.h>
#include <access/heapam.h>
#include <access/heapam.h>
#include <access/relscan.h>
#include <access/relscan.h>
#include <fmgr.h>
#include <utils/builtins.h>
#include <utils/sets.h>
#include <catalog/catname.h>
#include <catalog/catname.h>
#include <catalog/indexing.h>
#include <catalog/indexing.h>
#include <parser/parse_query.h>
#include <catalog/pg_type.h>
#include <parser/parse_node.h>
#include <tcop/tcopprot.h>
#include <tcop/tcopprot.h>
#include <parser/catalog_utils.h>
#include <utils/builtins.h>
#include <utils/sets.h>
#include <utils/lsyscache.h>
#include <optimizer/internal.h>
#include <optimizer/internal.h>
#include <optimizer/planner.h>
#include <optimizer/planner.h>
#include <utils/lsyscache.h>
#include <miscadmin.h>
#ifndef HAVE_MEMMOVE
#ifndef HAVE_MEMMOVE
#include <regex/utils.h>
#include <regex/utils.h>
#else
#else
...
@@ -200,7 +200,7 @@ ProcedureCreate(char *procedureName,
...
@@ -200,7 +200,7 @@ ProcedureCreate(char *procedureName,
if
(
parameterCount
==
1
&&
if
(
parameterCount
==
1
&&
(
toid
=
TypeGet
(
strVal
(
lfirst
(
argList
)),
&
defined
))
&&
(
toid
=
TypeGet
(
strVal
(
lfirst
(
argList
)),
&
defined
))
&&
defined
&&
defined
&&
(
relid
=
typeid
_get_r
elid
(
toid
))
!=
0
&&
(
relid
=
typeid
TypeR
elid
(
toid
))
!=
0
&&
get_attnum
(
relid
,
procedureName
)
!=
InvalidAttrNumber
)
get_attnum
(
relid
,
procedureName
)
!=
InvalidAttrNumber
)
elog
(
WARN
,
"method %s already an attribute of type %s"
,
elog
(
WARN
,
"method %s already an attribute of type %s"
,
procedureName
,
strVal
(
lfirst
(
argList
)));
procedureName
,
strVal
(
lfirst
(
argList
)));
...
...
src/backend/catalog/pg_type.c
View file @
4a5b781d
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.1
3 1997/11/24 05:08:17
momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.1
4 1997/11/25 21:58:50
momjian Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -20,9 +20,10 @@
...
@@ -20,9 +20,10 @@
#include <utils/builtins.h>
#include <utils/builtins.h>
#include <utils/tqual.h>
#include <utils/tqual.h>
#include <fmgr.h>
#include <fmgr.h>
#include <parser/catalog_utils.h>
#include <catalog/catname.h>
#include <catalog/catname.h>
#include <catalog/indexing.h>
#include <catalog/indexing.h>
#include <catalog/pg_type.h>
#include <parser/parse_func.h>
#include <storage/lmgr.h>
#include <storage/lmgr.h>
#include <miscadmin.h>
#include <miscadmin.h>
#ifndef HAVE_MEMMOVE
#ifndef HAVE_MEMMOVE
...
...
src/backend/commands/_deadcode/version.c
View file @
4a5b781d
...
@@ -10,7 +10,7 @@
...
@@ -10,7 +10,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/_deadcode/Attic/version.c,v 1.
7 1997/09/08 02:22:18
momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/_deadcode/Attic/version.c,v 1.
8 1997/11/25 21:59:11
momjian Exp $
*
*
* NOTES
* NOTES
* At the point the version is defined, 2 physical relations are created
* At the point the version is defined, 2 physical relations are created
...
@@ -30,6 +30,7 @@
...
@@ -30,6 +30,7 @@
#include <utils/builtins.h>
#include <utils/builtins.h>
#include <commands/version.h>
#include <commands/version.h>
#include <access/xact.h>
/* for GetCurrentXactStartTime */
#include <access/xact.h>
/* for GetCurrentXactStartTime */
#include <parser/parse_node.h>
#include <tcop/tcopprot.h>
#include <tcop/tcopprot.h>
#define MAX_QUERY_LEN 1024
#define MAX_QUERY_LEN 1024
...
...
src/backend/commands/explain.c
View file @
4a5b781d
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.1
4 1997/09/18 20:20:22
momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.1
5 1997/11/25 21:58:53
momjian Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -16,12 +16,11 @@
...
@@ -16,12 +16,11 @@
#include <postgres.h>
#include <postgres.h>
#include <parser/catalog_utils.h>
#include <parser/parse_query.h>
/* for MakeTimeRange() */
#include <nodes/plannodes.h>
#include <nodes/plannodes.h>
#include <tcop/tcopprot.h>
#include <tcop/tcopprot.h>
#include <lib/stringinfo.h>
#include <lib/stringinfo.h>
#include <commands/explain.h>
#include <commands/explain.h>
#include <parser/parse_node.h>
#include <optimizer/planner.h>
#include <optimizer/planner.h>
#include <access/xact.h>
#include <access/xact.h>
...
...
src/backend/commands/recipe.c
View file @
4a5b781d
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/recipe.c,v 1.1
2 1997/11/21 18:09:51
momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/recipe.c,v 1.1
3 1997/11/25 21:59:00
momjian Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -20,9 +20,9 @@
...
@@ -20,9 +20,9 @@
#include <catalog/pg_type.h>
#include <catalog/pg_type.h>
#include <commands/recipe.h>
#include <commands/recipe.h>
#include <libpq/libpq-be.h>
#include <libpq/libpq-be.h>
#include <parser/parse_node.h>
#include <utils/builtins.h>
#include <utils/builtins.h>
#include <utils/relcache.h>
/* for RelationNameGetRelation */
#include <utils/relcache.h>
/* for RelationNameGetRelation */
#include <parser/parse_query.h>
#include <rewrite/rewriteHandler.h>
#include <rewrite/rewriteHandler.h>
#include <rewrite/rewriteManip.h>
#include <rewrite/rewriteManip.h>
#include <tcop/pquery.h>
#include <tcop/pquery.h>
...
@@ -488,7 +488,7 @@ tg_replaceNumberedParam(Node *expression,
...
@@ -488,7 +488,7 @@ tg_replaceNumberedParam(Node *expression,
* "result" attribute from the tee relation
* "result" attribute from the tee relation
*/
*/
isRel
=
(
typeid
_get_r
elid
(
p
->
paramtype
)
!=
0
);
isRel
=
(
typeid
TypeR
elid
(
p
->
paramtype
)
!=
0
);
if
(
isRel
)
if
(
isRel
)
{
{
newVar
=
makeVar
(
rt_ind
,
newVar
=
makeVar
(
rt_ind
,
...
...
src/backend/commands/remove.c
View file @
4a5b781d
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.1
6 1997/11/20 23:21:1
3 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.1
7 1997/11/25 21:59:0
3 momjian Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -24,7 +24,8 @@
...
@@ -24,7 +24,8 @@
#include <catalog/pg_language.h>
#include <catalog/pg_language.h>
#include <catalog/pg_operator.h>
#include <catalog/pg_operator.h>
#include <catalog/pg_proc.h>
#include <catalog/pg_proc.h>
#include <parser/catalog_utils.h>
#include <catalog/pg_type.h>
#include <parser/parse_func.h>
#include <storage/bufmgr.h>
#include <storage/bufmgr.h>
#include <fmgr.h>
#include <fmgr.h>
#ifndef HAVE_MEMMOVE
#ifndef HAVE_MEMMOVE
...
...
src/backend/commands/vacuum.c
View file @
4a5b781d
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.5
2 1997/11/21 19:59:34
momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.5
3 1997/11/25 21:59:09
momjian Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -36,6 +36,7 @@
...
@@ -36,6 +36,7 @@
#include <catalog/pg_statistic.h>
#include <catalog/pg_statistic.h>
#include <catalog/pg_type.h>
#include <catalog/pg_type.h>
#include <catalog/pg_operator.h>
#include <catalog/pg_operator.h>
#include <parser/parse_oper.h>
#include <storage/smgr.h>
#include <storage/smgr.h>
#include <storage/lmgr.h>
#include <storage/lmgr.h>
#include <utils/inval.h>
#include <utils/inval.h>
...
@@ -44,7 +45,6 @@
...
@@ -44,7 +45,6 @@
#include <utils/syscache.h>
#include <utils/syscache.h>
#include <utils/builtins.h>
#include <utils/builtins.h>
#include <commands/vacuum.h>
#include <commands/vacuum.h>
#include <parser/catalog_utils.h>
#include <storage/bufpage.h>
#include <storage/bufpage.h>
#include "storage/shmem.h"
#include "storage/shmem.h"
#ifndef HAVE_GETRUSAGE
#ifndef HAVE_GETRUSAGE
...
...
src/backend/commands/view.c
View file @
4a5b781d
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/view.c,v 1.1
5 1997/11/21 18:09:58
momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/view.c,v 1.1
6 1997/11/25 21:59:12
momjian Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -21,8 +21,8 @@
...
@@ -21,8 +21,8 @@
#include <access/xact.h>
#include <access/xact.h>
#include <utils/builtins.h>
#include <utils/builtins.h>
#include <nodes/relation.h>
#include <nodes/relation.h>
#include <parser/
catalog_utils
.h>
#include <parser/
parse_relation
.h>
#include <parser/parse_
query
.h>
#include <parser/parse_
type
.h>
#include <rewrite/rewriteDefine.h>
#include <rewrite/rewriteDefine.h>
#include <rewrite/rewriteHandler.h>
#include <rewrite/rewriteHandler.h>
#include <rewrite/rewriteManip.h>
#include <rewrite/rewriteManip.h>
...
@@ -72,7 +72,7 @@ DefineVirtualRelation(char *relname, List *tlist)
...
@@ -72,7 +72,7 @@ DefineVirtualRelation(char *relname, List *tlist)
entry
=
lfirst
(
t
);
entry
=
lfirst
(
t
);
res
=
entry
->
resdom
;
res
=
entry
->
resdom
;
resname
=
res
->
resname
;
resname
=
res
->
resname
;
restypename
=
t
name
(
get_id_type
(
res
->
restype
)
);
restypename
=
t
ypeidTypeName
(
res
->
restype
);
typename
=
makeNode
(
TypeName
);
typename
=
makeNode
(
TypeName
);
...
...
src/backend/executor/execTuples.c
View file @
4a5b781d
...
@@ -14,7 +14,7 @@
...
@@ -14,7 +14,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.1
0 1997/09/18 20:20:32
momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.1
1 1997/11/25 21:59:16
momjian Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -125,11 +125,11 @@
...
@@ -125,11 +125,11 @@
#undef ExecStoreTuple
#undef ExecStoreTuple
#include "access/tupdesc.h"
#include "access/tupdesc.h"
#include "catalog/pg_type.h"
#include "parser/parse_type.h"
#include "storage/bufmgr.h"
#include "utils/palloc.h"
#include "utils/palloc.h"
#include "utils/lsyscache.h"
#include "utils/lsyscache.h"
#include "storage/bufmgr.h"
#include "parser/catalog_utils.h"
#include "catalog/pg_type.h"
static
TupleTableSlot
*
NodeGetResultTupleSlot
(
Plan
*
node
);
static
TupleTableSlot
*
NodeGetResultTupleSlot
(
Plan
*
node
);
...
...
src/backend/executor/functions.c
View file @
4a5b781d
...
@@ -8,7 +8,7 @@
...
@@ -8,7 +8,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.1
2 1997/09/18 20:20:37
momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.1
3 1997/11/25 21:59:19
momjian Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -21,7 +21,6 @@
...
@@ -21,7 +21,6 @@
#include "nodes/plannodes.h"
#include "nodes/plannodes.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_proc.h"
#include "parser/parse_query.h"
#include "tcop/pquery.h"
#include "tcop/pquery.h"
#include "tcop/tcopprot.h"
#include "tcop/tcopprot.h"
#include "tcop/utility.h"
#include "tcop/utility.h"
...
...
src/backend/executor/nodeAgg.c
View file @
4a5b781d
...
@@ -23,12 +23,12 @@
...
@@ -23,12 +23,12 @@
#include "access/heapam.h"
#include "access/heapam.h"
#include "catalog/pg_aggregate.h"
#include "catalog/pg_aggregate.h"
#include "catalog/catalog.h"
#include "catalog/catalog.h"
#include "parser/parse_type.h"
#include "executor/executor.h"
#include "executor/executor.h"
#include "executor/nodeAgg.h"
#include "executor/nodeAgg.h"
#include "storage/bufmgr.h"
#include "storage/bufmgr.h"
#include "utils/palloc.h"
#include "utils/palloc.h"
#include "utils/syscache.h"
#include "utils/syscache.h"
#include "parser/catalog_utils.h"
/*
/*
* AggFuncInfo -
* AggFuncInfo -
...
@@ -172,7 +172,7 @@ ExecAgg(Agg *node)
...
@@ -172,7 +172,7 @@ ExecAgg(Agg *node)
if
(
!
HeapTupleIsValid
(
aggTuple
))
if
(
!
HeapTupleIsValid
(
aggTuple
))
elog
(
WARN
,
"ExecAgg: cache lookup failed for aggregate
\"
%s
\"
(%s)"
,
elog
(
WARN
,
"ExecAgg: cache lookup failed for aggregate
\"
%s
\"
(%s)"
,
aggname
,
aggname
,
t
name
(
get_id_type
(
agg
->
basetype
)
));
t
ypeidTypeName
(
agg
->
basetype
));
aggp
=
(
Form_pg_aggregate
)
GETSTRUCT
(
aggTuple
);
aggp
=
(
Form_pg_aggregate
)
GETSTRUCT
(
aggTuple
);
xfn1_oid
=
aggp
->
aggtransfn1
;
xfn1_oid
=
aggp
->
aggtransfn1
;
...
...
src/backend/executor/spi.c
View file @
4a5b781d
...
@@ -6,6 +6,7 @@
...
@@ -6,6 +6,7 @@
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
#include "executor/spi.h"
#include "executor/spi.h"
#include "catalog/pg_type.h"
#include "access/printtup.h"
#include "access/printtup.h"
#include "fmgr.h"
#include "fmgr.h"
...
...
src/backend/nodes/copyfuncs.c
View file @
4a5b781d
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.1
5 1997/11/20 23:21
:40 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.1
6 1997/11/25 21:59
:40 momjian Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -22,7 +22,6 @@
...
@@ -22,7 +22,6 @@
#include "nodes/parsenodes.h"
#include "nodes/parsenodes.h"
#include "nodes/primnodes.h"
#include "nodes/primnodes.h"
#include "nodes/relation.h"
#include "nodes/relation.h"
#include "parser/parse_query.h"
#include "utils/syscache.h"
#include "utils/syscache.h"
#include "utils/builtins.h"
/* for namecpy */
#include "utils/builtins.h"
/* for namecpy */
...
...
src/backend/nodes/print.c
View file @
4a5b781d
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/print.c,v 1.1
0 1997/10/25 01:09:28
momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/print.c,v 1.1
1 1997/11/25 21:59:44
momjian Exp $
*
*
* HISTORY
* HISTORY
* AUTHOR DATE MAJOR EVENT
* AUTHOR DATE MAJOR EVENT
...
@@ -26,11 +26,11 @@
...
@@ -26,11 +26,11 @@
#include "nodes/parsenodes.h"
#include "nodes/parsenodes.h"
#include "nodes/print.h"
#include "nodes/print.h"
#include "parser/parsetree.h"
#include "parser/parsetree.h"
#include "parser/catalog_utils.h"
#include "access/heapam.h"
#include "access/heapam.h"
#include "utils/lsyscache.h"
#include "utils/lsyscache.h"
#include "nodes/nodes.h"
#include "nodes/nodes.h"
#include "nodes/plannodes.h"
#include "nodes/plannodes.h"
#include "parser/parse_relation.h"
#include "optimizer/clauses.h"
#include "optimizer/clauses.h"
static
char
*
plannode_type
(
Plan
*
p
);
static
char
*
plannode_type
(
Plan
*
p
);
...
@@ -194,7 +194,7 @@ print_expr(Node *expr, List *rtable)
...
@@ -194,7 +194,7 @@ print_expr(Node *expr, List *rtable)
r
=
heap_openr
(
relname
);
r
=
heap_openr
(
relname
);
if
(
rt
->
refname
)
if
(
rt
->
refname
)
relname
=
rt
->
refname
;
/* table renamed */
relname
=
rt
->
refname
;
/* table renamed */
attname
=
getAttr
Name
(
r
,
var
->
varattno
);
attname
=
attnumAtt
Name
(
r
,
var
->
varattno
);
heap_close
(
r
);
heap_close
(
r
);
}
}
break
;
break
;
...
...
src/backend/optimizer/path/xfunc.c
View file @
4a5b781d
...
@@ -9,7 +9,7 @@
...
@@ -9,7 +9,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/xfunc.c,v 1.
6 1997/09/08 21:45:1
0 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/xfunc.c,v 1.
7 1997/11/25 21:59:5
0 momjian Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -641,10 +641,10 @@ xfunc_width(LispValue clause)
...
@@ -641,10 +641,10 @@ xfunc_width(LispValue clause)
}
}
else
if
(
IsA
(
clause
,
Param
))
else
if
(
IsA
(
clause
,
Param
))
{
{
if
(
typeid
_get_r
elid
(
get_paramtype
((
Param
)
clause
)))
if
(
typeid
TypeR
elid
(
get_paramtype
((
Param
)
clause
)))
{
{
/* Param node returns a tuple. Find its width */
/* Param node returns a tuple. Find its width */
rd
=
heap_open
(
typeid
_get_r
elid
(
get_paramtype
((
Param
)
clause
)));
rd
=
heap_open
(
typeid
TypeR
elid
(
get_paramtype
((
Param
)
clause
)));
retval
=
xfunc_tuple_width
(
rd
);
retval
=
xfunc_tuple_width
(
rd
);
heap_close
(
rd
);
heap_close
(
rd
);
}
}
...
@@ -659,7 +659,7 @@ xfunc_width(LispValue clause)
...
@@ -659,7 +659,7 @@ xfunc_width(LispValue clause)
else
else
{
{
/* Param node returns a base type */
/* Param node returns a base type */
retval
=
t
len
(
get_id_t
ype
(
get_paramtype
((
Param
)
clause
)));
retval
=
t
ypeLen
(
typeidT
ype
(
get_paramtype
((
Param
)
clause
)));
}
}
goto
exit
;
goto
exit
;
}
}
...
@@ -1324,9 +1324,9 @@ xfunc_func_width(RegProcedure funcid, LispValue args)
...
@@ -1324,9 +1324,9 @@ xfunc_func_width(RegProcedure funcid, LispValue args)
proc
=
(
Form_pg_proc
)
GETSTRUCT
(
tupl
);
proc
=
(
Form_pg_proc
)
GETSTRUCT
(
tupl
);
/* if function returns a tuple, get the width of that */
/* if function returns a tuple, get the width of that */
if
(
typeid
_get_r
elid
(
proc
->
prorettype
))
if
(
typeid
TypeR
elid
(
proc
->
prorettype
))
{
{
rd
=
heap_open
(
typeid
_get_r
elid
(
proc
->
prorettype
));
rd
=
heap_open
(
typeid
TypeR
elid
(
proc
->
prorettype
));
retval
=
xfunc_tuple_width
(
rd
);
retval
=
xfunc_tuple_width
(
rd
);
heap_close
(
rd
);
heap_close
(
rd
);
goto
exit
;
goto
exit
;
...
...
src/backend/optimizer/plan/createplan.c
View file @
4a5b781d
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.1
5 1997/09/08 21:45:13
momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.1
6 1997/11/25 21:59:56
momjian Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -31,7 +31,6 @@
...
@@ -31,7 +31,6 @@
#include "utils/palloc.h"
#include "utils/palloc.h"
#include "utils/builtins.h"
#include "utils/builtins.h"
#include "parser/parse_query.h"
#include "optimizer/clauseinfo.h"
#include "optimizer/clauseinfo.h"
#include "optimizer/clauses.h"
#include "optimizer/clauses.h"
#include "optimizer/planmain.h"
#include "optimizer/planmain.h"
...
...
src/backend/optimizer/plan/planner.c
View file @
4a5b781d
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.1
0 1997/11/21 18:10:26
momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.1
1 1997/11/25 21:59:59
momjian Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -19,9 +19,8 @@
...
@@ -19,9 +19,8 @@
#include "nodes/plannodes.h"
#include "nodes/plannodes.h"
#include "nodes/parsenodes.h"
#include "nodes/parsenodes.h"
#include "nodes/relation.h"
#include "nodes/relation.h"
#include "parser/parse_expr.h"
#include "parser/catalog_utils.h"
#include "parser/parse_query.h"
#include "utils/elog.h"
#include "utils/elog.h"
#include "utils/lsyscache.h"
#include "utils/lsyscache.h"
#include "access/heapam.h"
#include "access/heapam.h"
...
@@ -310,7 +309,7 @@ pg_checkretval(Oid rettype, QueryTreeList *queryTreeList)
...
@@ -310,7 +309,7 @@ pg_checkretval(Oid rettype, QueryTreeList *queryTreeList)
}
}
/* by here, the function is declared to return some type */
/* by here, the function is declared to return some type */
if
((
typ
=
(
Type
)
get_id_t
ype
(
rettype
))
==
NULL
)
if
((
typ
=
typeidT
ype
(
rettype
))
==
NULL
)
elog
(
WARN
,
"can't find return type %d for function
\n
"
,
rettype
);
elog
(
WARN
,
"can't find return type %d for function
\n
"
,
rettype
);
/*
/*
...
@@ -318,21 +317,21 @@ pg_checkretval(Oid rettype, QueryTreeList *queryTreeList)
...
@@ -318,21 +317,21 @@ pg_checkretval(Oid rettype, QueryTreeList *queryTreeList)
* final query had better be a retrieve.
* final query had better be a retrieve.
*/
*/
if
(
cmd
!=
CMD_SELECT
)
if
(
cmd
!=
CMD_SELECT
)
elog
(
WARN
,
"function declared to return type %s, but final query is not a retrieve"
,
t
n
ame
(
typ
));
elog
(
WARN
,
"function declared to return type %s, but final query is not a retrieve"
,
t
ypeTypeN
ame
(
typ
));
/*
/*
* test 4: for base type returns, the target list should have exactly
* test 4: for base type returns, the target list should have exactly
* one entry, and its type should agree with what the user declared.
* one entry, and its type should agree with what the user declared.
*/
*/
if
(
get_typr
elid
(
typ
)
==
InvalidOid
)
if
(
typeTypeR
elid
(
typ
)
==
InvalidOid
)
{
{
if
(
exec_tlist_length
(
tlist
)
>
1
)
if
(
exec_tlist_length
(
tlist
)
>
1
)
elog
(
WARN
,
"function declared to return %s returns multiple values in final retrieve"
,
t
n
ame
(
typ
));
elog
(
WARN
,
"function declared to return %s returns multiple values in final retrieve"
,
t
ypeTypeN
ame
(
typ
));
resnode
=
(
Resdom
*
)
((
TargetEntry
*
)
lfirst
(
tlist
))
->
resdom
;
resnode
=
(
Resdom
*
)
((
TargetEntry
*
)
lfirst
(
tlist
))
->
resdom
;
if
(
resnode
->
restype
!=
rettype
)
if
(
resnode
->
restype
!=
rettype
)
elog
(
WARN
,
"return type mismatch in function: declared to return %s, returns %s"
,
t
name
(
typ
),
tname
(
get_id_type
(
resnode
->
restype
)
));
elog
(
WARN
,
"return type mismatch in function: declared to return %s, returns %s"
,
t
ypeTypeName
(
typ
),
typeidTypeName
(
resnode
->
restype
));
/* by here, base return types match */
/* by here, base return types match */
return
;
return
;
...
@@ -358,16 +357,16 @@ pg_checkretval(Oid rettype, QueryTreeList *queryTreeList)
...
@@ -358,16 +357,16 @@ pg_checkretval(Oid rettype, QueryTreeList *queryTreeList)
* declared return type, and be sure that attributes 1 .. n in the
* declared return type, and be sure that attributes 1 .. n in the
* target list match the declared types.
* target list match the declared types.
*/
*/
reln
=
heap_open
(
get_typr
elid
(
typ
));
reln
=
heap_open
(
typeTypeR
elid
(
typ
));
if
(
!
RelationIsValid
(
reln
))
if
(
!
RelationIsValid
(
reln
))
elog
(
WARN
,
"cannot open relation relid %d"
,
get_typr
elid
(
typ
));
elog
(
WARN
,
"cannot open relation relid %d"
,
typeTypeR
elid
(
typ
));
relid
=
reln
->
rd_id
;
relid
=
reln
->
rd_id
;
relnatts
=
reln
->
rd_rel
->
relnatts
;
relnatts
=
reln
->
rd_rel
->
relnatts
;
if
(
exec_tlist_length
(
tlist
)
!=
relnatts
)
if
(
exec_tlist_length
(
tlist
)
!=
relnatts
)
elog
(
WARN
,
"function declared to return type %s does not retrieve (%s.*)"
,
t
name
(
typ
),
tn
ame
(
typ
));
elog
(
WARN
,
"function declared to return type %s does not retrieve (%s.*)"
,
t
ypeTypeName
(
typ
),
typeTypeN
ame
(
typ
));
/* expect attributes 1 .. n in order */
/* expect attributes 1 .. n in order */
for
(
i
=
1
;
i
<=
relnatts
;
i
++
)
for
(
i
=
1
;
i
<=
relnatts
;
i
++
)
...
@@ -397,14 +396,14 @@ pg_checkretval(Oid rettype, QueryTreeList *queryTreeList)
...
@@ -397,14 +396,14 @@ pg_checkretval(Oid rettype, QueryTreeList *queryTreeList)
else if (IsA(thenode, Func))
else if (IsA(thenode, Func))
tletype = (Oid) get_functype((Func *) thenode);
tletype = (Oid) get_functype((Func *) thenode);
else
else
elog(WARN, "function declared to return type %s does not retrieve (%s.all)", t
name(typ), tn
ame(typ));
elog(WARN, "function declared to return type %s does not retrieve (%s.all)", t
ypeTypeName(typ), typeTypeN
ame(typ));
}
}
else
else
elog(WARN, "function declared to return type %s does not retrieve (%s.all)", t
name(typ), tn
ame(typ));
elog(WARN, "function declared to return type %s does not retrieve (%s.all)", t
ypeTypeName(typ), typeTypeN
ame(typ));
#endif
#endif
/* reach right in there, why don't you? */
/* reach right in there, why don't you? */
if
(
tletype
!=
reln
->
rd_att
->
attrs
[
i
-
1
]
->
atttypid
)
if
(
tletype
!=
reln
->
rd_att
->
attrs
[
i
-
1
]
->
atttypid
)
elog
(
WARN
,
"function declared to return type %s does not retrieve (%s.all)"
,
t
name
(
typ
),
tn
ame
(
typ
));
elog
(
WARN
,
"function declared to return type %s does not retrieve (%s.all)"
,
t
ypeTypeName
(
typ
),
typeTypeN
ame
(
typ
));
}
}
heap_close
(
reln
);
heap_close
(
reln
);
...
...
src/backend/optimizer/prep/preptlist.c
View file @
4a5b781d
...
@@ -7,13 +7,14 @@
...
@@ -7,13 +7,14 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.
5 1997/09/08 21:45:3
6 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.
6 1997/11/25 22:00:0
6 momjian Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
#include <string.h>
#include <string.h>
#include "postgres.h"
#include "postgres.h"
#include "catalog/pg_type.h"
#include "nodes/pg_list.h"
#include "nodes/pg_list.h"
#include "nodes/relation.h"
#include "nodes/relation.h"
#include "nodes/primnodes.h"
#include "nodes/primnodes.h"
...
@@ -24,9 +25,9 @@
...
@@ -24,9 +25,9 @@
#include "utils/builtins.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/lsyscache.h"
#include "utils/palloc.h"
#include "utils/palloc.h"
#include "parser/parse_type.h"
#include "parser/parsetree.h"
/* for getrelid() */
#include "parser/parsetree.h"
/* for getrelid() */
#include "parser/catalog_utils.h"
#include "optimizer/internal.h"
#include "optimizer/internal.h"
#include "optimizer/prep.h"
#include "optimizer/prep.h"
...
@@ -278,7 +279,7 @@ new_relation_targetlist(Oid relid, Index rt_index, NodeTag node_type)
...
@@ -278,7 +279,7 @@ new_relation_targetlist(Oid relid, Index rt_index, NodeTag node_type)
attisset
=
get_attisset
(
/* type_id, */
relid
,
attname
);
attisset
=
get_attisset
(
/* type_id, */
relid
,
attname
);
if
(
attisset
)
if
(
attisset
)
{
{
typlen
=
t
len
(
type
(
"oid"
));
typlen
=
t
ypeLen
(
typeidType
(
OIDOID
));
}
}
else
else
{
{
...
...
src/backend/optimizer/prep/prepunion.c
View file @
4a5b781d
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.
8 1997/11/21 18:10:44
momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.
9 1997/11/25 22:00:10
momjian Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -22,7 +22,6 @@
...
@@ -22,7 +22,6 @@
#include "nodes/plannodes.h"
#include "nodes/plannodes.h"
#include "nodes/relation.h"
#include "nodes/relation.h"
#include "parser/parse_query.h"
#include "parser/parsetree.h"
#include "parser/parsetree.h"
#include "utils/elog.h"
#include "utils/elog.h"
...
...
src/backend/optimizer/util/tlist.c
View file @
4a5b781d
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/tlist.c,v 1.
7 1997/09/08 21:45:55
momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/tlist.c,v 1.
8 1997/11/25 22:00:16
momjian Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -26,7 +26,6 @@
...
@@ -26,7 +26,6 @@
#include "optimizer/clauses.h"
#include "optimizer/clauses.h"
#include "nodes/makefuncs.h"
#include "nodes/makefuncs.h"
#include "parser/catalog_utils.h"
static
Node
*
flatten_tlistentry
(
Node
*
tlistentry
,
List
*
flat_tlist
);
static
Node
*
flatten_tlistentry
(
Node
*
tlistentry
,
List
*
flat_tlist
);
...
...
src/backend/parser/Makefile
View file @
4a5b781d
...
@@ -4,7 +4,7 @@
...
@@ -4,7 +4,7 @@
# Makefile for parser
# Makefile for parser
#
#
# IDENTIFICATION
# IDENTIFICATION
# $Header: /cvsroot/pgsql/src/backend/parser/Makefile,v 1.1
1 1997/11/24 05:20:57
momjian Exp $
# $Header: /cvsroot/pgsql/src/backend/parser/Makefile,v 1.1
2 1997/11/25 22:00:21
momjian Exp $
#
#
#-------------------------------------------------------------------------
#-------------------------------------------------------------------------
...
@@ -22,8 +22,9 @@ CFLAGS+= -Wno-error
...
@@ -22,8 +22,9 @@ CFLAGS+= -Wno-error
endif
endif
OBJS
=
analyze.o catalog_utils.o gram.o
\
OBJS
=
analyze.o gram.o keywords.o parser.o parse_agg.o parse_clause.o
\
keywords.o parser.o parse_query.o scan.o scansup.o
parse_expr.o parse_func.o parse_node.o parse_oper.o parse_relation.o
\
parse_type.o parse_target.o scan.o scansup.o
all
:
SUBSYS.o
all
:
SUBSYS.o
...
...
src/backend/parser/analyze.c
View file @
4a5b781d
...
@@ -7,46 +7,30 @@
...
@@ -7,46 +7,30 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.
49 1997/11/20 23:22:11
momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.
50 1997/11/25 22:00:27
momjian Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdlib.h>
#include <string.h>
#include <string.h>
#include "postgres.h"
#include "postgres.h"
#include "nodes/nodes.h"
#include "nodes/params.h"
#include "nodes/primnodes.h"
#include "nodes/parsenodes.h"
#include "nodes/relation.h"
#include "parse.h"
/* for AND, OR, etc. */
#include "catalog/pg_aggregate.h"
#include "catalog/pg_type.h"
/* for INT4OID, etc. */
#include "catalog/pg_proc.h"
#include "utils/elog.h"
#include "utils/builtins.h"
/* namecmp(), textout() */
#include "utils/lsyscache.h"
#include "utils/palloc.h"
#include "utils/mcxt.h"
#include "utils/syscache.h"
#include "utils/acl.h"
#include "parser/parse_query.h"
#include "parser/parse_state.h"
#include "nodes/makefuncs.h"
/* for makeResdom(), etc. */
#include "nodes/nodeFuncs.h"
#include "commands/sequence.h"
#include "optimizer/clauses.h"
#include "access/heapam.h"
#include "miscadmin.h"
#include "port-protos.h"
/* strdup() */
#include "access/heapam.h"
#include "nodes/makefuncs.h"
#include "nodes/memnodes.h"
#include "nodes/pg_list.h"
#include "parser/analyze.h"
#include "parser/parse_agg.h"
#include "parser/parse_node.h"
#include "parser/parse_relation.h"
#include "parser/parse_target.h"
#include "parser/parse_clause.h"
#include "utils/builtins.h"
#include "utils/mcxt.h"
/* convert the parse tree into a query tree */
static
Query
*
transformStmt
(
ParseState
*
pstate
,
Node
*
stmt
);
static
Query
*
transformStmt
(
ParseState
*
pstate
,
Node
*
stmt
);
static
Query
*
transformDeleteStmt
(
ParseState
*
pstate
,
DeleteStmt
*
stmt
);
static
Query
*
transformDeleteStmt
(
ParseState
*
pstate
,
DeleteStmt
*
stmt
);
static
Query
*
transformInsertStmt
(
ParseState
*
pstate
,
AppendStmt
*
stmt
);
static
Query
*
transformInsertStmt
(
ParseState
*
pstate
,
AppendStmt
*
stmt
);
static
Query
*
transformIndexStmt
(
ParseState
*
pstate
,
IndexStmt
*
stmt
);
static
Query
*
transformIndexStmt
(
ParseState
*
pstate
,
IndexStmt
*
stmt
);
...
@@ -55,74 +39,7 @@ static Query *transformRuleStmt(ParseState *query, RuleStmt *stmt);
...
@@ -55,74 +39,7 @@ static Query *transformRuleStmt(ParseState *query, RuleStmt *stmt);
static
Query
*
transformSelectStmt
(
ParseState
*
pstate
,
RetrieveStmt
*
stmt
);
static
Query
*
transformSelectStmt
(
ParseState
*
pstate
,
RetrieveStmt
*
stmt
);
static
Query
*
transformUpdateStmt
(
ParseState
*
pstate
,
ReplaceStmt
*
stmt
);
static
Query
*
transformUpdateStmt
(
ParseState
*
pstate
,
ReplaceStmt
*
stmt
);
static
Query
*
transformCursorStmt
(
ParseState
*
pstate
,
CursorStmt
*
stmt
);
static
Query
*
transformCursorStmt
(
ParseState
*
pstate
,
CursorStmt
*
stmt
);
static
Node
*
handleNestedDots
(
ParseState
*
pstate
,
Attr
*
attr
,
int
*
curr_resno
);
#define EXPR_COLUMN_FIRST 1
#define EXPR_RELATION_FIRST 2
static
Node
*
transformExpr
(
ParseState
*
pstate
,
Node
*
expr
,
int
precedence
);
static
Node
*
transformIdent
(
ParseState
*
pstate
,
Node
*
expr
,
int
precedence
);
static
void
makeRangeTable
(
ParseState
*
pstate
,
char
*
relname
,
List
*
frmList
);
static
List
*
expandAllTables
(
ParseState
*
pstate
);
static
char
*
figureColname
(
Node
*
expr
,
Node
*
resval
);
static
List
*
makeTargetNames
(
ParseState
*
pstate
,
List
*
cols
);
static
List
*
transformTargetList
(
ParseState
*
pstate
,
List
*
targetlist
);
static
TargetEntry
*
make_targetlist_expr
(
ParseState
*
pstate
,
char
*
colname
,
Node
*
expr
,
List
*
arrayRef
);
static
bool
inWhereClause
=
false
;
static
Node
*
transformWhereClause
(
ParseState
*
pstate
,
Node
*
a_expr
);
static
List
*
transformGroupClause
(
ParseState
*
pstate
,
List
*
grouplist
,
List
*
targetlist
);
static
List
*
transformSortClause
(
ParseState
*
pstate
,
List
*
orderlist
,
List
*
targetlist
,
char
*
uniqueFlag
);
static
void
parseFromClause
(
ParseState
*
pstate
,
List
*
frmList
);
static
Node
*
ParseFunc
(
ParseState
*
pstate
,
char
*
funcname
,
List
*
fargs
,
int
*
curr_resno
);
static
List
*
setup_tlist
(
char
*
attname
,
Oid
relid
);
static
List
*
setup_base_tlist
(
Oid
typeid
);
static
void
make_arguments
(
int
nargs
,
List
*
fargs
,
Oid
*
input_typeids
,
Oid
*
function_typeids
);
static
void
AddAggToParseState
(
ParseState
*
pstate
,
Aggreg
*
aggreg
);
static
void
finalizeAggregates
(
ParseState
*
pstate
,
Query
*
qry
);
static
void
parseCheckAggregates
(
ParseState
*
pstate
,
Query
*
qry
);
static
ParseState
*
makeParseState
(
void
);
static
Node
*
parser_typecast
(
Value
*
expr
,
TypeName
*
typename
,
int
typlen
);
static
Node
*
parser_typecast2
(
Node
*
expr
,
Oid
exprType
,
Type
tp
,
int
typlen
);
static
Aggreg
*
ParseAgg
(
char
*
aggname
,
Oid
basetype
,
Node
*
target
);
/*****************************************************************************
*
*****************************************************************************/
/*
* makeParseState() --
* allocate and initialize a new ParseState.
* the CALLERS is responsible for freeing the ParseState* returned
*
*/
static
ParseState
*
makeParseState
(
void
)
{
ParseState
*
pstate
;
pstate
=
malloc
(
sizeof
(
ParseState
));
pstate
->
p_last_resno
=
1
;
pstate
->
p_rtable
=
NIL
;
pstate
->
p_numAgg
=
0
;
pstate
->
p_aggs
=
NIL
;
pstate
->
p_is_insert
=
false
;
pstate
->
p_insert_columns
=
NIL
;
pstate
->
p_is_update
=
false
;
pstate
->
p_is_rule
=
false
;
pstate
->
p_target_relation
=
NULL
;
pstate
->
p_target_rangetblentry
=
NULL
;
return
(
pstate
);
}
/*
/*
* parse_analyze -
* parse_analyze -
...
@@ -144,11 +61,9 @@ parse_analyze(List *pl)
...
@@ -144,11 +61,9 @@ parse_analyze(List *pl)
result
->
len
=
length
(
pl
);
result
->
len
=
length
(
pl
);
result
->
qtrees
=
(
Query
**
)
malloc
(
result
->
len
*
sizeof
(
Query
*
));
result
->
qtrees
=
(
Query
**
)
malloc
(
result
->
len
*
sizeof
(
Query
*
));
inWhereClause
=
false
;
/* to avoid nextval(sequence) in WHERE */
while
(
pl
!=
NIL
)
while
(
pl
!=
NIL
)
{
{
pstate
=
make
ParseS
tate
();
pstate
=
make
_parses
tate
();
result
->
qtrees
[
i
++
]
=
transformStmt
(
pstate
,
lfirst
(
pl
));
result
->
qtrees
[
i
++
]
=
transformStmt
(
pstate
,
lfirst
(
pl
));
pl
=
lnext
(
pl
);
pl
=
lnext
(
pl
);
if
(
pstate
->
p_target_relation
!=
NULL
)
if
(
pstate
->
p_target_relation
!=
NULL
)
...
@@ -620,2580 +535,3 @@ transformCursorStmt(ParseState *pstate, CursorStmt *stmt)
...
@@ -620,2580 +535,3 @@ transformCursorStmt(ParseState *pstate, CursorStmt *stmt)
return
(
Query
*
)
qry
;
return
(
Query
*
)
qry
;
}
}
/*****************************************************************************
*
* Transform Exprs, Aggs, etc.
*
*****************************************************************************/
/*
* transformExpr -
* analyze and transform expressions. Type checking and type casting is
* done here. The optimizer and the executor cannot handle the original
* (raw) expressions collected by the parse tree. Hence the transformation
* here.
*/
static
Node
*
transformExpr
(
ParseState
*
pstate
,
Node
*
expr
,
int
precedence
)
{
Node
*
result
=
NULL
;
if
(
expr
==
NULL
)
return
NULL
;
switch
(
nodeTag
(
expr
))
{
case
T_Attr
:
{
Attr
*
att
=
(
Attr
*
)
expr
;
Node
*
temp
;
/* what if att.attrs == "*"?? */
temp
=
handleNestedDots
(
pstate
,
att
,
&
pstate
->
p_last_resno
);
if
(
att
->
indirection
!=
NIL
)
{
List
*
idx
=
att
->
indirection
;
while
(
idx
!=
NIL
)
{
A_Indices
*
ai
=
(
A_Indices
*
)
lfirst
(
idx
);
Node
*
lexpr
=
NULL
,
*
uexpr
;
uexpr
=
transformExpr
(
pstate
,
ai
->
uidx
,
precedence
);
/* must exists */
if
(
exprType
(
uexpr
)
!=
INT4OID
)
elog
(
WARN
,
"array index expressions must be int4's"
);
if
(
ai
->
lidx
!=
NULL
)
{
lexpr
=
transformExpr
(
pstate
,
ai
->
lidx
,
precedence
);
if
(
exprType
(
lexpr
)
!=
INT4OID
)
elog
(
WARN
,
"array index expressions must be int4's"
);
}
#if 0
pfree(ai->uidx);
if (ai->lidx != NULL)
pfree(ai->lidx);
#endif
ai
->
lidx
=
lexpr
;
ai
->
uidx
=
uexpr
;
/*
* note we reuse the list of indices, make sure we
* don't free them! Otherwise, make a new list
* here
*/
idx
=
lnext
(
idx
);
}
result
=
(
Node
*
)
make_array_ref
(
temp
,
att
->
indirection
);
}
else
{
result
=
temp
;
}
break
;
}
case
T_A_Const
:
{
A_Const
*
con
=
(
A_Const
*
)
expr
;
Value
*
val
=
&
con
->
val
;
if
(
con
->
typename
!=
NULL
)
{
result
=
parser_typecast
(
val
,
con
->
typename
,
-
1
);
}
else
{
result
=
(
Node
*
)
make_const
(
val
);
}
break
;
}
case
T_ParamNo
:
{
ParamNo
*
pno
=
(
ParamNo
*
)
expr
;
Oid
toid
;
int
paramno
;
Param
*
param
;
paramno
=
pno
->
number
;
toid
=
param_type
(
paramno
);
if
(
!
OidIsValid
(
toid
))
{
elog
(
WARN
,
"Parameter '$%d' is out of range"
,
paramno
);
}
param
=
makeNode
(
Param
);
param
->
paramkind
=
PARAM_NUM
;
param
->
paramid
=
(
AttrNumber
)
paramno
;
param
->
paramname
=
"<unnamed>"
;
param
->
paramtype
=
(
Oid
)
toid
;
param
->
param_tlist
=
(
List
*
)
NULL
;
result
=
(
Node
*
)
param
;
break
;
}
case
T_A_Expr
:
{
A_Expr
*
a
=
(
A_Expr
*
)
expr
;
switch
(
a
->
oper
)
{
case
OP
:
{
Node
*
lexpr
=
transformExpr
(
pstate
,
a
->
lexpr
,
precedence
);
Node
*
rexpr
=
transformExpr
(
pstate
,
a
->
rexpr
,
precedence
);
result
=
(
Node
*
)
make_op
(
a
->
opname
,
lexpr
,
rexpr
);
}
break
;
case
ISNULL
:
{
Node
*
lexpr
=
transformExpr
(
pstate
,
a
->
lexpr
,
precedence
);
result
=
ParseFunc
(
pstate
,
"nullvalue"
,
lcons
(
lexpr
,
NIL
),
&
pstate
->
p_last_resno
);
}
break
;
case
NOTNULL
:
{
Node
*
lexpr
=
transformExpr
(
pstate
,
a
->
lexpr
,
precedence
);
result
=
ParseFunc
(
pstate
,
"nonnullvalue"
,
lcons
(
lexpr
,
NIL
),
&
pstate
->
p_last_resno
);
}
break
;
case
AND
:
{
Expr
*
expr
=
makeNode
(
Expr
);
Node
*
lexpr
=
transformExpr
(
pstate
,
a
->
lexpr
,
precedence
);
Node
*
rexpr
=
transformExpr
(
pstate
,
a
->
rexpr
,
precedence
);
if
(
exprType
(
lexpr
)
!=
BOOLOID
)
elog
(
WARN
,
"left-hand side of AND is type '%s', not bool"
,
tname
(
get_id_type
(
exprType
(
lexpr
))));
if
(
exprType
(
rexpr
)
!=
BOOLOID
)
elog
(
WARN
,
"right-hand side of AND is type '%s', not bool"
,
tname
(
get_id_type
(
exprType
(
rexpr
))));
expr
->
typeOid
=
BOOLOID
;
expr
->
opType
=
AND_EXPR
;
expr
->
args
=
makeList
(
lexpr
,
rexpr
,
-
1
);
result
=
(
Node
*
)
expr
;
}
break
;
case
OR
:
{
Expr
*
expr
=
makeNode
(
Expr
);
Node
*
lexpr
=
transformExpr
(
pstate
,
a
->
lexpr
,
precedence
);
Node
*
rexpr
=
transformExpr
(
pstate
,
a
->
rexpr
,
precedence
);
if
(
exprType
(
lexpr
)
!=
BOOLOID
)
elog
(
WARN
,
"left-hand side of OR is type '%s', not bool"
,
tname
(
get_id_type
(
exprType
(
lexpr
))));
if
(
exprType
(
rexpr
)
!=
BOOLOID
)
elog
(
WARN
,
"right-hand side of OR is type '%s', not bool"
,
tname
(
get_id_type
(
exprType
(
rexpr
))));
expr
->
typeOid
=
BOOLOID
;
expr
->
opType
=
OR_EXPR
;
expr
->
args
=
makeList
(
lexpr
,
rexpr
,
-
1
);
result
=
(
Node
*
)
expr
;
}
break
;
case
NOT
:
{
Expr
*
expr
=
makeNode
(
Expr
);
Node
*
rexpr
=
transformExpr
(
pstate
,
a
->
rexpr
,
precedence
);
if
(
exprType
(
rexpr
)
!=
BOOLOID
)
elog
(
WARN
,
"argument to NOT is type '%s', not bool"
,
tname
(
get_id_type
(
exprType
(
rexpr
))));
expr
->
typeOid
=
BOOLOID
;
expr
->
opType
=
NOT_EXPR
;
expr
->
args
=
makeList
(
rexpr
,
-
1
);
result
=
(
Node
*
)
expr
;
}
break
;
}
break
;
}
case
T_Ident
:
{
/*
* look for a column name or a relation name (the default
* behavior)
*/
result
=
transformIdent
(
pstate
,
expr
,
precedence
);
break
;
}
case
T_FuncCall
:
{
FuncCall
*
fn
=
(
FuncCall
*
)
expr
;
List
*
args
;
/* transform the list of arguments */
foreach
(
args
,
fn
->
args
)
lfirst
(
args
)
=
transformExpr
(
pstate
,
(
Node
*
)
lfirst
(
args
),
precedence
);
result
=
ParseFunc
(
pstate
,
fn
->
funcname
,
fn
->
args
,
&
pstate
->
p_last_resno
);
break
;
}
default:
/* should not reach here */
elog
(
WARN
,
"transformExpr: does not know how to transform %d
\n
"
,
nodeTag
(
expr
));
break
;
}
return
result
;
}
static
Node
*
transformIdent
(
ParseState
*
pstate
,
Node
*
expr
,
int
precedence
)
{
Ident
*
ident
=
(
Ident
*
)
expr
;
RangeTblEntry
*
rte
;
Node
*
column_result
,
*
relation_result
,
*
result
;
column_result
=
relation_result
=
result
=
0
;
/* try to find the ident as a column */
if
((
rte
=
colnameRangeTableEntry
(
pstate
,
ident
->
name
))
!=
NULL
)
{
Attr
*
att
=
makeNode
(
Attr
);
att
->
relname
=
rte
->
refname
;
att
->
attrs
=
lcons
(
makeString
(
ident
->
name
),
NIL
);
column_result
=
(
Node
*
)
handleNestedDots
(
pstate
,
att
,
&
pstate
->
p_last_resno
);
}
/* try to find the ident as a relation */
if
(
refnameRangeTableEntry
(
pstate
->
p_rtable
,
ident
->
name
)
!=
NULL
)
{
ident
->
isRel
=
TRUE
;
relation_result
=
(
Node
*
)
ident
;
}
/* choose the right result based on the precedence */
if
(
precedence
==
EXPR_COLUMN_FIRST
)
{
if
(
column_result
)
result
=
column_result
;
else
result
=
relation_result
;
}
else
{
if
(
relation_result
)
result
=
relation_result
;
else
result
=
column_result
;
}
if
(
result
==
NULL
)
elog
(
WARN
,
"attribute '%s' not found"
,
ident
->
name
);
return
result
;
}
/*****************************************************************************
*
* From Clause
*
*****************************************************************************/
/*
* parseFromClause -
* turns the table references specified in the from-clause into a
* range table. The range table may grow as we transform the expressions
* in the target list. (Note that this happens because in POSTQUEL, we
* allow references to relations not specified in the from-clause. We
* also allow that in our POST-SQL)
*
*/
static
void
parseFromClause
(
ParseState
*
pstate
,
List
*
frmList
)
{
List
*
fl
;
foreach
(
fl
,
frmList
)
{
RangeVar
*
r
=
lfirst
(
fl
);
RelExpr
*
baserel
=
r
->
relExpr
;
char
*
relname
=
baserel
->
relname
;
char
*
refname
=
r
->
name
;
RangeTblEntry
*
rte
;
if
(
refname
==
NULL
)
refname
=
relname
;
/*
* marks this entry to indicate it comes from the FROM clause. In
* SQL, the target list can only refer to range variables
* specified in the from clause but we follow the more powerful
* POSTQUEL semantics and automatically generate the range
* variable if not specified. However there are times we need to
* know whether the entries are legitimate.
*
* eg. select * from foo f where f.x = 1; will generate wrong answer
* if we expand * to foo.x.
*/
rte
=
addRangeTableEntry
(
pstate
,
relname
,
refname
,
baserel
->
inh
,
TRUE
);
}
}
/*
* makeRangeTable -
* make a range table with the specified relation (optional) and the
* from-clause.
*/
static
void
makeRangeTable
(
ParseState
*
pstate
,
char
*
relname
,
List
*
frmList
)
{
RangeTblEntry
*
rte
;
parseFromClause
(
pstate
,
frmList
);
if
(
relname
==
NULL
)
return
;
if
(
refnameRangeTablePosn
(
pstate
->
p_rtable
,
relname
)
<
1
)
rte
=
addRangeTableEntry
(
pstate
,
relname
,
relname
,
FALSE
,
FALSE
);
else
rte
=
refnameRangeTableEntry
(
pstate
->
p_rtable
,
relname
);
pstate
->
p_target_rangetblentry
=
rte
;
Assert
(
pstate
->
p_target_relation
==
NULL
);
pstate
->
p_target_relation
=
heap_open
(
rte
->
relid
);
Assert
(
pstate
->
p_target_relation
!=
NULL
);
/* will close relation later */
}
/*
* exprType -
* returns the Oid of the type of the expression. (Used for typechecking.)
*/
Oid
exprType
(
Node
*
expr
)
{
Oid
type
=
(
Oid
)
0
;
switch
(
nodeTag
(
expr
))
{
case
T_Func
:
type
=
((
Func
*
)
expr
)
->
functype
;
break
;
case
T_Iter
:
type
=
((
Iter
*
)
expr
)
->
itertype
;
break
;
case
T_Var
:
type
=
((
Var
*
)
expr
)
->
vartype
;
break
;
case
T_Expr
:
type
=
((
Expr
*
)
expr
)
->
typeOid
;
break
;
case
T_Const
:
type
=
((
Const
*
)
expr
)
->
consttype
;
break
;
case
T_ArrayRef
:
type
=
((
ArrayRef
*
)
expr
)
->
refelemtype
;
break
;
case
T_Aggreg
:
type
=
((
Aggreg
*
)
expr
)
->
aggtype
;
break
;
case
T_Param
:
type
=
((
Param
*
)
expr
)
->
paramtype
;
break
;
case
T_Ident
:
/* is this right? */
type
=
UNKNOWNOID
;
break
;
default:
elog
(
WARN
,
"exprType: don't know how to get type for %d node"
,
nodeTag
(
expr
));
break
;
}
return
type
;
}
/*
* expandAllTables -
* turns '*' (in the target list) into a list of attributes
* (of all relations in the range table)
*/
static
List
*
expandAllTables
(
ParseState
*
pstate
)
{
List
*
target
=
NIL
;
List
*
legit_rtable
=
NIL
;
List
*
rt
,
*
rtable
;
rtable
=
pstate
->
p_rtable
;
if
(
pstate
->
p_is_rule
)
{
/*
* skip first two entries, "*new*" and "*current*"
*/
rtable
=
lnext
(
lnext
(
pstate
->
p_rtable
));
}
/* this should not happen */
if
(
rtable
==
NULL
)
elog
(
WARN
,
"cannot expand: null p_rtable"
);
/*
* go through the range table and make a list of range table entries
* which we will expand.
*/
foreach
(
rt
,
rtable
)
{
RangeTblEntry
*
rte
=
lfirst
(
rt
);
/*
* we only expand those specify in the from clause. (This will
* also prevent us from using the wrong table in inserts: eg.
* tenk2 in "insert into tenk2 select * from tenk1;")
*/
if
(
!
rte
->
inFromCl
)
continue
;
legit_rtable
=
lappend
(
legit_rtable
,
rte
);
}
foreach
(
rt
,
legit_rtable
)
{
RangeTblEntry
*
rte
=
lfirst
(
rt
);
List
*
temp
=
target
;
if
(
temp
==
NIL
)
target
=
expandAll
(
pstate
,
rte
->
relname
,
rte
->
refname
,
&
pstate
->
p_last_resno
);
else
{
while
(
temp
!=
NIL
&&
lnext
(
temp
)
!=
NIL
)
temp
=
lnext
(
temp
);
lnext
(
temp
)
=
expandAll
(
pstate
,
rte
->
relname
,
rte
->
refname
,
&
pstate
->
p_last_resno
);
}
}
return
target
;
}
/*
* figureColname -
* if the name of the resulting column is not specified in the target
* list, we have to guess.
*
*/
static
char
*
figureColname
(
Node
*
expr
,
Node
*
resval
)
{
switch
(
nodeTag
(
expr
))
{
case
T_Aggreg
:
return
(
char
*
)
/* XXX */
((
Aggreg
*
)
expr
)
->
aggname
;
case
T_Expr
:
if
(((
Expr
*
)
expr
)
->
opType
==
FUNC_EXPR
)
{
if
(
nodeTag
(
resval
)
==
T_FuncCall
)
return
((
FuncCall
*
)
resval
)
->
funcname
;
}
break
;
default:
break
;
}
return
"?column?"
;
}
/*****************************************************************************
*
* Target list
*
*****************************************************************************/
/*
* makeTargetNames -
* generate a list of column names if not supplied or
* test supplied column names to make sure they are in target table
* (used exclusively for inserts)
*/
static
List
*
makeTargetNames
(
ParseState
*
pstate
,
List
*
cols
)
{
List
*
tl
=
NULL
;
/* Generate ResTarget if not supplied */
if
(
cols
==
NIL
)
{
int
numcol
;
int
i
;
AttributeTupleForm
*
attr
=
pstate
->
p_target_relation
->
rd_att
->
attrs
;
numcol
=
pstate
->
p_target_relation
->
rd_rel
->
relnatts
;
for
(
i
=
0
;
i
<
numcol
;
i
++
)
{
Ident
*
id
=
makeNode
(
Ident
);
id
->
name
=
palloc
(
NAMEDATALEN
);
StrNCpy
(
id
->
name
,
attr
[
i
]
->
attname
.
data
,
NAMEDATALEN
);
id
->
indirection
=
NIL
;
id
->
isRel
=
false
;
if
(
tl
==
NIL
)
cols
=
tl
=
lcons
(
id
,
NIL
);
else
{
lnext
(
tl
)
=
lcons
(
id
,
NIL
);
tl
=
lnext
(
tl
);
}
}
}
else
{
foreach
(
tl
,
cols
)
{
List
*
nxt
;
char
*
name
=
((
Ident
*
)
lfirst
(
tl
))
->
name
;
/* elog on failure */
varattno
(
pstate
->
p_target_relation
,
name
);
foreach
(
nxt
,
lnext
(
tl
))
if
(
!
strcmp
(
name
,
((
Ident
*
)
lfirst
(
nxt
))
->
name
))
elog
(
WARN
,
"Attribute '%s' should be specified only once"
,
name
);
}
}
return
cols
;
}
/*
* transformTargetList -
* turns a list of ResTarget's into a list of TargetEntry's
*/
static
List
*
transformTargetList
(
ParseState
*
pstate
,
List
*
targetlist
)
{
List
*
p_target
=
NIL
;
List
*
tail_p_target
=
NIL
;
while
(
targetlist
!=
NIL
)
{
ResTarget
*
res
=
(
ResTarget
*
)
lfirst
(
targetlist
);
TargetEntry
*
tent
=
makeNode
(
TargetEntry
);
switch
(
nodeTag
(
res
->
val
))
{
case
T_Ident
:
{
Node
*
expr
;
Oid
type_id
;
int
type_len
;
char
*
identname
;
char
*
resname
;
identname
=
((
Ident
*
)
res
->
val
)
->
name
;
handleTargetColname
(
pstate
,
&
res
->
name
,
NULL
,
identname
);
/*
* here we want to look for column names only, not relation
* names (even though they can be stored in Ident nodes, too)
*/
expr
=
transformIdent
(
pstate
,
(
Node
*
)
res
->
val
,
EXPR_COLUMN_FIRST
);
type_id
=
exprType
(
expr
);
type_len
=
tlen
(
get_id_type
(
type_id
));
resname
=
(
res
->
name
)
?
res
->
name
:
identname
;
tent
->
resdom
=
makeResdom
((
AttrNumber
)
pstate
->
p_last_resno
++
,
(
Oid
)
type_id
,
(
Size
)
type_len
,
resname
,
(
Index
)
0
,
(
Oid
)
0
,
0
);
tent
->
expr
=
expr
;
break
;
}
case
T_ParamNo
:
case
T_FuncCall
:
case
T_A_Const
:
case
T_A_Expr
:
{
Node
*
expr
=
transformExpr
(
pstate
,
(
Node
*
)
res
->
val
,
EXPR_COLUMN_FIRST
);
handleTargetColname
(
pstate
,
&
res
->
name
,
NULL
,
NULL
);
/* note indirection has not been transformed */
if
(
pstate
->
p_is_insert
&&
res
->
indirection
!=
NIL
)
{
/* this is an array assignment */
char
*
val
;
char
*
str
,
*
save_str
;
List
*
elt
;
int
i
=
0
,
ndims
;
int
lindx
[
MAXDIM
],
uindx
[
MAXDIM
];
int
resdomno
;
Relation
rd
;
Value
*
constval
;
if
(
exprType
(
expr
)
!=
UNKNOWNOID
||
!
IsA
(
expr
,
Const
))
elog
(
WARN
,
"yyparse: string constant expected"
);
val
=
(
char
*
)
textout
((
struct
varlena
*
)
((
Const
*
)
expr
)
->
constvalue
);
str
=
save_str
=
(
char
*
)
palloc
(
strlen
(
val
)
+
MAXDIM
*
25
+
2
);
foreach
(
elt
,
res
->
indirection
)
{
A_Indices
*
aind
=
(
A_Indices
*
)
lfirst
(
elt
);
aind
->
uidx
=
transformExpr
(
pstate
,
aind
->
uidx
,
EXPR_COLUMN_FIRST
);
if
(
!
IsA
(
aind
->
uidx
,
Const
))
elog
(
WARN
,
"Array Index for Append should be a constant"
);
uindx
[
i
]
=
((
Const
*
)
aind
->
uidx
)
->
constvalue
;
if
(
aind
->
lidx
!=
NULL
)
{
aind
->
lidx
=
transformExpr
(
pstate
,
aind
->
lidx
,
EXPR_COLUMN_FIRST
);
if
(
!
IsA
(
aind
->
lidx
,
Const
))
elog
(
WARN
,
"Array Index for Append should be a constant"
);
lindx
[
i
]
=
((
Const
*
)
aind
->
lidx
)
->
constvalue
;
}
else
{
lindx
[
i
]
=
1
;
}
if
(
lindx
[
i
]
>
uindx
[
i
])
elog
(
WARN
,
"yyparse: lower index cannot be greater than upper index"
);
sprintf
(
str
,
"[%d:%d]"
,
lindx
[
i
],
uindx
[
i
]);
str
+=
strlen
(
str
);
i
++
;
}
sprintf
(
str
,
"=%s"
,
val
);
rd
=
pstate
->
p_target_relation
;
Assert
(
rd
!=
NULL
);
resdomno
=
varattno
(
rd
,
res
->
name
);
ndims
=
att_attnelems
(
rd
,
resdomno
);
if
(
i
!=
ndims
)
elog
(
WARN
,
"yyparse: array dimensions do not match"
);
constval
=
makeNode
(
Value
);
constval
->
type
=
T_String
;
constval
->
val
.
str
=
save_str
;
tent
=
make_targetlist_expr
(
pstate
,
res
->
name
,
(
Node
*
)
make_const
(
constval
),
NULL
);
pfree
(
save_str
);
}
else
{
char
*
colname
=
res
->
name
;
/* this is not an array assignment */
if
(
colname
==
NULL
)
{
/*
* if you're wondering why this is here, look
* at the yacc grammar for why a name can be
* missing. -ay
*/
colname
=
figureColname
(
expr
,
res
->
val
);
}
if
(
res
->
indirection
)
{
List
*
ilist
=
res
->
indirection
;
while
(
ilist
!=
NIL
)
{
A_Indices
*
ind
=
lfirst
(
ilist
);
ind
->
lidx
=
transformExpr
(
pstate
,
ind
->
lidx
,
EXPR_COLUMN_FIRST
);
ind
->
uidx
=
transformExpr
(
pstate
,
ind
->
uidx
,
EXPR_COLUMN_FIRST
);
ilist
=
lnext
(
ilist
);
}
}
res
->
name
=
colname
;
tent
=
make_targetlist_expr
(
pstate
,
res
->
name
,
expr
,
res
->
indirection
);
}
break
;
}
case
T_Attr
:
{
Oid
type_id
;
int
type_len
;
Attr
*
att
=
(
Attr
*
)
res
->
val
;
Node
*
result
;
char
*
attrname
;
char
*
resname
;
Resdom
*
resnode
;
List
*
attrs
=
att
->
attrs
;
/*
* Target item is a single '*', expand all tables (eg.
* SELECT * FROM emp)
*/
if
(
att
->
relname
!=
NULL
&&
!
strcmp
(
att
->
relname
,
"*"
))
{
if
(
tail_p_target
==
NIL
)
p_target
=
tail_p_target
=
expandAllTables
(
pstate
);
else
lnext
(
tail_p_target
)
=
expandAllTables
(
pstate
);
while
(
lnext
(
tail_p_target
)
!=
NIL
)
/* make sure we point to the last target entry */
tail_p_target
=
lnext
(
tail_p_target
);
/*
* skip rest of while loop
*/
targetlist
=
lnext
(
targetlist
);
continue
;
}
/*
* Target item is relation.*, expand the table (eg.
* SELECT emp.*, dname FROM emp, dept)
*/
attrname
=
strVal
(
lfirst
(
att
->
attrs
));
if
(
att
->
attrs
!=
NIL
&&
!
strcmp
(
attrname
,
"*"
))
{
/*
* tail_p_target is the target list we're building
* in the while loop. Make sure we fix it after
* appending more nodes.
*/
if
(
tail_p_target
==
NIL
)
p_target
=
tail_p_target
=
expandAll
(
pstate
,
att
->
relname
,
att
->
relname
,
&
pstate
->
p_last_resno
);
else
lnext
(
tail_p_target
)
=
expandAll
(
pstate
,
att
->
relname
,
att
->
relname
,
&
pstate
->
p_last_resno
);
while
(
lnext
(
tail_p_target
)
!=
NIL
)
/* make sure we point to the last target entry */
tail_p_target
=
lnext
(
tail_p_target
);
/*
* skip the rest of the while loop
*/
targetlist
=
lnext
(
targetlist
);
continue
;
}
/*
* Target item is fully specified: ie.
* relation.attribute
*/
result
=
handleNestedDots
(
pstate
,
att
,
&
pstate
->
p_last_resno
);
handleTargetColname
(
pstate
,
&
res
->
name
,
att
->
relname
,
attrname
);
if
(
att
->
indirection
!=
NIL
)
{
List
*
ilist
=
att
->
indirection
;
while
(
ilist
!=
NIL
)
{
A_Indices
*
ind
=
lfirst
(
ilist
);
ind
->
lidx
=
transformExpr
(
pstate
,
ind
->
lidx
,
EXPR_COLUMN_FIRST
);
ind
->
uidx
=
transformExpr
(
pstate
,
ind
->
uidx
,
EXPR_COLUMN_FIRST
);
ilist
=
lnext
(
ilist
);
}
result
=
(
Node
*
)
make_array_ref
(
result
,
att
->
indirection
);
}
type_id
=
exprType
(
result
);
type_len
=
tlen
(
get_id_type
(
type_id
));
/* move to last entry */
while
(
lnext
(
attrs
)
!=
NIL
)
attrs
=
lnext
(
attrs
);
resname
=
(
res
->
name
)
?
res
->
name
:
strVal
(
lfirst
(
attrs
));
resnode
=
makeResdom
((
AttrNumber
)
pstate
->
p_last_resno
++
,
(
Oid
)
type_id
,
(
Size
)
type_len
,
resname
,
(
Index
)
0
,
(
Oid
)
0
,
0
);
tent
->
resdom
=
resnode
;
tent
->
expr
=
result
;
break
;
}
default:
/* internal error */
elog
(
WARN
,
"internal error: do not know how to transform targetlist"
);
break
;
}
if
(
p_target
==
NIL
)
{
p_target
=
tail_p_target
=
lcons
(
tent
,
NIL
);
}
else
{
lnext
(
tail_p_target
)
=
lcons
(
tent
,
NIL
);
tail_p_target
=
lnext
(
tail_p_target
);
}
targetlist
=
lnext
(
targetlist
);
}
return
p_target
;
}
/*
* make_targetlist_expr -
* make a TargetEntry from an expression
*
* arrayRef is a list of transformed A_Indices
*/
static
TargetEntry
*
make_targetlist_expr
(
ParseState
*
pstate
,
char
*
colname
,
Node
*
expr
,
List
*
arrayRef
)
{
Oid
type_id
,
attrtype
;
int
type_len
,
attrlen
;
int
resdomno
;
Relation
rd
;
bool
attrisset
;
TargetEntry
*
tent
;
Resdom
*
resnode
;
if
(
expr
==
NULL
)
elog
(
WARN
,
"make_targetlist_expr: invalid use of NULL expression"
);
type_id
=
exprType
(
expr
);
if
(
type_id
==
InvalidOid
)
{
type_len
=
0
;
}
else
type_len
=
tlen
(
get_id_type
(
type_id
));
/* I have no idea what the following does! */
/* It appears to process target columns that will be receiving results */
if
(
pstate
->
p_is_insert
||
pstate
->
p_is_update
)
{
/*
* append or replace query -- append, replace work only on one
* relation, so multiple occurence of same resdomno is bogus
*/
rd
=
pstate
->
p_target_relation
;
Assert
(
rd
!=
NULL
);
resdomno
=
varattno
(
rd
,
colname
);
attrisset
=
varisset
(
rd
,
colname
);
attrtype
=
att_typeid
(
rd
,
resdomno
);
if
((
arrayRef
!=
NIL
)
&&
(
lfirst
(
arrayRef
)
==
NIL
))
attrtype
=
GetArrayElementType
(
attrtype
);
if
(
attrtype
==
BPCHAROID
||
attrtype
==
VARCHAROID
)
{
attrlen
=
rd
->
rd_att
->
attrs
[
resdomno
-
1
]
->
attlen
;
}
else
{
attrlen
=
tlen
(
get_id_type
(
attrtype
));
}
#if 0
if (Input_is_string && Typecast_ok)
{
Datum val;
if (type_id == typeid(type("unknown")))
{
val = (Datum) textout((struct varlena *)
((Const) lnext(expr))->constvalue);
}
else
{
val = ((Const) lnext(expr))->constvalue;
}
if (attrisset)
{
lnext(expr) = makeConst(attrtype,
attrlen,
val,
false,
true,
true, /* is set */
false);
}
else
{
lnext(expr) =
makeConst(attrtype,
attrlen,
(Datum) fmgr(typeid_get_retinfunc(attrtype),
val, get_typelem(attrtype), -1),
false,
true /* Maybe correct-- 80% chance */ ,
false, /* is not a set */
false);
}
}
else if ((Typecast_ok) && (attrtype != type_id))
{
lnext(expr) =
parser_typecast2(expr, get_id_type(attrtype));
}
else if (attrtype != type_id)
{
if ((attrtype == INT2OID) && (type_id == INT4OID))
lfirst(expr) = lispInteger(INT2OID); /* handle CASHOID too */
else if ((attrtype == FLOAT4OID) && (type_id == FLOAT8OID))
lfirst(expr) = lispInteger(FLOAT4OID);
else
elog(WARN, "unequal type in tlist : %s \n", colname);
}
Input_is_string = false;
Input_is_integer = false;
Typecast_ok = true;
#endif
if
(
attrtype
!=
type_id
)
{
if
(
IsA
(
expr
,
Const
))
{
/* try to cast the constant */
if
(
arrayRef
&&
!
(((
A_Indices
*
)
lfirst
(
arrayRef
))
->
lidx
))
{
/* updating a single item */
Oid
typelem
=
get_typelem
(
attrtype
);
expr
=
(
Node
*
)
parser_typecast2
(
expr
,
type_id
,
get_id_type
(
typelem
),
attrlen
);
}
else
expr
=
(
Node
*
)
parser_typecast2
(
expr
,
type_id
,
get_id_type
(
attrtype
),
attrlen
);
}
else
{
/* currently, we can't handle casting of expressions */
elog
(
WARN
,
"parser: attribute '%s' is of type '%s' but expression is of type '%s'"
,
colname
,
get_id_typname
(
attrtype
),
get_id_typname
(
type_id
));
}
}
if
(
arrayRef
!=
NIL
)
{
Expr
*
target_expr
;
Attr
*
att
=
makeNode
(
Attr
);
List
*
ar
=
arrayRef
;
List
*
upperIndexpr
=
NIL
;
List
*
lowerIndexpr
=
NIL
;
att
->
relname
=
pstrdup
(
RelationGetRelationName
(
rd
)
->
data
);
att
->
attrs
=
lcons
(
makeString
(
colname
),
NIL
);
target_expr
=
(
Expr
*
)
handleNestedDots
(
pstate
,
att
,
&
pstate
->
p_last_resno
);
while
(
ar
!=
NIL
)
{
A_Indices
*
ind
=
lfirst
(
ar
);
if
(
lowerIndexpr
||
(
!
upperIndexpr
&&
ind
->
lidx
))
{
/*
* XXX assume all lowerIndexpr is non-null in this
* case
*/
lowerIndexpr
=
lappend
(
lowerIndexpr
,
ind
->
lidx
);
}
upperIndexpr
=
lappend
(
upperIndexpr
,
ind
->
uidx
);
ar
=
lnext
(
ar
);
}
expr
=
(
Node
*
)
make_array_set
(
target_expr
,
upperIndexpr
,
lowerIndexpr
,
(
Expr
*
)
expr
);
attrtype
=
att_typeid
(
rd
,
resdomno
);
attrlen
=
tlen
(
get_id_type
(
attrtype
));
}
}
else
{
resdomno
=
pstate
->
p_last_resno
++
;
attrtype
=
type_id
;
attrlen
=
type_len
;
}
tent
=
makeNode
(
TargetEntry
);
resnode
=
makeResdom
((
AttrNumber
)
resdomno
,
(
Oid
)
attrtype
,
(
Size
)
attrlen
,
colname
,
(
Index
)
0
,
(
Oid
)
0
,
0
);
tent
->
resdom
=
resnode
;
tent
->
expr
=
expr
;
return
tent
;
}
/*****************************************************************************
*
* Where Clause
*
*****************************************************************************/
/*
* transformWhereClause -
* transforms the qualification and make sure it is of type Boolean
*
*/
static
Node
*
transformWhereClause
(
ParseState
*
pstate
,
Node
*
a_expr
)
{
Node
*
qual
;
if
(
a_expr
==
NULL
)
return
(
Node
*
)
NULL
;
/* no qualifiers */
inWhereClause
=
true
;
qual
=
transformExpr
(
pstate
,
a_expr
,
EXPR_COLUMN_FIRST
);
inWhereClause
=
false
;
if
(
exprType
(
qual
)
!=
BOOLOID
)
{
elog
(
WARN
,
"where clause must return type bool, not %s"
,
tname
(
get_id_type
(
exprType
(
qual
))));
}
return
qual
;
}
/*****************************************************************************
*
* Sort Clause
*
*****************************************************************************/
/*
* find_targetlist_entry -
* returns the Resdom in the target list matching the specified varname
* and range
*
*/
static
TargetEntry
*
find_targetlist_entry
(
ParseState
*
pstate
,
SortGroupBy
*
sortgroupby
,
List
*
tlist
)
{
List
*
i
;
int
real_rtable_pos
=
0
,
target_pos
=
0
;
TargetEntry
*
target_result
=
NULL
;
if
(
sortgroupby
->
range
)
real_rtable_pos
=
refnameRangeTablePosn
(
pstate
->
p_rtable
,
sortgroupby
->
range
);
foreach
(
i
,
tlist
)
{
TargetEntry
*
target
=
(
TargetEntry
*
)
lfirst
(
i
);
Resdom
*
resnode
=
target
->
resdom
;
Var
*
var
=
(
Var
*
)
target
->
expr
;
char
*
resname
=
resnode
->
resname
;
int
test_rtable_pos
=
var
->
varno
;
#ifdef PARSEDEBUG
printf
(
"find_targetlist_entry- target name is %s, position %d, resno %d
\n
"
,
(
sortgroupby
->
name
?
sortgroupby
->
name
:
"(null)"
),
target_pos
+
1
,
sortgroupby
->
resno
);
#endif
if
(
!
sortgroupby
->
name
)
{
if
(
sortgroupby
->
resno
==
++
target_pos
)
{
target_result
=
target
;
break
;
}
}
else
{
if
(
!
strcmp
(
resname
,
sortgroupby
->
name
))
{
if
(
sortgroupby
->
range
)
{
if
(
real_rtable_pos
==
test_rtable_pos
)
{
if
(
target_result
!=
NULL
)
elog
(
WARN
,
"Order/Group By '%s' is ambiguous"
,
sortgroupby
->
name
);
else
target_result
=
target
;
}
}
else
{
if
(
target_result
!=
NULL
)
elog
(
WARN
,
"Order/Group By '%s' is ambiguous"
,
sortgroupby
->
name
);
else
target_result
=
target
;
}
}
}
}
return
target_result
;
}
static
Oid
any_ordering_op
(
int
restype
)
{
Operator
order_op
;
Oid
order_opid
;
order_op
=
oper
(
"<"
,
restype
,
restype
,
false
);
order_opid
=
oprid
(
order_op
);
return
order_opid
;
}
/*
* transformGroupClause -
* transform a Group By clause
*
*/
static
List
*
transformGroupClause
(
ParseState
*
pstate
,
List
*
grouplist
,
List
*
targetlist
)
{
List
*
glist
=
NIL
,
*
gl
=
NIL
;
while
(
grouplist
!=
NIL
)
{
GroupClause
*
grpcl
=
makeNode
(
GroupClause
);
TargetEntry
*
restarget
;
Resdom
*
resdom
;
restarget
=
find_targetlist_entry
(
pstate
,
lfirst
(
grouplist
),
targetlist
);
if
(
restarget
==
NULL
)
elog
(
WARN
,
"The field being grouped by must appear in the target list"
);
grpcl
->
entry
=
restarget
;
resdom
=
restarget
->
resdom
;
grpcl
->
grpOpoid
=
oprid
(
oper
(
"<"
,
resdom
->
restype
,
resdom
->
restype
,
false
));
if
(
glist
==
NIL
)
gl
=
glist
=
lcons
(
grpcl
,
NIL
);
else
{
List
*
i
;
foreach
(
i
,
glist
)
{
GroupClause
*
gcl
=
(
GroupClause
*
)
lfirst
(
i
);
if
(
gcl
->
entry
==
grpcl
->
entry
)
break
;
}
if
(
i
==
NIL
)
/* not in grouplist already */
{
lnext
(
gl
)
=
lcons
(
grpcl
,
NIL
);
gl
=
lnext
(
gl
);
}
else
pfree
(
grpcl
);
/* get rid of this */
}
grouplist
=
lnext
(
grouplist
);
}
return
glist
;
}
/*
* transformSortClause -
* transform an Order By clause
*
*/
static
List
*
transformSortClause
(
ParseState
*
pstate
,
List
*
orderlist
,
List
*
targetlist
,
char
*
uniqueFlag
)
{
List
*
sortlist
=
NIL
;
List
*
s
=
NIL
;
while
(
orderlist
!=
NIL
)
{
SortGroupBy
*
sortby
=
lfirst
(
orderlist
);
SortClause
*
sortcl
=
makeNode
(
SortClause
);
TargetEntry
*
restarget
;
Resdom
*
resdom
;
restarget
=
find_targetlist_entry
(
pstate
,
sortby
,
targetlist
);
if
(
restarget
==
NULL
)
elog
(
WARN
,
"The field being ordered by must appear in the target list"
);
sortcl
->
resdom
=
resdom
=
restarget
->
resdom
;
sortcl
->
opoid
=
oprid
(
oper
(
sortby
->
useOp
,
resdom
->
restype
,
resdom
->
restype
,
false
));
if
(
sortlist
==
NIL
)
{
s
=
sortlist
=
lcons
(
sortcl
,
NIL
);
}
else
{
List
*
i
;
foreach
(
i
,
sortlist
)
{
SortClause
*
scl
=
(
SortClause
*
)
lfirst
(
i
);
if
(
scl
->
resdom
==
sortcl
->
resdom
)
break
;
}
if
(
i
==
NIL
)
/* not in sortlist already */
{
lnext
(
s
)
=
lcons
(
sortcl
,
NIL
);
s
=
lnext
(
s
);
}
else
pfree
(
sortcl
);
/* get rid of this */
}
orderlist
=
lnext
(
orderlist
);
}
if
(
uniqueFlag
)
{
List
*
i
;
if
(
uniqueFlag
[
0
]
==
'*'
)
{
/*
* concatenate all elements from target list that are not
* already in the sortby list
*/
foreach
(
i
,
targetlist
)
{
TargetEntry
*
tlelt
=
(
TargetEntry
*
)
lfirst
(
i
);
s
=
sortlist
;
while
(
s
!=
NIL
)
{
SortClause
*
sortcl
=
lfirst
(
s
);
if
(
sortcl
->
resdom
==
tlelt
->
resdom
)
break
;
s
=
lnext
(
s
);
}
if
(
s
==
NIL
)
{
/* not a member of the sortclauses yet */
SortClause
*
sortcl
=
makeNode
(
SortClause
);
sortcl
->
resdom
=
tlelt
->
resdom
;
sortcl
->
opoid
=
any_ordering_op
(
tlelt
->
resdom
->
restype
);
sortlist
=
lappend
(
sortlist
,
sortcl
);
}
}
}
else
{
TargetEntry
*
tlelt
=
NULL
;
char
*
uniqueAttrName
=
uniqueFlag
;
/* only create sort clause with the specified unique attribute */
foreach
(
i
,
targetlist
)
{
tlelt
=
(
TargetEntry
*
)
lfirst
(
i
);
if
(
strcmp
(
tlelt
->
resdom
->
resname
,
uniqueAttrName
)
==
0
)
break
;
}
if
(
i
==
NIL
)
{
elog
(
WARN
,
"The field specified in the UNIQUE ON clause is not in the targetlist"
);
}
s
=
sortlist
;
foreach
(
s
,
sortlist
)
{
SortClause
*
sortcl
=
lfirst
(
s
);
if
(
sortcl
->
resdom
==
tlelt
->
resdom
)
break
;
}
if
(
s
==
NIL
)
{
/* not a member of the sortclauses yet */
SortClause
*
sortcl
=
makeNode
(
SortClause
);
sortcl
->
resdom
=
tlelt
->
resdom
;
sortcl
->
opoid
=
any_ordering_op
(
tlelt
->
resdom
->
restype
);
sortlist
=
lappend
(
sortlist
,
sortcl
);
}
}
}
return
sortlist
;
}
/*
** HandleNestedDots --
** Given a nested dot expression (i.e. (relation func ... attr), build up
** a tree with of Iter and Func nodes.
*/
static
Node
*
handleNestedDots
(
ParseState
*
pstate
,
Attr
*
attr
,
int
*
curr_resno
)
{
List
*
mutator_iter
;
Node
*
retval
=
NULL
;
if
(
attr
->
paramNo
!=
NULL
)
{
Param
*
param
=
(
Param
*
)
transformExpr
(
pstate
,
(
Node
*
)
attr
->
paramNo
,
EXPR_RELATION_FIRST
);
retval
=
ParseFunc
(
pstate
,
strVal
(
lfirst
(
attr
->
attrs
)),
lcons
(
param
,
NIL
),
curr_resno
);
}
else
{
Ident
*
ident
=
makeNode
(
Ident
);
ident
->
name
=
attr
->
relname
;
ident
->
isRel
=
TRUE
;
retval
=
ParseFunc
(
pstate
,
strVal
(
lfirst
(
attr
->
attrs
)),
lcons
(
ident
,
NIL
),
curr_resno
);
}
foreach
(
mutator_iter
,
lnext
(
attr
->
attrs
))
{
retval
=
ParseFunc
(
pstate
,
strVal
(
lfirst
(
mutator_iter
)),
lcons
(
retval
,
NIL
),
curr_resno
);
}
return
(
retval
);
}
/*
** make_arguments --
** Given the number and types of arguments to a function, and the
** actual arguments and argument types, do the necessary typecasting.
*/
static
void
make_arguments
(
int
nargs
,
List
*
fargs
,
Oid
*
input_typeids
,
Oid
*
function_typeids
)
{
/*
* there are two ways an input typeid can differ from a function
* typeid : either the input type inherits the function type, so no
* typecasting is necessary, or the input type can be typecast into
* the function type. right now, we only typecast unknowns, and that
* is all we check for.
*/
List
*
current_fargs
;
int
i
;
for
(
i
=
0
,
current_fargs
=
fargs
;
i
<
nargs
;
i
++
,
current_fargs
=
lnext
(
current_fargs
))
{
if
(
input_typeids
[
i
]
==
UNKNOWNOID
&&
function_typeids
[
i
]
!=
InvalidOid
)
{
lfirst
(
current_fargs
)
=
parser_typecast2
(
lfirst
(
current_fargs
),
input_typeids
[
i
],
get_id_type
(
function_typeids
[
i
]),
-
1
);
}
}
}
/*
** setup_tlist --
** Build a tlist that says which attribute to project to.
** This routine is called by ParseFunc() to set up a target list
** on a tuple parameter or return value. Due to a bug in 4.0,
** it's not possible to refer to system attributes in this case.
*/
static
List
*
setup_tlist
(
char
*
attname
,
Oid
relid
)
{
TargetEntry
*
tle
;
Resdom
*
resnode
;
Var
*
varnode
;
Oid
typeid
;
int
attno
;
attno
=
get_attnum
(
relid
,
attname
);
if
(
attno
<
0
)
elog
(
WARN
,
"cannot reference attribute '%s' of tuple params/return values for functions"
,
attname
);
typeid
=
find_atttype
(
relid
,
attname
);
resnode
=
makeResdom
(
1
,
typeid
,
tlen
(
get_id_type
(
typeid
)),
get_attname
(
relid
,
attno
),
0
,
(
Oid
)
0
,
0
);
varnode
=
makeVar
(
-
1
,
attno
,
typeid
,
-
1
,
attno
);
tle
=
makeNode
(
TargetEntry
);
tle
->
resdom
=
resnode
;
tle
->
expr
=
(
Node
*
)
varnode
;
return
(
lcons
(
tle
,
NIL
));
}
/*
** setup_base_tlist --
** Build a tlist that extracts a base type from the tuple
** returned by the executor.
*/
static
List
*
setup_base_tlist
(
Oid
typeid
)
{
TargetEntry
*
tle
;
Resdom
*
resnode
;
Var
*
varnode
;
resnode
=
makeResdom
(
1
,
typeid
,
tlen
(
get_id_type
(
typeid
)),
"<noname>"
,
0
,
(
Oid
)
0
,
0
);
varnode
=
makeVar
(
-
1
,
1
,
typeid
,
-
1
,
1
);
tle
=
makeNode
(
TargetEntry
);
tle
->
resdom
=
resnode
;
tle
->
expr
=
(
Node
*
)
varnode
;
return
(
lcons
(
tle
,
NIL
));
}
/*
* ParseComplexProjection -
* handles function calls with a single argument that is of complex type.
* This routine returns NULL if it can't handle the projection (eg. sets).
*/
static
Node
*
ParseComplexProjection
(
ParseState
*
pstate
,
char
*
funcname
,
Node
*
first_arg
,
bool
*
attisset
)
{
Oid
argtype
;
Oid
argrelid
;
Name
relname
;
Relation
rd
;
Oid
relid
;
int
attnum
;
switch
(
nodeTag
(
first_arg
))
{
case
T_Iter
:
{
Func
*
func
;
Iter
*
iter
;
iter
=
(
Iter
*
)
first_arg
;
func
=
(
Func
*
)
((
Expr
*
)
iter
->
iterexpr
)
->
oper
;
argtype
=
funcid_get_rettype
(
func
->
funcid
);
argrelid
=
typeid_get_relid
(
argtype
);
if
(
argrelid
&&
((
attnum
=
get_attnum
(
argrelid
,
funcname
))
!=
InvalidAttrNumber
))
{
/*
* the argument is a function returning a tuple, so
* funcname may be a projection
*/
/* add a tlist to the func node and return the Iter */
rd
=
heap_openr
(
tname
(
get_id_type
(
argtype
)));
if
(
RelationIsValid
(
rd
))
{
relid
=
RelationGetRelationId
(
rd
);
relname
=
RelationGetRelationName
(
rd
);
heap_close
(
rd
);
}
if
(
RelationIsValid
(
rd
))
{
func
->
func_tlist
=
setup_tlist
(
funcname
,
argrelid
);
iter
->
itertype
=
att_typeid
(
rd
,
attnum
);
return
((
Node
*
)
iter
);
}
else
{
elog
(
WARN
,
"Function '%s' has bad returntype %d"
,
funcname
,
argtype
);
}
}
else
{
/* drop through */
;
}
break
;
}
case
T_Var
:
{
/*
* The argument is a set, so this is either a projection
* or a function call on this set.
*/
*
attisset
=
true
;
break
;
}
case
T_Expr
:
{
Expr
*
expr
=
(
Expr
*
)
first_arg
;
Func
*
funcnode
;
if
(
expr
->
opType
!=
FUNC_EXPR
)
break
;
funcnode
=
(
Func
*
)
expr
->
oper
;
argtype
=
funcid_get_rettype
(
funcnode
->
funcid
);
argrelid
=
typeid_get_relid
(
argtype
);
/*
* the argument is a function returning a tuple, so
* funcname may be a projection
*/
if
(
argrelid
&&
(
attnum
=
get_attnum
(
argrelid
,
funcname
))
!=
InvalidAttrNumber
)
{
/* add a tlist to the func node */
rd
=
heap_openr
(
tname
(
get_id_type
(
argtype
)));
if
(
RelationIsValid
(
rd
))
{
relid
=
RelationGetRelationId
(
rd
);
relname
=
RelationGetRelationName
(
rd
);
heap_close
(
rd
);
}
if
(
RelationIsValid
(
rd
))
{
Expr
*
newexpr
;
funcnode
->
func_tlist
=
setup_tlist
(
funcname
,
argrelid
);
funcnode
->
functype
=
att_typeid
(
rd
,
attnum
);
newexpr
=
makeNode
(
Expr
);
newexpr
->
typeOid
=
funcnode
->
functype
;
newexpr
->
opType
=
FUNC_EXPR
;
newexpr
->
oper
=
(
Node
*
)
funcnode
;
newexpr
->
args
=
lcons
(
first_arg
,
NIL
);
return
((
Node
*
)
newexpr
);
}
}
elog
(
WARN
,
"Function '%s' has bad returntype %d"
,
funcname
,
argtype
);
break
;
}
case
T_Param
:
{
Param
*
param
=
(
Param
*
)
first_arg
;
/*
* If the Param is a complex type, this could be a
* projection
*/
rd
=
heap_openr
(
tname
(
get_id_type
(
param
->
paramtype
)));
if
(
RelationIsValid
(
rd
))
{
relid
=
RelationGetRelationId
(
rd
);
relname
=
RelationGetRelationName
(
rd
);
heap_close
(
rd
);
}
if
(
RelationIsValid
(
rd
)
&&
(
attnum
=
get_attnum
(
relid
,
funcname
))
!=
InvalidAttrNumber
)
{
param
->
paramtype
=
att_typeid
(
rd
,
attnum
);
param
->
param_tlist
=
setup_tlist
(
funcname
,
relid
);
return
((
Node
*
)
param
);
}
break
;
}
default:
break
;
}
return
NULL
;
}
static
Node
*
ParseFunc
(
ParseState
*
pstate
,
char
*
funcname
,
List
*
fargs
,
int
*
curr_resno
)
{
Oid
rettype
=
(
Oid
)
0
;
Oid
argrelid
=
(
Oid
)
0
;
Oid
funcid
=
(
Oid
)
0
;
List
*
i
=
NIL
;
Node
*
first_arg
=
NULL
;
char
*
relname
=
NULL
;
char
*
refname
=
NULL
;
Relation
rd
;
Oid
relid
;
int
nargs
;
Func
*
funcnode
;
Oid
oid_array
[
8
];
Oid
*
true_oid_array
;
Node
*
retval
;
bool
retset
;
bool
exists
;
bool
attisset
=
false
;
Oid
toid
=
(
Oid
)
0
;
Expr
*
expr
;
if
(
fargs
)
{
first_arg
=
lfirst
(
fargs
);
if
(
first_arg
==
NULL
)
elog
(
WARN
,
"function '%s' does not allow NULL input"
,
funcname
);
}
/*
* * check for projection methods: if function takes one argument, and *
* that argument is a relation, param, or PQ function returning a
* complex * type, then the function could be a projection.
*/
if
(
length
(
fargs
)
==
1
)
{
if
(
nodeTag
(
first_arg
)
==
T_Ident
&&
((
Ident
*
)
first_arg
)
->
isRel
)
{
RangeTblEntry
*
rte
;
Ident
*
ident
=
(
Ident
*
)
first_arg
;
/*
* first arg is a relation. This could be a projection.
*/
refname
=
ident
->
name
;
rte
=
refnameRangeTableEntry
(
pstate
->
p_rtable
,
refname
);
if
(
rte
==
NULL
)
rte
=
addRangeTableEntry
(
pstate
,
refname
,
refname
,
FALSE
,
FALSE
);
relname
=
rte
->
relname
;
relid
=
rte
->
relid
;
/*
* If the attr isn't a set, just make a var for it. If it is
* a set, treat it like a function and drop through.
*/
if
(
get_attnum
(
relid
,
funcname
)
!=
InvalidAttrNumber
)
{
Oid
dummyTypeId
;
return
((
Node
*
)
make_var
(
pstate
,
refname
,
funcname
,
&
dummyTypeId
));
}
else
{
/* drop through - attr is a set */
;
}
}
else
if
(
ISCOMPLEX
(
exprType
(
first_arg
)))
{
/*
* Attempt to handle projection of a complex argument. If
* ParseComplexProjection can't handle the projection, we have
* to keep going.
*/
retval
=
ParseComplexProjection
(
pstate
,
funcname
,
first_arg
,
&
attisset
);
if
(
attisset
)
{
toid
=
exprType
(
first_arg
);
rd
=
heap_openr
(
tname
(
get_id_type
(
toid
)));
if
(
RelationIsValid
(
rd
))
{
relname
=
RelationGetRelationName
(
rd
)
->
data
;
heap_close
(
rd
);
}
else
elog
(
WARN
,
"Type '%s' is not a relation type"
,
tname
(
get_id_type
(
toid
)));
argrelid
=
typeid_get_relid
(
toid
);
/*
* A projection contains either an attribute name or the
* "*".
*/
if
((
get_attnum
(
argrelid
,
funcname
)
==
InvalidAttrNumber
)
&&
strcmp
(
funcname
,
"*"
))
{
elog
(
WARN
,
"Functions on sets are not yet supported"
);
}
}
if
(
retval
)
return
retval
;
}
else
{
/*
* Parsing aggregates.
*/
Oid
basetype
;
/*
* the aggregate count is a special case, ignore its base
* type. Treat it as zero
*/
if
(
strcmp
(
funcname
,
"count"
)
==
0
)
basetype
=
0
;
else
basetype
=
exprType
(
lfirst
(
fargs
));
if
(
SearchSysCacheTuple
(
AGGNAME
,
PointerGetDatum
(
funcname
),
ObjectIdGetDatum
(
basetype
),
0
,
0
))
{
Aggreg
*
aggreg
=
ParseAgg
(
funcname
,
basetype
,
lfirst
(
fargs
));
AddAggToParseState
(
pstate
,
aggreg
);
return
(
Node
*
)
aggreg
;
}
}
}
/*
* * If we dropped through to here it's really a function (or a set,
* which * is implemented as a function.) * extract arg type info and
* transform relation name arguments into * varnodes of the
* appropriate form.
*/
MemSet
(
&
oid_array
[
0
],
0
,
8
*
sizeof
(
Oid
));
nargs
=
0
;
foreach
(
i
,
fargs
)
{
int
vnum
;
RangeTblEntry
*
rte
;
Node
*
pair
=
lfirst
(
i
);
if
(
nodeTag
(
pair
)
==
T_Ident
&&
((
Ident
*
)
pair
)
->
isRel
)
{
/*
* a relation
*/
refname
=
((
Ident
*
)
pair
)
->
name
;
rte
=
refnameRangeTableEntry
(
pstate
->
p_rtable
,
refname
);
if
(
rte
==
NULL
)
rte
=
addRangeTableEntry
(
pstate
,
refname
,
refname
,
FALSE
,
FALSE
);
relname
=
rte
->
relname
;
vnum
=
refnameRangeTablePosn
(
pstate
->
p_rtable
,
rte
->
refname
);
/*
* for func(relname), the param to the function is the tuple
* under consideration. we build a special VarNode to reflect
* this -- it has varno set to the correct range table entry,
* but has varattno == 0 to signal that the whole tuple is the
* argument.
*/
toid
=
typeid
(
type
(
relname
));
/* replace it in the arg list */
lfirst
(
fargs
)
=
makeVar
(
vnum
,
0
,
toid
,
vnum
,
0
);
}
else
if
(
!
attisset
)
{
/* set functions don't have parameters */
/*
* any functiona args which are typed "unknown", but aren't
* constants, we don't know what to do with, because we can't
* cast them - jolly
*/
if
(
exprType
(
pair
)
==
UNKNOWNOID
&&
!
IsA
(
pair
,
Const
))
{
elog
(
WARN
,
"ParseFunc: no function named '%s' that takes in an unknown type as argument #%d"
,
funcname
,
nargs
);
}
else
toid
=
exprType
(
pair
);
}
oid_array
[
nargs
++
]
=
toid
;
}
/*
* func_get_detail looks up the function in the catalogs, does
* disambiguation for polymorphic functions, handles inheritance, and
* returns the funcid and type and set or singleton status of the
* function's return value. it also returns the true argument types
* to the function. if func_get_detail returns true, the function
* exists. otherwise, there was an error.
*/
if
(
attisset
)
{
/* we know all of these fields already */
/*
* We create a funcnode with a placeholder function SetEval.
* SetEval() never actually gets executed. When the function
* evaluation routines see it, they use the funcid projected out
* from the relation as the actual function to call. Example:
* retrieve (emp.mgr.name) The plan for this will scan the emp
* relation, projecting out the mgr attribute, which is a funcid.
* This function is then called (instead of SetEval) and "name" is
* projected from its result.
*/
funcid
=
SetEvalRegProcedure
;
rettype
=
toid
;
retset
=
true
;
true_oid_array
=
oid_array
;
exists
=
true
;
}
else
{
exists
=
func_get_detail
(
funcname
,
nargs
,
oid_array
,
&
funcid
,
&
rettype
,
&
retset
,
&
true_oid_array
);
}
if
(
!
exists
)
elog
(
WARN
,
"no such attribute or function '%s'"
,
funcname
);
/* got it */
funcnode
=
makeNode
(
Func
);
funcnode
->
funcid
=
funcid
;
funcnode
->
functype
=
rettype
;
funcnode
->
funcisindex
=
false
;
funcnode
->
funcsize
=
0
;
funcnode
->
func_fcache
=
NULL
;
funcnode
->
func_tlist
=
NIL
;
funcnode
->
func_planlist
=
NIL
;
/* perform the necessary typecasting */
make_arguments
(
nargs
,
fargs
,
oid_array
,
true_oid_array
);
/*
* for functions returning base types, we want to project out the
* return value. set up a target list to do that. the executor will
* ignore these for c functions, and do the right thing for postquel
* functions.
*/
if
(
typeid_get_relid
(
rettype
)
==
InvalidOid
)
funcnode
->
func_tlist
=
setup_base_tlist
(
rettype
);
/*
* For sets, we want to make a targetlist to project out this
* attribute of the set tuples.
*/
if
(
attisset
)
{
if
(
!
strcmp
(
funcname
,
"*"
))
{
funcnode
->
func_tlist
=
expandAll
(
pstate
,
relname
,
refname
,
curr_resno
);
}
else
{
funcnode
->
func_tlist
=
setup_tlist
(
funcname
,
argrelid
);
rettype
=
find_atttype
(
argrelid
,
funcname
);
}
}
/*
* Sequence handling.
*/
if
(
funcid
==
SeqNextValueRegProcedure
||
funcid
==
SeqCurrValueRegProcedure
)
{
Const
*
seq
;
char
*
seqrel
;
text
*
seqname
;
int32
aclcheck_result
=
-
1
;
extern
text
*
lower
(
text
*
string
);
Assert
(
length
(
fargs
)
==
1
);
seq
=
(
Const
*
)
lfirst
(
fargs
);
if
(
!
IsA
((
Node
*
)
seq
,
Const
))
elog
(
WARN
,
"%s: only constant sequence names are acceptable"
,
funcname
);
seqname
=
lower
((
text
*
)
DatumGetPointer
(
seq
->
constvalue
));
pfree
(
DatumGetPointer
(
seq
->
constvalue
));
seq
->
constvalue
=
PointerGetDatum
(
seqname
);
seqrel
=
textout
(
seqname
);
if
((
aclcheck_result
=
pg_aclcheck
(
seqrel
,
GetPgUserName
(),
((
funcid
==
SeqNextValueRegProcedure
)
?
ACL_WR
:
ACL_RD
)))
!=
ACLCHECK_OK
)
elog
(
WARN
,
"%s.%s: %s"
,
seqrel
,
funcname
,
aclcheck_error_strings
[
aclcheck_result
]);
pfree
(
seqrel
);
if
(
funcid
==
SeqNextValueRegProcedure
&&
inWhereClause
)
elog
(
WARN
,
"nextval of a sequence in WHERE disallowed"
);
}
expr
=
makeNode
(
Expr
);
expr
->
typeOid
=
rettype
;
expr
->
opType
=
FUNC_EXPR
;
expr
->
oper
=
(
Node
*
)
funcnode
;
expr
->
args
=
fargs
;
retval
=
(
Node
*
)
expr
;
/*
* if the function returns a set of values, then we need to iterate
* over all the returned values in the executor, so we stick an iter
* node here. if it returns a singleton, then we don't need the iter
* node.
*/
if
(
retset
)
{
Iter
*
iter
=
makeNode
(
Iter
);
iter
->
itertype
=
rettype
;
iter
->
iterexpr
=
retval
;
retval
=
(
Node
*
)
iter
;
}
return
(
retval
);
}
/*****************************************************************************
*
*****************************************************************************/
/*
* AddAggToParseState -
* add the aggregate to the list of unique aggregates in pstate.
*
* SIDE EFFECT: aggno in target list entry will be modified
*/
static
void
AddAggToParseState
(
ParseState
*
pstate
,
Aggreg
*
aggreg
)
{
List
*
ag
;
int
i
;
/*
* see if we have the aggregate already (we only need to record the
* aggregate once)
*/
i
=
0
;
foreach
(
ag
,
pstate
->
p_aggs
)
{
Aggreg
*
a
=
lfirst
(
ag
);
if
(
!
strcmp
(
a
->
aggname
,
aggreg
->
aggname
)
&&
equal
(
a
->
target
,
aggreg
->
target
))
{
/* fill in the aggno and we're done */
aggreg
->
aggno
=
i
;
return
;
}
i
++
;
}
/* not found, new aggregate */
aggreg
->
aggno
=
i
;
pstate
->
p_numAgg
++
;
pstate
->
p_aggs
=
lappend
(
pstate
->
p_aggs
,
aggreg
);
return
;
}
/*
* finalizeAggregates -
* fill in qry_aggs from pstate. Also checks to make sure that aggregates
* are used in the proper place.
*/
static
void
finalizeAggregates
(
ParseState
*
pstate
,
Query
*
qry
)
{
List
*
l
;
int
i
;
parseCheckAggregates
(
pstate
,
qry
);
qry
->
qry_numAgg
=
pstate
->
p_numAgg
;
qry
->
qry_aggs
=
(
Aggreg
**
)
palloc
(
sizeof
(
Aggreg
*
)
*
qry
->
qry_numAgg
);
i
=
0
;
foreach
(
l
,
pstate
->
p_aggs
)
qry
->
qry_aggs
[
i
++
]
=
(
Aggreg
*
)
lfirst
(
l
);
}
/*
* contain_agg_clause--
* Recursively find aggreg nodes from a clause.
*
* Returns true if any aggregate found.
*/
static
bool
contain_agg_clause
(
Node
*
clause
)
{
if
(
clause
==
NULL
)
return
FALSE
;
else
if
(
IsA
(
clause
,
Aggreg
))
return
TRUE
;
else
if
(
IsA
(
clause
,
Iter
))
return
contain_agg_clause
(((
Iter
*
)
clause
)
->
iterexpr
);
else
if
(
single_node
(
clause
))
return
FALSE
;
else
if
(
or_clause
(
clause
))
{
List
*
temp
;
foreach
(
temp
,
((
Expr
*
)
clause
)
->
args
)
if
(
contain_agg_clause
(
lfirst
(
temp
)))
return
TRUE
;
return
FALSE
;
}
else
if
(
is_funcclause
(
clause
))
{
List
*
temp
;
foreach
(
temp
,
((
Expr
*
)
clause
)
->
args
)
if
(
contain_agg_clause
(
lfirst
(
temp
)))
return
TRUE
;
return
FALSE
;
}
else
if
(
IsA
(
clause
,
ArrayRef
))
{
List
*
temp
;
foreach
(
temp
,
((
ArrayRef
*
)
clause
)
->
refupperindexpr
)
if
(
contain_agg_clause
(
lfirst
(
temp
)))
return
TRUE
;
foreach
(
temp
,
((
ArrayRef
*
)
clause
)
->
reflowerindexpr
)
if
(
contain_agg_clause
(
lfirst
(
temp
)))
return
TRUE
;
if
(
contain_agg_clause
(((
ArrayRef
*
)
clause
)
->
refexpr
))
return
TRUE
;
if
(
contain_agg_clause
(((
ArrayRef
*
)
clause
)
->
refassgnexpr
))
return
TRUE
;
return
FALSE
;
}
else
if
(
not_clause
(
clause
))
return
contain_agg_clause
((
Node
*
)
get_notclausearg
((
Expr
*
)
clause
));
else
if
(
is_opclause
(
clause
))
return
(
contain_agg_clause
((
Node
*
)
get_leftop
((
Expr
*
)
clause
))
||
contain_agg_clause
((
Node
*
)
get_rightop
((
Expr
*
)
clause
)));
return
FALSE
;
}
/*
* exprIsAggOrGroupCol -
* returns true if the expression does not contain non-group columns.
*/
static
bool
exprIsAggOrGroupCol
(
Node
*
expr
,
List
*
groupClause
)
{
List
*
gl
;
if
(
expr
==
NULL
||
IsA
(
expr
,
Const
)
||
IsA
(
expr
,
Param
)
||
IsA
(
expr
,
Aggreg
))
return
TRUE
;
foreach
(
gl
,
groupClause
)
{
GroupClause
*
grpcl
=
lfirst
(
gl
);
if
(
equal
(
expr
,
grpcl
->
entry
->
expr
))
return
TRUE
;
}
if
(
IsA
(
expr
,
Expr
))
{
List
*
temp
;
foreach
(
temp
,
((
Expr
*
)
expr
)
->
args
)
if
(
!
exprIsAggOrGroupCol
(
lfirst
(
temp
),
groupClause
))
return
FALSE
;
return
TRUE
;
}
return
FALSE
;
}
/*
* tleIsAggOrGroupCol -
* returns true if the TargetEntry is Agg or GroupCol.
*/
static
bool
tleIsAggOrGroupCol
(
TargetEntry
*
tle
,
List
*
groupClause
)
{
Node
*
expr
=
tle
->
expr
;
List
*
gl
;
if
(
expr
==
NULL
||
IsA
(
expr
,
Const
)
||
IsA
(
expr
,
Param
))
return
TRUE
;
foreach
(
gl
,
groupClause
)
{
GroupClause
*
grpcl
=
lfirst
(
gl
);
if
(
tle
->
resdom
->
resno
==
grpcl
->
entry
->
resdom
->
resno
)
{
if
(
contain_agg_clause
((
Node
*
)
expr
))
elog
(
WARN
,
"parser: aggregates not allowed in GROUP BY clause"
);
return
TRUE
;
}
}
if
(
IsA
(
expr
,
Aggreg
))
return
TRUE
;
if
(
IsA
(
expr
,
Expr
))
{
List
*
temp
;
foreach
(
temp
,
((
Expr
*
)
expr
)
->
args
)
if
(
!
exprIsAggOrGroupCol
(
lfirst
(
temp
),
groupClause
))
return
FALSE
;
return
TRUE
;
}
return
FALSE
;
}
/*
* parseCheckAggregates -
* this should really be done earlier but the current grammar
* cannot differentiate functions from aggregates. So we have do check
* here when the target list and the qualifications are finalized.
*/
static
void
parseCheckAggregates
(
ParseState
*
pstate
,
Query
*
qry
)
{
List
*
tl
;
Assert
(
pstate
->
p_numAgg
>
0
);
/*
* aggregates never appear in WHERE clauses. (we have to check where
* clause first because if there is an aggregate, the check for
* non-group column in target list may fail.)
*/
if
(
contain_agg_clause
(
qry
->
qual
))
elog
(
WARN
,
"parser: aggregates not allowed in WHERE clause"
);
/*
* the target list can only contain aggregates, group columns and
* functions thereof.
*/
foreach
(
tl
,
qry
->
targetList
)
{
TargetEntry
*
tle
=
lfirst
(
tl
);
if
(
!
tleIsAggOrGroupCol
(
tle
,
qry
->
groupClause
))
elog
(
WARN
,
"parser: illegal use of aggregates or non-group column in target list"
);
}
/*
* the expression specified in the HAVING clause has the same
* restriction as those in the target list.
*/
/*
* Need to change here when we get HAVING works. Currently
* qry->havingQual is NULL. - vadim 04/05/97
if (!exprIsAggOrGroupCol(qry->havingQual, qry->groupClause))
elog(WARN,
"parser: illegal use of aggregates or non-group column in HAVING clause");
*/
return
;
}
/* not used
#define PSIZE(PTR) (*((int32 *)(PTR) - 1))
*/
static
Node
*
parser_typecast
(
Value
*
expr
,
TypeName
*
typename
,
int
typlen
)
{
/* check for passing non-ints */
Const
*
adt
;
Datum
lcp
;
Type
tp
;
char
type_string
[
NAMEDATALEN
];
int32
len
;
char
*
cp
=
NULL
;
char
*
const_string
=
NULL
;
bool
string_palloced
=
false
;
switch
(
nodeTag
(
expr
))
{
case
T_String
:
const_string
=
DatumGetPointer
(
expr
->
val
.
str
);
break
;
case
T_Integer
:
const_string
=
(
char
*
)
palloc
(
256
);
string_palloced
=
true
;
sprintf
(
const_string
,
"%ld"
,
expr
->
val
.
ival
);
break
;
default:
elog
(
WARN
,
"parser_typecast: cannot cast this expression to type
\"
%s
\"
"
,
typename
->
name
);
}
if
(
typename
->
arrayBounds
!=
NIL
)
{
sprintf
(
type_string
,
"_%s"
,
typename
->
name
);
tp
=
(
Type
)
type
(
type_string
);
}
else
{
tp
=
(
Type
)
type
(
typename
->
name
);
}
len
=
tlen
(
tp
);
#if 0 /* fix me */
switch (CInteger(lfirst(expr)))
{
case INT4OID: /* int4 */
const_string = (char *) palloc(256);
string_palloced = true;
sprintf(const_string, "%d", ((Const *) lnext(expr))->constvalue);
break;
case NAMEOID: /* char16 */
const_string = (char *) palloc(256);
string_palloced = true;
sprintf(const_string, "%s", ((Const *) lnext(expr))->constvalue);
break;
case CHAROID: /* char */
const_string = (char *) palloc(256);
string_palloced = true;
sprintf(const_string, "%c", ((Const) lnext(expr))->constvalue);
break;
case FLOAT8OID: /* float8 */
const_string = (char *) palloc(256);
string_palloced = true;
sprintf(const_string, "%f", ((Const) lnext(expr))->constvalue);
break;
case CASHOID: /* money */
const_string = (char *) palloc(256);
string_palloced = true;
sprintf(const_string, "%d",
(int) ((Const *) expr)->constvalue);
break;
case TEXTOID: /* text */
const_string = DatumGetPointer(((Const) lnext(expr))->constvalue);
const_string = (char *) textout((struct varlena *) const_string);
break;
case UNKNOWNOID: /* unknown */
const_string = DatumGetPointer(((Const) lnext(expr))->constvalue);
const_string = (char *) textout((struct varlena *) const_string);
break;
default:
elog(WARN, "unknown type %d", CInteger(lfirst(expr)));
}
#endif
cp
=
instr2
(
tp
,
const_string
,
typlen
);
if
(
!
tbyvalue
(
tp
))
{
/*
if (len >= 0 && len != PSIZE(cp)) {
char *pp;
pp = (char *) palloc(len);
memmove(pp, cp, len);
cp = pp;
}
*/
lcp
=
PointerGetDatum
(
cp
);
}
else
{
switch
(
len
)
{
case
1
:
lcp
=
Int8GetDatum
(
cp
);
break
;
case
2
:
lcp
=
Int16GetDatum
(
cp
);
break
;
case
4
:
lcp
=
Int32GetDatum
(
cp
);
break
;
default:
lcp
=
PointerGetDatum
(
cp
);
break
;
}
}
adt
=
makeConst
(
typeid
(
tp
),
len
,
(
Datum
)
lcp
,
false
,
tbyvalue
(
tp
),
false
,
/* not a set */
true
/* is cast */
);
if
(
string_palloced
)
pfree
(
const_string
);
return
(
Node
*
)
adt
;
}
static
Node
*
parser_typecast2
(
Node
*
expr
,
Oid
exprType
,
Type
tp
,
int
typlen
)
{
/* check for passing non-ints */
Const
*
adt
;
Datum
lcp
;
int32
len
=
tlen
(
tp
);
char
*
cp
=
NULL
;
char
*
const_string
=
NULL
;
bool
string_palloced
=
false
;
Assert
(
IsA
(
expr
,
Const
));
switch
(
exprType
)
{
case
0
:
/* NULL */
break
;
case
INT4OID
:
/* int4 */
const_string
=
(
char
*
)
palloc
(
256
);
string_palloced
=
true
;
sprintf
(
const_string
,
"%d"
,
(
int
)
((
Const
*
)
expr
)
->
constvalue
);
break
;
case
NAMEOID
:
/* char16 */
const_string
=
(
char
*
)
palloc
(
256
);
string_palloced
=
true
;
sprintf
(
const_string
,
"%s"
,
(
char
*
)
((
Const
*
)
expr
)
->
constvalue
);
break
;
case
CHAROID
:
/* char */
const_string
=
(
char
*
)
palloc
(
256
);
string_palloced
=
true
;
sprintf
(
const_string
,
"%c"
,
(
char
)
((
Const
*
)
expr
)
->
constvalue
);
break
;
case
FLOAT4OID
:
/* float4 */
{
float32
floatVal
=
DatumGetFloat32
(((
Const
*
)
expr
)
->
constvalue
);
const_string
=
(
char
*
)
palloc
(
256
);
string_palloced
=
true
;
sprintf
(
const_string
,
"%f"
,
*
floatVal
);
break
;
}
case
FLOAT8OID
:
/* float8 */
{
float64
floatVal
=
DatumGetFloat64
(((
Const
*
)
expr
)
->
constvalue
);
const_string
=
(
char
*
)
palloc
(
256
);
string_palloced
=
true
;
sprintf
(
const_string
,
"%f"
,
*
floatVal
);
break
;
}
case
CASHOID
:
/* money */
const_string
=
(
char
*
)
palloc
(
256
);
string_palloced
=
true
;
sprintf
(
const_string
,
"%ld"
,
(
long
)
((
Const
*
)
expr
)
->
constvalue
);
break
;
case
TEXTOID
:
/* text */
const_string
=
DatumGetPointer
(((
Const
*
)
expr
)
->
constvalue
);
const_string
=
(
char
*
)
textout
((
struct
varlena
*
)
const_string
);
break
;
case
UNKNOWNOID
:
/* unknown */
const_string
=
DatumGetPointer
(((
Const
*
)
expr
)
->
constvalue
);
const_string
=
(
char
*
)
textout
((
struct
varlena
*
)
const_string
);
break
;
default:
elog
(
WARN
,
"unknown type %u "
,
exprType
);
}
if
(
!
exprType
)
{
adt
=
makeConst
(
typeid
(
tp
),
(
Size
)
0
,
(
Datum
)
NULL
,
true
,
/* isnull */
false
,
/* was omitted */
false
,
/* not a set */
true
/* is cast */
);
return
((
Node
*
)
adt
);
}
cp
=
instr2
(
tp
,
const_string
,
typlen
);
if
(
!
tbyvalue
(
tp
))
{
/*
if (len >= 0 && len != PSIZE(cp)) {
char *pp;
pp = (char *) palloc(len);
memmove(pp, cp, len);
cp = pp;
}
*/
lcp
=
PointerGetDatum
(
cp
);
}
else
{
switch
(
len
)
{
case
1
:
lcp
=
Int8GetDatum
(
cp
);
break
;
case
2
:
lcp
=
Int16GetDatum
(
cp
);
break
;
case
4
:
lcp
=
Int32GetDatum
(
cp
);
break
;
default:
lcp
=
PointerGetDatum
(
cp
);
break
;
}
}
adt
=
makeConst
(
typeid
(
tp
),
(
Size
)
len
,
(
Datum
)
lcp
,
false
,
false
,
/* was omitted */
false
,
/* not a set */
true
/* is cast */
);
/*
* printf("adt %s : %u %d %d\n",CString(expr),typeid(tp) , len,cp);
*/
if
(
string_palloced
)
pfree
(
const_string
);
return
((
Node
*
)
adt
);
}
static
Aggreg
*
ParseAgg
(
char
*
aggname
,
Oid
basetype
,
Node
*
target
)
{
Oid
fintype
;
Oid
vartype
;
Oid
xfn1
;
Form_pg_aggregate
aggform
;
Aggreg
*
aggreg
;
HeapTuple
theAggTuple
;
theAggTuple
=
SearchSysCacheTuple
(
AGGNAME
,
PointerGetDatum
(
aggname
),
ObjectIdGetDatum
(
basetype
),
0
,
0
);
if
(
!
HeapTupleIsValid
(
theAggTuple
))
{
elog
(
WARN
,
"aggregate %s does not exist"
,
aggname
);
}
aggform
=
(
Form_pg_aggregate
)
GETSTRUCT
(
theAggTuple
);
fintype
=
aggform
->
aggfinaltype
;
xfn1
=
aggform
->
aggtransfn1
;
if
(
nodeTag
(
target
)
!=
T_Var
&&
nodeTag
(
target
)
!=
T_Expr
)
elog
(
WARN
,
"parser: aggregate can only be applied on an attribute or expression"
);
/* only aggregates with transfn1 need a base type */
if
(
OidIsValid
(
xfn1
))
{
basetype
=
aggform
->
aggbasetype
;
if
(
nodeTag
(
target
)
==
T_Var
)
vartype
=
((
Var
*
)
target
)
->
vartype
;
else
vartype
=
((
Expr
*
)
target
)
->
typeOid
;
if
(
basetype
!=
vartype
)
{
Type
tp1
,
tp2
;
tp1
=
get_id_type
(
basetype
);
tp2
=
get_id_type
(
vartype
);
elog
(
NOTICE
,
"Aggregate type mismatch:"
);
elog
(
WARN
,
"%s works on %s, not %s"
,
aggname
,
tname
(
tp1
),
tname
(
tp2
));
}
}
aggreg
=
makeNode
(
Aggreg
);
aggreg
->
aggname
=
pstrdup
(
aggname
);
aggreg
->
basetype
=
aggform
->
aggbasetype
;
aggreg
->
aggtype
=
fintype
;
aggreg
->
target
=
target
;
return
aggreg
;
}
src/backend/parser/gram.y
View file @
4a5b781d
...
@@ -10,7 +10,7 @@
...
@@ -10,7 +10,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 1.7
1 1997/11/24 16:55:22
momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 1.7
2 1997/11/25 22:05:29
momjian Exp $
*
*
* HISTORY
* HISTORY
* AUTHOR DATE MAJOR EVENT
* AUTHOR DATE MAJOR EVENT
...
@@ -39,8 +39,6 @@
...
@@ -39,8 +39,6 @@
#include "nodes/parsenodes.h"
#include "nodes/parsenodes.h"
#include "nodes/print.h"
#include "nodes/print.h"
#include "parser/gramparse.h"
#include "parser/gramparse.h"
#include "parser/catalog_utils.h"
#include "parser/parse_query.h"
#include "utils/acl.h"
#include "utils/acl.h"
#include "catalog/catname.h"
#include "catalog/catname.h"
#include "utils/elog.h"
#include "utils/elog.h"
...
@@ -49,8 +47,11 @@
...
@@ -49,8 +47,11 @@
static char saved_relname[NAMEDATALEN]; /* need this for complex attributes */
static char saved_relname[NAMEDATALEN]; /* need this for complex attributes */
static bool QueryIsRule = FALSE;
static bool QueryIsRule = FALSE;
static Node *saved_In_Expr;
static Node *saved_In_Expr;
static Oid *param_type_info;
static int pfunc_num_args;
extern List *parsetree;
extern List *parsetree;
/*
/*
* If you need access to certain yacc-generated variables and find that
* If you need access to certain yacc-generated variables and find that
* they're static by default, uncomment the next line. (this is not a
* they're static by default, uncomment the next line. (this is not a
...
@@ -64,6 +65,9 @@ static List *makeConstantList( A_Const *node);
...
@@ -64,6 +65,9 @@ static List *makeConstantList( A_Const *node);
static char *FlattenStringList(List *list);
static char *FlattenStringList(List *list);
static char *fmtId(char *rawid);
static char *fmtId(char *rawid);
static Node *makeIndexable(char *opname, Node *lexpr, Node *rexpr);
static Node *makeIndexable(char *opname, Node *lexpr, Node *rexpr);
static void param_type_init(Oid *typev, int nargs);
Oid param_type(int t); /* used in parse_expr.c */
/* old versions of flex define this as a macro */
/* old versions of flex define this as a macro */
#if defined(yywrap)
#if defined(yywrap)
...
@@ -2324,7 +2328,7 @@ Typename: Array opt_array_bounds
...
@@ -2324,7 +2328,7 @@ Typename: Array opt_array_bounds
* emp(name=text,mgr=emp)
* emp(name=text,mgr=emp)
*/
*/
$$->setof = TRUE;
$$->setof = TRUE;
else if (
get_typrelid((Type)t
ype($$->name)) != InvalidOid)
else if (
typeTypeRelid(typenameT
ype($$->name)) != InvalidOid)
/* (Eventually add in here that the set can only
/* (Eventually add in here that the set can only
* contain one element.)
* contain one element.)
*/
*/
...
@@ -3690,4 +3694,24 @@ printf("fmtId- %sconvert %s to %s\n", ((cp == rawid)? "do not ": ""), rawid, cp)
...
@@ -3690,4 +3694,24 @@ printf("fmtId- %sconvert %s to %s\n", ((cp == rawid)? "do not ": ""), rawid, cp)
#endif
#endif
return(cp);
return(cp);
} /* fmtId() */
}
/*
* param_type_init()
*
* keep enough information around fill out the type of param nodes
* used in postquel functions
*/
static void
param_type_init(Oid *typev, int nargs)
{
pfunc_num_args = nargs;
param_type_info = typev;
}
Oid param_type(int t)
{
if ((t > pfunc_num_args) || (t == 0))
return InvalidOid;
return param_type_info[t - 1];
}
src/backend/parser/keywords.c
View file @
4a5b781d
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.2
4 1997/11/24 05:32:28
momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.2
5 1997/11/25 22:05:32
momjian Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -18,8 +18,8 @@
...
@@ -18,8 +18,8 @@
#include "nodes/pg_list.h"
#include "nodes/pg_list.h"
#include "nodes/parsenodes.h"
#include "nodes/parsenodes.h"
#include "parse.h"
#include "parse.h"
#include "utils/elog.h"
#include "parser/keywords.h"
#include "parser/keywords.h"
#include "utils/elog.h"
/*
/*
* List of (keyword-name, keyword-token-value) pairs.
* List of (keyword-name, keyword-token-value) pairs.
...
...
src/backend/parser/parse_agg.c
0 → 100644
View file @
4a5b781d
/*-------------------------------------------------------------------------
*
* parse_agg.c--
* handle aggregates in parser
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.1 1997/11/25 22:05:34 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "postgres.h"
#include "access/heapam.h"
#include "catalog/pg_aggregate.h"
#include "nodes/nodeFuncs.h"
#include "nodes/primnodes.h"
#include "nodes/relation.h"
#include "optimizer/clauses.h"
#include "parser/parse_agg.h"
#include "parser/parse_node.h"
#include "parser/parse_target.h"
#include "utils/syscache.h"
#ifdef 0
#include "nodes/nodes.h"
#include "nodes/params.h"
#include "parse.h"
/* for AND, OR, etc. */
#include "catalog/pg_type.h"
/* for INT4OID, etc. */
#include "catalog/pg_proc.h"
#include "utils/elog.h"
#include "utils/builtins.h"
/* namecmp(), textout() */
#include "utils/lsyscache.h"
#include "utils/palloc.h"
#include "utils/mcxt.h"
#include "utils/acl.h"
#include "nodes/makefuncs.h"
/* for makeResdom(), etc. */
#include "commands/sequence.h"
#endif
/*
* AddAggToParseState -
* add the aggregate to the list of unique aggregates in pstate.
*
* SIDE EFFECT: aggno in target list entry will be modified
*/
void
AddAggToParseState
(
ParseState
*
pstate
,
Aggreg
*
aggreg
)
{
List
*
ag
;
int
i
;
/*
* see if we have the aggregate already (we only need to record the
* aggregate once)
*/
i
=
0
;
foreach
(
ag
,
pstate
->
p_aggs
)
{
Aggreg
*
a
=
lfirst
(
ag
);
if
(
!
strcmp
(
a
->
aggname
,
aggreg
->
aggname
)
&&
equal
(
a
->
target
,
aggreg
->
target
))
{
/* fill in the aggno and we're done */
aggreg
->
aggno
=
i
;
return
;
}
i
++
;
}
/* not found, new aggregate */
aggreg
->
aggno
=
i
;
pstate
->
p_numAgg
++
;
pstate
->
p_aggs
=
lappend
(
pstate
->
p_aggs
,
aggreg
);
return
;
}
/*
* finalizeAggregates -
* fill in qry_aggs from pstate. Also checks to make sure that aggregates
* are used in the proper place.
*/
void
finalizeAggregates
(
ParseState
*
pstate
,
Query
*
qry
)
{
List
*
l
;
int
i
;
parseCheckAggregates
(
pstate
,
qry
);
qry
->
qry_numAgg
=
pstate
->
p_numAgg
;
qry
->
qry_aggs
=
(
Aggreg
**
)
palloc
(
sizeof
(
Aggreg
*
)
*
qry
->
qry_numAgg
);
i
=
0
;
foreach
(
l
,
pstate
->
p_aggs
)
qry
->
qry_aggs
[
i
++
]
=
(
Aggreg
*
)
lfirst
(
l
);
}
/*
* contain_agg_clause--
* Recursively find aggreg nodes from a clause.
*
* Returns true if any aggregate found.
*/
bool
contain_agg_clause
(
Node
*
clause
)
{
if
(
clause
==
NULL
)
return
FALSE
;
else
if
(
IsA
(
clause
,
Aggreg
))
return
TRUE
;
else
if
(
IsA
(
clause
,
Iter
))
return
contain_agg_clause
(((
Iter
*
)
clause
)
->
iterexpr
);
else
if
(
single_node
(
clause
))
return
FALSE
;
else
if
(
or_clause
(
clause
))
{
List
*
temp
;
foreach
(
temp
,
((
Expr
*
)
clause
)
->
args
)
if
(
contain_agg_clause
(
lfirst
(
temp
)))
return
TRUE
;
return
FALSE
;
}
else
if
(
is_funcclause
(
clause
))
{
List
*
temp
;
foreach
(
temp
,
((
Expr
*
)
clause
)
->
args
)
if
(
contain_agg_clause
(
lfirst
(
temp
)))
return
TRUE
;
return
FALSE
;
}
else
if
(
IsA
(
clause
,
ArrayRef
))
{
List
*
temp
;
foreach
(
temp
,
((
ArrayRef
*
)
clause
)
->
refupperindexpr
)
if
(
contain_agg_clause
(
lfirst
(
temp
)))
return
TRUE
;
foreach
(
temp
,
((
ArrayRef
*
)
clause
)
->
reflowerindexpr
)
if
(
contain_agg_clause
(
lfirst
(
temp
)))
return
TRUE
;
if
(
contain_agg_clause
(((
ArrayRef
*
)
clause
)
->
refexpr
))
return
TRUE
;
if
(
contain_agg_clause
(((
ArrayRef
*
)
clause
)
->
refassgnexpr
))
return
TRUE
;
return
FALSE
;
}
else
if
(
not_clause
(
clause
))
return
contain_agg_clause
((
Node
*
)
get_notclausearg
((
Expr
*
)
clause
));
else
if
(
is_opclause
(
clause
))
return
(
contain_agg_clause
((
Node
*
)
get_leftop
((
Expr
*
)
clause
))
||
contain_agg_clause
((
Node
*
)
get_rightop
((
Expr
*
)
clause
)));
return
FALSE
;
}
/*
* exprIsAggOrGroupCol -
* returns true if the expression does not contain non-group columns.
*/
bool
exprIsAggOrGroupCol
(
Node
*
expr
,
List
*
groupClause
)
{
List
*
gl
;
if
(
expr
==
NULL
||
IsA
(
expr
,
Const
)
||
IsA
(
expr
,
Param
)
||
IsA
(
expr
,
Aggreg
))
return
TRUE
;
foreach
(
gl
,
groupClause
)
{
GroupClause
*
grpcl
=
lfirst
(
gl
);
if
(
equal
(
expr
,
grpcl
->
entry
->
expr
))
return
TRUE
;
}
if
(
IsA
(
expr
,
Expr
))
{
List
*
temp
;
foreach
(
temp
,
((
Expr
*
)
expr
)
->
args
)
if
(
!
exprIsAggOrGroupCol
(
lfirst
(
temp
),
groupClause
))
return
FALSE
;
return
TRUE
;
}
return
FALSE
;
}
/*
* tleIsAggOrGroupCol -
* returns true if the TargetEntry is Agg or GroupCol.
*/
bool
tleIsAggOrGroupCol
(
TargetEntry
*
tle
,
List
*
groupClause
)
{
Node
*
expr
=
tle
->
expr
;
List
*
gl
;
if
(
expr
==
NULL
||
IsA
(
expr
,
Const
)
||
IsA
(
expr
,
Param
))
return
TRUE
;
foreach
(
gl
,
groupClause
)
{
GroupClause
*
grpcl
=
lfirst
(
gl
);
if
(
tle
->
resdom
->
resno
==
grpcl
->
entry
->
resdom
->
resno
)
{
if
(
contain_agg_clause
((
Node
*
)
expr
))
elog
(
WARN
,
"parser: aggregates not allowed in GROUP BY clause"
);
return
TRUE
;
}
}
if
(
IsA
(
expr
,
Aggreg
))
return
TRUE
;
if
(
IsA
(
expr
,
Expr
))
{
List
*
temp
;
foreach
(
temp
,
((
Expr
*
)
expr
)
->
args
)
if
(
!
exprIsAggOrGroupCol
(
lfirst
(
temp
),
groupClause
))
return
FALSE
;
return
TRUE
;
}
return
FALSE
;
}
/*
* parseCheckAggregates -
* this should really be done earlier but the current grammar
* cannot differentiate functions from aggregates. So we have do check
* here when the target list and the qualifications are finalized.
*/
void
parseCheckAggregates
(
ParseState
*
pstate
,
Query
*
qry
)
{
List
*
tl
;
Assert
(
pstate
->
p_numAgg
>
0
);
/*
* aggregates never appear in WHERE clauses. (we have to check where
* clause first because if there is an aggregate, the check for
* non-group column in target list may fail.)
*/
if
(
contain_agg_clause
(
qry
->
qual
))
elog
(
WARN
,
"parser: aggregates not allowed in WHERE clause"
);
/*
* the target list can only contain aggregates, group columns and
* functions thereof.
*/
foreach
(
tl
,
qry
->
targetList
)
{
TargetEntry
*
tle
=
lfirst
(
tl
);
if
(
!
tleIsAggOrGroupCol
(
tle
,
qry
->
groupClause
))
elog
(
WARN
,
"parser: illegal use of aggregates or non-group column in target list"
);
}
/*
* the expression specified in the HAVING clause has the same
* restriction as those in the target list.
*/
/*
* Need to change here when we get HAVING works. Currently
* qry->havingQual is NULL. - vadim 04/05/97
if (!exprIsAggOrGroupCol(qry->havingQual, qry->groupClause))
elog(WARN,
"parser: illegal use of aggregates or non-group column in HAVING clause");
*/
return
;
}
Aggreg
*
ParseAgg
(
char
*
aggname
,
Oid
basetype
,
Node
*
target
)
{
Oid
fintype
;
Oid
vartype
;
Oid
xfn1
;
Form_pg_aggregate
aggform
;
Aggreg
*
aggreg
;
HeapTuple
theAggTuple
;
theAggTuple
=
SearchSysCacheTuple
(
AGGNAME
,
PointerGetDatum
(
aggname
),
ObjectIdGetDatum
(
basetype
),
0
,
0
);
if
(
!
HeapTupleIsValid
(
theAggTuple
))
{
elog
(
WARN
,
"aggregate %s does not exist"
,
aggname
);
}
aggform
=
(
Form_pg_aggregate
)
GETSTRUCT
(
theAggTuple
);
fintype
=
aggform
->
aggfinaltype
;
xfn1
=
aggform
->
aggtransfn1
;
if
(
nodeTag
(
target
)
!=
T_Var
&&
nodeTag
(
target
)
!=
T_Expr
)
elog
(
WARN
,
"parser: aggregate can only be applied on an attribute or expression"
);
/* only aggregates with transfn1 need a base type */
if
(
OidIsValid
(
xfn1
))
{
basetype
=
aggform
->
aggbasetype
;
if
(
nodeTag
(
target
)
==
T_Var
)
vartype
=
((
Var
*
)
target
)
->
vartype
;
else
vartype
=
((
Expr
*
)
target
)
->
typeOid
;
if
(
basetype
!=
vartype
)
{
Type
tp1
,
tp2
;
tp1
=
typeidType
(
basetype
);
tp2
=
typeidType
(
vartype
);
elog
(
NOTICE
,
"Aggregate type mismatch:"
);
elog
(
WARN
,
"%s works on %s, not %s"
,
aggname
,
typeTypeName
(
tp1
),
typeTypeName
(
tp2
));
}
}
aggreg
=
makeNode
(
Aggreg
);
aggreg
->
aggname
=
pstrdup
(
aggname
);
aggreg
->
basetype
=
aggform
->
aggbasetype
;
aggreg
->
aggtype
=
fintype
;
aggreg
->
target
=
target
;
return
aggreg
;
}
/*
* Error message when aggregate lookup fails that gives details of the
* basetype
*/
void
agg_error
(
char
*
caller
,
char
*
aggname
,
Oid
basetypeID
)
{
/*
* basetypeID that is Invalid (zero) means aggregate over all types.
* (count)
*/
if
(
basetypeID
==
InvalidOid
)
{
elog
(
WARN
,
"%s: aggregate '%s' for all types does not exist"
,
caller
,
aggname
);
}
else
{
elog
(
WARN
,
"%s: aggregate '%s' for '%s' does not exist"
,
caller
,
aggname
,
typeidTypeName
(
basetypeID
));
}
}
src/backend/parser/parse_clause.c
0 → 100644
View file @
4a5b781d
/*-------------------------------------------------------------------------
*
* parse_clause.c--
* handle clauses in parser
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.1 1997/11/25 22:05:35 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "postgres.h"
#include "access/heapam.h"
#include "parser/parse_clause.h"
#include "parser/parse_expr.h"
#include "parser/parse_node.h"
#include "parser/parse_oper.h"
#include "parser/parse_relation.h"
#include "parser/parse_target.h"
#include "catalog/pg_type.h"
#ifdef 0
#include "nodes/nodes.h"
#include "nodes/params.h"
#include "nodes/primnodes.h"
#include "nodes/parsenodes.h"
#include "nodes/relation.h"
#include "parse.h"
/* for AND, OR, etc. */
#include "catalog/pg_aggregate.h"
#include "catalog/pg_proc.h"
#include "utils/elog.h"
#include "utils/builtins.h"
/* namecmp(), textout() */
#include "utils/lsyscache.h"
#include "utils/palloc.h"
#include "utils/mcxt.h"
#include "utils/syscache.h"
#include "utils/acl.h"
#include "nodes/makefuncs.h"
/* for makeResdom(), etc. */
#include "nodes/nodeFuncs.h"
#include "commands/sequence.h"
#include "optimizer/clauses.h"
#include "miscadmin.h"
#include "port-protos.h"
/* strdup() */
#endif
/*
* parseFromClause -
* turns the table references specified in the from-clause into a
* range table. The range table may grow as we transform the expressions
* in the target list. (Note that this happens because in POSTQUEL, we
* allow references to relations not specified in the from-clause. We
* also allow that in our POST-SQL)
*
*/
void
parseFromClause
(
ParseState
*
pstate
,
List
*
frmList
)
{
List
*
fl
;
foreach
(
fl
,
frmList
)
{
RangeVar
*
r
=
lfirst
(
fl
);
RelExpr
*
baserel
=
r
->
relExpr
;
char
*
relname
=
baserel
->
relname
;
char
*
refname
=
r
->
name
;
RangeTblEntry
*
rte
;
if
(
refname
==
NULL
)
refname
=
relname
;
/*
* marks this entry to indicate it comes from the FROM clause. In
* SQL, the target list can only refer to range variables
* specified in the from clause but we follow the more powerful
* POSTQUEL semantics and automatically generate the range
* variable if not specified. However there are times we need to
* know whether the entries are legitimate.
*
* eg. select * from foo f where f.x = 1; will generate wrong answer
* if we expand * to foo.x.
*/
rte
=
addRangeTableEntry
(
pstate
,
relname
,
refname
,
baserel
->
inh
,
TRUE
);
}
}
/*
* makeRangeTable -
* make a range table with the specified relation (optional) and the
* from-clause.
*/
void
makeRangeTable
(
ParseState
*
pstate
,
char
*
relname
,
List
*
frmList
)
{
RangeTblEntry
*
rte
;
parseFromClause
(
pstate
,
frmList
);
if
(
relname
==
NULL
)
return
;
if
(
refnameRangeTablePosn
(
pstate
->
p_rtable
,
relname
)
<
1
)
rte
=
addRangeTableEntry
(
pstate
,
relname
,
relname
,
FALSE
,
FALSE
);
else
rte
=
refnameRangeTableEntry
(
pstate
->
p_rtable
,
relname
);
pstate
->
p_target_rangetblentry
=
rte
;
Assert
(
pstate
->
p_target_relation
==
NULL
);
pstate
->
p_target_relation
=
heap_open
(
rte
->
relid
);
Assert
(
pstate
->
p_target_relation
!=
NULL
);
/* will close relation later */
}
/*****************************************************************************
*
* Where Clause
*
*****************************************************************************/
/*
* transformWhereClause -
* transforms the qualification and make sure it is of type Boolean
*
*/
Node
*
transformWhereClause
(
ParseState
*
pstate
,
Node
*
a_expr
)
{
Node
*
qual
;
if
(
a_expr
==
NULL
)
return
(
Node
*
)
NULL
;
/* no qualifiers */
pstate
->
p_in_where_clause
=
true
;
qual
=
transformExpr
(
pstate
,
a_expr
,
EXPR_COLUMN_FIRST
);
pstate
->
p_in_where_clause
=
false
;
if
(
exprType
(
qual
)
!=
BOOLOID
)
{
elog
(
WARN
,
"where clause must return type bool, not %s"
,
typeidTypeName
(
exprType
(
qual
)));
}
return
qual
;
}
/*****************************************************************************
*
* Sort Clause
*
*****************************************************************************/
/*
* find_targetlist_entry -
* returns the Resdom in the target list matching the specified varname
* and range
*
*/
TargetEntry
*
find_targetlist_entry
(
ParseState
*
pstate
,
SortGroupBy
*
sortgroupby
,
List
*
tlist
)
{
List
*
i
;
int
real_rtable_pos
=
0
,
target_pos
=
0
;
TargetEntry
*
target_result
=
NULL
;
if
(
sortgroupby
->
range
)
real_rtable_pos
=
refnameRangeTablePosn
(
pstate
->
p_rtable
,
sortgroupby
->
range
);
foreach
(
i
,
tlist
)
{
TargetEntry
*
target
=
(
TargetEntry
*
)
lfirst
(
i
);
Resdom
*
resnode
=
target
->
resdom
;
Var
*
var
=
(
Var
*
)
target
->
expr
;
char
*
resname
=
resnode
->
resname
;
int
test_rtable_pos
=
var
->
varno
;
#ifdef PARSEDEBUG
printf
(
"find_targetlist_entry- target name is %s, position %d, resno %d
\n
"
,
(
sortgroupby
->
name
?
sortgroupby
->
name
:
"(null)"
),
target_pos
+
1
,
sortgroupby
->
resno
);
#endif
if
(
!
sortgroupby
->
name
)
{
if
(
sortgroupby
->
resno
==
++
target_pos
)
{
target_result
=
target
;
break
;
}
}
else
{
if
(
!
strcmp
(
resname
,
sortgroupby
->
name
))
{
if
(
sortgroupby
->
range
)
{
if
(
real_rtable_pos
==
test_rtable_pos
)
{
if
(
target_result
!=
NULL
)
elog
(
WARN
,
"Order/Group By '%s' is ambiguous"
,
sortgroupby
->
name
);
else
target_result
=
target
;
}
}
else
{
if
(
target_result
!=
NULL
)
elog
(
WARN
,
"Order/Group By '%s' is ambiguous"
,
sortgroupby
->
name
);
else
target_result
=
target
;
}
}
}
}
return
target_result
;
}
/*
* transformGroupClause -
* transform a Group By clause
*
*/
List
*
transformGroupClause
(
ParseState
*
pstate
,
List
*
grouplist
,
List
*
targetlist
)
{
List
*
glist
=
NIL
,
*
gl
=
NIL
;
while
(
grouplist
!=
NIL
)
{
GroupClause
*
grpcl
=
makeNode
(
GroupClause
);
TargetEntry
*
restarget
;
Resdom
*
resdom
;
restarget
=
find_targetlist_entry
(
pstate
,
lfirst
(
grouplist
),
targetlist
);
if
(
restarget
==
NULL
)
elog
(
WARN
,
"The field being grouped by must appear in the target list"
);
grpcl
->
entry
=
restarget
;
resdom
=
restarget
->
resdom
;
grpcl
->
grpOpoid
=
oprid
(
oper
(
"<"
,
resdom
->
restype
,
resdom
->
restype
,
false
));
if
(
glist
==
NIL
)
gl
=
glist
=
lcons
(
grpcl
,
NIL
);
else
{
List
*
i
;
foreach
(
i
,
glist
)
{
GroupClause
*
gcl
=
(
GroupClause
*
)
lfirst
(
i
);
if
(
gcl
->
entry
==
grpcl
->
entry
)
break
;
}
if
(
i
==
NIL
)
/* not in grouplist already */
{
lnext
(
gl
)
=
lcons
(
grpcl
,
NIL
);
gl
=
lnext
(
gl
);
}
else
pfree
(
grpcl
);
/* get rid of this */
}
grouplist
=
lnext
(
grouplist
);
}
return
glist
;
}
/*
* transformSortClause -
* transform an Order By clause
*
*/
List
*
transformSortClause
(
ParseState
*
pstate
,
List
*
orderlist
,
List
*
targetlist
,
char
*
uniqueFlag
)
{
List
*
sortlist
=
NIL
;
List
*
s
=
NIL
;
while
(
orderlist
!=
NIL
)
{
SortGroupBy
*
sortby
=
lfirst
(
orderlist
);
SortClause
*
sortcl
=
makeNode
(
SortClause
);
TargetEntry
*
restarget
;
Resdom
*
resdom
;
restarget
=
find_targetlist_entry
(
pstate
,
sortby
,
targetlist
);
if
(
restarget
==
NULL
)
elog
(
WARN
,
"The field being ordered by must appear in the target list"
);
sortcl
->
resdom
=
resdom
=
restarget
->
resdom
;
sortcl
->
opoid
=
oprid
(
oper
(
sortby
->
useOp
,
resdom
->
restype
,
resdom
->
restype
,
false
));
if
(
sortlist
==
NIL
)
{
s
=
sortlist
=
lcons
(
sortcl
,
NIL
);
}
else
{
List
*
i
;
foreach
(
i
,
sortlist
)
{
SortClause
*
scl
=
(
SortClause
*
)
lfirst
(
i
);
if
(
scl
->
resdom
==
sortcl
->
resdom
)
break
;
}
if
(
i
==
NIL
)
/* not in sortlist already */
{
lnext
(
s
)
=
lcons
(
sortcl
,
NIL
);
s
=
lnext
(
s
);
}
else
pfree
(
sortcl
);
/* get rid of this */
}
orderlist
=
lnext
(
orderlist
);
}
if
(
uniqueFlag
)
{
List
*
i
;
if
(
uniqueFlag
[
0
]
==
'*'
)
{
/*
* concatenate all elements from target list that are not
* already in the sortby list
*/
foreach
(
i
,
targetlist
)
{
TargetEntry
*
tlelt
=
(
TargetEntry
*
)
lfirst
(
i
);
s
=
sortlist
;
while
(
s
!=
NIL
)
{
SortClause
*
sortcl
=
lfirst
(
s
);
if
(
sortcl
->
resdom
==
tlelt
->
resdom
)
break
;
s
=
lnext
(
s
);
}
if
(
s
==
NIL
)
{
/* not a member of the sortclauses yet */
SortClause
*
sortcl
=
makeNode
(
SortClause
);
sortcl
->
resdom
=
tlelt
->
resdom
;
sortcl
->
opoid
=
any_ordering_op
(
tlelt
->
resdom
->
restype
);
sortlist
=
lappend
(
sortlist
,
sortcl
);
}
}
}
else
{
TargetEntry
*
tlelt
=
NULL
;
char
*
uniqueAttrName
=
uniqueFlag
;
/* only create sort clause with the specified unique attribute */
foreach
(
i
,
targetlist
)
{
tlelt
=
(
TargetEntry
*
)
lfirst
(
i
);
if
(
strcmp
(
tlelt
->
resdom
->
resname
,
uniqueAttrName
)
==
0
)
break
;
}
if
(
i
==
NIL
)
{
elog
(
WARN
,
"The field specified in the UNIQUE ON clause is not in the targetlist"
);
}
s
=
sortlist
;
foreach
(
s
,
sortlist
)
{
SortClause
*
sortcl
=
lfirst
(
s
);
if
(
sortcl
->
resdom
==
tlelt
->
resdom
)
break
;
}
if
(
s
==
NIL
)
{
/* not a member of the sortclauses yet */
SortClause
*
sortcl
=
makeNode
(
SortClause
);
sortcl
->
resdom
=
tlelt
->
resdom
;
sortcl
->
opoid
=
any_ordering_op
(
tlelt
->
resdom
->
restype
);
sortlist
=
lappend
(
sortlist
,
sortcl
);
}
}
}
return
sortlist
;
}
src/backend/parser/parse_expr.c
0 → 100644
View file @
4a5b781d
/*-------------------------------------------------------------------------
*
* parse_expr.c
* handle expressions in parser
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.1 1997/11/25 22:05:39 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "postgres.h"
#include "catalog/pg_type.h"
#include "nodes/makefuncs.h"
#include "nodes/nodes.h"
#include "nodes/params.h"
#include "nodes/relation.h"
#include "parser/parse_expr.h"
#include "parser/parse_func.h"
#include "parser/parse_node.h"
#include "parser/parse_relation.h"
#include "parser/parse_target.h"
#include "parse.h"
#include "utils/builtins.h"
#ifdef 0
#include "nodes/primnodes.h"
#include "nodes/parsenodes.h"
#include "catalog/pg_aggregate.h"
#include "catalog/pg_proc.h"
#include "utils/elog.h"
#include "utils/lsyscache.h"
#include "utils/palloc.h"
#include "utils/mcxt.h"
#include "utils/syscache.h"
#include "utils/acl.h"
#include "nodes/nodeFuncs.h"
#include "commands/sequence.h"
#include "optimizer/clauses.h"
#include "access/heapam.h"
#include "miscadmin.h"
#endif
Oid
param_type
(
int
t
);
/* from gram.y */
/*
* transformExpr -
* analyze and transform expressions. Type checking and type casting is
* done here. The optimizer and the executor cannot handle the original
* (raw) expressions collected by the parse tree. Hence the transformation
* here.
*/
Node
*
transformExpr
(
ParseState
*
pstate
,
Node
*
expr
,
int
precedence
)
{
Node
*
result
=
NULL
;
if
(
expr
==
NULL
)
return
NULL
;
switch
(
nodeTag
(
expr
))
{
case
T_Attr
:
{
Attr
*
att
=
(
Attr
*
)
expr
;
Node
*
temp
;
/* what if att.attrs == "*"?? */
temp
=
handleNestedDots
(
pstate
,
att
,
&
pstate
->
p_last_resno
);
if
(
att
->
indirection
!=
NIL
)
{
List
*
idx
=
att
->
indirection
;
while
(
idx
!=
NIL
)
{
A_Indices
*
ai
=
(
A_Indices
*
)
lfirst
(
idx
);
Node
*
lexpr
=
NULL
,
*
uexpr
;
uexpr
=
transformExpr
(
pstate
,
ai
->
uidx
,
precedence
);
/* must exists */
if
(
exprType
(
uexpr
)
!=
INT4OID
)
elog
(
WARN
,
"array index expressions must be int4's"
);
if
(
ai
->
lidx
!=
NULL
)
{
lexpr
=
transformExpr
(
pstate
,
ai
->
lidx
,
precedence
);
if
(
exprType
(
lexpr
)
!=
INT4OID
)
elog
(
WARN
,
"array index expressions must be int4's"
);
}
#if 0
pfree(ai->uidx);
if (ai->lidx != NULL)
pfree(ai->lidx);
#endif
ai
->
lidx
=
lexpr
;
ai
->
uidx
=
uexpr
;
/*
* note we reuse the list of indices, make sure we
* don't free them! Otherwise, make a new list
* here
*/
idx
=
lnext
(
idx
);
}
result
=
(
Node
*
)
make_array_ref
(
temp
,
att
->
indirection
);
}
else
{
result
=
temp
;
}
break
;
}
case
T_A_Const
:
{
A_Const
*
con
=
(
A_Const
*
)
expr
;
Value
*
val
=
&
con
->
val
;
if
(
con
->
typename
!=
NULL
)
{
result
=
parser_typecast
(
val
,
con
->
typename
,
-
1
);
}
else
{
result
=
(
Node
*
)
make_const
(
val
);
}
break
;
}
case
T_ParamNo
:
{
ParamNo
*
pno
=
(
ParamNo
*
)
expr
;
Oid
toid
;
int
paramno
;
Param
*
param
;
paramno
=
pno
->
number
;
toid
=
param_type
(
paramno
);
if
(
!
OidIsValid
(
toid
))
{
elog
(
WARN
,
"Parameter '$%d' is out of range"
,
paramno
);
}
param
=
makeNode
(
Param
);
param
->
paramkind
=
PARAM_NUM
;
param
->
paramid
=
(
AttrNumber
)
paramno
;
param
->
paramname
=
"<unnamed>"
;
param
->
paramtype
=
(
Oid
)
toid
;
param
->
param_tlist
=
(
List
*
)
NULL
;
result
=
(
Node
*
)
param
;
break
;
}
case
T_A_Expr
:
{
A_Expr
*
a
=
(
A_Expr
*
)
expr
;
switch
(
a
->
oper
)
{
case
OP
:
{
Node
*
lexpr
=
transformExpr
(
pstate
,
a
->
lexpr
,
precedence
);
Node
*
rexpr
=
transformExpr
(
pstate
,
a
->
rexpr
,
precedence
);
result
=
(
Node
*
)
make_op
(
a
->
opname
,
lexpr
,
rexpr
);
}
break
;
case
ISNULL
:
{
Node
*
lexpr
=
transformExpr
(
pstate
,
a
->
lexpr
,
precedence
);
result
=
ParseFunc
(
pstate
,
"nullvalue"
,
lcons
(
lexpr
,
NIL
),
&
pstate
->
p_last_resno
);
}
break
;
case
NOTNULL
:
{
Node
*
lexpr
=
transformExpr
(
pstate
,
a
->
lexpr
,
precedence
);
result
=
ParseFunc
(
pstate
,
"nonnullvalue"
,
lcons
(
lexpr
,
NIL
),
&
pstate
->
p_last_resno
);
}
break
;
case
AND
:
{
Expr
*
expr
=
makeNode
(
Expr
);
Node
*
lexpr
=
transformExpr
(
pstate
,
a
->
lexpr
,
precedence
);
Node
*
rexpr
=
transformExpr
(
pstate
,
a
->
rexpr
,
precedence
);
if
(
exprType
(
lexpr
)
!=
BOOLOID
)
elog
(
WARN
,
"left-hand side of AND is type '%s', not bool"
,
typeidTypeName
(
exprType
(
lexpr
)));
if
(
exprType
(
rexpr
)
!=
BOOLOID
)
elog
(
WARN
,
"right-hand side of AND is type '%s', not bool"
,
typeidTypeName
(
exprType
(
rexpr
)));
expr
->
typeOid
=
BOOLOID
;
expr
->
opType
=
AND_EXPR
;
expr
->
args
=
makeList
(
lexpr
,
rexpr
,
-
1
);
result
=
(
Node
*
)
expr
;
}
break
;
case
OR
:
{
Expr
*
expr
=
makeNode
(
Expr
);
Node
*
lexpr
=
transformExpr
(
pstate
,
a
->
lexpr
,
precedence
);
Node
*
rexpr
=
transformExpr
(
pstate
,
a
->
rexpr
,
precedence
);
if
(
exprType
(
lexpr
)
!=
BOOLOID
)
elog
(
WARN
,
"left-hand side of OR is type '%s', not bool"
,
typeidTypeName
(
exprType
(
lexpr
)));
if
(
exprType
(
rexpr
)
!=
BOOLOID
)
elog
(
WARN
,
"right-hand side of OR is type '%s', not bool"
,
typeidTypeName
(
exprType
(
rexpr
)));
expr
->
typeOid
=
BOOLOID
;
expr
->
opType
=
OR_EXPR
;
expr
->
args
=
makeList
(
lexpr
,
rexpr
,
-
1
);
result
=
(
Node
*
)
expr
;
}
break
;
case
NOT
:
{
Expr
*
expr
=
makeNode
(
Expr
);
Node
*
rexpr
=
transformExpr
(
pstate
,
a
->
rexpr
,
precedence
);
if
(
exprType
(
rexpr
)
!=
BOOLOID
)
elog
(
WARN
,
"argument to NOT is type '%s', not bool"
,
typeidTypeName
(
exprType
(
rexpr
)));
expr
->
typeOid
=
BOOLOID
;
expr
->
opType
=
NOT_EXPR
;
expr
->
args
=
makeList
(
rexpr
,
-
1
);
result
=
(
Node
*
)
expr
;
}
break
;
}
break
;
}
case
T_Ident
:
{
/*
* look for a column name or a relation name (the default
* behavior)
*/
result
=
transformIdent
(
pstate
,
expr
,
precedence
);
break
;
}
case
T_FuncCall
:
{
FuncCall
*
fn
=
(
FuncCall
*
)
expr
;
List
*
args
;
/* transform the list of arguments */
foreach
(
args
,
fn
->
args
)
lfirst
(
args
)
=
transformExpr
(
pstate
,
(
Node
*
)
lfirst
(
args
),
precedence
);
result
=
ParseFunc
(
pstate
,
fn
->
funcname
,
fn
->
args
,
&
pstate
->
p_last_resno
);
break
;
}
default:
/* should not reach here */
elog
(
WARN
,
"transformExpr: does not know how to transform %d
\n
"
,
nodeTag
(
expr
));
break
;
}
return
result
;
}
Node
*
transformIdent
(
ParseState
*
pstate
,
Node
*
expr
,
int
precedence
)
{
Ident
*
ident
=
(
Ident
*
)
expr
;
RangeTblEntry
*
rte
;
Node
*
column_result
,
*
relation_result
,
*
result
;
column_result
=
relation_result
=
result
=
0
;
/* try to find the ident as a column */
if
((
rte
=
colnameRangeTableEntry
(
pstate
,
ident
->
name
))
!=
NULL
)
{
Attr
*
att
=
makeNode
(
Attr
);
att
->
relname
=
rte
->
refname
;
att
->
attrs
=
lcons
(
makeString
(
ident
->
name
),
NIL
);
column_result
=
(
Node
*
)
handleNestedDots
(
pstate
,
att
,
&
pstate
->
p_last_resno
);
}
/* try to find the ident as a relation */
if
(
refnameRangeTableEntry
(
pstate
->
p_rtable
,
ident
->
name
)
!=
NULL
)
{
ident
->
isRel
=
TRUE
;
relation_result
=
(
Node
*
)
ident
;
}
/* choose the right result based on the precedence */
if
(
precedence
==
EXPR_COLUMN_FIRST
)
{
if
(
column_result
)
result
=
column_result
;
else
result
=
relation_result
;
}
else
{
if
(
relation_result
)
result
=
relation_result
;
else
result
=
column_result
;
}
if
(
result
==
NULL
)
elog
(
WARN
,
"attribute '%s' not found"
,
ident
->
name
);
return
result
;
}
/*
* exprType -
* returns the Oid of the type of the expression. (Used for typechecking.)
*/
Oid
exprType
(
Node
*
expr
)
{
Oid
type
=
(
Oid
)
0
;
switch
(
nodeTag
(
expr
))
{
case
T_Func
:
type
=
((
Func
*
)
expr
)
->
functype
;
break
;
case
T_Iter
:
type
=
((
Iter
*
)
expr
)
->
itertype
;
break
;
case
T_Var
:
type
=
((
Var
*
)
expr
)
->
vartype
;
break
;
case
T_Expr
:
type
=
((
Expr
*
)
expr
)
->
typeOid
;
break
;
case
T_Const
:
type
=
((
Const
*
)
expr
)
->
consttype
;
break
;
case
T_ArrayRef
:
type
=
((
ArrayRef
*
)
expr
)
->
refelemtype
;
break
;
case
T_Aggreg
:
type
=
((
Aggreg
*
)
expr
)
->
aggtype
;
break
;
case
T_Param
:
type
=
((
Param
*
)
expr
)
->
paramtype
;
break
;
case
T_Ident
:
/* is this right? */
type
=
UNKNOWNOID
;
break
;
default:
elog
(
WARN
,
"exprType: don't know how to get type for %d node"
,
nodeTag
(
expr
));
break
;
}
return
type
;
}
/*
** HandleNestedDots --
** Given a nested dot expression (i.e. (relation func ... attr), build up
** a tree with of Iter and Func nodes.
*/
Node
*
handleNestedDots
(
ParseState
*
pstate
,
Attr
*
attr
,
int
*
curr_resno
)
{
List
*
mutator_iter
;
Node
*
retval
=
NULL
;
if
(
attr
->
paramNo
!=
NULL
)
{
Param
*
param
=
(
Param
*
)
transformExpr
(
pstate
,
(
Node
*
)
attr
->
paramNo
,
EXPR_RELATION_FIRST
);
retval
=
ParseFunc
(
pstate
,
strVal
(
lfirst
(
attr
->
attrs
)),
lcons
(
param
,
NIL
),
curr_resno
);
}
else
{
Ident
*
ident
=
makeNode
(
Ident
);
ident
->
name
=
attr
->
relname
;
ident
->
isRel
=
TRUE
;
retval
=
ParseFunc
(
pstate
,
strVal
(
lfirst
(
attr
->
attrs
)),
lcons
(
ident
,
NIL
),
curr_resno
);
}
foreach
(
mutator_iter
,
lnext
(
attr
->
attrs
))
{
retval
=
ParseFunc
(
pstate
,
strVal
(
lfirst
(
mutator_iter
)),
lcons
(
retval
,
NIL
),
curr_resno
);
}
return
(
retval
);
}
Node
*
parser_typecast
(
Value
*
expr
,
TypeName
*
typename
,
int
typlen
)
{
/* check for passing non-ints */
Const
*
adt
;
Datum
lcp
;
Type
tp
;
char
type_string
[
NAMEDATALEN
];
int32
len
;
char
*
cp
=
NULL
;
char
*
const_string
=
NULL
;
bool
string_palloced
=
false
;
switch
(
nodeTag
(
expr
))
{
case
T_String
:
const_string
=
DatumGetPointer
(
expr
->
val
.
str
);
break
;
case
T_Integer
:
const_string
=
(
char
*
)
palloc
(
256
);
string_palloced
=
true
;
sprintf
(
const_string
,
"%ld"
,
expr
->
val
.
ival
);
break
;
default:
elog
(
WARN
,
"parser_typecast: cannot cast this expression to type
\"
%s
\"
"
,
typename
->
name
);
}
if
(
typename
->
arrayBounds
!=
NIL
)
{
sprintf
(
type_string
,
"_%s"
,
typename
->
name
);
tp
=
(
Type
)
typenameType
(
type_string
);
}
else
{
tp
=
(
Type
)
typenameType
(
typename
->
name
);
}
len
=
typeLen
(
tp
);
#if 0 /* fix me */
switch (CInteger(lfirst(expr)))
{
case INT4OID: /* int4 */
const_string = (char *) palloc(256);
string_palloced = true;
sprintf(const_string, "%d", ((Const *) lnext(expr))->constvalue);
break;
case NAMEOID: /* char16 */
const_string = (char *) palloc(256);
string_palloced = true;
sprintf(const_string, "%s", ((Const *) lnext(expr))->constvalue);
break;
case CHAROID: /* char */
const_string = (char *) palloc(256);
string_palloced = true;
sprintf(const_string, "%c", ((Const) lnext(expr))->constvalue);
break;
case FLOAT8OID: /* float8 */
const_string = (char *) palloc(256);
string_palloced = true;
sprintf(const_string, "%f", ((Const) lnext(expr))->constvalue);
break;
case CASHOID: /* money */
const_string = (char *) palloc(256);
string_palloced = true;
sprintf(const_string, "%d",
(int) ((Const *) expr)->constvalue);
break;
case TEXTOID: /* text */
const_string = DatumGetPointer(((Const) lnext(expr))->constvalue);
const_string = (char *) textout((struct varlena *) const_string);
break;
case UNKNOWNOID: /* unknown */
const_string = DatumGetPointer(((Const) lnext(expr))->constvalue);
const_string = (char *) textout((struct varlena *) const_string);
break;
default:
elog(WARN, "unknown type %d", CInteger(lfirst(expr)));
}
#endif
cp
=
stringTypeString
(
tp
,
const_string
,
typlen
);
if
(
!
typeByVal
(
tp
))
{
/*
if (len >= 0 && len != PSIZE(cp)) {
char *pp;
pp = (char *) palloc(len);
memmove(pp, cp, len);
cp = pp;
}
*/
lcp
=
PointerGetDatum
(
cp
);
}
else
{
switch
(
len
)
{
case
1
:
lcp
=
Int8GetDatum
(
cp
);
break
;
case
2
:
lcp
=
Int16GetDatum
(
cp
);
break
;
case
4
:
lcp
=
Int32GetDatum
(
cp
);
break
;
default:
lcp
=
PointerGetDatum
(
cp
);
break
;
}
}
adt
=
makeConst
(
typeTypeId
(
tp
),
len
,
(
Datum
)
lcp
,
false
,
typeByVal
(
tp
),
false
,
/* not a set */
true
/* is cast */
);
if
(
string_palloced
)
pfree
(
const_string
);
return
(
Node
*
)
adt
;
}
Node
*
parser_typecast2
(
Node
*
expr
,
Oid
exprType
,
Type
tp
,
int
typlen
)
{
/* check for passing non-ints */
Const
*
adt
;
Datum
lcp
;
int32
len
=
typeLen
(
tp
);
char
*
cp
=
NULL
;
char
*
const_string
=
NULL
;
bool
string_palloced
=
false
;
Assert
(
IsA
(
expr
,
Const
));
switch
(
exprType
)
{
case
0
:
/* NULL */
break
;
case
INT4OID
:
/* int4 */
const_string
=
(
char
*
)
palloc
(
256
);
string_palloced
=
true
;
sprintf
(
const_string
,
"%d"
,
(
int
)
((
Const
*
)
expr
)
->
constvalue
);
break
;
case
NAMEOID
:
/* char16 */
const_string
=
(
char
*
)
palloc
(
256
);
string_palloced
=
true
;
sprintf
(
const_string
,
"%s"
,
(
char
*
)
((
Const
*
)
expr
)
->
constvalue
);
break
;
case
CHAROID
:
/* char */
const_string
=
(
char
*
)
palloc
(
256
);
string_palloced
=
true
;
sprintf
(
const_string
,
"%c"
,
(
char
)
((
Const
*
)
expr
)
->
constvalue
);
break
;
case
FLOAT4OID
:
/* float4 */
{
float32
floatVal
=
DatumGetFloat32
(((
Const
*
)
expr
)
->
constvalue
);
const_string
=
(
char
*
)
palloc
(
256
);
string_palloced
=
true
;
sprintf
(
const_string
,
"%f"
,
*
floatVal
);
break
;
}
case
FLOAT8OID
:
/* float8 */
{
float64
floatVal
=
DatumGetFloat64
(((
Const
*
)
expr
)
->
constvalue
);
const_string
=
(
char
*
)
palloc
(
256
);
string_palloced
=
true
;
sprintf
(
const_string
,
"%f"
,
*
floatVal
);
break
;
}
case
CASHOID
:
/* money */
const_string
=
(
char
*
)
palloc
(
256
);
string_palloced
=
true
;
sprintf
(
const_string
,
"%ld"
,
(
long
)
((
Const
*
)
expr
)
->
constvalue
);
break
;
case
TEXTOID
:
/* text */
const_string
=
DatumGetPointer
(((
Const
*
)
expr
)
->
constvalue
);
const_string
=
(
char
*
)
textout
((
struct
varlena
*
)
const_string
);
break
;
case
UNKNOWNOID
:
/* unknown */
const_string
=
DatumGetPointer
(((
Const
*
)
expr
)
->
constvalue
);
const_string
=
(
char
*
)
textout
((
struct
varlena
*
)
const_string
);
break
;
default:
elog
(
WARN
,
"unknown type %u "
,
exprType
);
}
if
(
!
exprType
)
{
adt
=
makeConst
(
typeTypeId
(
tp
),
(
Size
)
0
,
(
Datum
)
NULL
,
true
,
/* isnull */
false
,
/* was omitted */
false
,
/* not a set */
true
/* is cast */
);
return
((
Node
*
)
adt
);
}
cp
=
stringTypeString
(
tp
,
const_string
,
typlen
);
if
(
!
typeByVal
(
tp
))
{
/*
if (len >= 0 && len != PSIZE(cp)) {
char *pp;
pp = (char *) palloc(len);
memmove(pp, cp, len);
cp = pp;
}
*/
lcp
=
PointerGetDatum
(
cp
);
}
else
{
switch
(
len
)
{
case
1
:
lcp
=
Int8GetDatum
(
cp
);
break
;
case
2
:
lcp
=
Int16GetDatum
(
cp
);
break
;
case
4
:
lcp
=
Int32GetDatum
(
cp
);
break
;
default:
lcp
=
PointerGetDatum
(
cp
);
break
;
}
}
adt
=
makeConst
(
typeTypeId
(
tp
),
(
Size
)
len
,
(
Datum
)
lcp
,
false
,
false
,
/* was omitted */
false
,
/* not a set */
true
/* is cast */
);
/*
* printf("adt %s : %u %d %d\n",CString(expr),typeTypeId(tp) , len,cp);
*/
if
(
string_palloced
)
pfree
(
const_string
);
return
((
Node
*
)
adt
);
}
src/backend/parser/
catalog_utils
.c
→
src/backend/parser/
parse_func
.c
View file @
4a5b781d
/*-------------------------------------------------------------------------
/*-------------------------------------------------------------------------
*
*
* catalog_utils.c--
* parse_func.c
* handle function calls in parser
*
*
* Copyright (c) 1994, Regents of the University of California
* Copyright (c) 1994, Regents of the University of California
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/
Attic/catalog_utils.c,v 1.30 1997/11/20 23:22:14
momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/
parse_func.c,v 1.1 1997/11/25 22:05:41
momjian Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
#include <string.h>
#include <string.h>
#include "postgres.h"
#include "postgres.h"
#include "fmgr.h"
#include "miscadmin.h"
#include "access/genam.h"
#include "access/heapam.h"
#include "access/itup.h"
#include "access/relscan.h"
#include "access/sdir.h"
#include "catalog/catname.h"
#include "catalog/indexing.h"
#include "catalog/pg_inherits.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "lib/dllist.h"
#include "lib/dllist.h"
#include "nodes/makefuncs.h"
#include "nodes/relation.h"
#include "parser/parse_agg.h"
#include "parser/parse_expr.h"
#include "parser/parse_func.h"
#include "parser/parse_node.h"
#include "parser/parse_relation.h"
#include "parser/parse_type.h"
#include "storage/bufmgr.h"
#include "storage/lmgr.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
#ifdef 0
#include "utils/datum.h"
#include "utils/datum.h"
#include "utils/builtins.h"
#include "utils/elog.h"
#include "utils/elog.h"
#include "utils/palloc.h"
#include "utils/palloc.h"
#include "fmgr.h"
#include "nodes/pg_list.h"
#include "nodes/pg_list.h"
#include "nodes/parsenodes.h"
#include "nodes/parsenodes.h"
#include "utils/syscache.h"
#include "catalog/catname.h"
#include "parser/catalog_utils.h"
#include "catalog/pg_inherits.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_type.h"
#include "catalog/pg_proc.h"
#include "catalog/indexing.h"
#include "catalog/catname.h"
#include "catalog/catname.h"
#include "access/skey.h"
#include "access/skey.h"
#include "access/relscan.h"
#include "access/tupdesc.h"
#include "access/tupdesc.h"
#include "access/htup.h"
#include "access/htup.h"
#include "access/heapam.h"
#include "access/genam.h"
#include "access/genam.h"
#include "access/itup.h"
#include "access/itup.h"
#include "access/tupmacs.h"
#include "access/tupmacs.h"
#include "storage/buf.h"
#include "storage/buf.h"
#include "storage/bufmgr.h"
#endif
#include "utils/lsyscache.h"
#include "storage/lmgr.h"
#include "port-protos.h"
/* strdup() */
struct
{
char
*
field
;
int
code
;
}
special_attr
[]
=
{
{
"ctid"
,
SelfItemPointerAttributeNumber
},
{
"oid"
,
ObjectIdAttributeNumber
},
{
"xmin"
,
MinTransactionIdAttributeNumber
},
{
"cmin"
,
MinCommandIdAttributeNumber
},
{
"xmax"
,
MaxTransactionIdAttributeNumber
},
{
"cmax"
,
MaxCommandIdAttributeNumber
},
};
#define SPECIALS (sizeof(special_attr)/sizeof(*special_attr))
static
char
*
attnum_type
[
SPECIALS
]
=
{
#define ISCOMPLEX(type) (typeidTypeRelid(type) ? true : false)
"tid"
,
"oid"
,
"xid"
,
"cid"
,
"xid"
,
"cid"
,
};
#define MAXFARGS 8
/* max # args to a c or postquel function */
#define MAXFARGS 8
/* max # args to a c or postquel function */
/*
typedef
struct
_SuperQE
* This structure is used to explore the inheritance hierarchy above
* nodes in the type tree in order to disambiguate among polymorphic
* functions.
*/
typedef
struct
_InhPaths
{
{
int
nsupers
;
/* number of superclasses */
Oid
sqe_relid
;
Oid
self
;
/* this class */
}
SuperQE
;
Oid
*
supervec
;
/* vector of superclasses */
}
InhPaths
;
/*
/*
* This structure holds a list of possible functions or operators that
* parse function
* agree with the known name and argument types of the function/operator.
*/
typedef
struct
_CandidateList
{
Oid
*
args
;
struct
_CandidateList
*
next
;
}
*
CandidateList
;
static
Oid
**
argtype_inherit
(
int
nargs
,
Oid
*
oid_array
);
static
Oid
**
genxprod
(
InhPaths
*
arginh
,
int
nargs
);
static
int
findsupers
(
Oid
relid
,
Oid
**
supervec
);
static
bool
check_typeid
(
Oid
id
);
static
char
*
instr1
(
TypeTupleForm
tp
,
char
*
string
,
int
typlen
);
static
void
op_error
(
char
*
op
,
Oid
arg1
,
Oid
arg2
);
/* check to see if a type id is valid,
* returns true if it is. By using this call before calling
* get_id_type or get_id_typname, more meaningful error messages
* can be produced because the caller typically has more context of
* what's going on - jolly
*/
*/
static
bool
check_typeid
(
Oid
id
)
{
return
(
SearchSysCacheTuple
(
TYPOID
,
ObjectIdGetDatum
(
id
),
0
,
0
,
0
)
!=
NULL
);
}
/* return a Type structure, given an typid */
Node
*
Type
ParseFunc
(
ParseState
*
pstate
,
char
*
funcname
,
List
*
fargs
,
int
*
curr_resno
)
get_id_type
(
Oid
id
)
{
{
HeapTuple
tup
;
Oid
rettype
=
(
Oid
)
0
;
Oid
argrelid
=
(
Oid
)
0
;
if
(
!
(
tup
=
SearchSysCacheTuple
(
TYPOID
,
ObjectIdGetDatum
(
id
),
Oid
funcid
=
(
Oid
)
0
;
0
,
0
,
0
)))
List
*
i
=
NIL
;
{
Node
*
first_arg
=
NULL
;
elog
(
WARN
,
"type id lookup of %ud failed"
,
id
);
char
*
relname
=
NULL
;
return
(
NULL
);
char
*
refname
=
NULL
;
}
Relation
rd
;
return
((
Type
)
tup
);
Oid
relid
;
}
int
nargs
;
Func
*
funcnode
;
/* return a type name, given a typeid */
Oid
oid_array
[
8
];
char
*
Oid
*
true_oid_array
;
get_id_typname
(
Oid
id
)
Node
*
retval
;
{
bool
retset
;
HeapTuple
tup
;
bool
exists
;
TypeTupleForm
typetuple
;
bool
attisset
=
false
;
Oid
toid
=
(
Oid
)
0
;
if
(
!
(
tup
=
SearchSysCacheTuple
(
TYPOID
,
ObjectIdGetDatum
(
id
),
Expr
*
expr
;
0
,
0
,
0
)))
{
if
(
fargs
)
elog
(
WARN
,
"type id lookup of %ud failed"
,
id
);
return
(
NULL
);
}
typetuple
=
(
TypeTupleForm
)
GETSTRUCT
(
tup
);
return
(
typetuple
->
typname
).
data
;
}
/* return a Type structure, given type name */
Type
type
(
char
*
s
)
{
HeapTuple
tup
;
if
(
s
==
NULL
)
{
elog
(
WARN
,
"type(): Null type"
);
}
if
(
!
(
tup
=
SearchSysCacheTuple
(
TYPNAME
,
PointerGetDatum
(
s
),
0
,
0
,
0
)))
{
elog
(
WARN
,
"type name lookup of %s failed"
,
s
);
}
return
((
Type
)
tup
);
}
/* given attribute id, return type of that attribute */
/* XXX Special case for pseudo-attributes is a hack */
Oid
att_typeid
(
Relation
rd
,
int
attid
)
{
if
(
attid
<
0
)
{
{
return
(
typeid
(
type
(
attnum_type
[
-
attid
-
1
])));
first_arg
=
lfirst
(
fargs
);
if
(
first_arg
==
NULL
)
elog
(
WARN
,
"function '%s' does not allow NULL input"
,
funcname
);
}
}
/*
/*
* -1 because varattno (where attid comes from) returns one more than
* check for projection methods: if function takes one argument, and
* index
* that argument is a relation, param, or PQ function returning a
* complex * type, then the function could be a projection.
*/
*/
return
(
rd
->
rd_att
->
attrs
[
attid
-
1
]
->
atttypid
);
if
(
length
(
fargs
)
==
1
)
}
int
att_attnelems
(
Relation
rd
,
int
attid
)
{
return
(
rd
->
rd_att
->
attrs
[
attid
-
1
]
->
attnelems
);
}
/* given type, return the type OID */
Oid
typeid
(
Type
tp
)
{
if
(
tp
==
NULL
)
{
{
elog
(
WARN
,
"typeid() called with NULL type struct"
);
}
return
(
tp
->
t_oid
);
}
/* given type (as type struct), return the length of type */
int16
tlen
(
Type
t
)
{
TypeTupleForm
typ
;
typ
=
(
TypeTupleForm
)
GETSTRUCT
(
t
);
return
(
typ
->
typlen
);
}
/* given type (as type struct), return the value of its 'byval' attribute.*/
bool
tbyval
(
Type
t
)
{
TypeTupleForm
typ
;
typ
=
(
TypeTupleForm
)
GETSTRUCT
(
t
);
return
(
typ
->
typbyval
);
}
/* given type (as type struct), return the name of type */
if
(
nodeTag
(
first_arg
)
==
T_Ident
&&
((
Ident
*
)
first_arg
)
->
isRel
)
char
*
{
tname
(
Type
t
)
RangeTblEntry
*
rte
;
{
Ident
*
ident
=
(
Ident
*
)
first_arg
;
TypeTupleForm
typ
;
typ
=
(
TypeTupleForm
)
GETSTRUCT
(
t
);
return
(
typ
->
typname
).
data
;
}
/* given type (as type struct), return wether type is passed by value */
int
tbyvalue
(
Type
t
)
{
TypeTupleForm
typ
;
typ
=
(
TypeTupleForm
)
GETSTRUCT
(
t
);
return
(
typ
->
typbyval
);
}
/* given a type, return its typetype ('c' for 'c'atalog types) */
static
char
typetypetype
(
Type
t
)
{
TypeTupleForm
typ
;
typ
=
(
TypeTupleForm
)
GETSTRUCT
(
t
);
return
(
typ
->
typtype
);
}
/* given operator, return the operator OID */
Oid
oprid
(
Operator
op
)
{
return
(
op
->
t_oid
);
}
/*
* given opname, leftTypeId and rightTypeId,
* find all possible (arg1, arg2) pairs for which an operator named
* opname exists, such that leftTypeId can be coerced to arg1 and
* rightTypeId can be coerced to arg2
*/
static
int
binary_oper_get_candidates
(
char
*
opname
,
Oid
leftTypeId
,
Oid
rightTypeId
,
CandidateList
*
candidates
)
{
CandidateList
current_candidate
;
Relation
pg_operator_desc
;
HeapScanDesc
pg_operator_scan
;
HeapTuple
tup
;
OperatorTupleForm
oper
;
Buffer
buffer
;
int
nkeys
;
int
ncandidates
=
0
;
ScanKeyData
opKey
[
3
];
*
candidates
=
NULL
;
ScanKeyEntryInitialize
(
&
opKey
[
0
],
0
,
/*
Anum_pg_operator_oprname
,
* first arg is a relation. This could be a projection.
NameEqualRegProcedure
,
*/
NameGetDatum
(
opname
))
;
refname
=
ident
->
name
;
ScanKeyEntryInitialize
(
&
opKey
[
1
],
0
,
rte
=
refnameRangeTableEntry
(
pstate
->
p_rtable
,
refname
);
Anum_pg_operator_oprkind
,
if
(
rte
==
NULL
)
CharacterEqualRegProcedure
,
rte
=
addRangeTableEntry
(
pstate
,
refname
,
refname
,
FALSE
,
FALSE
);
CharGetDatum
(
'b'
));
relname
=
rte
->
relname
;
relid
=
rte
->
relid
;
if
(
leftTypeId
==
UNKNOWNOID
)
/*
{
* If the attr isn't a set, just make a var for it. If it is
if
(
rightTypeId
==
UNKNOWNOID
)
* a set, treat it like a function and drop through.
{
*/
nkeys
=
2
;
if
(
get_attnum
(
relid
,
funcname
)
!=
InvalidAttrNumber
)
}
{
else
Oid
dummyTypeId
;
{
nkeys
=
3
;
ScanKeyEntryInitialize
(
&
opKey
[
2
],
0
,
return
Anum_pg_operator_oprright
,
((
Node
*
)
make_var
(
pstate
,
ObjectIdEqualRegProcedure
,
refname
,
ObjectIdGetDatum
(
rightTypeId
));
funcname
,
&
dummyTypeId
));
}
else
{
/* drop through - attr is a set */
;
}
}
}
}
else
if
(
ISCOMPLEX
(
exprType
(
first_arg
)))
else
if
(
rightTypeId
==
UNKNOWNOID
)
{
nkeys
=
3
;
ScanKeyEntryInitialize
(
&
opKey
[
2
],
0
,
Anum_pg_operator_oprleft
,
ObjectIdEqualRegProcedure
,
ObjectIdGetDatum
(
leftTypeId
));
}
else
{
/* currently only "unknown" can be coerced */
return
0
;
}
pg_operator_desc
=
heap_openr
(
OperatorRelationName
);
pg_operator_scan
=
heap_beginscan
(
pg_operator_desc
,
0
,
true
,
nkeys
,
opKey
);
do
{
tup
=
heap_getnext
(
pg_operator_scan
,
0
,
&
buffer
);
if
(
HeapTupleIsValid
(
tup
))
{
{
current_candidate
=
(
CandidateList
)
palloc
(
sizeof
(
struct
_CandidateList
));
current_candidate
->
args
=
(
Oid
*
)
palloc
(
2
*
sizeof
(
Oid
));
oper
=
(
OperatorTupleForm
)
GETSTRUCT
(
tup
);
current_candidate
->
args
[
0
]
=
oper
->
oprleft
;
current_candidate
->
args
[
1
]
=
oper
->
oprright
;
current_candidate
->
next
=
*
candidates
;
*
candidates
=
current_candidate
;
ncandidates
++
;
ReleaseBuffer
(
buffer
);
}
}
while
(
HeapTupleIsValid
(
tup
));
heap_endscan
(
pg_operator_scan
);
heap_close
(
pg_operator_desc
);
return
ncandidates
;
/*
}
* Attempt to handle projection of a complex argument. If
* ParseComplexProjection can't handle the projection, we have
/*
* to keep going.
* equivalentOpersAfterPromotion -
*/
* checks if a list of candidate operators obtained from
retval
=
ParseComplexProjection
(
pstate
,
* binary_oper_get_candidates() contain equivalent operators. If
funcname
,
* this routine is called, we have more than 1 candidate and need to
first_arg
,
* decided whether to pick one of them. This routine returns true if
&
attisset
);
* the all the candidates operate on the same data types after
if
(
attisset
)
* promotion (int2, int4, float4 -> float8).
{
*/
toid
=
exprType
(
first_arg
);
static
bool
rd
=
heap_openr
(
typeidTypeName
(
toid
));
equivalentOpersAfterPromotion
(
CandidateList
candidates
)
if
(
RelationIsValid
(
rd
))
{
{
CandidateList
result
;
relname
=
RelationGetRelationName
(
rd
)
->
data
;
CandidateList
promotedCandidates
=
NULL
;
heap_close
(
rd
);
Oid
leftarg
,
}
rightarg
;
else
elog
(
WARN
,
for
(
result
=
candidates
;
result
!=
NULL
;
result
=
result
->
next
)
"Type '%s' is not a relation type"
,
{
typeidTypeName
(
toid
));
CandidateList
c
;
argrelid
=
typeidTypeRelid
(
toid
);
/*
* A projection contains either an attribute name or the
* "*".
*/
if
((
get_attnum
(
argrelid
,
funcname
)
==
InvalidAttrNumber
)
&&
strcmp
(
funcname
,
"*"
))
{
elog
(
WARN
,
"Functions on sets are not yet supported"
);
}
}
c
=
(
CandidateList
)
palloc
(
sizeof
(
*
c
));
if
(
retval
)
c
->
args
=
(
Oid
*
)
palloc
(
2
*
sizeof
(
Oid
));
return
retval
;
switch
(
result
->
args
[
0
])
{
case
FLOAT4OID
:
case
INT4OID
:
case
INT2OID
:
case
CASHOID
:
c
->
args
[
0
]
=
FLOAT8OID
;
break
;
default:
c
->
args
[
0
]
=
result
->
args
[
0
];
break
;
}
}
switch
(
result
->
args
[
1
])
else
{
{
case
FLOAT4OID
:
case
INT4OID
:
case
INT2OID
:
case
CASHOID
:
c
->
args
[
1
]
=
FLOAT8OID
;
break
;
default:
c
->
args
[
1
]
=
result
->
args
[
1
];
break
;
}
c
->
next
=
promotedCandidates
;
promotedCandidates
=
c
;
}
/*
* if we get called, we have more than 1 candidates so we can do the
* following safely
*/
leftarg
=
promotedCandidates
->
args
[
0
];
rightarg
=
promotedCandidates
->
args
[
1
];
for
(
result
=
promotedCandidates
->
next
;
result
!=
NULL
;
result
=
result
->
next
)
{
if
(
result
->
args
[
0
]
!=
leftarg
||
result
->
args
[
1
]
!=
rightarg
)
/*
/*
* this list contains operators that operate on different data
* Parsing aggregates.
* types even after promotion. Hence we can't decide on which
* one to pick. The user must do explicit type casting.
*/
*/
return
FALSE
;
Oid
basetype
;
}
/*
* all the candidates are equivalent in the following sense: they
* operate on equivalent data types and picking any one of them is as
* good.
*/
return
TRUE
;
}
/*
/*
* given a choice of argument type pairs for a binary operator,
* the aggregate count is a special case, ignore its base
* try to choose a default pair
* type. Treat it as zero
*/
*/
static
CandidateList
if
(
strcmp
(
funcname
,
"count"
)
==
0
)
binary_oper_select_candidate
(
Oid
arg1
,
basetype
=
0
;
Oid
arg2
,
else
CandidateList
candidates
)
basetype
=
exprType
(
lfirst
(
fargs
));
{
if
(
SearchSysCacheTuple
(
AGGNAME
,
CandidateList
result
;
PointerGetDatum
(
funcname
),
ObjectIdGetDatum
(
basetype
),
0
,
0
))
{
Aggreg
*
aggreg
=
ParseAgg
(
funcname
,
basetype
,
lfirst
(
fargs
));
/*
AddAggToParseState
(
pstate
,
aggreg
);
* if both are "unknown", there is no way to select a candidate
return
(
Node
*
)
aggreg
;
*
}
* current wisdom holds that the default operator should be one in which
}
* both operands have the same type (there will only be one such
}
* operator)
*
* 7.27.93 - I have decided not to do this; it's too hard to justify, and
* it's easy enough to typecast explicitly -avi [the rest of this
* routine were commented out since then -ay]
*/
if
(
arg1
==
UNKNOWNOID
&&
arg2
==
UNKNOWNOID
)
return
(
NULL
);
/*
/*
* 6/23/95 - I don't complete agree with avi. In particular, casting
* * If we dropped through to here it's really a function (or a set,
* floats is a pain for users. Whatever the rationale behind not doing
* which * is implemented as a function.) * extract arg type info and
* this is, I need the following special case to work.
* transform relation name arguments into * varnodes of the
*
* appropriate form.
* In the WHERE clause of a query, if a float is specified without
* quotes, we treat it as float8. I added the float48* operators so
* that we can operate on float4 and float8. But now we have more than
* one matching operator if the right arg is unknown (eg. float
* specified with quotes). This break some stuff in the regression
* test where there are floats in quotes not properly casted. Below is
* the solution. In addition to requiring the operator operates on the
* same type for both operands [as in the code Avi originally
* commented out], we also require that the operators be equivalent in
* some sense. (see equivalentOpersAfterPromotion for details.) - ay
* 6/95
*/
*/
if
(
!
equivalentOpersAfterPromotion
(
candidates
))
MemSet
(
&
oid_array
[
0
],
0
,
8
*
sizeof
(
Oid
));
return
NULL
;
/*
nargs
=
0
;
* if we get here, any one will do but we're more picky and require
foreach
(
i
,
fargs
)
* both operands be the same.
*/
for
(
result
=
candidates
;
result
!=
NULL
;
result
=
result
->
next
)
{
{
if
(
result
->
args
[
0
]
==
result
->
args
[
1
])
int
vnum
;
return
result
;
RangeTblEntry
*
rte
;
}
Node
*
pair
=
lfirst
(
i
);
return
(
NULL
);
}
/* Given operator, types of arg1, and arg2, return oper struct */
if
(
nodeTag
(
pair
)
==
T_Ident
&&
((
Ident
*
)
pair
)
->
isRel
)
/* arg1, arg2 --typeids */
Operator
oper
(
char
*
op
,
Oid
arg1
,
Oid
arg2
,
bool
noWarnings
)
{
HeapTuple
tup
;
CandidateList
candidates
;
int
ncandidates
;
if
(
!
arg2
)
arg2
=
arg1
;
if
(
!
arg1
)
arg1
=
arg2
;
if
(
!
(
tup
=
SearchSysCacheTuple
(
OPRNAME
,
PointerGetDatum
(
op
),
ObjectIdGetDatum
(
arg1
),
ObjectIdGetDatum
(
arg2
),
Int8GetDatum
(
'b'
))))
{
ncandidates
=
binary_oper_get_candidates
(
op
,
arg1
,
arg2
,
&
candidates
);
if
(
ncandidates
==
0
)
{
{
/*
/*
*
no operators of the desired types found
*
a relation
*/
*/
if
(
!
noWarnings
)
refname
=
((
Ident
*
)
pair
)
->
name
;
op_error
(
op
,
arg1
,
arg2
);
return
(
NULL
);
rte
=
refnameRangeTableEntry
(
pstate
->
p_rtable
,
refname
);
}
if
(
rte
==
NULL
)
else
if
(
ncandidates
==
1
)
rte
=
addRangeTableEntry
(
pstate
,
refname
,
refname
,
{
FALSE
,
FALSE
);
relname
=
rte
->
relname
;
vnum
=
refnameRangeTablePosn
(
pstate
->
p_rtable
,
rte
->
refname
);
/*
/*
* exactly one operator of the desired types found
* for func(relname), the param to the function is the tuple
* under consideration. we build a special VarNode to reflect
* this -- it has varno set to the correct range table entry,
* but has varattno == 0 to signal that the whole tuple is the
* argument.
*/
*/
tup
=
SearchSysCacheTuple
(
OPRNAME
,
toid
=
typeTypeId
(
typenameType
(
relname
));
PointerGetDatum
(
op
),
/* replace it in the arg list */
ObjectIdGetDatum
(
candidates
->
args
[
0
]),
lfirst
(
fargs
)
=
ObjectIdGetDatum
(
candidates
->
args
[
1
]),
makeVar
(
vnum
,
0
,
toid
,
vnum
,
0
);
Int8GetDatum
(
'b'
));
Assert
(
HeapTupleIsValid
(
tup
));
}
}
else
else
if
(
!
attisset
)
{
{
/* set functions don't have parameters */
/*
/*
* multiple operators of the desired types found
* any functiona args which are typed "unknown", but aren't
* constants, we don't know what to do with, because we can't
* cast them - jolly
*/
*/
candidates
=
binary_oper_select_candidate
(
arg1
,
arg2
,
candidates
);
if
(
exprType
(
pair
)
==
UNKNOWNOID
&&
if
(
candidates
!=
NULL
)
!
IsA
(
pair
,
Const
)
)
{
{
/* we chose one of them */
elog
(
WARN
,
"ParseFunc: no function named '%s' that takes in an unknown type as argument #%d"
,
funcname
,
nargs
);
tup
=
SearchSysCacheTuple
(
OPRNAME
,
PointerGetDatum
(
op
),
ObjectIdGetDatum
(
candidates
->
args
[
0
]),
ObjectIdGetDatum
(
candidates
->
args
[
1
]),
Int8GetDatum
(
'b'
));
Assert
(
HeapTupleIsValid
(
tup
));
}
}
else
else
{
toid
=
exprType
(
pair
);
Type
tp1
,
tp2
;
/* we chose none of them */
tp1
=
get_id_type
(
arg1
);
tp2
=
get_id_type
(
arg2
);
if
(
!
noWarnings
)
{
elog
(
NOTICE
,
"there is more than one operator %s for types"
,
op
);
elog
(
NOTICE
,
"%s and %s. You will have to retype this query"
,
tname
(
tp1
),
tname
(
tp2
));
elog
(
WARN
,
"using an explicit cast"
);
}
return
(
NULL
);
}
}
}
}
return
((
Operator
)
tup
);
}
/*
* given opname and typeId, find all possible types for which
* a right/left unary operator named opname exists,
* such that typeId can be coerced to it
*/
static
int
unary_oper_get_candidates
(
char
*
op
,
Oid
typeId
,
CandidateList
*
candidates
,
char
rightleft
)
{
CandidateList
current_candidate
;
Relation
pg_operator_desc
;
HeapScanDesc
pg_operator_scan
;
HeapTuple
tup
;
OperatorTupleForm
oper
;
Buffer
buffer
;
int
ncandidates
=
0
;
static
ScanKeyData
opKey
[
2
]
=
{
{
0
,
Anum_pg_operator_oprname
,
NameEqualRegProcedure
},
{
0
,
Anum_pg_operator_oprkind
,
CharacterEqualRegProcedure
}};
*
candidates
=
NULL
;
fmgr_info
(
NameEqualRegProcedure
,
(
func_ptr
*
)
&
opKey
[
0
].
sk_func
,
oid_array
[
nargs
++
]
=
toid
;
&
opKey
[
0
].
sk_nargs
);
}
opKey
[
0
].
sk_argument
=
NameGetDatum
(
op
);
fmgr_info
(
CharacterEqualRegProcedure
,
(
func_ptr
*
)
&
opKey
[
1
].
sk_func
,
&
opKey
[
1
].
sk_nargs
);
opKey
[
1
].
sk_argument
=
CharGetDatum
(
rightleft
);
/* currently, only "unknown" can be coerced */
/*
/*
* but we should allow types that are internally the same to be
* func_get_detail looks up the function in the catalogs, does
* "coerced"
* disambiguation for polymorphic functions, handles inheritance, and
* returns the funcid and type and set or singleton status of the
* function's return value. it also returns the true argument types
* to the function. if func_get_detail returns true, the function
* exists. otherwise, there was an error.
*/
*/
if
(
typeId
!=
UNKNOWNOID
)
if
(
attisset
)
{
{
/* we know all of these fields already */
return
0
;
/*
* We create a funcnode with a placeholder function SetEval.
* SetEval() never actually gets executed. When the function
* evaluation routines see it, they use the funcid projected out
* from the relation as the actual function to call. Example:
* retrieve (emp.mgr.name) The plan for this will scan the emp
* relation, projecting out the mgr attribute, which is a funcid.
* This function is then called (instead of SetEval) and "name" is
* projected from its result.
*/
funcid
=
SetEvalRegProcedure
;
rettype
=
toid
;
retset
=
true
;
true_oid_array
=
oid_array
;
exists
=
true
;
}
}
else
pg_operator_desc
=
heap_openr
(
OperatorRelationName
);
pg_operator_scan
=
heap_beginscan
(
pg_operator_desc
,
0
,
true
,
2
,
opKey
);
do
{
{
tup
=
heap_getnext
(
pg_operator_scan
,
0
,
&
buffer
);
exists
=
func_get_detail
(
funcname
,
nargs
,
oid_array
,
&
funcid
,
if
(
HeapTupleIsValid
(
tup
))
&
rettype
,
&
retset
,
&
true_oid_array
);
{
}
current_candidate
=
(
CandidateList
)
palloc
(
sizeof
(
struct
_CandidateList
));
current_candidate
->
args
=
(
Oid
*
)
palloc
(
sizeof
(
Oid
));
oper
=
(
OperatorTupleForm
)
GETSTRUCT
(
tup
);
if
(
rightleft
==
'r'
)
current_candidate
->
args
[
0
]
=
oper
->
oprleft
;
else
current_candidate
->
args
[
0
]
=
oper
->
oprright
;
current_candidate
->
next
=
*
candidates
;
*
candidates
=
current_candidate
;
ncandidates
++
;
ReleaseBuffer
(
buffer
);
}
}
while
(
HeapTupleIsValid
(
tup
));
heap_endscan
(
pg_operator_scan
);
if
(
!
exists
)
heap_close
(
pg_operator_desc
);
elog
(
WARN
,
"no such attribute or function '%s'"
,
funcname
);
return
ncandidates
;
/* got it */
}
funcnode
=
makeNode
(
Func
);
funcnode
->
funcid
=
funcid
;
funcnode
->
functype
=
rettype
;
funcnode
->
funcisindex
=
false
;
funcnode
->
funcsize
=
0
;
funcnode
->
func_fcache
=
NULL
;
funcnode
->
func_tlist
=
NIL
;
funcnode
->
func_planlist
=
NIL
;
/* Given unary right-side operator (operator on right), return oper struct */
/* perform the necessary typecasting */
/* arg-- type id */
make_arguments
(
nargs
,
fargs
,
oid_array
,
true_oid_array
);
Operator
right_oper
(
char
*
op
,
Oid
arg
)
{
HeapTuple
tup
;
CandidateList
candidates
;
int
ncandidates
;
/*
/*
* if (!OpCache) { init_op_cache(); }
* for functions returning base types, we want to project out the
* return value. set up a target list to do that. the executor will
* ignore these for c functions, and do the right thing for postquel
* functions.
*/
*/
if
(
!
(
tup
=
SearchSysCacheTuple
(
OPRNAME
,
PointerGetDatum
(
op
),
ObjectIdGetDatum
(
arg
),
ObjectIdGetDatum
(
InvalidOid
),
Int8GetDatum
(
'r'
))))
{
ncandidates
=
unary_oper_get_candidates
(
op
,
arg
,
&
candidates
,
'r'
);
if
(
ncandidates
==
0
)
{
elog
(
WARN
,
"Can't find right op: %s for type %d"
,
op
,
arg
);
return
(
NULL
);
}
else
if
(
ncandidates
==
1
)
{
tup
=
SearchSysCacheTuple
(
OPRNAME
,
PointerGetDatum
(
op
),
ObjectIdGetDatum
(
candidates
->
args
[
0
]),
ObjectIdGetDatum
(
InvalidOid
),
Int8GetDatum
(
'r'
));
Assert
(
HeapTupleIsValid
(
tup
));
}
else
{
elog
(
NOTICE
,
"there is more than one right operator %s"
,
op
);
elog
(
NOTICE
,
"you will have to retype this query"
);
elog
(
WARN
,
"using an explicit cast"
);
return
(
NULL
);
}
}
return
((
Operator
)
tup
);
}
/* Given unary left-side operator (operator on left), return oper struct */
if
(
typeidTypeRelid
(
rettype
)
==
InvalidOid
)
/* arg--type id */
funcnode
->
func_tlist
=
setup_base_tlist
(
rettype
);
Operator
left_oper
(
char
*
op
,
Oid
arg
)
{
HeapTuple
tup
;
CandidateList
candidates
;
int
ncandidates
;
/*
/*
* if (!OpCache) { init_op_cache(); }
* For sets, we want to make a targetlist to project out this
* attribute of the set tuples.
*/
*/
if
(
!
(
tup
=
SearchSysCacheTuple
(
OPRNAME
,
if
(
attisset
)
PointerGetDatum
(
op
),
ObjectIdGetDatum
(
InvalidOid
),
ObjectIdGetDatum
(
arg
),
Int8GetDatum
(
'l'
))))
{
{
ncandidates
=
unary_oper_get_candidates
(
op
,
arg
,
&
candidates
,
'l'
);
if
(
!
strcmp
(
funcname
,
"*"
))
if
(
ncandidates
==
0
)
{
{
elog
(
WARN
,
funcnode
->
func_tlist
=
"Can't find left op: %s for type %d"
,
op
,
arg
);
expandAll
(
pstate
,
relname
,
refname
,
curr_resno
);
return
(
NULL
);
}
else
if
(
ncandidates
==
1
)
{
tup
=
SearchSysCacheTuple
(
OPRNAME
,
PointerGetDatum
(
op
),
ObjectIdGetDatum
(
InvalidOid
),
ObjectIdGetDatum
(
candidates
->
args
[
0
]),
Int8GetDatum
(
'l'
));
Assert
(
HeapTupleIsValid
(
tup
));
}
}
else
else
{
{
elog
(
NOTICE
,
"there is more than one left operator %s"
,
op
);
funcnode
->
func_tlist
=
setup_tlist
(
funcname
,
argrelid
);
elog
(
NOTICE
,
"you will have to retype this query"
);
rettype
=
attnameTypeId
(
argrelid
,
funcname
);
elog
(
WARN
,
"using an explicit cast"
);
return
(
NULL
);
}
}
return
((
Operator
)
tup
);
}
/* given range variable, return id of variable */
int
varattno
(
Relation
rd
,
char
*
a
)
{
int
i
;
for
(
i
=
0
;
i
<
rd
->
rd_rel
->
relnatts
;
i
++
)
{
if
(
!
namestrcmp
(
&
(
rd
->
rd_att
->
attrs
[
i
]
->
attname
),
a
))
{
return
(
i
+
1
);
}
}
for
(
i
=
0
;
i
<
SPECIALS
;
i
++
)
{
if
(
!
strcmp
(
special_attr
[
i
].
field
,
a
))
{
return
(
special_attr
[
i
].
code
);
}
}
}
}
elog
(
WARN
,
"Relation %s does not have attribute %s"
,
/*
RelationGetRelationName
(
rd
),
a
);
* Sequence handling.
return
(
-
1
);
*/
}
if
(
funcid
==
SeqNextValueRegProcedure
||
funcid
==
SeqCurrValueRegProcedure
)
/* Given range variable, return whether attribute of this name
* is a set.
* NOTE the ASSUMPTION here that no system attributes are, or ever
* will be, sets.
*/
bool
varisset
(
Relation
rd
,
char
*
name
)
{
int
i
;
/* First check if this is a system attribute */
for
(
i
=
0
;
i
<
SPECIALS
;
i
++
)
{
if
(
!
strcmp
(
special_attr
[
i
].
field
,
name
))
{
return
(
false
);
/* no sys attr is a set */
}
}
return
(
get_attisset
(
rd
->
rd_id
,
name
));
}
/* given range variable, return id of variable */
int
nf_varattno
(
Relation
rd
,
char
*
a
)
{
int
i
;
for
(
i
=
0
;
i
<
rd
->
rd_rel
->
relnatts
;
i
++
)
{
if
(
!
namestrcmp
(
&
(
rd
->
rd_att
->
attrs
[
i
]
->
attname
),
a
))
{
return
(
i
+
1
);
}
}
for
(
i
=
0
;
i
<
SPECIALS
;
i
++
)
{
{
if
(
!
strcmp
(
special_attr
[
i
].
field
,
a
))
Const
*
seq
;
{
char
*
seqrel
;
return
(
special_attr
[
i
].
code
);
text
*
seqname
;
}
int32
aclcheck_result
=
-
1
;
extern
text
*
lower
(
text
*
string
);
Assert
(
length
(
fargs
)
==
1
);
seq
=
(
Const
*
)
lfirst
(
fargs
);
if
(
!
IsA
((
Node
*
)
seq
,
Const
))
elog
(
WARN
,
"%s: only constant sequence names are acceptable"
,
funcname
);
seqname
=
lower
((
text
*
)
DatumGetPointer
(
seq
->
constvalue
));
pfree
(
DatumGetPointer
(
seq
->
constvalue
));
seq
->
constvalue
=
PointerGetDatum
(
seqname
);
seqrel
=
textout
(
seqname
);
if
((
aclcheck_result
=
pg_aclcheck
(
seqrel
,
GetPgUserName
(),
((
funcid
==
SeqNextValueRegProcedure
)
?
ACL_WR
:
ACL_RD
)))
!=
ACLCHECK_OK
)
elog
(
WARN
,
"%s.%s: %s"
,
seqrel
,
funcname
,
aclcheck_error_strings
[
aclcheck_result
]);
pfree
(
seqrel
);
if
(
funcid
==
SeqNextValueRegProcedure
&&
pstate
->
p_in_where_clause
)
elog
(
WARN
,
"nextval of a sequence in WHERE disallowed"
);
}
}
return
InvalidAttrNumber
;
}
/*-------------
expr
=
makeNode
(
Expr
);
* given an attribute number and a relation, return its relation name
expr
->
typeOid
=
rettype
;
*/
expr
->
opType
=
FUNC_EXPR
;
char
*
expr
->
oper
=
(
Node
*
)
funcnode
;
getAttrName
(
Relation
rd
,
int
attrno
)
expr
->
args
=
fargs
;
{
retval
=
(
Node
*
)
expr
;
char
*
name
;
int
i
;
if
(
attrno
<
0
)
{
for
(
i
=
0
;
i
<
SPECIALS
;
i
++
)
{
if
(
special_attr
[
i
].
code
==
attrno
)
{
name
=
special_attr
[
i
].
field
;
return
(
name
);
}
}
elog
(
WARN
,
"Illegal attr no %d for relation %s"
,
attrno
,
RelationGetRelationName
(
rd
));
}
else
if
(
attrno
>=
1
&&
attrno
<=
RelationGetNumberOfAttributes
(
rd
))
{
name
=
(
rd
->
rd_att
->
attrs
[
attrno
-
1
]
->
attname
).
data
;
return
(
name
);
}
else
{
elog
(
WARN
,
"Illegal attr no %d for relation %s"
,
attrno
,
RelationGetRelationName
(
rd
));
}
/*
/*
* Shouldn't get here, but we want lint to be happy...
* if the function returns a set of values, then we need to iterate
* over all the returned values in the executor, so we stick an iter
* node here. if it returns a singleton, then we don't need the iter
* node.
*/
*/
return
(
NULL
);
if
(
retset
)
}
/* Given a typename and value, returns the ascii form of the value */
#ifdef NOT_USED
char
*
outstr
(
char
*
typename
,
/* Name of type of value */
char
*
value
)
/* Could be of any type */
{
TypeTupleForm
tp
;
Oid
op
;
tp
=
(
TypeTupleForm
)
GETSTRUCT
(
type
(
typename
));
op
=
tp
->
typoutput
;
return
((
char
*
)
fmgr
(
op
,
value
));
}
#endif
/* Given a Type and a string, return the internal form of that string */
char
*
instr2
(
Type
tp
,
char
*
string
,
int
typlen
)
{
return
(
instr1
((
TypeTupleForm
)
GETSTRUCT
(
tp
),
string
,
typlen
));
}
/* Given a type structure and a string, returns the internal form of
that string */
static
char
*
instr1
(
TypeTupleForm
tp
,
char
*
string
,
int
typlen
)
{
Oid
op
;
Oid
typelem
;
op
=
tp
->
typinput
;
typelem
=
tp
->
typelem
;
/* XXX - used for array_in */
/* typlen is for bpcharin() and varcharin() */
return
((
char
*
)
fmgr
(
op
,
string
,
typelem
,
typlen
));
}
/* Given the attribute type of an array return the arrtribute type of
an element of the array */
Oid
GetArrayElementType
(
Oid
typearray
)
{
HeapTuple
type_tuple
;
TypeTupleForm
type_struct_array
;
type_tuple
=
SearchSysCacheTuple
(
TYPOID
,
ObjectIdGetDatum
(
typearray
),
0
,
0
,
0
);
if
(
!
HeapTupleIsValid
(
type_tuple
))
elog
(
WARN
,
"GetArrayElementType: Cache lookup failed for type %d"
,
typearray
);
/* get the array type struct from the type tuple */
type_struct_array
=
(
TypeTupleForm
)
GETSTRUCT
(
type_tuple
);
if
(
type_struct_array
->
typelem
==
InvalidOid
)
{
{
elog
(
WARN
,
"GetArrayElementType: type %s is not an array"
,
Iter
*
iter
=
makeNode
(
Iter
);
(
Name
)
&
(
type_struct_array
->
typname
.
data
[
0
]));
iter
->
itertype
=
rettype
;
iter
->
iterexpr
=
retval
;
retval
=
(
Node
*
)
iter
;
}
}
return
(
type_struct_array
->
typelem
);
return
(
retval
);
}
}
Oid
Oid
...
@@ -962,7 +443,7 @@ funcid_get_rettype(Oid funcid)
...
@@ -962,7 +443,7 @@ funcid_get_rettype(Oid funcid)
* get a list of all argument type vectors for which a function named
* get a list of all argument type vectors for which a function named
* funcname taking nargs arguments exists
* funcname taking nargs arguments exists
*/
*/
static
CandidateList
CandidateList
func_get_candidates
(
char
*
funcname
,
int
nargs
)
func_get_candidates
(
char
*
funcname
,
int
nargs
)
{
{
Relation
heapRelation
;
Relation
heapRelation
;
...
@@ -1040,7 +521,7 @@ func_get_candidates(char *funcname, int nargs)
...
@@ -1040,7 +521,7 @@ func_get_candidates(char *funcname, int nargs)
/*
/*
* can input_typeids be coerced to func_typeids?
* can input_typeids be coerced to func_typeids?
*/
*/
static
bool
bool
can_coerce
(
int
nargs
,
Oid
*
input_typeids
,
Oid
*
func_typeids
)
can_coerce
(
int
nargs
,
Oid
*
input_typeids
,
Oid
*
func_typeids
)
{
{
int
i
;
int
i
;
...
@@ -1064,8 +545,8 @@ can_coerce(int nargs, Oid *input_typeids, Oid *func_typeids)
...
@@ -1064,8 +545,8 @@ can_coerce(int nargs, Oid *input_typeids, Oid *func_typeids)
else
if
(
input_typeids
[
i
]
!=
UNKNOWNOID
||
func_typeids
[
i
]
==
0
)
else
if
(
input_typeids
[
i
]
!=
UNKNOWNOID
||
func_typeids
[
i
]
==
0
)
return
false
;
return
false
;
tp
=
get_id_t
ype
(
input_typeids
[
i
]);
tp
=
typeidT
ype
(
input_typeids
[
i
]);
if
(
type
typetype
(
tp
)
==
'c'
)
if
(
type
TypeFlag
(
tp
)
==
'c'
)
return
false
;
return
false
;
}
}
}
}
...
@@ -1079,7 +560,7 @@ can_coerce(int nargs, Oid *input_typeids, Oid *func_typeids)
...
@@ -1079,7 +560,7 @@ can_coerce(int nargs, Oid *input_typeids, Oid *func_typeids)
* that match the input typeids (either exactly or by coercion), and
* that match the input typeids (either exactly or by coercion), and
* return the number of such arrays
* return the number of such arrays
*/
*/
static
int
int
match_argtypes
(
int
nargs
,
match_argtypes
(
int
nargs
,
Oid
*
input_typeids
,
Oid
*
input_typeids
,
CandidateList
function_typeids
,
CandidateList
function_typeids
,
...
@@ -1117,7 +598,7 @@ match_argtypes(int nargs,
...
@@ -1117,7 +598,7 @@ match_argtypes(int nargs,
* returns the selected argtype array if the conflict can be resolved,
* returns the selected argtype array if the conflict can be resolved,
* otherwise returns NULL
* otherwise returns NULL
*/
*/
static
Oid
*
Oid
*
func_select_candidate
(
int
nargs
,
func_select_candidate
(
int
nargs
,
Oid
*
input_typeids
,
Oid
*
input_typeids
,
CandidateList
candidates
)
CandidateList
candidates
)
...
@@ -1228,8 +709,8 @@ func_get_detail(char *funcname,
...
@@ -1228,8 +709,8 @@ func_get_detail(char *funcname,
if
(
nargs
==
1
)
if
(
nargs
==
1
)
{
{
tp
=
get_id_t
ype
(
oid_array
[
0
]);
tp
=
typeidT
ype
(
oid_array
[
0
]);
if
(
type
typetype
(
tp
)
==
'c'
)
if
(
type
TypeFlag
(
tp
)
==
'c'
)
elog
(
WARN
,
"no such attribute or function
\"
%s
\"
"
,
elog
(
WARN
,
"no such attribute or function
\"
%s
\"
"
,
funcname
);
funcname
);
}
}
...
@@ -1271,7 +752,7 @@ func_get_detail(char *funcname,
...
@@ -1271,7 +752,7 @@ func_get_detail(char *funcname,
* not defined. There are lots of these (mostly builtins) in the
* not defined. There are lots of these (mostly builtins) in the
* catalogs.
* catalogs.
*/
*/
static
Oid
**
Oid
**
argtype_inherit
(
int
nargs
,
Oid
*
oid_array
)
argtype_inherit
(
int
nargs
,
Oid
*
oid_array
)
{
{
Oid
relid
;
Oid
relid
;
...
@@ -1283,7 +764,7 @@ argtype_inherit(int nargs, Oid *oid_array)
...
@@ -1283,7 +764,7 @@ argtype_inherit(int nargs, Oid *oid_array)
if
(
i
<
nargs
)
if
(
i
<
nargs
)
{
{
arginh
[
i
].
self
=
oid_array
[
i
];
arginh
[
i
].
self
=
oid_array
[
i
];
if
((
relid
=
typeid
_get_r
elid
(
oid_array
[
i
]))
!=
InvalidOid
)
if
((
relid
=
typeid
TypeR
elid
(
oid_array
[
i
]))
!=
InvalidOid
)
{
{
arginh
[
i
].
nsupers
=
findsupers
(
relid
,
&
(
arginh
[
i
].
supervec
));
arginh
[
i
].
nsupers
=
findsupers
(
relid
,
&
(
arginh
[
i
].
supervec
));
}
}
...
@@ -1305,13 +786,7 @@ argtype_inherit(int nargs, Oid *oid_array)
...
@@ -1305,13 +786,7 @@ argtype_inherit(int nargs, Oid *oid_array)
return
(
genxprod
(
arginh
,
nargs
));
return
(
genxprod
(
arginh
,
nargs
));
}
}
typedef
struct
_SuperQE
int
findsupers
(
Oid
relid
,
Oid
**
supervec
)
{
Oid
sqe_relid
;
}
SuperQE
;
static
int
findsupers
(
Oid
relid
,
Oid
**
supervec
)
{
{
Oid
*
relidvec
;
Oid
*
relidvec
;
Relation
inhrel
;
Relation
inhrel
;
...
@@ -1399,7 +874,7 @@ findsupers(Oid relid, Oid **supervec)
...
@@ -1399,7 +874,7 @@ findsupers(Oid relid, Oid **supervec)
/* save the type id, rather than the relation id */
/* save the type id, rather than the relation id */
if
((
rd
=
heap_open
(
qentry
->
sqe_relid
))
==
(
Relation
)
NULL
)
if
((
rd
=
heap_open
(
qentry
->
sqe_relid
))
==
(
Relation
)
NULL
)
elog
(
WARN
,
"relid %d does not exist"
,
qentry
->
sqe_relid
);
elog
(
WARN
,
"relid %d does not exist"
,
qentry
->
sqe_relid
);
qentry
->
sqe_relid
=
type
id
(
t
ype
(
RelationGetRelationName
(
rd
)
->
data
));
qentry
->
sqe_relid
=
type
TypeId
(
typenameT
ype
(
RelationGetRelationName
(
rd
)
->
data
));
heap_close
(
rd
);
heap_close
(
rd
);
DLAddTail
(
visited
,
qe
);
DLAddTail
(
visited
,
qe
);
...
@@ -1431,7 +906,7 @@ findsupers(Oid relid, Oid **supervec)
...
@@ -1431,7 +906,7 @@ findsupers(Oid relid, Oid **supervec)
return
(
nvisited
);
return
(
nvisited
);
}
}
static
Oid
**
Oid
**
genxprod
(
InhPaths
*
arginh
,
int
nargs
)
genxprod
(
InhPaths
*
arginh
,
int
nargs
)
{
{
int
nanswers
;
int
nanswers
;
...
@@ -1486,146 +961,270 @@ genxprod(InhPaths *arginh, int nargs)
...
@@ -1486,146 +961,270 @@ genxprod(InhPaths *arginh, int nargs)
}
}
}
}
/* Given a type id, returns the in-conversion function of the type */
Oid
/*
typeid_get_retinfunc
(
Oid
type_id
)
** make_arguments --
** Given the number and types of arguments to a function, and the
** actual arguments and argument types, do the necessary typecasting.
*/
void
make_arguments
(
int
nargs
,
List
*
fargs
,
Oid
*
input_typeids
,
Oid
*
function_typeids
)
{
{
HeapTuple
typeTuple
;
TypeTupleForm
type
;
/*
Oid
infunc
;
* there are two ways an input typeid can differ from a function
* typeid : either the input type inherits the function type, so no
typeTuple
=
SearchSysCacheTuple
(
TYPOID
,
* typecasting is necessary, or the input type can be typecast into
ObjectIdGetDatum
(
type_id
),
* the function type. right now, we only typecast unknowns, and that
0
,
0
,
0
);
* is all we check for.
if
(
!
HeapTupleIsValid
(
typeTuple
))
*/
elog
(
WARN
,
"typeid_get_retinfunc: Invalid type - oid = %u"
,
type_id
);
List
*
current_fargs
;
type
=
(
TypeTupleForm
)
GETSTRUCT
(
typeTuple
);
int
i
;
infunc
=
type
->
typinput
;
return
(
infunc
);
for
(
i
=
0
,
current_fargs
=
fargs
;
i
<
nargs
;
i
++
,
current_fargs
=
lnext
(
current_fargs
))
{
if
(
input_typeids
[
i
]
==
UNKNOWNOID
&&
function_typeids
[
i
]
!=
InvalidOid
)
{
lfirst
(
current_fargs
)
=
parser_typecast2
(
lfirst
(
current_fargs
),
input_typeids
[
i
],
typeidType
(
function_typeids
[
i
]),
-
1
);
}
}
}
}
/* Given a type id, returns the out-conversion function of the type */
/*
Oid
** setup_tlist --
typeid_get_retoutfunc
(
Oid
type_id
)
** Build a tlist that says which attribute to project to.
** This routine is called by ParseFunc() to set up a target list
** on a tuple parameter or return value. Due to a bug in 4.0,
** it's not possible to refer to system attributes in this case.
*/
List
*
setup_tlist
(
char
*
attname
,
Oid
relid
)
{
{
HeapTuple
typeTuple
;
TargetEntry
*
tle
;
TypeTupleForm
type
;
Resdom
*
resnode
;
Oid
outfunc
;
Var
*
varnode
;
Oid
typeid
;
typeTuple
=
SearchSysCacheTuple
(
TYPOID
,
int
attno
;
ObjectIdGetDatum
(
type_id
),
0
,
0
,
0
);
attno
=
get_attnum
(
relid
,
attname
);
if
(
!
HeapTupleIsValid
(
typeTuple
))
if
(
attno
<
0
)
elog
(
WARN
,
"typeid_get_retoutfunc: Invalid type - oid = %u"
,
type_id
);
elog
(
WARN
,
"cannot reference attribute '%s' of tuple params/return values for functions"
,
attname
);
type
=
(
TypeTupleForm
)
GETSTRUCT
(
typeTuple
);
typeid
=
attnameTypeId
(
relid
,
attname
);
outfunc
=
type
->
typoutput
;
resnode
=
makeResdom
(
1
,
return
(
outfunc
);
typeid
,
typeLen
(
typeidType
(
typeid
)),
get_attname
(
relid
,
attno
),
0
,
(
Oid
)
0
,
0
);
varnode
=
makeVar
(
-
1
,
attno
,
typeid
,
-
1
,
attno
);
tle
=
makeNode
(
TargetEntry
);
tle
->
resdom
=
resnode
;
tle
->
expr
=
(
Node
*
)
varnode
;
return
(
lcons
(
tle
,
NIL
));
}
}
Oid
/*
typeid_get_relid
(
Oid
type_id
)
** setup_base_tlist --
** Build a tlist that extracts a base type from the tuple
** returned by the executor.
*/
List
*
setup_base_tlist
(
Oid
typeid
)
{
{
HeapTuple
typeTuple
;
TargetEntry
*
tle
;
TypeTupleForm
type
;
Resdom
*
resnode
;
Oid
infunc
;
Var
*
varnode
;
typeTuple
=
SearchSysCacheTuple
(
TYPOID
,
resnode
=
makeResdom
(
1
,
ObjectIdGetDatum
(
type_id
),
typeid
,
0
,
0
,
0
);
typeLen
(
typeidType
(
typeid
)),
if
(
!
HeapTupleIsValid
(
typeTuple
))
"<noname>"
,
elog
(
WARN
,
"typeid_get_relid: Invalid type - oid = %u"
,
type_id
);
0
,
(
Oid
)
0
,
type
=
(
TypeTupleForm
)
GETSTRUCT
(
typeTuple
);
0
);
infunc
=
type
->
typrelid
;
varnode
=
makeVar
(
-
1
,
1
,
typeid
,
-
1
,
1
);
return
(
infunc
);
tle
=
makeNode
(
TargetEntry
);
tle
->
resdom
=
resnode
;
tle
->
expr
=
(
Node
*
)
varnode
;
return
(
lcons
(
tle
,
NIL
));
}
}
Oid
/*
get_typrelid
(
Type
typ
)
* ParseComplexProjection -
* handles function calls with a single argument that is of complex type.
* This routine returns NULL if it can't handle the projection (eg. sets).
*/
Node
*
ParseComplexProjection
(
ParseState
*
pstate
,
char
*
funcname
,
Node
*
first_arg
,
bool
*
attisset
)
{
{
TypeTupleForm
typtup
;
Oid
argtype
;
Oid
argrelid
;
Name
relname
;
Relation
rd
;
Oid
relid
;
int
attnum
;
typtup
=
(
TypeTupleForm
)
GETSTRUCT
(
typ
);
switch
(
nodeTag
(
first_arg
))
{
case
T_Iter
:
{
Func
*
func
;
Iter
*
iter
;
iter
=
(
Iter
*
)
first_arg
;
func
=
(
Func
*
)
((
Expr
*
)
iter
->
iterexpr
)
->
oper
;
argtype
=
funcid_get_rettype
(
func
->
funcid
);
argrelid
=
typeidTypeRelid
(
argtype
);
if
(
argrelid
&&
((
attnum
=
get_attnum
(
argrelid
,
funcname
))
!=
InvalidAttrNumber
))
{
return
(
typtup
->
typrelid
);
/*
}
* the argument is a function returning a tuple, so
* funcname may be a projection
*/
Oid
/* add a tlist to the func node and return the Iter */
get_typelem
(
Oid
type_id
)
rd
=
heap_openr
(
typeidTypeName
(
argtype
));
{
if
(
RelationIsValid
(
rd
))
HeapTuple
typeTuple
;
{
TypeTupleForm
type
;
relid
=
RelationGetRelationId
(
rd
);
relname
=
RelationGetRelationName
(
rd
);
heap_close
(
rd
);
}
if
(
RelationIsValid
(
rd
))
{
func
->
func_tlist
=
setup_tlist
(
funcname
,
argrelid
);
iter
->
itertype
=
attnumTypeId
(
rd
,
attnum
);
return
((
Node
*
)
iter
);
}
else
{
elog
(
WARN
,
"Function '%s' has bad returntype %d"
,
funcname
,
argtype
);
}
}
else
{
/* drop through */
;
}
break
;
}
case
T_Var
:
{
if
(
!
(
typeTuple
=
SearchSysCacheTuple
(
TYPOID
,
/*
ObjectIdGetDatum
(
type_id
),
* The argument is a set, so this is either a projection
0
,
0
,
0
)))
* or a function call on this set.
{
*/
elog
(
WARN
,
"type id lookup of %u failed"
,
type_id
);
*
attisset
=
true
;
}
break
;
type
=
(
TypeTupleForm
)
GETSTRUCT
(
typeTuple
);
}
case
T_Expr
:
{
Expr
*
expr
=
(
Expr
*
)
first_arg
;
Func
*
funcnode
;
return
(
type
->
typelem
);
if
(
expr
->
opType
!=
FUNC_EXPR
)
}
break
;
#ifdef NOT_USED
funcnode
=
(
Func
*
)
expr
->
oper
;
char
argtype
=
funcid_get_rettype
(
funcnode
->
funcid
);
FindDelimiter
(
char
*
typename
)
argrelid
=
typeidTypeRelid
(
argtype
);
{
char
delim
;
/*
HeapTuple
typeTuple
;
* the argument is a function returning a tuple, so
TypeTupleForm
type
;
* funcname may be a projection
*/
if
(
argrelid
&&
(
attnum
=
get_attnum
(
argrelid
,
funcname
))
!=
InvalidAttrNumber
)
{
/* add a tlist to the func node */
rd
=
heap_openr
(
typeidTypeName
(
argtype
));
if
(
RelationIsValid
(
rd
))
{
relid
=
RelationGetRelationId
(
rd
);
relname
=
RelationGetRelationName
(
rd
);
heap_close
(
rd
);
}
if
(
RelationIsValid
(
rd
))
{
Expr
*
newexpr
;
if
(
!
(
typeTuple
=
SearchSysCacheTuple
(
TYPNAME
,
funcnode
->
func_tlist
=
PointerGetDatum
(
typename
),
setup_tlist
(
funcname
,
argrelid
);
0
,
0
,
0
)))
funcnode
->
functype
=
attnumTypeId
(
rd
,
attnum
);
{
elog
(
WARN
,
"type name lookup of %s failed"
,
typename
);
}
type
=
(
TypeTupleForm
)
GETSTRUCT
(
typeTuple
);
delim
=
type
->
typdelim
;
newexpr
=
makeNode
(
Expr
);
return
(
delim
);
newexpr
->
typeOid
=
funcnode
->
functype
;
}
newexpr
->
opType
=
FUNC_EXPR
;
newexpr
->
oper
=
(
Node
*
)
funcnode
;
newexpr
->
args
=
lcons
(
first_arg
,
NIL
);
#endif
return
((
Node
*
)
newexpr
);
}
/*
}
* Give a somewhat useful error message when the operator for two types
* is not found.
*/
static
void
op_error
(
char
*
op
,
Oid
arg1
,
Oid
arg2
)
{
Type
tp1
=
NULL
,
tp2
=
NULL
;
if
(
check_typeid
(
arg1
))
elog
(
WARN
,
"Function '%s' has bad returntype %d"
,
{
funcname
,
argtype
);
tp1
=
get_id_type
(
arg1
);
break
;
}
}
else
case
T_Param
:
{
{
elog
(
WARN
,
"left hand side of operator %s has an unknown type, probably a bad attribute name"
,
op
);
Param
*
param
=
(
Param
*
)
first_arg
;
}
/*
* If the Param is a complex type, this could be a
* projection
*/
rd
=
heap_openr
(
typeidTypeName
(
param
->
paramtype
));
if
(
RelationIsValid
(
rd
))
{
relid
=
RelationGetRelationId
(
rd
);
relname
=
RelationGetRelationName
(
rd
);
heap_close
(
rd
);
}
if
(
RelationIsValid
(
rd
)
&&
(
attnum
=
get_attnum
(
relid
,
funcname
))
!=
InvalidAttrNumber
)
{
if
(
check_typeid
(
arg2
))
param
->
paramtype
=
attnumTypeId
(
rd
,
attnum
);
{
param
->
param_tlist
=
setup_tlist
(
funcname
,
relid
);
tp2
=
get_id_type
(
arg2
);
return
((
Node
*
)
param
);
}
}
else
break
;
{
}
elog
(
WARN
,
"right hand side of operator %s has an unknown type, probably a bad attribute name"
,
op
);
default:
break
;
}
}
elog
(
NOTICE
,
"there is no operator %s for types %s and %s"
,
return
NULL
;
op
,
tname
(
tp1
),
tname
(
tp2
));
elog
(
NOTICE
,
"You will either have to retype this query using an"
);
elog
(
NOTICE
,
"explicit cast, or you will have to define the operator"
);
elog
(
WARN
,
"%s for %s and %s using CREATE OPERATOR"
,
op
,
tname
(
tp1
),
tname
(
tp2
));
}
}
/*
/*
...
@@ -1650,7 +1249,7 @@ func_error(char *caller, char *funcname, int nargs, Oid *argtypes)
...
@@ -1650,7 +1249,7 @@ func_error(char *caller, char *funcname, int nargs, Oid *argtypes)
}
}
if
(
argtypes
[
i
]
!=
0
)
if
(
argtypes
[
i
]
!=
0
)
{
{
strcpy
(
ptr
,
t
name
(
get_id_type
(
argtypes
[
i
])
));
strcpy
(
ptr
,
t
ypeidTypeName
(
argtypes
[
i
]
));
*
(
ptr
+
NAMEDATALEN
)
=
'\0'
;
*
(
ptr
+
NAMEDATALEN
)
=
'\0'
;
}
}
else
else
...
@@ -1661,26 +1260,5 @@ func_error(char *caller, char *funcname, int nargs, Oid *argtypes)
...
@@ -1661,26 +1260,5 @@ func_error(char *caller, char *funcname, int nargs, Oid *argtypes)
elog
(
WARN
,
"%s: function %s(%s) does not exist"
,
caller
,
funcname
,
p
);
elog
(
WARN
,
"%s: function %s(%s) does not exist"
,
caller
,
funcname
,
p
);
}
}
/*
* Error message when aggregate lookup fails that gives details of the
* basetype
*/
void
agg_error
(
char
*
caller
,
char
*
aggname
,
Oid
basetypeID
)
{
/*
* basetypeID that is Invalid (zero) means aggregate over all types.
* (count)
*/
if
(
basetypeID
==
InvalidOid
)
{
elog
(
WARN
,
"%s: aggregate '%s' for all types does not exist"
,
caller
,
aggname
);
}
else
{
elog
(
WARN
,
"%s: aggregate '%s' for '%s' does not exist"
,
caller
,
aggname
,
tname
(
get_id_type
(
basetypeID
)));
}
}
src/backend/parser/parse_
query
.c
→
src/backend/parser/parse_
node
.c
View file @
4a5b781d
/*-------------------------------------------------------------------------
/*-------------------------------------------------------------------------
*
*
* parse_query.c--
* parse_node.c--
* take an "optimizable" stmt and make the query tree that
* various routines that make nodes for query plans
* the planner requires.
*
*
* Copyright (c) 1994, Regents of the University of California
* Copyright (c) 1994, Regents of the University of California
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/
Attic/parse_query.c,v 1.25 1997/11/24 05:08:27
momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/
parse_node.c,v 1.1 1997/11/25 22:05:42
momjian Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
#include <ctype.h>
#include <ctype.h>
#include <string.h>
#include <string.h>
#include "postgres.h"
#include "postgres.h"
#include "fmgr.h"
#include "fmgr.h"
#include "access/heapam.h"
#include "access/heapam.h"
#include "access/tupmacs.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_type.h"
#include "nodes/makefuncs.h"
#include "parser/parse_expr.h"
#include "parser/parse_oper.h"
#include "parser/parse_node.h"
#include "parser/parse_relation.h"
#include "parser/parse_type.h"
#include "utils/builtins.h"
#include "utils/builtins.h"
#include "utils/syscache.h"
#ifdef 0
#include "access/tupmacs.h"
#include "utils/elog.h"
#include "utils/elog.h"
#include "utils/palloc.h"
#include "utils/palloc.h"
#include "utils/acl.h"
/* for ACL_NO_PRIV_WARNING */
#include "utils/acl.h"
/* for ACL_NO_PRIV_WARNING */
#include "utils/rel.h"
/* Relation stuff */
#include "utils/rel.h"
/* Relation stuff */
#include "utils/syscache.h"
#include "utils/syscache.h"
#include "catalog/pg_type.h"
#include "catalog/pg_operator.h"
#include "parser/catalog_utils.h"
#include "parser/parse_query.h"
#include "utils/lsyscache.h"
#include "nodes/pg_list.h"
#include "nodes/pg_list.h"
#include "nodes/primnodes.h"
#include "nodes/primnodes.h"
#include "nodes/parsenodes.h"
#include "nodes/parsenodes.h"
#include "nodes/makefuncs.h"
#endif
static
void
checkTargetTypes
(
ParseState
*
pstate
,
char
*
target_colname
,
char
*
refname
,
char
*
colname
);
Oid
*
param_type_info
;
int
pfunc_num_args
;
/* given refname, return a pointer to the range table entry */
RangeTblEntry
*
refnameRangeTableEntry
(
List
*
rtable
,
char
*
refname
)
{
List
*
temp
;
foreach
(
temp
,
rtable
)
{
RangeTblEntry
*
rte
=
lfirst
(
temp
);
if
(
!
strcmp
(
rte
->
refname
,
refname
))
return
rte
;
}
return
NULL
;
}
/* given refname, return id of variable; position starts with 1 */
int
refnameRangeTablePosn
(
List
*
rtable
,
char
*
refname
)
{
int
index
;
List
*
temp
;
index
=
1
;
foreach
(
temp
,
rtable
)
{
RangeTblEntry
*
rte
=
lfirst
(
temp
);
if
(
!
strcmp
(
rte
->
refname
,
refname
))
return
index
;
index
++
;
}
return
(
0
);
}
/*
/*
* returns range entry if found, else NULL
* make_parsestate() --
* allocate and initialize a new ParseState.
* the CALLERS is responsible for freeing the ParseState* returned
*
*/
*/
RangeTblEntry
*
colnameRangeTableEntry
(
ParseState
*
pstate
,
char
*
colname
)
{
List
*
et
;
List
*
rtable
;
RangeTblEntry
*
rte_result
;
if
(
pstate
->
p_is_rule
)
rtable
=
lnext
(
lnext
(
pstate
->
p_rtable
));
else
rtable
=
pstate
->
p_rtable
;
rte_result
=
NULL
;
foreach
(
et
,
rtable
)
{
RangeTblEntry
*
rte
=
lfirst
(
et
);
/* only entries on outer(non-function?) scope */
if
(
!
rte
->
inFromCl
&&
rte
!=
pstate
->
p_target_rangetblentry
)
continue
;
if
(
get_attnum
(
rte
->
relid
,
colname
)
!=
InvalidAttrNumber
)
{
if
(
rte_result
!=
NULL
)
{
if
(
!
pstate
->
p_is_insert
||
rte
!=
pstate
->
p_target_rangetblentry
)
elog
(
WARN
,
"Column %s is ambiguous"
,
colname
);
}
else
rte_result
=
rte
;
}
}
return
rte_result
;
}
/*
ParseState
*
* put new entry in pstate p_rtable structure, or return pointer
make_parsestate
(
void
)
* if pstate null
*/
RangeTblEntry
*
addRangeTableEntry
(
ParseState
*
pstate
,
char
*
relname
,
char
*
refname
,
bool
inh
,
bool
inFromCl
)
{
Relation
relation
;
RangeTblEntry
*
rte
=
makeNode
(
RangeTblEntry
);
if
(
pstate
!=
NULL
&&
refnameRangeTableEntry
(
pstate
->
p_rtable
,
refname
)
!=
NULL
)
elog
(
WARN
,
"Table name %s specified more than once"
,
refname
);
rte
->
relname
=
pstrdup
(
relname
);
rte
->
refname
=
pstrdup
(
refname
);
relation
=
heap_openr
(
relname
);
if
(
relation
==
NULL
)
{
elog
(
WARN
,
"%s: %s"
,
relname
,
aclcheck_error_strings
[
ACLCHECK_NO_CLASS
]);
}
/*
* Flags - zero or more from inheritance,union,version or
* recursive (transitive closure) [we don't support them all -- ay
* 9/94 ]
*/
rte
->
inh
=
inh
;
/* RelOID */
rte
->
relid
=
RelationGetRelationId
(
relation
);
rte
->
inFromCl
=
inFromCl
;
/*
* close the relation we're done with it for now.
*/
if
(
pstate
!=
NULL
)
pstate
->
p_rtable
=
lappend
(
pstate
->
p_rtable
,
rte
);
heap_close
(
relation
);
return
rte
;
}
/*
* expandAll -
* makes a list of attributes
* assumes reldesc caching works
*/
List
*
expandAll
(
ParseState
*
pstate
,
char
*
relname
,
char
*
refname
,
int
*
this_resno
)
{
{
Relation
rdesc
;
ParseState
*
pstate
;
List
*
te_tail
=
NIL
,
*
te_head
=
NIL
;
pstate
=
malloc
(
sizeof
(
ParseState
));
Var
*
varnode
;
pstate
->
p_last_resno
=
1
;
int
varattno
,
pstate
->
p_rtable
=
NIL
;
maxattrs
;
pstate
->
p_numAgg
=
0
;
Oid
type_id
;
pstate
->
p_aggs
=
NIL
;
int
type_len
;
pstate
->
p_is_insert
=
false
;
RangeTblEntry
*
rte
;
pstate
->
p_insert_columns
=
NIL
;
pstate
->
p_is_update
=
false
;
rte
=
refnameRangeTableEntry
(
pstate
->
p_rtable
,
refname
);
pstate
->
p_is_rule
=
false
;
if
(
rte
==
NULL
)
pstate
->
p_in_where_clause
=
false
;
rte
=
addRangeTableEntry
(
pstate
,
relname
,
refname
,
FALSE
,
FALSE
);
pstate
->
p_target_relation
=
NULL
;
pstate
->
p_target_rangetblentry
=
NULL
;
rdesc
=
heap_open
(
rte
->
relid
);
return
(
pstate
);
if
(
rdesc
==
NULL
)
{
elog
(
WARN
,
"Unable to expand all -- heap_open failed on %s"
,
rte
->
refname
);
return
NIL
;
}
maxattrs
=
RelationGetNumberOfAttributes
(
rdesc
);
for
(
varattno
=
0
;
varattno
<=
maxattrs
-
1
;
varattno
++
)
{
char
*
attrname
;
char
*
resname
=
NULL
;
TargetEntry
*
te
=
makeNode
(
TargetEntry
);
attrname
=
pstrdup
((
rdesc
->
rd_att
->
attrs
[
varattno
]
->
attname
).
data
);
varnode
=
(
Var
*
)
make_var
(
pstate
,
refname
,
attrname
,
&
type_id
);
type_len
=
(
int
)
tlen
(
get_id_type
(
type_id
));
handleTargetColname
(
pstate
,
&
resname
,
refname
,
attrname
);
if
(
resname
!=
NULL
)
attrname
=
resname
;
/*
* Even if the elements making up a set are complex, the set
* itself is not.
*/
te
->
resdom
=
makeResdom
((
AttrNumber
)
(
*
this_resno
)
++
,
type_id
,
(
Size
)
type_len
,
attrname
,
(
Index
)
0
,
(
Oid
)
0
,
0
);
te
->
expr
=
(
Node
*
)
varnode
;
if
(
te_head
==
NIL
)
te_head
=
te_tail
=
lcons
(
te
,
NIL
);
else
te_tail
=
lappend
(
te_tail
,
te
);
}
heap_close
(
rdesc
);
return
(
te_head
);
}
}
static
void
Node
*
disallow_setop
(
char
*
op
,
Type
optype
,
Node
*
operand
)
{
if
(
operand
==
NULL
)
return
;
if
(
nodeTag
(
operand
)
==
T_Iter
)
{
elog
(
NOTICE
,
"An operand to the '%s' operator returns a set of %s,"
,
op
,
tname
(
optype
));
elog
(
WARN
,
"but '%s' takes single values, not sets."
,
op
);
}
}
static
Node
*
make_operand
(
char
*
opname
,
make_operand
(
char
*
opname
,
Node
*
tree
,
Node
*
tree
,
Oid
orig_typeId
,
Oid
orig_typeId
,
...
@@ -267,7 +84,7 @@ make_operand(char *opname,
...
@@ -267,7 +84,7 @@ make_operand(char *opname,
if
(
tree
!=
NULL
)
if
(
tree
!=
NULL
)
{
{
result
=
tree
;
result
=
tree
;
true_type
=
get_id_t
ype
(
true_typeId
);
true_type
=
typeidT
ype
(
true_typeId
);
disallow_setop
(
opname
,
true_type
,
result
);
disallow_setop
(
opname
,
true_type
,
result
);
if
(
true_typeId
!=
orig_typeId
)
if
(
true_typeId
!=
orig_typeId
)
{
/* must coerce */
{
/* must coerce */
...
@@ -276,13 +93,13 @@ make_operand(char *opname,
...
@@ -276,13 +93,13 @@ make_operand(char *opname,
Assert
(
nodeTag
(
result
)
==
T_Const
);
Assert
(
nodeTag
(
result
)
==
T_Const
);
val
=
(
Datum
)
textout
((
struct
varlena
*
)
val
=
(
Datum
)
textout
((
struct
varlena
*
)
con
->
constvalue
);
con
->
constvalue
);
infunc
=
typeid
_get_r
etinfunc
(
true_typeId
);
infunc
=
typeid
R
etinfunc
(
true_typeId
);
con
=
makeNode
(
Const
);
con
=
makeNode
(
Const
);
con
->
consttype
=
true_typeId
;
con
->
consttype
=
true_typeId
;
con
->
constlen
=
t
l
en
(
true_type
);
con
->
constlen
=
t
ypeL
en
(
true_type
);
con
->
constvalue
=
(
Datum
)
fmgr
(
infunc
,
con
->
constvalue
=
(
Datum
)
fmgr
(
infunc
,
val
,
val
,
get_type
lem
(
true_typeId
),
typeidTypE
lem
(
true_typeId
),
-
1
/* for varchar() type */
);
-
1
/* for varchar() type */
);
con
->
constisnull
=
false
;
con
->
constisnull
=
false
;
con
->
constbyval
=
true
;
con
->
constbyval
=
true
;
...
@@ -307,6 +124,21 @@ make_operand(char *opname,
...
@@ -307,6 +124,21 @@ make_operand(char *opname,
}
}
void
disallow_setop
(
char
*
op
,
Type
optype
,
Node
*
operand
)
{
if
(
operand
==
NULL
)
return
;
if
(
nodeTag
(
operand
)
==
T_Iter
)
{
elog
(
NOTICE
,
"An operand to the '%s' operator returns a set of %s,"
,
op
,
typeTypeName
(
optype
));
elog
(
WARN
,
"but '%s' takes single values, not sets."
,
op
);
}
}
Expr
*
Expr
*
make_op
(
char
*
opname
,
Node
*
ltree
,
Node
*
rtree
)
make_op
(
char
*
opname
,
Node
*
ltree
,
Node
*
rtree
)
{
{
...
@@ -367,30 +199,30 @@ make_op(char *opname, Node *ltree, Node *rtree)
...
@@ -367,30 +199,30 @@ make_op(char *opname, Node *ltree, Node *rtree)
CONVERTABLE_TYPE
(
rtypeId
)
&&
nodeTag
(
rtree
)
==
T_Const
&&
CONVERTABLE_TYPE
(
rtypeId
)
&&
nodeTag
(
rtree
)
==
T_Const
&&
!
((
Const
*
)
rtree
)
->
constiscast
)
!
((
Const
*
)
rtree
)
->
constiscast
)
{
{
outfunc
=
typeid
_get_r
etoutfunc
(
rtypeId
);
outfunc
=
typeid
R
etoutfunc
(
rtypeId
);
infunc
=
typeid
_get_r
etinfunc
(
ltypeId
);
infunc
=
typeid
R
etinfunc
(
ltypeId
);
outstr
=
(
char
*
)
fmgr
(
outfunc
,
((
Const
*
)
rtree
)
->
constvalue
);
outstr
=
(
char
*
)
fmgr
(
outfunc
,
((
Const
*
)
rtree
)
->
constvalue
);
((
Const
*
)
rtree
)
->
constvalue
=
(
Datum
)
fmgr
(
infunc
,
outstr
);
((
Const
*
)
rtree
)
->
constvalue
=
(
Datum
)
fmgr
(
infunc
,
outstr
);
pfree
(
outstr
);
pfree
(
outstr
);
((
Const
*
)
rtree
)
->
consttype
=
rtypeId
=
ltypeId
;
((
Const
*
)
rtree
)
->
consttype
=
rtypeId
=
ltypeId
;
newtype
=
get_id_t
ype
(
rtypeId
);
newtype
=
typeidT
ype
(
rtypeId
);
((
Const
*
)
rtree
)
->
constlen
=
t
l
en
(
newtype
);
((
Const
*
)
rtree
)
->
constlen
=
t
ypeL
en
(
newtype
);
((
Const
*
)
rtree
)
->
constbyval
=
t
byv
al
(
newtype
);
((
Const
*
)
rtree
)
->
constbyval
=
t
ypeByV
al
(
newtype
);
}
}
if
(
CONVERTABLE_TYPE
(
rtypeId
)
&&
nodeTag
(
rtree
)
!=
T_Const
&&
if
(
CONVERTABLE_TYPE
(
rtypeId
)
&&
nodeTag
(
rtree
)
!=
T_Const
&&
CONVERTABLE_TYPE
(
ltypeId
)
&&
nodeTag
(
ltree
)
==
T_Const
&&
CONVERTABLE_TYPE
(
ltypeId
)
&&
nodeTag
(
ltree
)
==
T_Const
&&
!
((
Const
*
)
ltree
)
->
constiscast
)
!
((
Const
*
)
ltree
)
->
constiscast
)
{
{
outfunc
=
typeid
_get_r
etoutfunc
(
ltypeId
);
outfunc
=
typeid
R
etoutfunc
(
ltypeId
);
infunc
=
typeid
_get_r
etinfunc
(
rtypeId
);
infunc
=
typeid
R
etinfunc
(
rtypeId
);
outstr
=
(
char
*
)
fmgr
(
outfunc
,
((
Const
*
)
ltree
)
->
constvalue
);
outstr
=
(
char
*
)
fmgr
(
outfunc
,
((
Const
*
)
ltree
)
->
constvalue
);
((
Const
*
)
ltree
)
->
constvalue
=
(
Datum
)
fmgr
(
infunc
,
outstr
);
((
Const
*
)
ltree
)
->
constvalue
=
(
Datum
)
fmgr
(
infunc
,
outstr
);
pfree
(
outstr
);
pfree
(
outstr
);
((
Const
*
)
ltree
)
->
consttype
=
ltypeId
=
rtypeId
;
((
Const
*
)
ltree
)
->
consttype
=
ltypeId
=
rtypeId
;
newtype
=
get_id_t
ype
(
ltypeId
);
newtype
=
typeidT
ype
(
ltypeId
);
((
Const
*
)
ltree
)
->
constlen
=
t
l
en
(
newtype
);
((
Const
*
)
ltree
)
->
constlen
=
t
ypeL
en
(
newtype
);
((
Const
*
)
ltree
)
->
constbyval
=
t
byv
al
(
newtype
);
((
Const
*
)
ltree
)
->
constbyval
=
t
ypeByV
al
(
newtype
);
}
}
temp
=
oper
(
opname
,
ltypeId
,
rtypeId
,
false
);
temp
=
oper
(
opname
,
ltypeId
,
rtypeId
,
false
);
...
@@ -426,38 +258,6 @@ make_op(char *opname, Node *ltree, Node *rtree)
...
@@ -426,38 +258,6 @@ make_op(char *opname, Node *ltree, Node *rtree)
return
result
;
return
result
;
}
}
Oid
find_atttype
(
Oid
relid
,
char
*
attrname
)
{
int
attid
;
Oid
vartype
;
Relation
rd
;
rd
=
heap_open
(
relid
);
if
(
!
RelationIsValid
(
rd
))
{
rd
=
heap_openr
(
tname
(
get_id_type
(
relid
)));
if
(
!
RelationIsValid
(
rd
))
elog
(
WARN
,
"cannot compute type of att %s for relid %d"
,
attrname
,
relid
);
}
attid
=
nf_varattno
(
rd
,
attrname
);
if
(
attid
==
InvalidAttrNumber
)
elog
(
WARN
,
"Invalid attribute %s
\n
"
,
attrname
);
vartype
=
att_typeid
(
rd
,
attid
);
/*
* close relation we're done with it now
*/
heap_close
(
rd
);
return
(
vartype
);
}
Var
*
Var
*
make_var
(
ParseState
*
pstate
,
char
*
refname
,
char
*
attrname
,
Oid
*
type_id
)
make_var
(
ParseState
*
pstate
,
char
*
refname
,
char
*
attrname
,
Oid
*
type_id
)
{
{
...
@@ -476,10 +276,8 @@ make_var(ParseState *pstate, char *refname, char *attrname, Oid *type_id)
...
@@ -476,10 +276,8 @@ make_var(ParseState *pstate, char *refname, char *attrname, Oid *type_id)
rd
=
heap_open
(
rte
->
relid
);
rd
=
heap_open
(
rte
->
relid
);
attid
=
nf_varattno
(
rd
,
attrname
);
attid
=
attnameAttNum
(
rd
,
attrname
);
/* could elog(WARN) */
if
(
attid
==
InvalidAttrNumber
)
vartypeid
=
attnumTypeId
(
rd
,
attid
);
elog
(
WARN
,
"Invalid attribute %s
\n
"
,
attrname
);
vartypeid
=
att_typeid
(
rd
,
attid
);
varnode
=
makeVar
(
vnum
,
attid
,
vartypeid
,
vnum
,
attid
);
varnode
=
makeVar
(
vnum
,
attid
,
vartypeid
,
vnum
,
attid
);
...
@@ -667,7 +465,7 @@ make_const(Value *value)
...
@@ -667,7 +465,7 @@ make_const(Value *value)
switch
(
nodeTag
(
value
))
switch
(
nodeTag
(
value
))
{
{
case
T_Integer
:
case
T_Integer
:
tp
=
type
(
"int4"
);
tp
=
type
idType
(
INT4OID
);
val
=
Int32GetDatum
(
intVal
(
value
));
val
=
Int32GetDatum
(
intVal
(
value
));
break
;
break
;
...
@@ -675,7 +473,7 @@ make_const(Value *value)
...
@@ -675,7 +473,7 @@ make_const(Value *value)
{
{
float64
dummy
;
float64
dummy
;
tp
=
type
(
"float8"
);
tp
=
type
idType
(
FLOAT8OID
);
dummy
=
(
float64
)
palloc
(
sizeof
(
float64data
));
dummy
=
(
float64
)
palloc
(
sizeof
(
float64data
));
*
dummy
=
floatVal
(
value
);
*
dummy
=
floatVal
(
value
);
...
@@ -685,7 +483,7 @@ make_const(Value *value)
...
@@ -685,7 +483,7 @@ make_const(Value *value)
break
;
break
;
case
T_String
:
case
T_String
:
tp
=
type
(
"unknown"
);
/* unknown for now, will be type
tp
=
type
idType
(
UNKNOWNOID
);
/* unknown for now, will be type
* coerced */
* coerced */
val
=
PointerGetDatum
(
textin
(
strVal
(
value
)));
val
=
PointerGetDatum
(
textin
(
strVal
(
value
)));
break
;
break
;
...
@@ -702,111 +500,14 @@ make_const(Value *value)
...
@@ -702,111 +500,14 @@ make_const(Value *value)
}
}
}
}
con
=
makeConst
(
type
i
d
(
tp
),
con
=
makeConst
(
type
TypeI
d
(
tp
),
t
l
en
(
tp
),
t
ypeL
en
(
tp
),
val
,
val
,
false
,
false
,
t
byv
al
(
tp
),
t
ypeByV
al
(
tp
),
false
,
/* not a set */
false
,
/* not a set */
false
);
false
);
return
(
con
);
return
(
con
);
}
}
/*
* param_type_init()
*
* keep enough information around fill out the type of param nodes
* used in postquel functions
*/
void
param_type_init
(
Oid
*
typev
,
int
nargs
)
{
pfunc_num_args
=
nargs
;
param_type_info
=
typev
;
}
Oid
param_type
(
int
t
)
{
if
((
t
>
pfunc_num_args
)
||
(
t
==
0
))
return
InvalidOid
;
return
param_type_info
[
t
-
1
];
}
/*
* handleTargetColname -
* use column names from insert
*/
void
handleTargetColname
(
ParseState
*
pstate
,
char
**
resname
,
char
*
refname
,
char
*
colname
)
{
if
(
pstate
->
p_is_insert
)
{
if
(
pstate
->
p_insert_columns
!=
NIL
)
{
Ident
*
id
=
lfirst
(
pstate
->
p_insert_columns
);
*
resname
=
id
->
name
;
pstate
->
p_insert_columns
=
lnext
(
pstate
->
p_insert_columns
);
}
else
elog
(
WARN
,
"insert: more expressions than target columns"
);
}
if
(
pstate
->
p_is_insert
||
pstate
->
p_is_update
)
checkTargetTypes
(
pstate
,
*
resname
,
refname
,
colname
);
}
/*
* checkTargetTypes -
* checks value and target column types
*/
static
void
checkTargetTypes
(
ParseState
*
pstate
,
char
*
target_colname
,
char
*
refname
,
char
*
colname
)
{
Oid
attrtype_id
,
attrtype_target
;
int
resdomno_id
,
resdomno_target
;
Relation
rd
;
RangeTblEntry
*
rte
;
if
(
target_colname
==
NULL
||
colname
==
NULL
)
return
;
if
(
refname
!=
NULL
)
rte
=
refnameRangeTableEntry
(
pstate
->
p_rtable
,
refname
);
else
{
rte
=
colnameRangeTableEntry
(
pstate
,
colname
);
if
(
rte
==
(
RangeTblEntry
*
)
NULL
)
elog
(
WARN
,
"attribute %s not found"
,
colname
);
refname
=
rte
->
refname
;
}
/*
if (pstate->p_is_insert && rte == pstate->p_target_rangetblentry)
elog(WARN, "%s not available in this context", colname);
*/
rd
=
heap_open
(
rte
->
relid
);
resdomno_id
=
varattno
(
rd
,
colname
);
attrtype_id
=
att_typeid
(
rd
,
resdomno_id
);
resdomno_target
=
varattno
(
pstate
->
p_target_relation
,
target_colname
);
attrtype_target
=
att_typeid
(
pstate
->
p_target_relation
,
resdomno_target
);
if
(
attrtype_id
!=
attrtype_target
)
elog
(
WARN
,
"Type of %s does not match target column %s"
,
colname
,
target_colname
);
if
((
attrtype_id
==
BPCHAROID
||
attrtype_id
==
VARCHAROID
)
&&
rd
->
rd_att
->
attrs
[
resdomno_id
-
1
]
->
attlen
!=
pstate
->
p_target_relation
->
rd_att
->
attrs
[
resdomno_target
-
1
]
->
attlen
)
elog
(
WARN
,
"Length of %s does not match length of target column %s"
,
colname
,
target_colname
);
heap_close
(
rd
);
}
src/backend/parser/parse_oper.c
0 → 100644
View file @
4a5b781d
/*-------------------------------------------------------------------------
*
* parse_oper.h
* handle operator things for parser
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.1 1997/11/25 22:05:43 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include <string.h>
#include "postgres.h"
#include <fmgr.h>
#include <access/heapam.h>
#include <access/relscan.h>
#include <catalog/catname.h>
#include <catalog/pg_operator.h>
#include <catalog/pg_proc.h>
#include <catalog/pg_type.h>
#include <parser/parse_oper.h>
#include <parser/parse_type.h>
#include <storage/bufmgr.h>
#include <utils/syscache.h>
#ifdef 0
#include "lib/dllist.h"
#include "utils/datum.h"
#include "utils/builtins.h"
#include "utils/elog.h"
#include "utils/palloc.h"
#include "nodes/pg_list.h"
#include "nodes/parsenodes.h"
#include "catalog/pg_inherits.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_proc.h"
#include "catalog/indexing.h"
#include "catalog/catname.h"
#include "access/skey.h"
#include "access/relscan.h"
#include "access/tupdesc.h"
#include "access/htup.h"
#include "access/genam.h"
#include "access/itup.h"
#include "access/tupmacs.h"
#include "storage/buf.h"
#include "utils/lsyscache.h"
#include "storage/lmgr.h"
#include "port-protos.h"
/* strdup() */
#endif
Oid
any_ordering_op
(
int
restype
)
{
Operator
order_op
;
Oid
order_opid
;
order_op
=
oper
(
"<"
,
restype
,
restype
,
false
);
order_opid
=
oprid
(
order_op
);
return
order_opid
;
}
/* given operator, return the operator OID */
Oid
oprid
(
Operator
op
)
{
return
(
op
->
t_oid
);
}
/*
* given opname, leftTypeId and rightTypeId,
* find all possible (arg1, arg2) pairs for which an operator named
* opname exists, such that leftTypeId can be coerced to arg1 and
* rightTypeId can be coerced to arg2
*/
int
binary_oper_get_candidates
(
char
*
opname
,
Oid
leftTypeId
,
Oid
rightTypeId
,
CandidateList
*
candidates
)
{
CandidateList
current_candidate
;
Relation
pg_operator_desc
;
HeapScanDesc
pg_operator_scan
;
HeapTuple
tup
;
OperatorTupleForm
oper
;
Buffer
buffer
;
int
nkeys
;
int
ncandidates
=
0
;
ScanKeyData
opKey
[
3
];
*
candidates
=
NULL
;
ScanKeyEntryInitialize
(
&
opKey
[
0
],
0
,
Anum_pg_operator_oprname
,
NameEqualRegProcedure
,
NameGetDatum
(
opname
));
ScanKeyEntryInitialize
(
&
opKey
[
1
],
0
,
Anum_pg_operator_oprkind
,
CharacterEqualRegProcedure
,
CharGetDatum
(
'b'
));
if
(
leftTypeId
==
UNKNOWNOID
)
{
if
(
rightTypeId
==
UNKNOWNOID
)
{
nkeys
=
2
;
}
else
{
nkeys
=
3
;
ScanKeyEntryInitialize
(
&
opKey
[
2
],
0
,
Anum_pg_operator_oprright
,
ObjectIdEqualRegProcedure
,
ObjectIdGetDatum
(
rightTypeId
));
}
}
else
if
(
rightTypeId
==
UNKNOWNOID
)
{
nkeys
=
3
;
ScanKeyEntryInitialize
(
&
opKey
[
2
],
0
,
Anum_pg_operator_oprleft
,
ObjectIdEqualRegProcedure
,
ObjectIdGetDatum
(
leftTypeId
));
}
else
/* currently only "unknown" can be coerced */
return
0
;
pg_operator_desc
=
heap_openr
(
OperatorRelationName
);
pg_operator_scan
=
heap_beginscan
(
pg_operator_desc
,
0
,
true
,
nkeys
,
opKey
);
do
{
tup
=
heap_getnext
(
pg_operator_scan
,
0
,
&
buffer
);
if
(
HeapTupleIsValid
(
tup
))
{
current_candidate
=
(
CandidateList
)
palloc
(
sizeof
(
struct
_CandidateList
));
current_candidate
->
args
=
(
Oid
*
)
palloc
(
2
*
sizeof
(
Oid
));
oper
=
(
OperatorTupleForm
)
GETSTRUCT
(
tup
);
current_candidate
->
args
[
0
]
=
oper
->
oprleft
;
current_candidate
->
args
[
1
]
=
oper
->
oprright
;
current_candidate
->
next
=
*
candidates
;
*
candidates
=
current_candidate
;
ncandidates
++
;
ReleaseBuffer
(
buffer
);
}
}
while
(
HeapTupleIsValid
(
tup
));
heap_endscan
(
pg_operator_scan
);
heap_close
(
pg_operator_desc
);
return
ncandidates
;
}
/*
* equivalentOpersAfterPromotion -
* checks if a list of candidate operators obtained from
* binary_oper_get_candidates() contain equivalent operators. If
* this routine is called, we have more than 1 candidate and need to
* decided whether to pick one of them. This routine returns true if
* the all the candidates operate on the same data types after
* promotion (int2, int4, float4 -> float8).
*/
bool
equivalentOpersAfterPromotion
(
CandidateList
candidates
)
{
CandidateList
result
;
CandidateList
promotedCandidates
=
NULL
;
Oid
leftarg
,
rightarg
;
for
(
result
=
candidates
;
result
!=
NULL
;
result
=
result
->
next
)
{
CandidateList
c
;
c
=
(
CandidateList
)
palloc
(
sizeof
(
*
c
));
c
->
args
=
(
Oid
*
)
palloc
(
2
*
sizeof
(
Oid
));
switch
(
result
->
args
[
0
])
{
case
FLOAT4OID
:
case
INT4OID
:
case
INT2OID
:
case
CASHOID
:
c
->
args
[
0
]
=
FLOAT8OID
;
break
;
default:
c
->
args
[
0
]
=
result
->
args
[
0
];
break
;
}
switch
(
result
->
args
[
1
])
{
case
FLOAT4OID
:
case
INT4OID
:
case
INT2OID
:
case
CASHOID
:
c
->
args
[
1
]
=
FLOAT8OID
;
break
;
default:
c
->
args
[
1
]
=
result
->
args
[
1
];
break
;
}
c
->
next
=
promotedCandidates
;
promotedCandidates
=
c
;
}
/*
* if we get called, we have more than 1 candidates so we can do the
* following safely
*/
leftarg
=
promotedCandidates
->
args
[
0
];
rightarg
=
promotedCandidates
->
args
[
1
];
for
(
result
=
promotedCandidates
->
next
;
result
!=
NULL
;
result
=
result
->
next
)
{
if
(
result
->
args
[
0
]
!=
leftarg
||
result
->
args
[
1
]
!=
rightarg
)
/*
* this list contains operators that operate on different data
* types even after promotion. Hence we can't decide on which
* one to pick. The user must do explicit type casting.
*/
return
FALSE
;
}
/*
* all the candidates are equivalent in the following sense: they
* operate on equivalent data types and picking any one of them is as
* good.
*/
return
TRUE
;
}
/*
* given a choice of argument type pairs for a binary operator,
* try to choose a default pair
*/
CandidateList
binary_oper_select_candidate
(
Oid
arg1
,
Oid
arg2
,
CandidateList
candidates
)
{
CandidateList
result
;
/*
* if both are "unknown", there is no way to select a candidate
*
* current wisdom holds that the default operator should be one in which
* both operands have the same type (there will only be one such
* operator)
*
* 7.27.93 - I have decided not to do this; it's too hard to justify, and
* it's easy enough to typecast explicitly -avi [the rest of this
* routine were commented out since then -ay]
*/
if
(
arg1
==
UNKNOWNOID
&&
arg2
==
UNKNOWNOID
)
return
(
NULL
);
/*
* 6/23/95 - I don't complete agree with avi. In particular, casting
* floats is a pain for users. Whatever the rationale behind not doing
* this is, I need the following special case to work.
*
* In the WHERE clause of a query, if a float is specified without
* quotes, we treat it as float8. I added the float48* operators so
* that we can operate on float4 and float8. But now we have more than
* one matching operator if the right arg is unknown (eg. float
* specified with quotes). This break some stuff in the regression
* test where there are floats in quotes not properly casted. Below is
* the solution. In addition to requiring the operator operates on the
* same type for both operands [as in the code Avi originally
* commented out], we also require that the operators be equivalent in
* some sense. (see equivalentOpersAfterPromotion for details.) - ay
* 6/95
*/
if
(
!
equivalentOpersAfterPromotion
(
candidates
))
return
NULL
;
/*
* if we get here, any one will do but we're more picky and require
* both operands be the same.
*/
for
(
result
=
candidates
;
result
!=
NULL
;
result
=
result
->
next
)
{
if
(
result
->
args
[
0
]
==
result
->
args
[
1
])
return
result
;
}
return
(
NULL
);
}
/* Given operator, types of arg1, and arg2, return oper struct */
/* arg1, arg2 --typeids */
Operator
oper
(
char
*
op
,
Oid
arg1
,
Oid
arg2
,
bool
noWarnings
)
{
HeapTuple
tup
;
CandidateList
candidates
;
int
ncandidates
;
if
(
!
arg2
)
arg2
=
arg1
;
if
(
!
arg1
)
arg1
=
arg2
;
if
(
!
(
tup
=
SearchSysCacheTuple
(
OPRNAME
,
PointerGetDatum
(
op
),
ObjectIdGetDatum
(
arg1
),
ObjectIdGetDatum
(
arg2
),
Int8GetDatum
(
'b'
))))
{
ncandidates
=
binary_oper_get_candidates
(
op
,
arg1
,
arg2
,
&
candidates
);
if
(
ncandidates
==
0
)
{
/*
* no operators of the desired types found
*/
if
(
!
noWarnings
)
op_error
(
op
,
arg1
,
arg2
);
return
(
NULL
);
}
else
if
(
ncandidates
==
1
)
{
/*
* exactly one operator of the desired types found
*/
tup
=
SearchSysCacheTuple
(
OPRNAME
,
PointerGetDatum
(
op
),
ObjectIdGetDatum
(
candidates
->
args
[
0
]),
ObjectIdGetDatum
(
candidates
->
args
[
1
]),
Int8GetDatum
(
'b'
));
Assert
(
HeapTupleIsValid
(
tup
));
}
else
{
/*
* multiple operators of the desired types found
*/
candidates
=
binary_oper_select_candidate
(
arg1
,
arg2
,
candidates
);
if
(
candidates
!=
NULL
)
{
/* we chose one of them */
tup
=
SearchSysCacheTuple
(
OPRNAME
,
PointerGetDatum
(
op
),
ObjectIdGetDatum
(
candidates
->
args
[
0
]),
ObjectIdGetDatum
(
candidates
->
args
[
1
]),
Int8GetDatum
(
'b'
));
Assert
(
HeapTupleIsValid
(
tup
));
}
else
{
Type
tp1
,
tp2
;
/* we chose none of them */
tp1
=
typeidType
(
arg1
);
tp2
=
typeidType
(
arg2
);
if
(
!
noWarnings
)
{
elog
(
NOTICE
,
"there is more than one operator %s for types"
,
op
);
elog
(
NOTICE
,
"%s and %s. You will have to retype this query"
,
typeTypeName
(
tp1
),
typeTypeName
(
tp2
));
elog
(
WARN
,
"using an explicit cast"
);
}
return
(
NULL
);
}
}
}
return
((
Operator
)
tup
);
}
/*
* given opname and typeId, find all possible types for which
* a right/left unary operator named opname exists,
* such that typeId can be coerced to it
*/
int
unary_oper_get_candidates
(
char
*
op
,
Oid
typeId
,
CandidateList
*
candidates
,
char
rightleft
)
{
CandidateList
current_candidate
;
Relation
pg_operator_desc
;
HeapScanDesc
pg_operator_scan
;
HeapTuple
tup
;
OperatorTupleForm
oper
;
Buffer
buffer
;
int
ncandidates
=
0
;
static
ScanKeyData
opKey
[
2
]
=
{
{
0
,
Anum_pg_operator_oprname
,
NameEqualRegProcedure
},
{
0
,
Anum_pg_operator_oprkind
,
CharacterEqualRegProcedure
}};
*
candidates
=
NULL
;
fmgr_info
(
NameEqualRegProcedure
,
(
func_ptr
*
)
&
opKey
[
0
].
sk_func
,
&
opKey
[
0
].
sk_nargs
);
opKey
[
0
].
sk_argument
=
NameGetDatum
(
op
);
fmgr_info
(
CharacterEqualRegProcedure
,
(
func_ptr
*
)
&
opKey
[
1
].
sk_func
,
&
opKey
[
1
].
sk_nargs
);
opKey
[
1
].
sk_argument
=
CharGetDatum
(
rightleft
);
/* currently, only "unknown" can be coerced */
/*
* but we should allow types that are internally the same to be
* "coerced"
*/
if
(
typeId
!=
UNKNOWNOID
)
{
return
0
;
}
pg_operator_desc
=
heap_openr
(
OperatorRelationName
);
pg_operator_scan
=
heap_beginscan
(
pg_operator_desc
,
0
,
true
,
2
,
opKey
);
do
{
tup
=
heap_getnext
(
pg_operator_scan
,
0
,
&
buffer
);
if
(
HeapTupleIsValid
(
tup
))
{
current_candidate
=
(
CandidateList
)
palloc
(
sizeof
(
struct
_CandidateList
));
current_candidate
->
args
=
(
Oid
*
)
palloc
(
sizeof
(
Oid
));
oper
=
(
OperatorTupleForm
)
GETSTRUCT
(
tup
);
if
(
rightleft
==
'r'
)
current_candidate
->
args
[
0
]
=
oper
->
oprleft
;
else
current_candidate
->
args
[
0
]
=
oper
->
oprright
;
current_candidate
->
next
=
*
candidates
;
*
candidates
=
current_candidate
;
ncandidates
++
;
ReleaseBuffer
(
buffer
);
}
}
while
(
HeapTupleIsValid
(
tup
));
heap_endscan
(
pg_operator_scan
);
heap_close
(
pg_operator_desc
);
return
ncandidates
;
}
/* Given unary right-side operator (operator on right), return oper struct */
/* arg-- type id */
Operator
right_oper
(
char
*
op
,
Oid
arg
)
{
HeapTuple
tup
;
CandidateList
candidates
;
int
ncandidates
;
/*
* if (!OpCache) { init_op_cache(); }
*/
if
(
!
(
tup
=
SearchSysCacheTuple
(
OPRNAME
,
PointerGetDatum
(
op
),
ObjectIdGetDatum
(
arg
),
ObjectIdGetDatum
(
InvalidOid
),
Int8GetDatum
(
'r'
))))
{
ncandidates
=
unary_oper_get_candidates
(
op
,
arg
,
&
candidates
,
'r'
);
if
(
ncandidates
==
0
)
{
elog
(
WARN
,
"Can't find right op: %s for type %d"
,
op
,
arg
);
return
(
NULL
);
}
else
if
(
ncandidates
==
1
)
{
tup
=
SearchSysCacheTuple
(
OPRNAME
,
PointerGetDatum
(
op
),
ObjectIdGetDatum
(
candidates
->
args
[
0
]),
ObjectIdGetDatum
(
InvalidOid
),
Int8GetDatum
(
'r'
));
Assert
(
HeapTupleIsValid
(
tup
));
}
else
{
elog
(
NOTICE
,
"there is more than one right operator %s"
,
op
);
elog
(
NOTICE
,
"you will have to retype this query"
);
elog
(
WARN
,
"using an explicit cast"
);
return
(
NULL
);
}
}
return
((
Operator
)
tup
);
}
/* Given unary left-side operator (operator on left), return oper struct */
/* arg--type id */
Operator
left_oper
(
char
*
op
,
Oid
arg
)
{
HeapTuple
tup
;
CandidateList
candidates
;
int
ncandidates
;
/*
* if (!OpCache) { init_op_cache(); }
*/
if
(
!
(
tup
=
SearchSysCacheTuple
(
OPRNAME
,
PointerGetDatum
(
op
),
ObjectIdGetDatum
(
InvalidOid
),
ObjectIdGetDatum
(
arg
),
Int8GetDatum
(
'l'
))))
{
ncandidates
=
unary_oper_get_candidates
(
op
,
arg
,
&
candidates
,
'l'
);
if
(
ncandidates
==
0
)
{
elog
(
WARN
,
"Can't find left op: %s for type %d"
,
op
,
arg
);
return
(
NULL
);
}
else
if
(
ncandidates
==
1
)
{
tup
=
SearchSysCacheTuple
(
OPRNAME
,
PointerGetDatum
(
op
),
ObjectIdGetDatum
(
InvalidOid
),
ObjectIdGetDatum
(
candidates
->
args
[
0
]),
Int8GetDatum
(
'l'
));
Assert
(
HeapTupleIsValid
(
tup
));
}
else
{
elog
(
NOTICE
,
"there is more than one left operator %s"
,
op
);
elog
(
NOTICE
,
"you will have to retype this query"
);
elog
(
WARN
,
"using an explicit cast"
);
return
(
NULL
);
}
}
return
((
Operator
)
tup
);
}
/* Given a typename and value, returns the ascii form of the value */
#ifdef NOT_USED
char
*
outstr
(
char
*
typename
,
/* Name of type of value */
char
*
value
)
/* Could be of any type */
{
TypeTupleForm
tp
;
Oid
op
;
tp
=
(
TypeTupleForm
)
GETSTRUCT
(
type
(
typename
));
op
=
tp
->
typoutput
;
return
((
char
*
)
fmgr
(
op
,
value
));
}
#endif
/*
* Give a somewhat useful error message when the operator for two types
* is not found.
*/
void
op_error
(
char
*
op
,
Oid
arg1
,
Oid
arg2
)
{
Type
tp1
=
NULL
,
tp2
=
NULL
;
if
(
typeidIsValid
(
arg1
))
{
tp1
=
typeidType
(
arg1
);
}
else
{
elog
(
WARN
,
"left hand side of operator %s has an unknown type, probably a bad attribute name"
,
op
);
}
if
(
typeidIsValid
(
arg2
))
{
tp2
=
typeidType
(
arg2
);
}
else
{
elog
(
WARN
,
"right hand side of operator %s has an unknown type, probably a bad attribute name"
,
op
);
}
elog
(
NOTICE
,
"there is no operator %s for types %s and %s"
,
op
,
typeTypeName
(
tp1
),
typeTypeName
(
tp2
));
elog
(
NOTICE
,
"You will either have to retype this query using an"
);
elog
(
NOTICE
,
"explicit cast, or you will have to define the operator"
);
elog
(
WARN
,
"%s for %s and %s using CREATE OPERATOR"
,
op
,
typeTypeName
(
tp1
),
typeTypeName
(
tp2
));
}
src/backend/parser/parse_relation.c
0 → 100644
View file @
4a5b781d
/*-------------------------------------------------------------------------
*
* parse_relation.c--
* parser support routines dealing with relations
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.1 1997/11/25 22:05:45 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include <ctype.h>
#include <string.h>
#include "postgres.h"
#include "access/heapam.h"
#include <access/htup.h>
#include <catalog/pg_type.h>
#include "nodes/makefuncs.h"
#include <parser/parse_relation.h>
#include <utils/acl.h>
#include "utils/builtins.h"
#include <utils/lsyscache.h>
#ifdef 0
#include "fmgr.h"
#include "access/tupmacs.h"
#include "utils/elog.h"
#include "utils/palloc.h"
#include "utils/acl.h"
/* for ACL_NO_PRIV_WARNING */
#include "utils/syscache.h"
#include "catalog/pg_operator.h"
#include "nodes/pg_list.h"
#include "nodes/primnodes.h"
#include "nodes/parsenodes.h"
#endif
struct
{
char
*
field
;
int
code
;
}
special_attr
[]
=
{
{
"ctid"
,
SelfItemPointerAttributeNumber
},
{
"oid"
,
ObjectIdAttributeNumber
},
{
"xmin"
,
MinTransactionIdAttributeNumber
},
{
"cmin"
,
MinCommandIdAttributeNumber
},
{
"xmax"
,
MaxTransactionIdAttributeNumber
},
{
"cmax"
,
MaxCommandIdAttributeNumber
},
};
#define SPECIALS (sizeof(special_attr)/sizeof(*special_attr))
static
char
*
attnum_type
[
SPECIALS
]
=
{
"tid"
,
"oid"
,
"xid"
,
"cid"
,
"xid"
,
"cid"
,
};
/* given refname, return a pointer to the range table entry */
RangeTblEntry
*
refnameRangeTableEntry
(
List
*
rtable
,
char
*
refname
)
{
List
*
temp
;
foreach
(
temp
,
rtable
)
{
RangeTblEntry
*
rte
=
lfirst
(
temp
);
if
(
!
strcmp
(
rte
->
refname
,
refname
))
return
rte
;
}
return
NULL
;
}
/* given refname, return id of variable; position starts with 1 */
int
refnameRangeTablePosn
(
List
*
rtable
,
char
*
refname
)
{
int
index
;
List
*
temp
;
index
=
1
;
foreach
(
temp
,
rtable
)
{
RangeTblEntry
*
rte
=
lfirst
(
temp
);
if
(
!
strcmp
(
rte
->
refname
,
refname
))
return
index
;
index
++
;
}
return
(
0
);
}
/*
* returns range entry if found, else NULL
*/
RangeTblEntry
*
colnameRangeTableEntry
(
ParseState
*
pstate
,
char
*
colname
)
{
List
*
et
;
List
*
rtable
;
RangeTblEntry
*
rte_result
;
if
(
pstate
->
p_is_rule
)
rtable
=
lnext
(
lnext
(
pstate
->
p_rtable
));
else
rtable
=
pstate
->
p_rtable
;
rte_result
=
NULL
;
foreach
(
et
,
rtable
)
{
RangeTblEntry
*
rte
=
lfirst
(
et
);
/* only entries on outer(non-function?) scope */
if
(
!
rte
->
inFromCl
&&
rte
!=
pstate
->
p_target_rangetblentry
)
continue
;
if
(
get_attnum
(
rte
->
relid
,
colname
)
!=
InvalidAttrNumber
)
{
if
(
rte_result
!=
NULL
)
{
if
(
!
pstate
->
p_is_insert
||
rte
!=
pstate
->
p_target_rangetblentry
)
elog
(
WARN
,
"Column %s is ambiguous"
,
colname
);
}
else
rte_result
=
rte
;
}
}
return
rte_result
;
}
/*
* put new entry in pstate p_rtable structure, or return pointer
* if pstate null
*/
RangeTblEntry
*
addRangeTableEntry
(
ParseState
*
pstate
,
char
*
relname
,
char
*
refname
,
bool
inh
,
bool
inFromCl
)
{
Relation
relation
;
RangeTblEntry
*
rte
=
makeNode
(
RangeTblEntry
);
if
(
pstate
!=
NULL
&&
refnameRangeTableEntry
(
pstate
->
p_rtable
,
refname
)
!=
NULL
)
elog
(
WARN
,
"Table name %s specified more than once"
,
refname
);
rte
->
relname
=
pstrdup
(
relname
);
rte
->
refname
=
pstrdup
(
refname
);
relation
=
heap_openr
(
relname
);
if
(
relation
==
NULL
)
{
elog
(
WARN
,
"%s: %s"
,
relname
,
aclcheck_error_strings
[
ACLCHECK_NO_CLASS
]);
}
/*
* Flags - zero or more from inheritance,union,version or
* recursive (transitive closure) [we don't support them all -- ay
* 9/94 ]
*/
rte
->
inh
=
inh
;
/* RelOID */
rte
->
relid
=
RelationGetRelationId
(
relation
);
rte
->
inFromCl
=
inFromCl
;
/*
* close the relation we're done with it for now.
*/
if
(
pstate
!=
NULL
)
pstate
->
p_rtable
=
lappend
(
pstate
->
p_rtable
,
rte
);
heap_close
(
relation
);
return
rte
;
}
/*
* expandAll -
* makes a list of attributes
* assumes reldesc caching works
*/
List
*
expandAll
(
ParseState
*
pstate
,
char
*
relname
,
char
*
refname
,
int
*
this_resno
)
{
Relation
rdesc
;
List
*
te_tail
=
NIL
,
*
te_head
=
NIL
;
Var
*
varnode
;
int
varattno
,
maxattrs
;
Oid
type_id
;
int
type_len
;
RangeTblEntry
*
rte
;
rte
=
refnameRangeTableEntry
(
pstate
->
p_rtable
,
refname
);
if
(
rte
==
NULL
)
rte
=
addRangeTableEntry
(
pstate
,
relname
,
refname
,
FALSE
,
FALSE
);
rdesc
=
heap_open
(
rte
->
relid
);
if
(
rdesc
==
NULL
)
{
elog
(
WARN
,
"Unable to expand all -- heap_open failed on %s"
,
rte
->
refname
);
return
NIL
;
}
maxattrs
=
RelationGetNumberOfAttributes
(
rdesc
);
for
(
varattno
=
0
;
varattno
<=
maxattrs
-
1
;
varattno
++
)
{
char
*
attrname
;
char
*
resname
=
NULL
;
TargetEntry
*
te
=
makeNode
(
TargetEntry
);
attrname
=
pstrdup
((
rdesc
->
rd_att
->
attrs
[
varattno
]
->
attname
).
data
);
varnode
=
(
Var
*
)
make_var
(
pstate
,
refname
,
attrname
,
&
type_id
);
type_len
=
(
int
)
typeLen
(
typeidType
(
type_id
));
handleTargetColname
(
pstate
,
&
resname
,
refname
,
attrname
);
if
(
resname
!=
NULL
)
attrname
=
resname
;
/*
* Even if the elements making up a set are complex, the set
* itself is not.
*/
te
->
resdom
=
makeResdom
((
AttrNumber
)
(
*
this_resno
)
++
,
type_id
,
(
Size
)
type_len
,
attrname
,
(
Index
)
0
,
(
Oid
)
0
,
0
);
te
->
expr
=
(
Node
*
)
varnode
;
if
(
te_head
==
NIL
)
te_head
=
te_tail
=
lcons
(
te
,
NIL
);
else
te_tail
=
lappend
(
te_tail
,
te
);
}
heap_close
(
rdesc
);
return
(
te_head
);
}
/* given relation and att name, return id of variable */
int
attnameAttNum
(
Relation
rd
,
char
*
a
)
{
int
i
;
for
(
i
=
0
;
i
<
rd
->
rd_rel
->
relnatts
;
i
++
)
if
(
!
namestrcmp
(
&
(
rd
->
rd_att
->
attrs
[
i
]
->
attname
),
a
))
return
(
i
+
1
);
for
(
i
=
0
;
i
<
SPECIALS
;
i
++
)
if
(
!
strcmp
(
special_attr
[
i
].
field
,
a
))
return
(
special_attr
[
i
].
code
);
/* on failure */
elog
(
WARN
,
"Relation %s does not have attribute %s"
,
RelationGetRelationName
(
rd
),
a
);
return
0
;
/* lint */
}
/* Given range variable, return whether attribute of this name
* is a set.
* NOTE the ASSUMPTION here that no system attributes are, or ever
* will be, sets.
*/
bool
attnameIsSet
(
Relation
rd
,
char
*
name
)
{
int
i
;
/* First check if this is a system attribute */
for
(
i
=
0
;
i
<
SPECIALS
;
i
++
)
{
if
(
!
strcmp
(
special_attr
[
i
].
field
,
name
))
{
return
(
false
);
/* no sys attr is a set */
}
}
return
(
get_attisset
(
rd
->
rd_id
,
name
));
}
/*-------------
* given an attribute number and a relation, return its relation name
*/
char
*
attnumAttName
(
Relation
rd
,
int
attrno
)
{
char
*
name
;
int
i
;
if
(
attrno
<
0
)
{
for
(
i
=
0
;
i
<
SPECIALS
;
i
++
)
{
if
(
special_attr
[
i
].
code
==
attrno
)
{
name
=
special_attr
[
i
].
field
;
return
(
name
);
}
}
elog
(
WARN
,
"Illegal attr no %d for relation %s"
,
attrno
,
RelationGetRelationName
(
rd
));
}
else
if
(
attrno
>=
1
&&
attrno
<=
RelationGetNumberOfAttributes
(
rd
))
{
name
=
(
rd
->
rd_att
->
attrs
[
attrno
-
1
]
->
attname
).
data
;
return
(
name
);
}
else
{
elog
(
WARN
,
"Illegal attr no %d for relation %s"
,
attrno
,
RelationGetRelationName
(
rd
));
}
/*
* Shouldn't get here, but we want lint to be happy...
*/
return
(
NULL
);
}
int
attnumAttNelems
(
Relation
rd
,
int
attid
)
{
return
(
rd
->
rd_att
->
attrs
[
attid
-
1
]
->
attnelems
);
}
Oid
attnameTypeId
(
Oid
relid
,
char
*
attrname
)
{
int
attid
;
Oid
vartype
;
Relation
rd
;
rd
=
heap_open
(
relid
);
if
(
!
RelationIsValid
(
rd
))
{
rd
=
heap_openr
(
typeidTypeName
(
relid
));
if
(
!
RelationIsValid
(
rd
))
elog
(
WARN
,
"cannot compute type of att %s for relid %d"
,
attrname
,
relid
);
}
attid
=
attnameAttNum
(
rd
,
attrname
);
/* could elog(WARN) and never return */
vartype
=
attnumTypeId
(
rd
,
attid
);
/*
* close relation we're done with it now
*/
heap_close
(
rd
);
return
(
vartype
);
}
/* given attribute id, return type of that attribute */
/* XXX Special case for pseudo-attributes is a hack */
Oid
attnumTypeId
(
Relation
rd
,
int
attid
)
{
if
(
attid
<
0
)
return
(
typeTypeId
(
typenameType
(
attnum_type
[
-
attid
-
1
])));
/*
* -1 because varattno (where attid comes from) returns one more than
* index
*/
return
(
rd
->
rd_att
->
attrs
[
attid
-
1
]
->
atttypid
);
}
/*
* handleTargetColname -
* use column names from insert
*/
void
handleTargetColname
(
ParseState
*
pstate
,
char
**
resname
,
char
*
refname
,
char
*
colname
)
{
if
(
pstate
->
p_is_insert
)
{
if
(
pstate
->
p_insert_columns
!=
NIL
)
{
Ident
*
id
=
lfirst
(
pstate
->
p_insert_columns
);
*
resname
=
id
->
name
;
pstate
->
p_insert_columns
=
lnext
(
pstate
->
p_insert_columns
);
}
else
elog
(
WARN
,
"insert: more expressions than target columns"
);
}
if
(
pstate
->
p_is_insert
||
pstate
->
p_is_update
)
checkTargetTypes
(
pstate
,
*
resname
,
refname
,
colname
);
}
/*
* checkTargetTypes -
* checks value and target column types
*/
void
checkTargetTypes
(
ParseState
*
pstate
,
char
*
target_colname
,
char
*
refname
,
char
*
colname
)
{
Oid
attrtype_id
,
attrtype_target
;
int
resdomno_id
,
resdomno_target
;
Relation
rd
;
RangeTblEntry
*
rte
;
if
(
target_colname
==
NULL
||
colname
==
NULL
)
return
;
if
(
refname
!=
NULL
)
rte
=
refnameRangeTableEntry
(
pstate
->
p_rtable
,
refname
);
else
{
rte
=
colnameRangeTableEntry
(
pstate
,
colname
);
if
(
rte
==
(
RangeTblEntry
*
)
NULL
)
elog
(
WARN
,
"attribute %s not found"
,
colname
);
refname
=
rte
->
refname
;
}
/*
if (pstate->p_is_insert && rte == pstate->p_target_rangetblentry)
elog(WARN, "%s not available in this context", colname);
*/
rd
=
heap_open
(
rte
->
relid
);
resdomno_id
=
attnameAttNum
(
rd
,
colname
);
attrtype_id
=
attnumTypeId
(
rd
,
resdomno_id
);
resdomno_target
=
attnameAttNum
(
pstate
->
p_target_relation
,
target_colname
);
attrtype_target
=
attnumTypeId
(
pstate
->
p_target_relation
,
resdomno_target
);
if
(
attrtype_id
!=
attrtype_target
)
elog
(
WARN
,
"Type of %s does not match target column %s"
,
colname
,
target_colname
);
if
((
attrtype_id
==
BPCHAROID
||
attrtype_id
==
VARCHAROID
)
&&
rd
->
rd_att
->
attrs
[
resdomno_id
-
1
]
->
attlen
!=
pstate
->
p_target_relation
->
rd_att
->
attrs
[
resdomno_target
-
1
]
->
attlen
)
elog
(
WARN
,
"Length of %s does not match length of target column %s"
,
colname
,
target_colname
);
heap_close
(
rd
);
}
src/backend/parser/parse_target.c
0 → 100644
View file @
4a5b781d
/*-------------------------------------------------------------------------
*
* parse_target.c
* handle target lists
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.1 1997/11/25 22:05:47 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "postgres.h"
#include "catalog/pg_type.h"
#include "nodes/makefuncs.h"
#include "nodes/primnodes.h"
#include "parser/parse_expr.h"
#include "parser/parse_relation.h"
#include "parser/parse_target.h"
#include "parser/parse_node.h"
#include "utils/builtins.h"
#ifdef 0
#include "nodes/nodes.h"
#include "nodes/params.h"
#include "nodes/parsenodes.h"
#include "nodes/relation.h"
#include "parse.h"
/* for AND, OR, etc. */
#include "catalog/pg_aggregate.h"
#include "catalog/pg_proc.h"
#include "utils/elog.h"
#include "utils/palloc.h"
#include "utils/mcxt.h"
#include "utils/syscache.h"
#include "utils/acl.h"
#include "nodes/nodeFuncs.h"
#include "commands/sequence.h"
#include "optimizer/clauses.h"
#include "access/heapam.h"
#include "miscadmin.h"
#include "port-protos.h"
/* strdup() */
#endif
/*
* transformTargetList -
* turns a list of ResTarget's into a list of TargetEntry's
*/
List
*
transformTargetList
(
ParseState
*
pstate
,
List
*
targetlist
)
{
List
*
p_target
=
NIL
;
List
*
tail_p_target
=
NIL
;
while
(
targetlist
!=
NIL
)
{
ResTarget
*
res
=
(
ResTarget
*
)
lfirst
(
targetlist
);
TargetEntry
*
tent
=
makeNode
(
TargetEntry
);
switch
(
nodeTag
(
res
->
val
))
{
case
T_Ident
:
{
Node
*
expr
;
Oid
type_id
;
int
type_len
;
char
*
identname
;
char
*
resname
;
identname
=
((
Ident
*
)
res
->
val
)
->
name
;
handleTargetColname
(
pstate
,
&
res
->
name
,
NULL
,
identname
);
/*
* here we want to look for column names only, not relation
* names (even though they can be stored in Ident nodes, too)
*/
expr
=
transformIdent
(
pstate
,
(
Node
*
)
res
->
val
,
EXPR_COLUMN_FIRST
);
type_id
=
exprType
(
expr
);
type_len
=
typeLen
(
typeidType
(
type_id
));
resname
=
(
res
->
name
)
?
res
->
name
:
identname
;
tent
->
resdom
=
makeResdom
((
AttrNumber
)
pstate
->
p_last_resno
++
,
(
Oid
)
type_id
,
(
Size
)
type_len
,
resname
,
(
Index
)
0
,
(
Oid
)
0
,
0
);
tent
->
expr
=
expr
;
break
;
}
case
T_ParamNo
:
case
T_FuncCall
:
case
T_A_Const
:
case
T_A_Expr
:
{
Node
*
expr
=
transformExpr
(
pstate
,
(
Node
*
)
res
->
val
,
EXPR_COLUMN_FIRST
);
handleTargetColname
(
pstate
,
&
res
->
name
,
NULL
,
NULL
);
/* note indirection has not been transformed */
if
(
pstate
->
p_is_insert
&&
res
->
indirection
!=
NIL
)
{
/* this is an array assignment */
char
*
val
;
char
*
str
,
*
save_str
;
List
*
elt
;
int
i
=
0
,
ndims
;
int
lindx
[
MAXDIM
],
uindx
[
MAXDIM
];
int
resdomno
;
Relation
rd
;
Value
*
constval
;
if
(
exprType
(
expr
)
!=
UNKNOWNOID
||
!
IsA
(
expr
,
Const
))
elog
(
WARN
,
"yyparse: string constant expected"
);
val
=
(
char
*
)
textout
((
struct
varlena
*
)
((
Const
*
)
expr
)
->
constvalue
);
str
=
save_str
=
(
char
*
)
palloc
(
strlen
(
val
)
+
MAXDIM
*
25
+
2
);
foreach
(
elt
,
res
->
indirection
)
{
A_Indices
*
aind
=
(
A_Indices
*
)
lfirst
(
elt
);
aind
->
uidx
=
transformExpr
(
pstate
,
aind
->
uidx
,
EXPR_COLUMN_FIRST
);
if
(
!
IsA
(
aind
->
uidx
,
Const
))
elog
(
WARN
,
"Array Index for Append should be a constant"
);
uindx
[
i
]
=
((
Const
*
)
aind
->
uidx
)
->
constvalue
;
if
(
aind
->
lidx
!=
NULL
)
{
aind
->
lidx
=
transformExpr
(
pstate
,
aind
->
lidx
,
EXPR_COLUMN_FIRST
);
if
(
!
IsA
(
aind
->
lidx
,
Const
))
elog
(
WARN
,
"Array Index for Append should be a constant"
);
lindx
[
i
]
=
((
Const
*
)
aind
->
lidx
)
->
constvalue
;
}
else
{
lindx
[
i
]
=
1
;
}
if
(
lindx
[
i
]
>
uindx
[
i
])
elog
(
WARN
,
"yyparse: lower index cannot be greater than upper index"
);
sprintf
(
str
,
"[%d:%d]"
,
lindx
[
i
],
uindx
[
i
]);
str
+=
strlen
(
str
);
i
++
;
}
sprintf
(
str
,
"=%s"
,
val
);
rd
=
pstate
->
p_target_relation
;
Assert
(
rd
!=
NULL
);
resdomno
=
attnameAttNum
(
rd
,
res
->
name
);
ndims
=
attnumAttNelems
(
rd
,
resdomno
);
if
(
i
!=
ndims
)
elog
(
WARN
,
"yyparse: array dimensions do not match"
);
constval
=
makeNode
(
Value
);
constval
->
type
=
T_String
;
constval
->
val
.
str
=
save_str
;
tent
=
make_targetlist_expr
(
pstate
,
res
->
name
,
(
Node
*
)
make_const
(
constval
),
NULL
);
pfree
(
save_str
);
}
else
{
char
*
colname
=
res
->
name
;
/* this is not an array assignment */
if
(
colname
==
NULL
)
{
/*
* if you're wondering why this is here, look
* at the yacc grammar for why a name can be
* missing. -ay
*/
colname
=
figureColname
(
expr
,
res
->
val
);
}
if
(
res
->
indirection
)
{
List
*
ilist
=
res
->
indirection
;
while
(
ilist
!=
NIL
)
{
A_Indices
*
ind
=
lfirst
(
ilist
);
ind
->
lidx
=
transformExpr
(
pstate
,
ind
->
lidx
,
EXPR_COLUMN_FIRST
);
ind
->
uidx
=
transformExpr
(
pstate
,
ind
->
uidx
,
EXPR_COLUMN_FIRST
);
ilist
=
lnext
(
ilist
);
}
}
res
->
name
=
colname
;
tent
=
make_targetlist_expr
(
pstate
,
res
->
name
,
expr
,
res
->
indirection
);
}
break
;
}
case
T_Attr
:
{
Oid
type_id
;
int
type_len
;
Attr
*
att
=
(
Attr
*
)
res
->
val
;
Node
*
result
;
char
*
attrname
;
char
*
resname
;
Resdom
*
resnode
;
List
*
attrs
=
att
->
attrs
;
/*
* Target item is a single '*', expand all tables (eg.
* SELECT * FROM emp)
*/
if
(
att
->
relname
!=
NULL
&&
!
strcmp
(
att
->
relname
,
"*"
))
{
if
(
tail_p_target
==
NIL
)
p_target
=
tail_p_target
=
expandAllTables
(
pstate
);
else
lnext
(
tail_p_target
)
=
expandAllTables
(
pstate
);
while
(
lnext
(
tail_p_target
)
!=
NIL
)
/* make sure we point to the last target entry */
tail_p_target
=
lnext
(
tail_p_target
);
/*
* skip rest of while loop
*/
targetlist
=
lnext
(
targetlist
);
continue
;
}
/*
* Target item is relation.*, expand the table (eg.
* SELECT emp.*, dname FROM emp, dept)
*/
attrname
=
strVal
(
lfirst
(
att
->
attrs
));
if
(
att
->
attrs
!=
NIL
&&
!
strcmp
(
attrname
,
"*"
))
{
/*
* tail_p_target is the target list we're building
* in the while loop. Make sure we fix it after
* appending more nodes.
*/
if
(
tail_p_target
==
NIL
)
p_target
=
tail_p_target
=
expandAll
(
pstate
,
att
->
relname
,
att
->
relname
,
&
pstate
->
p_last_resno
);
else
lnext
(
tail_p_target
)
=
expandAll
(
pstate
,
att
->
relname
,
att
->
relname
,
&
pstate
->
p_last_resno
);
while
(
lnext
(
tail_p_target
)
!=
NIL
)
/* make sure we point to the last target entry */
tail_p_target
=
lnext
(
tail_p_target
);
/*
* skip the rest of the while loop
*/
targetlist
=
lnext
(
targetlist
);
continue
;
}
/*
* Target item is fully specified: ie.
* relation.attribute
*/
result
=
handleNestedDots
(
pstate
,
att
,
&
pstate
->
p_last_resno
);
handleTargetColname
(
pstate
,
&
res
->
name
,
att
->
relname
,
attrname
);
if
(
att
->
indirection
!=
NIL
)
{
List
*
ilist
=
att
->
indirection
;
while
(
ilist
!=
NIL
)
{
A_Indices
*
ind
=
lfirst
(
ilist
);
ind
->
lidx
=
transformExpr
(
pstate
,
ind
->
lidx
,
EXPR_COLUMN_FIRST
);
ind
->
uidx
=
transformExpr
(
pstate
,
ind
->
uidx
,
EXPR_COLUMN_FIRST
);
ilist
=
lnext
(
ilist
);
}
result
=
(
Node
*
)
make_array_ref
(
result
,
att
->
indirection
);
}
type_id
=
exprType
(
result
);
type_len
=
typeLen
(
typeidType
(
type_id
));
/* move to last entry */
while
(
lnext
(
attrs
)
!=
NIL
)
attrs
=
lnext
(
attrs
);
resname
=
(
res
->
name
)
?
res
->
name
:
strVal
(
lfirst
(
attrs
));
resnode
=
makeResdom
((
AttrNumber
)
pstate
->
p_last_resno
++
,
(
Oid
)
type_id
,
(
Size
)
type_len
,
resname
,
(
Index
)
0
,
(
Oid
)
0
,
0
);
tent
->
resdom
=
resnode
;
tent
->
expr
=
result
;
break
;
}
default:
/* internal error */
elog
(
WARN
,
"internal error: do not know how to transform targetlist"
);
break
;
}
if
(
p_target
==
NIL
)
{
p_target
=
tail_p_target
=
lcons
(
tent
,
NIL
);
}
else
{
lnext
(
tail_p_target
)
=
lcons
(
tent
,
NIL
);
tail_p_target
=
lnext
(
tail_p_target
);
}
targetlist
=
lnext
(
targetlist
);
}
return
p_target
;
}
/*
* make_targetlist_expr -
* make a TargetEntry from an expression
*
* arrayRef is a list of transformed A_Indices
*/
TargetEntry
*
make_targetlist_expr
(
ParseState
*
pstate
,
char
*
colname
,
Node
*
expr
,
List
*
arrayRef
)
{
Oid
type_id
,
attrtype
;
int
type_len
,
attrlen
;
int
resdomno
;
Relation
rd
;
bool
attrisset
;
TargetEntry
*
tent
;
Resdom
*
resnode
;
if
(
expr
==
NULL
)
elog
(
WARN
,
"make_targetlist_expr: invalid use of NULL expression"
);
type_id
=
exprType
(
expr
);
if
(
type_id
==
InvalidOid
)
{
type_len
=
0
;
}
else
type_len
=
typeLen
(
typeidType
(
type_id
));
/* I have no idea what the following does! */
/* It appears to process target columns that will be receiving results */
if
(
pstate
->
p_is_insert
||
pstate
->
p_is_update
)
{
/*
* append or replace query -- append, replace work only on one
* relation, so multiple occurence of same resdomno is bogus
*/
rd
=
pstate
->
p_target_relation
;
Assert
(
rd
!=
NULL
);
resdomno
=
attnameAttNum
(
rd
,
colname
);
attrisset
=
attnameIsSet
(
rd
,
colname
);
attrtype
=
attnumTypeId
(
rd
,
resdomno
);
if
((
arrayRef
!=
NIL
)
&&
(
lfirst
(
arrayRef
)
==
NIL
))
attrtype
=
GetArrayElementType
(
attrtype
);
if
(
attrtype
==
BPCHAROID
||
attrtype
==
VARCHAROID
)
{
attrlen
=
rd
->
rd_att
->
attrs
[
resdomno
-
1
]
->
attlen
;
}
else
{
attrlen
=
typeLen
(
typeidType
(
attrtype
));
}
#if 0
if (Input_is_string && Typecast_ok)
{
Datum val;
if (type_id == typeTypeId(type("unknown")))
{
val = (Datum) textout((struct varlena *)
((Const) lnext(expr))->constvalue);
}
else
{
val = ((Const) lnext(expr))->constvalue;
}
if (attrisset)
{
lnext(expr) = makeConst(attrtype,
attrlen,
val,
false,
true,
true, /* is set */
false);
}
else
{
lnext(expr) =
makeConst(attrtype,
attrlen,
(Datum) fmgr(typeidRetinfunc(attrtype),
val, typeidTypElem(attrtype), -1),
false,
true /* Maybe correct-- 80% chance */ ,
false, /* is not a set */
false);
}
}
else if ((Typecast_ok) && (attrtype != type_id))
{
lnext(expr) =
parser_typecast2(expr, typeidType(attrtype));
}
else if (attrtype != type_id)
{
if ((attrtype == INT2OID) && (type_id == INT4OID))
lfirst(expr) = lispInteger(INT2OID); /* handle CASHOID too */
else if ((attrtype == FLOAT4OID) && (type_id == FLOAT8OID))
lfirst(expr) = lispInteger(FLOAT4OID);
else
elog(WARN, "unequal type in tlist : %s \n", colname);
}
Input_is_string = false;
Input_is_integer = false;
Typecast_ok = true;
#endif
if
(
attrtype
!=
type_id
)
{
if
(
IsA
(
expr
,
Const
))
{
/* try to cast the constant */
if
(
arrayRef
&&
!
(((
A_Indices
*
)
lfirst
(
arrayRef
))
->
lidx
))
{
/* updating a single item */
Oid
typelem
=
typeidTypElem
(
attrtype
);
expr
=
(
Node
*
)
parser_typecast2
(
expr
,
type_id
,
typeidType
(
typelem
),
attrlen
);
}
else
expr
=
(
Node
*
)
parser_typecast2
(
expr
,
type_id
,
typeidType
(
attrtype
),
attrlen
);
}
else
{
/* currently, we can't handle casting of expressions */
elog
(
WARN
,
"parser: attribute '%s' is of type '%s' but expression is of type '%s'"
,
colname
,
typeidTypeName
(
attrtype
),
typeidTypeName
(
type_id
));
}
}
if
(
arrayRef
!=
NIL
)
{
Expr
*
target_expr
;
Attr
*
att
=
makeNode
(
Attr
);
List
*
ar
=
arrayRef
;
List
*
upperIndexpr
=
NIL
;
List
*
lowerIndexpr
=
NIL
;
att
->
relname
=
pstrdup
(
RelationGetRelationName
(
rd
)
->
data
);
att
->
attrs
=
lcons
(
makeString
(
colname
),
NIL
);
target_expr
=
(
Expr
*
)
handleNestedDots
(
pstate
,
att
,
&
pstate
->
p_last_resno
);
while
(
ar
!=
NIL
)
{
A_Indices
*
ind
=
lfirst
(
ar
);
if
(
lowerIndexpr
||
(
!
upperIndexpr
&&
ind
->
lidx
))
{
/*
* XXX assume all lowerIndexpr is non-null in this
* case
*/
lowerIndexpr
=
lappend
(
lowerIndexpr
,
ind
->
lidx
);
}
upperIndexpr
=
lappend
(
upperIndexpr
,
ind
->
uidx
);
ar
=
lnext
(
ar
);
}
expr
=
(
Node
*
)
make_array_set
(
target_expr
,
upperIndexpr
,
lowerIndexpr
,
(
Expr
*
)
expr
);
attrtype
=
attnumTypeId
(
rd
,
resdomno
);
attrlen
=
typeLen
(
typeidType
(
attrtype
));
}
}
else
{
resdomno
=
pstate
->
p_last_resno
++
;
attrtype
=
type_id
;
attrlen
=
type_len
;
}
tent
=
makeNode
(
TargetEntry
);
resnode
=
makeResdom
((
AttrNumber
)
resdomno
,
(
Oid
)
attrtype
,
(
Size
)
attrlen
,
colname
,
(
Index
)
0
,
(
Oid
)
0
,
0
);
tent
->
resdom
=
resnode
;
tent
->
expr
=
expr
;
return
tent
;
}
/*
* makeTargetNames -
* generate a list of column names if not supplied or
* test supplied column names to make sure they are in target table
* (used exclusively for inserts)
*/
List
*
makeTargetNames
(
ParseState
*
pstate
,
List
*
cols
)
{
List
*
tl
=
NULL
;
/* Generate ResTarget if not supplied */
if
(
cols
==
NIL
)
{
int
numcol
;
int
i
;
AttributeTupleForm
*
attr
=
pstate
->
p_target_relation
->
rd_att
->
attrs
;
numcol
=
pstate
->
p_target_relation
->
rd_rel
->
relnatts
;
for
(
i
=
0
;
i
<
numcol
;
i
++
)
{
Ident
*
id
=
makeNode
(
Ident
);
id
->
name
=
palloc
(
NAMEDATALEN
);
StrNCpy
(
id
->
name
,
attr
[
i
]
->
attname
.
data
,
NAMEDATALEN
);
id
->
indirection
=
NIL
;
id
->
isRel
=
false
;
if
(
tl
==
NIL
)
cols
=
tl
=
lcons
(
id
,
NIL
);
else
{
lnext
(
tl
)
=
lcons
(
id
,
NIL
);
tl
=
lnext
(
tl
);
}
}
}
else
{
foreach
(
tl
,
cols
)
{
List
*
nxt
;
char
*
name
=
((
Ident
*
)
lfirst
(
tl
))
->
name
;
/* elog on failure */
attnameAttNum
(
pstate
->
p_target_relation
,
name
);
foreach
(
nxt
,
lnext
(
tl
))
if
(
!
strcmp
(
name
,
((
Ident
*
)
lfirst
(
nxt
))
->
name
))
elog
(
WARN
,
"Attribute '%s' should be specified only once"
,
name
);
}
}
return
cols
;
}
/*
* expandAllTables -
* turns '*' (in the target list) into a list of attributes
* (of all relations in the range table)
*/
List
*
expandAllTables
(
ParseState
*
pstate
)
{
List
*
target
=
NIL
;
List
*
legit_rtable
=
NIL
;
List
*
rt
,
*
rtable
;
rtable
=
pstate
->
p_rtable
;
if
(
pstate
->
p_is_rule
)
{
/*
* skip first two entries, "*new*" and "*current*"
*/
rtable
=
lnext
(
lnext
(
pstate
->
p_rtable
));
}
/* this should not happen */
if
(
rtable
==
NULL
)
elog
(
WARN
,
"cannot expand: null p_rtable"
);
/*
* go through the range table and make a list of range table entries
* which we will expand.
*/
foreach
(
rt
,
rtable
)
{
RangeTblEntry
*
rte
=
lfirst
(
rt
);
/*
* we only expand those specify in the from clause. (This will
* also prevent us from using the wrong table in inserts: eg.
* tenk2 in "insert into tenk2 select * from tenk1;")
*/
if
(
!
rte
->
inFromCl
)
continue
;
legit_rtable
=
lappend
(
legit_rtable
,
rte
);
}
foreach
(
rt
,
legit_rtable
)
{
RangeTblEntry
*
rte
=
lfirst
(
rt
);
List
*
temp
=
target
;
if
(
temp
==
NIL
)
target
=
expandAll
(
pstate
,
rte
->
relname
,
rte
->
refname
,
&
pstate
->
p_last_resno
);
else
{
while
(
temp
!=
NIL
&&
lnext
(
temp
)
!=
NIL
)
temp
=
lnext
(
temp
);
lnext
(
temp
)
=
expandAll
(
pstate
,
rte
->
relname
,
rte
->
refname
,
&
pstate
->
p_last_resno
);
}
}
return
target
;
}
/*
* figureColname -
* if the name of the resulting column is not specified in the target
* list, we have to guess.
*
*/
char
*
figureColname
(
Node
*
expr
,
Node
*
resval
)
{
switch
(
nodeTag
(
expr
))
{
case
T_Aggreg
:
return
(
char
*
)
/* XXX */
((
Aggreg
*
)
expr
)
->
aggname
;
case
T_Expr
:
if
(((
Expr
*
)
expr
)
->
opType
==
FUNC_EXPR
)
{
if
(
nodeTag
(
resval
)
==
T_FuncCall
)
return
((
FuncCall
*
)
resval
)
->
funcname
;
}
break
;
default:
break
;
}
return
"?column?"
;
}
src/backend/parser/parse_type.c
0 → 100644
View file @
4a5b781d
/*-------------------------------------------------------------------------
*
* parse_type.h
* handle type operations for parser
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_type.c,v 1.1 1997/11/25 22:05:51 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include <string.h>
#include "postgres.h"
#include "fmgr.h"
#include <catalog/pg_type.h>
#include <parser/parse_target.h>
#include <parser/parse_type.h>
#include "utils/syscache.h"
#ifdef 0
#include "lib/dllist.h"
#include "utils/datum.h"
#include "utils/builtins.h"
#include "utils/elog.h"
#include "utils/palloc.h"
#include "nodes/pg_list.h"
#include "nodes/parsenodes.h"
#include "catalog/catname.h"
#include "catalog/pg_inherits.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_proc.h"
#include "catalog/indexing.h"
#include "catalog/catname.h"
#include "access/skey.h"
#include "access/relscan.h"
#include "access/tupdesc.h"
#include "access/htup.h"
#include "access/heapam.h"
#include "access/genam.h"
#include "access/itup.h"
#include "access/tupmacs.h"
#include "storage/buf.h"
#include "storage/bufmgr.h"
#include "utils/lsyscache.h"
#include "storage/lmgr.h"
#include "port-protos.h"
/* strdup() */
#endif
/* check to see if a type id is valid,
* returns true if it is. By using this call before calling
* typeidType or typeidTypeName, more meaningful error messages
* can be produced because the caller typically has more context of
* what's going on - jolly
*/
bool
typeidIsValid
(
Oid
id
)
{
return
(
SearchSysCacheTuple
(
TYPOID
,
ObjectIdGetDatum
(
id
),
0
,
0
,
0
)
!=
NULL
);
}
/* return a type name, given a typeid */
char
*
typeidTypeName
(
Oid
id
)
{
HeapTuple
tup
;
TypeTupleForm
typetuple
;
if
(
!
(
tup
=
SearchSysCacheTuple
(
TYPOID
,
ObjectIdGetDatum
(
id
),
0
,
0
,
0
)))
{
elog
(
WARN
,
"type id lookup of %ud failed"
,
id
);
return
(
NULL
);
}
typetuple
=
(
TypeTupleForm
)
GETSTRUCT
(
tup
);
return
(
typetuple
->
typname
).
data
;
}
/* return a Type structure, given an typid */
Type
typeidType
(
Oid
id
)
{
HeapTuple
tup
;
if
(
!
(
tup
=
SearchSysCacheTuple
(
TYPOID
,
ObjectIdGetDatum
(
id
),
0
,
0
,
0
)))
{
elog
(
WARN
,
"type id lookup of %ud failed"
,
id
);
return
(
NULL
);
}
return
((
Type
)
tup
);
}
/* return a Type structure, given type name */
Type
typenameType
(
char
*
s
)
{
HeapTuple
tup
;
if
(
s
==
NULL
)
{
elog
(
WARN
,
"type(): Null type"
);
}
if
(
!
(
tup
=
SearchSysCacheTuple
(
TYPNAME
,
PointerGetDatum
(
s
),
0
,
0
,
0
)))
{
elog
(
WARN
,
"type name lookup of %s failed"
,
s
);
}
return
((
Type
)
tup
);
}
/* given type, return the type OID */
Oid
typeTypeId
(
Type
tp
)
{
if
(
tp
==
NULL
)
elog
(
WARN
,
"typeTypeId() called with NULL type struct"
);
return
(
tp
->
t_oid
);
}
/* given type (as type struct), return the length of type */
int16
typeLen
(
Type
t
)
{
TypeTupleForm
typ
;
typ
=
(
TypeTupleForm
)
GETSTRUCT
(
t
);
return
(
typ
->
typlen
);
}
/* given type (as type struct), return the value of its 'byval' attribute.*/
bool
typeByVal
(
Type
t
)
{
TypeTupleForm
typ
;
typ
=
(
TypeTupleForm
)
GETSTRUCT
(
t
);
return
(
typ
->
typbyval
);
}
/* given type (as type struct), return the name of type */
char
*
typeTypeName
(
Type
t
)
{
TypeTupleForm
typ
;
typ
=
(
TypeTupleForm
)
GETSTRUCT
(
t
);
return
(
typ
->
typname
).
data
;
}
/* given a type, return its typetype ('c' for 'c'atalog types) */
char
typeTypeFlag
(
Type
t
)
{
TypeTupleForm
typ
;
typ
=
(
TypeTupleForm
)
GETSTRUCT
(
t
);
return
(
typ
->
typtype
);
}
/* Given a type structure and a string, returns the internal form of
that string */
char
*
stringTypeString
(
Type
tp
,
char
*
string
,
int
typlen
)
{
Oid
op
;
Oid
typelem
;
op
=
((
TypeTupleForm
)
GETSTRUCT
(
tp
))
->
typinput
;
typelem
=
((
TypeTupleForm
)
GETSTRUCT
(
tp
))
->
typelem
;
/* XXX - used for array_in */
/* typlen is for bpcharin() and varcharin() */
return
((
char
*
)
fmgr
(
op
,
string
,
typelem
,
typlen
));
}
/* Given a type id, returns the out-conversion function of the type */
Oid
typeidRetoutfunc
(
Oid
type_id
)
{
HeapTuple
typeTuple
;
TypeTupleForm
type
;
Oid
outfunc
;
typeTuple
=
SearchSysCacheTuple
(
TYPOID
,
ObjectIdGetDatum
(
type_id
),
0
,
0
,
0
);
if
(
!
HeapTupleIsValid
(
typeTuple
))
elog
(
WARN
,
"typeidRetoutfunc: Invalid type - oid = %u"
,
type_id
);
type
=
(
TypeTupleForm
)
GETSTRUCT
(
typeTuple
);
outfunc
=
type
->
typoutput
;
return
(
outfunc
);
}
Oid
typeidTypeRelid
(
Oid
type_id
)
{
HeapTuple
typeTuple
;
TypeTupleForm
type
;
Oid
infunc
;
typeTuple
=
SearchSysCacheTuple
(
TYPOID
,
ObjectIdGetDatum
(
type_id
),
0
,
0
,
0
);
if
(
!
HeapTupleIsValid
(
typeTuple
))
elog
(
WARN
,
"typeidTypeRelid: Invalid type - oid = %u"
,
type_id
);
type
=
(
TypeTupleForm
)
GETSTRUCT
(
typeTuple
);
infunc
=
type
->
typrelid
;
return
(
infunc
);
}
Oid
typeTypeRelid
(
Type
typ
)
{
TypeTupleForm
typtup
;
typtup
=
(
TypeTupleForm
)
GETSTRUCT
(
typ
);
return
(
typtup
->
typrelid
);
}
Oid
typeidTypElem
(
Oid
type_id
)
{
HeapTuple
typeTuple
;
TypeTupleForm
type
;
if
(
!
(
typeTuple
=
SearchSysCacheTuple
(
TYPOID
,
ObjectIdGetDatum
(
type_id
),
0
,
0
,
0
)))
{
elog
(
WARN
,
"type id lookup of %u failed"
,
type_id
);
}
type
=
(
TypeTupleForm
)
GETSTRUCT
(
typeTuple
);
return
(
type
->
typelem
);
}
/* Given the attribute type of an array return the arrtribute type of
an element of the array */
Oid
GetArrayElementType
(
Oid
typearray
)
{
HeapTuple
type_tuple
;
TypeTupleForm
type_struct_array
;
type_tuple
=
SearchSysCacheTuple
(
TYPOID
,
ObjectIdGetDatum
(
typearray
),
0
,
0
,
0
);
if
(
!
HeapTupleIsValid
(
type_tuple
))
elog
(
WARN
,
"GetArrayElementType: Cache lookup failed for type %d"
,
typearray
);
/* get the array type struct from the type tuple */
type_struct_array
=
(
TypeTupleForm
)
GETSTRUCT
(
type_tuple
);
if
(
type_struct_array
->
typelem
==
InvalidOid
)
{
elog
(
WARN
,
"GetArrayElementType: type %s is not an array"
,
(
Name
)
&
(
type_struct_array
->
typname
.
data
[
0
]));
}
return
(
type_struct_array
->
typelem
);
}
/* Given a type id, returns the in-conversion function of the type */
Oid
typeidRetinfunc
(
Oid
type_id
)
{
HeapTuple
typeTuple
;
TypeTupleForm
type
;
Oid
infunc
;
typeTuple
=
SearchSysCacheTuple
(
TYPOID
,
ObjectIdGetDatum
(
type_id
),
0
,
0
,
0
);
if
(
!
HeapTupleIsValid
(
typeTuple
))
elog
(
WARN
,
"typeidRetinfunc: Invalid type - oid = %u"
,
type_id
);
type
=
(
TypeTupleForm
)
GETSTRUCT
(
typeTuple
);
infunc
=
type
->
typinput
;
return
(
infunc
);
}
#ifdef NOT_USED
char
FindDelimiter
(
char
*
typename
)
{
char
delim
;
HeapTuple
typeTuple
;
TypeTupleForm
type
;
if
(
!
(
typeTuple
=
SearchSysCacheTuple
(
TYPNAME
,
PointerGetDatum
(
typename
),
0
,
0
,
0
)))
{
elog
(
WARN
,
"type name lookup of %s failed"
,
typename
);
}
type
=
(
TypeTupleForm
)
GETSTRUCT
(
typeTuple
);
delim
=
type
->
typdelim
;
return
(
delim
);
}
#endif
src/backend/parser/parser.c
View file @
4a5b781d
...
@@ -6,7 +6,7 @@
...
@@ -6,7 +6,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parser.c,v 1.2
8 1997/11/20 23:22:24
momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/parser.c,v 1.2
9 1997/11/25 22:05:52
momjian Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -14,9 +14,20 @@
...
@@ -14,9 +14,20 @@
#include <stdio.h>
#include <stdio.h>
#include "postgres.h"
#include "postgres.h"
#include "nodes/pg_list.h"
#include "parser/parser.h"
#include "parser/analyze.h"
#include "parser/parse_node.h"
void
init_io
();
/* from scan.l */
void
parser_init
(
Oid
*
typev
,
int
nargs
);
/* from gram.y */
int
yyparse
();
/* from gram.c */
#ifdef 0
#include "parser/parse.h"
#include "parser/gramparse.h"
#include "parser/gramparse.h"
#include "parser/parse_query.h"
#include "utils/palloc.h"
#include "utils/palloc.h"
#endif
char
*
parseString
;
/* the char* which holds the string to be
char
*
parseString
;
/* the char* which holds the string to be
* parsed */
* parsed */
...
@@ -103,10 +114,10 @@ static void
...
@@ -103,10 +114,10 @@ static void
define_sets
(
Node
*
clause
)
define_sets
(
Node
*
clause
)
{
{
Oid
setoid
;
Oid
setoid
;
Type
t
=
type
(
"oid"
);
Type
t
=
type
idType
(
OIDOID
);
Oid
typeoid
=
type
i
d
(
t
);
Oid
typeoid
=
type
TypeI
d
(
t
);
Size
oidsize
=
t
l
en
(
t
);
Size
oidsize
=
t
ypeL
en
(
t
);
bool
oidbyval
=
t
byv
al
(
t
);
bool
oidbyval
=
t
ypeByV
al
(
t
);
if
(
clause
==
NULL
)
if
(
clause
==
NULL
)
{
{
...
@@ -125,11 +136,11 @@ define_sets(Node *clause)
...
@@ -125,11 +136,11 @@ define_sets(Node *clause)
return
;
return
;
}
}
setoid
=
SetDefine
(((
Const
*
)
clause
)
->
constvalue
,
setoid
=
SetDefine
(((
Const
*
)
clause
)
->
constvalue
,
get_id_typn
ame
(((
Const
*
)
clause
)
->
consttype
));
typeidTypeN
ame
(((
Const
*
)
clause
)
->
consttype
));
set_constvalue
((
Const
)
clause
,
setoid
);
set_constvalue
((
Const
)
clause
,
setoid
);
set_consttype
((
Const
)
clause
,
typeoid
);
set_consttype
((
Const
)
clause
,
typeoid
);
set_constlen
((
Const
)
clause
,
oidsize
);
set_constlen
((
Const
)
clause
,
oidsize
);
set_const
byv
al
((
Const
)
clause
,
oidbyval
);
set_const
ypeByV
al
((
Const
)
clause
,
oidbyval
);
}
}
else
if
(
IsA
(
clause
,
Iter
))
else
if
(
IsA
(
clause
,
Iter
))
{
{
...
@@ -173,6 +184,5 @@ define_sets(Node *clause)
...
@@ -173,6 +184,5 @@ define_sets(Node *clause)
define_sets
(
get_rightop
(
clause
));
define_sets
(
get_rightop
(
clause
));
}
}
}
}
#endif
#endif
src/backend/parser/scansup.c
View file @
4a5b781d
...
@@ -8,7 +8,7 @@
...
@@ -8,7 +8,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/scansup.c,v 1.
7 1997/09/08 02:25:22
momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/scansup.c,v 1.
8 1997/11/25 22:05:55
momjian Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -17,7 +17,6 @@
...
@@ -17,7 +17,6 @@
#include <ctype.h>
#include <ctype.h>
#include <string.h>
#include <string.h>
#include "c.h"
#include "postgres.h"
#include "postgres.h"
#include "miscadmin.h"
#include "miscadmin.h"
#include "utils/elog.h"
#include "utils/elog.h"
...
...
src/backend/rewrite/rewriteDefine.c
View file @
4a5b781d
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.
7 1997/10/25 05:37:07 thomas
Exp $
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.
8 1997/11/25 22:06:04 momjian
Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -23,7 +23,8 @@
...
@@ -23,7 +23,8 @@
#include "utils/lsyscache.h"
/* for get_typlen */
#include "utils/lsyscache.h"
/* for get_typlen */
#include "nodes/pg_list.h"
/* for Lisp support */
#include "nodes/pg_list.h"
/* for Lisp support */
#include "nodes/parsenodes.h"
#include "nodes/parsenodes.h"
#include "parser/catalog_utils.h"
#include "parser/parse_relation.h"
#include "rewrite/locks.h"
#include "rewrite/locks.h"
#include "rewrite/rewriteDefine.h"
#include "rewrite/rewriteDefine.h"
#include "rewrite/rewriteRemove.h"
#include "rewrite/rewriteRemove.h"
...
@@ -107,7 +108,7 @@ InsertRule(char *rulname,
...
@@ -107,7 +108,7 @@ InsertRule(char *rulname,
if
(
evslot
==
NULL
)
if
(
evslot
==
NULL
)
evslot_index
=
-
1
;
evslot_index
=
-
1
;
else
else
evslot_index
=
varattno
(
eventrel
,
(
char
*
)
evslot
);
evslot_index
=
attnameAttNum
(
eventrel
,
(
char
*
)
evslot
);
heap_close
(
eventrel
);
heap_close
(
eventrel
);
if
(
evinstead
)
if
(
evinstead
)
...
@@ -221,8 +222,8 @@ DefineQueryRewrite(RuleStmt *stmt)
...
@@ -221,8 +222,8 @@ DefineQueryRewrite(RuleStmt *stmt)
}
}
else
else
{
{
event_attno
=
varattno
(
event_relation
,
eslot_string
);
event_attno
=
attnameAttNum
(
event_relation
,
eslot_string
);
event_attype
=
att
_typei
d
(
event_relation
,
event_attno
);
event_attype
=
att
numTypeI
d
(
event_relation
,
event_attno
);
}
}
heap_close
(
event_relation
);
heap_close
(
event_relation
);
...
...
src/backend/tcop/aclchk.c
View file @
4a5b781d
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/Attic/aclchk.c,v 1.
19 1997/11/24 05:08:47
momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/tcop/Attic/aclchk.c,v 1.
20 1997/11/25 22:06:08
momjian Exp $
*
*
* NOTES
* NOTES
* See acl.h.
* See acl.h.
...
@@ -31,10 +31,12 @@
...
@@ -31,10 +31,12 @@
#include "catalog/pg_operator.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_aggregate.h"
#include "catalog/pg_aggregate.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "catalog/pg_user.h"
#include "catalog/pg_user.h"
#include "parser/parse_agg.h"
#include "parser/parse_func.h"
#include "utils/syscache.h"
#include "utils/syscache.h"
#include "utils/tqual.h"
#include "utils/tqual.h"
#include "parser/catalog_utils.h"
#include "fmgr.h"
#include "fmgr.h"
static
int32
aclcheck
(
Acl
*
acl
,
AclId
id
,
AclIdType
idtype
,
AclMode
mode
);
static
int32
aclcheck
(
Acl
*
acl
,
AclId
id
,
AclIdType
idtype
,
AclMode
mode
);
...
...
src/backend/tcop/postgres.c
View file @
4a5b781d
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.5
4 1997/11/10 15:24:55 thomas
Exp $
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.5
5 1997/11/25 22:06:14 momjian
Exp $
*
*
* NOTES
* NOTES
* this is the "main" module of the postgres backend and
* this is the "main" module of the postgres backend and
...
@@ -45,11 +45,10 @@
...
@@ -45,11 +45,10 @@
#include "lib/dllist.h"
#include "lib/dllist.h"
#include "parser/catalog_utils.h"
#include "parser/parse_query.h"
/* for MakeTimeRange() */
#include "commands/async.h"
#include "commands/async.h"
#include "tcop/tcopprot.h"
/* where declarations for this file go */
#include "tcop/tcopprot.h"
/* where declarations for this file go */
#include "optimizer/planner.h"
#include "optimizer/planner.h"
#include "parser/parser.h"
#include "tcop/tcopprot.h"
#include "tcop/tcopprot.h"
#include "tcop/tcopdebug.h"
#include "tcop/tcopdebug.h"
...
@@ -1341,7 +1340,7 @@ PostgresMain(int argc, char *argv[])
...
@@ -1341,7 +1340,7 @@ PostgresMain(int argc, char *argv[])
if
(
IsUnderPostmaster
==
false
)
if
(
IsUnderPostmaster
==
false
)
{
{
puts
(
"
\n
POSTGRES backend interactive interface"
);
puts
(
"
\n
POSTGRES backend interactive interface"
);
puts
(
"$Revision: 1.5
4 $ $Date: 1997/11/10 15:24:55
$"
);
puts
(
"$Revision: 1.5
5 $ $Date: 1997/11/25 22:06:14
$"
);
}
}
/* ----------------
/* ----------------
...
...
src/include/executor/spi.h
View file @
4a5b781d
...
@@ -15,7 +15,6 @@
...
@@ -15,7 +15,6 @@
#include "nodes/execnodes.h"
#include "nodes/execnodes.h"
#include "nodes/plannodes.h"
#include "nodes/plannodes.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_proc.h"
#include "parser/parse_query.h"
#include "tcop/pquery.h"
#include "tcop/pquery.h"
#include "tcop/tcopprot.h"
#include "tcop/tcopprot.h"
#include "tcop/utility.h"
#include "tcop/utility.h"
...
...
src/include/nodes/nodeFuncs.h
View file @
4a5b781d
...
@@ -6,13 +6,16 @@
...
@@ -6,13 +6,16 @@
*
*
* Copyright (c) 1994, Regents of the University of California
* Copyright (c) 1994, Regents of the University of California
*
*
* $Id: nodeFuncs.h,v 1.
5 1997/09/08 21:52:45
momjian Exp $
* $Id: nodeFuncs.h,v 1.
6 1997/11/25 22:06:30
momjian Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
#ifndef NODEFUNCS_H
#ifndef NODEFUNCS_H
#define NODEFUNCS_H
#define NODEFUNCS_H
#include <nodes/nodes.h>
#include <nodes/primnodes.h>
extern
bool
single_node
(
Node
*
node
);
extern
bool
single_node
(
Node
*
node
);
extern
bool
var_is_outer
(
Var
*
var
);
extern
bool
var_is_outer
(
Var
*
var
);
extern
bool
var_is_rel
(
Var
*
var
);
extern
bool
var_is_rel
(
Var
*
var
);
...
...
src/include/optimizer/planner.h
View file @
4a5b781d
...
@@ -6,7 +6,7 @@
...
@@ -6,7 +6,7 @@
*
*
* Copyright (c) 1994, Regents of the University of California
* Copyright (c) 1994, Regents of the University of California
*
*
* $Id: planner.h,v 1.
5 1997/09/08 21:53:29
momjian Exp $
* $Id: planner.h,v 1.
6 1997/11/25 22:06:37
momjian Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -16,6 +16,8 @@
...
@@ -16,6 +16,8 @@
/*
/*
*/
*/
#include <parser/parse_node.h>
extern
Plan
*
planner
(
Query
*
parse
);
extern
Plan
*
planner
(
Query
*
parse
);
extern
void
pg_checkretval
(
Oid
rettype
,
QueryTreeList
*
querytree_list
);
extern
void
pg_checkretval
(
Oid
rettype
,
QueryTreeList
*
querytree_list
);
...
...
src/include/parser/analyze.h
0 → 100644
View file @
4a5b781d
/*-------------------------------------------------------------------------
*
* analyze.h
*
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: analyze.h,v 1.1 1997/11/25 22:06:47 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef ANALYZE_H
#define ANALYZE_H
#include <parser/parse_node.h>
QueryTreeList
*
parse_analyze
(
List
*
pl
);
#endif
/* ANALYZE_H */
src/include/parser/catalog_utils.h
deleted
100644 → 0
View file @
3aff4011
/*-------------------------------------------------------------------------
*
* catalog_utils.h--
*
*
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: catalog_utils.h,v 1.13 1997/09/08 21:53:35 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef CATALOG_UTILS_H
#define CATALOG_UTILS_H
#include <catalog/pg_type.h>
#include <access/htup.h>
typedef
HeapTuple
Type
;
typedef
HeapTuple
Operator
;
extern
Type
get_id_type
(
Oid
id
);
extern
char
*
get_id_typname
(
Oid
id
);
extern
Type
type
(
char
*
);
extern
Oid
att_typeid
(
Relation
rd
,
int
attid
);
extern
int
att_attnelems
(
Relation
rd
,
int
attid
);
extern
Oid
typeid
(
Type
tp
);
extern
int16
tlen
(
Type
t
);
extern
bool
tbyval
(
Type
t
);
extern
char
*
tname
(
Type
t
);
extern
int
tbyvalue
(
Type
t
);
extern
Oid
oprid
(
Operator
op
);
extern
Operator
oper
(
char
*
op
,
Oid
arg1
,
Oid
arg2
,
bool
noWarnings
);
extern
Operator
right_oper
(
char
*
op
,
Oid
arg
);
extern
Operator
left_oper
(
char
*
op
,
Oid
arg
);
extern
int
varattno
(
Relation
rd
,
char
*
a
);
extern
bool
varisset
(
Relation
rd
,
char
*
name
);
extern
int
nf_varattno
(
Relation
rd
,
char
*
a
);
extern
char
*
getAttrName
(
Relation
rd
,
int
attrno
);
extern
char
*
instr2
(
Type
tp
,
char
*
string
,
int
typlen
);
extern
Oid
GetArrayElementType
(
Oid
typearray
);
extern
Oid
funcid_get_rettype
(
Oid
funcid
);
extern
bool
func_get_detail
(
char
*
funcname
,
int
nargs
,
Oid
*
oid_array
,
Oid
*
funcid
,
Oid
*
rettype
,
bool
*
retset
,
Oid
**
true_typeids
);
extern
Oid
typeid_get_retinfunc
(
Oid
type_id
);
extern
Oid
typeid_get_retoutfunc
(
Oid
type_id
);
extern
Oid
typeid_get_relid
(
Oid
type_id
);
extern
Oid
get_typrelid
(
Type
typ
);
extern
Oid
get_typelem
(
Oid
type_id
);
extern
void
func_error
(
char
*
caller
,
char
*
funcname
,
int
nargs
,
Oid
*
argtypes
);
extern
void
agg_error
(
char
*
caller
,
char
*
aggname
,
Oid
basetypeID
);
#endif
/* CATALOG_UTILS_H */
src/include/parser/parse_agg.h
0 → 100644
View file @
4a5b781d
/*-------------------------------------------------------------------------
*
* parse_agg.h
*
*
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: parse_agg.h,v 1.1 1997/11/25 22:06:53 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef PARSE_AGG_H
#define PARSE_AGG_H
#include <nodes/nodes.h>
#include <nodes/parsenodes.h>
#include <nodes/primnodes.h>
#include <parser/parse_node.h>
void
AddAggToParseState
(
ParseState
*
pstate
,
Aggreg
*
aggreg
);
void
finalizeAggregates
(
ParseState
*
pstate
,
Query
*
qry
);
bool
contain_agg_clause
(
Node
*
clause
);
bool
exprIsAggOrGroupCol
(
Node
*
expr
,
List
*
groupClause
);
bool
tleIsAggOrGroupCol
(
TargetEntry
*
tle
,
List
*
groupClause
);
void
parseCheckAggregates
(
ParseState
*
pstate
,
Query
*
qry
);
Aggreg
*
ParseAgg
(
char
*
aggname
,
Oid
basetype
,
Node
*
target
);
void
agg_error
(
char
*
caller
,
char
*
aggname
,
Oid
basetypeID
);
#endif
/* PARSE_AGG_H */
src/include/parser/parse_clause.h
0 → 100644
View file @
4a5b781d
/*-------------------------------------------------------------------------
*
* parse_clause.h
*
*
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: parse_clause.h,v 1.1 1997/11/25 22:06:54 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef PARSE_CLAUSE_H
#define PARSE_CLAUSE_H
#include <nodes/pg_list.h>
#include <nodes/nodes.h>
#include <nodes/parsenodes.h>
#include <nodes/primnodes.h>
#include <parser/parse_node.h>
void
parseFromClause
(
ParseState
*
pstate
,
List
*
frmList
);
void
makeRangeTable
(
ParseState
*
pstate
,
char
*
relname
,
List
*
frmList
);
Node
*
transformWhereClause
(
ParseState
*
pstate
,
Node
*
a_expr
);
TargetEntry
*
find_targetlist_entry
(
ParseState
*
pstate
,
SortGroupBy
*
sortgroupby
,
List
*
tlist
);
List
*
transformGroupClause
(
ParseState
*
pstate
,
List
*
grouplist
,
List
*
targetlist
);
List
*
transformSortClause
(
ParseState
*
pstate
,
List
*
orderlist
,
List
*
targetlist
,
char
*
uniqueFlag
);
#endif
/* PARSE_CLAUSE_H */
src/include/parser/parse_expr.h
0 → 100644
View file @
4a5b781d
/*-------------------------------------------------------------------------
*
* parse_exer.h
*
*
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: parse_expr.h,v 1.1 1997/11/25 22:06:55 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef PARSE_EXPR_H
#define PARSE_EXPR_H
#include <nodes/nodes.h>
#include <nodes/parsenodes.h>
#include <nodes/primnodes.h>
#include <parser/parse_node.h>
Node
*
transformExpr
(
ParseState
*
pstate
,
Node
*
expr
,
int
precedence
);
Node
*
transformIdent
(
ParseState
*
pstate
,
Node
*
expr
,
int
precedence
);
Oid
exprType
(
Node
*
expr
);
Node
*
handleNestedDots
(
ParseState
*
pstate
,
Attr
*
attr
,
int
*
curr_resno
);
Node
*
parser_typecast
(
Value
*
expr
,
TypeName
*
typename
,
int
typlen
);
Node
*
parser_typecast2
(
Node
*
expr
,
Oid
exprType
,
Type
tp
,
int
typlen
);
#endif
/* PARSE_EXPR_H */
src/include/parser/parse_func.h
0 → 100644
View file @
4a5b781d
/*-------------------------------------------------------------------------
*
* catalog_utils.h--
*
*
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: parse_func.h,v 1.1 1997/11/25 22:06:56 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef PARSER_FUNC_H
#define PARSER_FUNC_H
#include <nodes/nodes.h>
#include <nodes/pg_list.h>
#include <nodes/parsenodes.h>
#include <nodes/primnodes.h>
#include <parser/parse_func.h>
#include <parser/parse_node.h>
/*
* This structure is used to explore the inheritance hierarchy above
* nodes in the type tree in order to disambiguate among polymorphic
* functions.
*/
typedef
struct
_InhPaths
{
int
nsupers
;
/* number of superclasses */
Oid
self
;
/* this class */
Oid
*
supervec
;
/* vector of superclasses */
}
InhPaths
;
/*
* This structure holds a list of possible functions or operators that
* agree with the known name and argument types of the function/operator.
*/
typedef
struct
_CandidateList
{
Oid
*
args
;
struct
_CandidateList
*
next
;
}
*
CandidateList
;
Node
*
ParseFunc
(
ParseState
*
pstate
,
char
*
funcname
,
List
*
fargs
,
int
*
curr_resno
);
Oid
funcid_get_rettype
(
Oid
funcid
);
CandidateList
func_get_candidates
(
char
*
funcname
,
int
nargs
);
bool
can_coerce
(
int
nargs
,
Oid
*
input_typeids
,
Oid
*
func_typeids
);
int
match_argtypes
(
int
nargs
,
Oid
*
input_typeids
,
CandidateList
function_typeids
,
CandidateList
*
candidates
);
Oid
*
func_select_candidate
(
int
nargs
,
Oid
*
input_typeids
,
CandidateList
candidates
);
bool
func_get_detail
(
char
*
funcname
,
int
nargs
,
Oid
*
oid_array
,
Oid
*
funcid
,
/* return value */
Oid
*
rettype
,
/* return value */
bool
*
retset
,
/* return value */
Oid
**
true_typeids
);
Oid
**
argtype_inherit
(
int
nargs
,
Oid
*
oid_array
);
int
findsupers
(
Oid
relid
,
Oid
**
supervec
);
Oid
**
genxprod
(
InhPaths
*
arginh
,
int
nargs
);
void
make_arguments
(
int
nargs
,
List
*
fargs
,
Oid
*
input_typeids
,
Oid
*
function_typeids
);
List
*
setup_tlist
(
char
*
attname
,
Oid
relid
);
List
*
setup_base_tlist
(
Oid
typeid
);
Node
*
ParseComplexProjection
(
ParseState
*
pstate
,
char
*
funcname
,
Node
*
first_arg
,
bool
*
attisset
);
void
func_error
(
char
*
caller
,
char
*
funcname
,
int
nargs
,
Oid
*
argtypes
);
#endif
/* PARSE_FUNC_H */
src/include/parser/parse_
stat
e.h
→
src/include/parser/parse_
nod
e.h
View file @
4a5b781d
/*-------------------------------------------------------------------------
/*-------------------------------------------------------------------------
*
*
* parse_state.h--
* parse_node.h
*
*
*
* Copyright (c) 1994, Regents of the University of California
* Copyright (c) 1994, Regents of the University of California
*
*
* $Id: parse_
state.h,v 1.8 1997/09/08 21:53:40
momjian Exp $
* $Id: parse_
node.h,v 1.1 1997/11/25 22:06:57
momjian Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
#ifndef PARSE_NODE_H
#define PARSE_NODE_H
#i
fndef PARSE_STATE_H
#i
nclude <nodes/nodes.h>
#
define PARSE_STATE_H
#
include <nodes/pg_list.h>
#include <nodes/primnodes.h>
#include <nodes/parsenodes.h>
#include <nodes/parsenodes.h>
#include <parser/parse_type.h>
#include <utils/rel.h>
#include <utils/rel.h>
typedef
struct
QueryTreeList
{
int
len
;
/* number of queries */
Query
**
qtrees
;
}
QueryTreeList
;
/* state information used during parse analysis */
/* state information used during parse analysis */
typedef
struct
ParseState
typedef
struct
ParseState
{
{
...
@@ -26,9 +36,32 @@ typedef struct ParseState
...
@@ -26,9 +36,32 @@ typedef struct ParseState
List
*
p_insert_columns
;
List
*
p_insert_columns
;
bool
p_is_update
;
bool
p_is_update
;
bool
p_is_rule
;
bool
p_is_rule
;
bool
p_in_where_clause
;
Relation
p_target_relation
;
Relation
p_target_relation
;
RangeTblEntry
*
p_target_rangetblentry
;
RangeTblEntry
*
p_target_rangetblentry
;
}
ParseState
;
}
ParseState
;
ParseState
*
make_parsestate
(
void
);
Node
*
make_operand
(
char
*
opname
,
Node
*
tree
,
Oid
orig_typeId
,
Oid
true_typeId
);
void
disallow_setop
(
char
*
op
,
Type
optype
,
Node
*
operand
);
Expr
*
make_op
(
char
*
opname
,
Node
*
ltree
,
Node
*
rtree
);
Var
*
make_var
(
ParseState
*
pstate
,
char
*
refname
,
char
*
attrname
,
Oid
*
type_id
);
ArrayRef
*
make_array_ref
(
Node
*
expr
,
List
*
indirection
);
ArrayRef
*
make_array_set
(
Expr
*
target_expr
,
List
*
upperIndexpr
,
List
*
lowerIndexpr
,
Expr
*
expr
);
#endif
/* PARSE_QUERY_H */
Const
*
make_const
(
Value
*
value
);
#endif
/* PARSE_NODE_H */
src/include/parser/parse_oper.h
0 → 100644
View file @
4a5b781d
/*-------------------------------------------------------------------------
*
* catalog_utils.h--
*
*
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: parse_oper.h,v 1.1 1997/11/25 22:06:59 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef PARSE_OPER_H
#define PARSE_OPER_H
#include <parser/parse_func.h>
#include <parser/parse_node.h>
typedef
HeapTuple
Operator
;
Oid
any_ordering_op
(
int
restype
);
Oid
oprid
(
Operator
op
);
int
binary_oper_get_candidates
(
char
*
opname
,
Oid
leftTypeId
,
Oid
rightTypeId
,
CandidateList
*
candidates
);
bool
equivalentOpersAfterPromotion
(
CandidateList
candidates
);
CandidateList
binary_oper_select_candidate
(
Oid
arg1
,
Oid
arg2
,
CandidateList
candidates
);
Operator
oper
(
char
*
op
,
Oid
arg1
,
Oid
arg2
,
bool
noWarnings
);
int
unary_oper_get_candidates
(
char
*
op
,
Oid
typeId
,
CandidateList
*
candidates
,
char
rightleft
);
Operator
right_oper
(
char
*
op
,
Oid
arg
);
Operator
left_oper
(
char
*
op
,
Oid
arg
);
void
op_error
(
char
*
op
,
Oid
arg1
,
Oid
arg2
);
#endif
/* PARSE_OPER_H */
src/include/parser/parse_query.h
deleted
100644 → 0
View file @
3aff4011
/*-------------------------------------------------------------------------
*
* parse_query.h--
* prototypes for parse_query.c.
*
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: parse_query.h,v 1.14 1997/11/20 23:23:53 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef PARSE_QUERY_H
#define PARSE_QUERY_H
#include <parser/catalog_utils.h>
#include <parser/parse_state.h>
#include <nodes/parsenodes.h>
typedef
struct
QueryTreeList
{
int
len
;
/* number of queries */
Query
**
qtrees
;
}
QueryTreeList
;
extern
RangeTblEntry
*
refnameRangeTableEntry
(
List
*
rtable
,
char
*
refname
);
extern
RangeTblEntry
*
colnameRangeTableEntry
(
ParseState
*
pstate
,
char
*
colname
);
extern
int
refnameRangeTablePosn
(
List
*
rtable
,
char
*
refname
);
extern
RangeTblEntry
*
addRangeTableEntry
(
ParseState
*
pstate
,
char
*
relname
,
char
*
refname
,
bool
inh
,
bool
inFromCl
);
extern
List
*
expandAll
(
ParseState
*
pstate
,
char
*
relname
,
char
*
refname
,
int
*
this_resno
);
extern
Expr
*
make_op
(
char
*
opname
,
Node
*
ltree
,
Node
*
rtree
);
extern
Oid
find_atttype
(
Oid
relid
,
char
*
attrname
);
extern
Var
*
make_var
(
ParseState
*
pstate
,
char
*
relname
,
char
*
attrname
,
Oid
*
type_id
);
extern
ArrayRef
*
make_array_ref
(
Node
*
array
,
List
*
indirection
);
extern
ArrayRef
*
make_array_set
(
Expr
*
target_expr
,
List
*
upperIndexpr
,
List
*
lowerIndexpr
,
Expr
*
expr
);
extern
Const
*
make_const
(
Value
*
value
);
extern
void
param_type_init
(
Oid
*
typev
,
int
nargs
);
extern
Oid
param_type
(
int
t
);
extern
QueryTreeList
*
parser
(
char
*
str
,
Oid
*
typev
,
int
nargs
);
extern
void
handleTargetColname
(
ParseState
*
pstate
,
char
**
resname
,
char
*
refname
,
char
*
colname
);
/*
* analyze.c
*/
Oid
exprType
(
Node
*
expr
);
QueryTreeList
*
parse_analyze
(
List
*
querytree_list
);
/* define in parse_query.c, used in gram.y */
extern
Oid
*
param_type_info
;
extern
int
pfunc_num_args
;
/* useful macros */
#define ISCOMPLEX(type) (typeid_get_relid(type) ? true : false)
#endif
/* PARSE_QUERY_H */
src/include/parser/parse_relation.h
0 → 100644
View file @
4a5b781d
/*-------------------------------------------------------------------------
*
* parse_query.h--
* prototypes for parse_query.c.
*
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: parse_relation.h,v 1.1 1997/11/25 22:07:02 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef PARSE_QUERY_H
#define PARSE_RANGE_H
#include <nodes/nodes.h>
#include <nodes/parsenodes.h>
#include <nodes/pg_list.h>
#include <nodes/primnodes.h>
#include <parser/parse_node.h>
#include <utils/rel.h>
RangeTblEntry
*
refnameRangeTableEntry
(
List
*
rtable
,
char
*
refname
);
int
refnameRangeTablePosn
(
List
*
rtable
,
char
*
refname
);
RangeTblEntry
*
colnameRangeTableEntry
(
ParseState
*
pstate
,
char
*
colname
);
RangeTblEntry
*
addRangeTableEntry
(
ParseState
*
pstate
,
char
*
relname
,
char
*
refname
,
bool
inh
,
bool
inFromCl
);
List
*
expandAll
(
ParseState
*
pstate
,
char
*
relname
,
char
*
refname
,
int
*
this_resno
);
int
attnameAttNum
(
Relation
rd
,
char
*
a
);
bool
attnameIsSet
(
Relation
rd
,
char
*
name
);
char
*
attnumAttName
(
Relation
rd
,
int
attrno
);
int
attnumAttNelems
(
Relation
rd
,
int
attid
);
Oid
attnameTypeId
(
Oid
relid
,
char
*
attrname
);
Oid
attnumTypeId
(
Relation
rd
,
int
attid
);
void
handleTargetColname
(
ParseState
*
pstate
,
char
**
resname
,
char
*
refname
,
char
*
colname
);
void
checkTargetTypes
(
ParseState
*
pstate
,
char
*
target_colname
,
char
*
refname
,
char
*
colname
);
#endif
/* PARSE_RANGE_H */
src/include/parser/parse_target.h
0 → 100644
View file @
4a5b781d
/*-------------------------------------------------------------------------
*
* parse_target.h
*
*
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: parse_target.h,v 1.1 1997/11/25 22:07:06 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef PARSE_TARGET_H
#define PARSE_TARGET_H
#include <nodes/pg_list.h>
#include <nodes/nodes.h>
#include <nodes/parsenodes.h>
#include <nodes/primnodes.h>
#include <parser/parse_node.h>
#define EXPR_COLUMN_FIRST 1
#define EXPR_RELATION_FIRST 2
List
*
transformTargetList
(
ParseState
*
pstate
,
List
*
targetlist
);
TargetEntry
*
make_targetlist_expr
(
ParseState
*
pstate
,
char
*
colname
,
Node
*
expr
,
List
*
arrayRef
);
List
*
expandAllTables
(
ParseState
*
pstate
);
char
*
figureColname
(
Node
*
expr
,
Node
*
resval
);
List
*
makeTargetNames
(
ParseState
*
pstate
,
List
*
cols
);
#endif
/* PARSE_TARGET_H */
src/include/parser/parse_type.h
0 → 100644
View file @
4a5b781d
/*-------------------------------------------------------------------------
*
* parse_type.h
*
*
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: parse_type.h,v 1.1 1997/11/25 22:07:07 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef PARSE_TYPE_H
#define PARSE_TYPE_H
#include "access/htup.h"
typedef
HeapTuple
Type
;
bool
typeidIsValid
(
Oid
id
);
Type
typeidType
(
Oid
id
);
Type
typenameType
(
char
*
s
);
char
*
typeidTypeName
(
Oid
id
);
Oid
typeTypeId
(
Type
tp
);
int16
typeLen
(
Type
t
);
bool
typeByVal
(
Type
t
);
char
*
typeTypeName
(
Type
t
);
char
typeTypeFlag
(
Type
t
);
char
*
stringTypeString
(
Type
tp
,
char
*
string
,
int
typlen
);
Oid
typeidRetoutfunc
(
Oid
type_id
);
Oid
typeidTypeRelid
(
Oid
type_id
);
Oid
typeTypeRelid
(
Type
typ
);
Oid
typeidTypElem
(
Oid
type_id
);
Oid
GetArrayElementType
(
Oid
typearray
);
Oid
typeidRetinfunc
(
Oid
type_id
);
#endif
/* PARSE_TYPE_H */
src/include/parser/parser.h
0 → 100644
View file @
4a5b781d
/*-------------------------------------------------------------------------
*
* parser.h
*
*
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: parser.h,v 1.1 1997/11/25 22:07:08 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef PARSER_H
#define PARSER_H
#include <parser/parse_node.h>
QueryTreeList
*
parser
(
char
*
str
,
Oid
*
typev
,
int
nargs
);
#endif
/* PARSER_H */
src/include/tcop/tcopprot.h
View file @
4a5b781d
...
@@ -6,7 +6,7 @@
...
@@ -6,7 +6,7 @@
*
*
* Copyright (c) 1994, Regents of the University of California
* Copyright (c) 1994, Regents of the University of California
*
*
* $Id: tcopprot.h,v 1.
7 1997/09/08 21:54:42
momjian Exp $
* $Id: tcopprot.h,v 1.
8 1997/11/25 22:07:10
momjian Exp $
*
*
* OLD COMMENTS
* OLD COMMENTS
* This file was created so that other c files could get the two
* This file was created so that other c files could get the two
...
@@ -19,7 +19,7 @@
...
@@ -19,7 +19,7 @@
#define TCOPPROT_H
#define TCOPPROT_H
#include <executor/execdesc.h>
#include <executor/execdesc.h>
#include <parser/parse_
query
.h>
#include <parser/parse_
node
.h>
#ifndef BOOTSTRAP_INCLUDE
#ifndef BOOTSTRAP_INCLUDE
extern
List
*
extern
List
*
...
...
src/test/regress/checkresults
View file @
4a5b781d
#!/bin/sh
#!/bin/sh
# check regression tests
# check regression tests
# usage: checkresults < results.out
# usage: checkresults [ regress.out ]
[
"$#"
-eq
0
]
&&
set
regress.out
for
file
in
`
cat
"
$@
"
|
grep
'failed$'
|
cut
-d
" "
-f
1
`
for
file
in
`
cat
"
$@
"
|
grep
'failed$'
|
cut
-d
" "
-f
1
`
do
do
...
...
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