Break parser functions into smaller files, group together.
This commit is contained in:
parent
3aff4011c7
commit
4a5b781d71
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/common/tupdesc.c,v 1.28 1997/11/24 05:07:42 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/common/tupdesc.c,v 1.29 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 @@
|
|||||||
|
|
||||||
#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,
|
|||||||
*/
|
*/
|
||||||
if (attisset)
|
if (attisset)
|
||||||
{
|
{
|
||||||
Type t = type("oid");
|
Type t = typeidType(OIDOID);
|
||||||
|
|
||||||
att->attlen = tlen(t);
|
att->attlen = typeLen(t);
|
||||||
att->attbyval = tbyval(t);
|
att->attbyval = typeByVal(t);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -410,12 +411,12 @@ TupleDescMakeSelfReference(TupleDesc desc,
|
|||||||
char *relname)
|
char *relname)
|
||||||
{
|
{
|
||||||
AttributeTupleForm att;
|
AttributeTupleForm att;
|
||||||
Type t = type("oid");
|
Type t = typeidType(OIDOID);
|
||||||
|
|
||||||
att = desc->attrs[attnum - 1];
|
att = desc->attrs[attnum - 1];
|
||||||
att->atttypid = TypeShellMake(relname);
|
att->atttypid = TypeShellMake(relname);
|
||||||
att->attlen = tlen(t);
|
att->attlen = typeLen(t);
|
||||||
att->attbyval = tbyval(t);
|
att->attbyval = typeByVal(t);
|
||||||
att->attnelems = 0;
|
att->attnelems = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.33 1997/11/24 05:08:07 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.34 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 @@
|
|||||||
#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)
|
|||||||
*/
|
*/
|
||||||
new_type_oid = TypeCreate(typeName, /* type name */
|
new_type_oid = TypeCreate(typeName, /* type name */
|
||||||
new_rel_oid, /* relation oid */
|
new_rel_oid, /* relation oid */
|
||||||
tlen(type("oid")), /* internal size */
|
typeLen(typeidType(OIDOID)), /* internal size */
|
||||||
tlen(type("oid")), /* external size */
|
typeLen(typeidType(OIDOID)), /* external size */
|
||||||
'c', /* type-type (catalog) */
|
'c', /* type-type (catalog) */
|
||||||
',', /* default array delimiter */
|
',', /* default array delimiter */
|
||||||
"int4in", /* input procedure */
|
"int4in", /* input procedure */
|
||||||
|
@ -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 @@
|
|||||||
#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>
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.16 1997/11/24 05:08:15 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.17 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 @@
|
|||||||
#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>
|
||||||
|
@ -7,28 +7,28 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.9 1997/09/18 20:20:18 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.10 1997/11/25 21:58:48 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,
|
|||||||
if (parameterCount == 1 &&
|
if (parameterCount == 1 &&
|
||||||
(toid = TypeGet(strVal(lfirst(argList)), &defined)) &&
|
(toid = TypeGet(strVal(lfirst(argList)), &defined)) &&
|
||||||
defined &&
|
defined &&
|
||||||
(relid = typeid_get_relid(toid)) != 0 &&
|
(relid = typeidTypeRelid(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)));
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.13 1997/11/24 05:08:17 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.14 1997/11/25 21:58:50 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -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
|
||||||
|
@ -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 @@
|
|||||||
#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
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.14 1997/09/18 20:20:22 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.15 1997/11/25 21:58:53 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -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>
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/recipe.c,v 1.12 1997/11/21 18:09:51 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/recipe.c,v 1.13 1997/11/25 21:59:00 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -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,
|
|||||||
* "result" attribute from the tee relation
|
* "result" attribute from the tee relation
|
||||||
*/
|
*/
|
||||||
|
|
||||||
isRel = (typeid_get_relid(p->paramtype) != 0);
|
isRel = (typeidTypeRelid(p->paramtype) != 0);
|
||||||
if (isRel)
|
if (isRel)
|
||||||
{
|
{
|
||||||
newVar = makeVar(rt_ind,
|
newVar = makeVar(rt_ind,
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.16 1997/11/20 23:21:13 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.17 1997/11/25 21:59:03 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -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
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.52 1997/11/21 19:59:34 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.53 1997/11/25 21:59:09 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -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 @@
|
|||||||
#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
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/view.c,v 1.15 1997/11/21 18:09:58 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/view.c,v 1.16 1997/11/25 21:59:12 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -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)
|
|||||||
entry = lfirst(t);
|
entry = lfirst(t);
|
||||||
res = entry->resdom;
|
res = entry->resdom;
|
||||||
resname = res->resname;
|
resname = res->resname;
|
||||||
restypename = tname(get_id_type(res->restype));
|
restypename = typeidTypeName(res->restype);
|
||||||
|
|
||||||
typename = makeNode(TypeName);
|
typename = makeNode(TypeName);
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.10 1997/09/18 20:20:32 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.11 1997/11/25 21:59:16 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -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);
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.12 1997/09/18 20:20:37 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.13 1997/11/25 21:59:19 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -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"
|
||||||
|
@ -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)
|
|||||||
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,
|
||||||
tname(get_id_type(agg->basetype)));
|
typeidTypeName(agg->basetype));
|
||||||
aggp = (Form_pg_aggregate) GETSTRUCT(aggTuple);
|
aggp = (Form_pg_aggregate) GETSTRUCT(aggTuple);
|
||||||
|
|
||||||
xfn1_oid = aggp->aggtransfn1;
|
xfn1_oid = aggp->aggtransfn1;
|
||||||
|
@ -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"
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.15 1997/11/20 23:21:40 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.16 1997/11/25 21:59:40 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -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 */
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/nodes/print.c,v 1.10 1997/10/25 01:09:28 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/nodes/print.c,v 1.11 1997/11/25 21:59:44 momjian Exp $
|
||||||
*
|
*
|
||||||
* HISTORY
|
* HISTORY
|
||||||
* AUTHOR DATE MAJOR EVENT
|
* AUTHOR DATE MAJOR EVENT
|
||||||
@ -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)
|
|||||||
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 = getAttrName(r, var->varattno);
|
attname = attnumAttName(r, var->varattno);
|
||||||
heap_close(r);
|
heap_close(r);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/xfunc.c,v 1.6 1997/09/08 21:45:10 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/xfunc.c,v 1.7 1997/11/25 21:59:50 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -641,10 +641,10 @@ xfunc_width(LispValue clause)
|
|||||||
}
|
}
|
||||||
else if (IsA(clause, Param))
|
else if (IsA(clause, Param))
|
||||||
{
|
{
|
||||||
if (typeid_get_relid(get_paramtype((Param) clause)))
|
if (typeidTypeRelid(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_relid(get_paramtype((Param) clause)));
|
rd = heap_open(typeidTypeRelid(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)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Param node returns a base type */
|
/* Param node returns a base type */
|
||||||
retval = tlen(get_id_type(get_paramtype((Param) clause)));
|
retval = typeLen(typeidType(get_paramtype((Param) clause)));
|
||||||
}
|
}
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
@ -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_relid(proc->prorettype))
|
if (typeidTypeRelid(proc->prorettype))
|
||||||
{
|
{
|
||||||
rd = heap_open(typeid_get_relid(proc->prorettype));
|
rd = heap_open(typeidTypeRelid(proc->prorettype));
|
||||||
retval = xfunc_tuple_width(rd);
|
retval = xfunc_tuple_width(rd);
|
||||||
heap_close(rd);
|
heap_close(rd);
|
||||||
goto exit;
|
goto exit;
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.15 1997/09/08 21:45:13 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.16 1997/11/25 21:59:56 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -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"
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.10 1997/11/21 18:10:26 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.11 1997/11/25 21:59:59 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 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_type(rettype)) == NULL)
|
if ((typ = typeidType(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)
|
|||||||
* 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", tname(typ));
|
elog(WARN, "function declared to return type %s, but final query is not a retrieve", typeTypeName(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_typrelid(typ) == InvalidOid)
|
if (typeTypeRelid(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", tname(typ));
|
elog(WARN, "function declared to return %s returns multiple values in final retrieve", typeTypeName(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", tname(typ), tname(get_id_type(resnode->restype)));
|
elog(WARN, "return type mismatch in function: declared to return %s, returns %s", typeTypeName(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)
|
|||||||
* 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_typrelid(typ));
|
reln = heap_open(typeTypeRelid(typ));
|
||||||
|
|
||||||
if (!RelationIsValid(reln))
|
if (!RelationIsValid(reln))
|
||||||
elog(WARN, "cannot open relation relid %d", get_typrelid(typ));
|
elog(WARN, "cannot open relation relid %d", typeTypeRelid(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.*)", tname(typ), tname(typ));
|
elog(WARN, "function declared to return type %s does not retrieve (%s.*)", typeTypeName(typ), typeTypeName(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)
|
|||||||
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)", tname(typ), tname(typ));
|
elog(WARN, "function declared to return type %s does not retrieve (%s.all)", typeTypeName(typ), typeTypeName(typ));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
elog(WARN, "function declared to return type %s does not retrieve (%s.all)", tname(typ), tname(typ));
|
elog(WARN, "function declared to return type %s does not retrieve (%s.all)", typeTypeName(typ), typeTypeName(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)", tname(typ), tname(typ));
|
elog(WARN, "function declared to return type %s does not retrieve (%s.all)", typeTypeName(typ), typeTypeName(typ));
|
||||||
}
|
}
|
||||||
|
|
||||||
heap_close(reln);
|
heap_close(reln);
|
||||||
|
@ -7,13 +7,14 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.5 1997/09/08 21:45:36 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.6 1997/11/25 22:00:06 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 @@
|
|||||||
#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)
|
|||||||
attisset = get_attisset( /* type_id, */ relid, attname);
|
attisset = get_attisset( /* type_id, */ relid, attname);
|
||||||
if (attisset)
|
if (attisset)
|
||||||
{
|
{
|
||||||
typlen = tlen(type("oid"));
|
typlen = typeLen(typeidType(OIDOID));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -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 @@
|
|||||||
#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"
|
||||||
|
@ -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 @@
|
|||||||
#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);
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
# Makefile for parser
|
# Makefile for parser
|
||||||
#
|
#
|
||||||
# IDENTIFICATION
|
# IDENTIFICATION
|
||||||
# $Header: /cvsroot/pgsql/src/backend/parser/Makefile,v 1.11 1997/11/24 05:20:57 momjian Exp $
|
# $Header: /cvsroot/pgsql/src/backend/parser/Makefile,v 1.12 1997/11/25 22:00:21 momjian Exp $
|
||||||
#
|
#
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
|
|
||||||
@ -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
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 1.71 1997/11/24 16:55:22 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 1.72 1997/11/25 22:05:29 momjian Exp $
|
||||||
*
|
*
|
||||||
* HISTORY
|
* HISTORY
|
||||||
* AUTHOR DATE MAJOR EVENT
|
* AUTHOR DATE MAJOR EVENT
|
||||||
@ -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 @@
|
|||||||
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);
|
|||||||
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
|
|||||||
* emp(name=text,mgr=emp)
|
* emp(name=text,mgr=emp)
|
||||||
*/
|
*/
|
||||||
$$->setof = TRUE;
|
$$->setof = TRUE;
|
||||||
else if (get_typrelid((Type)type($$->name)) != InvalidOid)
|
else if (typeTypeRelid(typenameType($$->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)
|
|||||||
#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];
|
||||||
|
}
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.24 1997/11/24 05:32:28 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.25 1997/11/25 22:05:32 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -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.
|
||||||
|
371
src/backend/parser/parse_agg.c
Normal file
371
src/backend/parser/parse_agg.c
Normal file
@ -0,0 +1,371 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* 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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
407
src/backend/parser/parse_clause.c
Normal file
407
src/backend/parser/parse_clause.c
Normal file
@ -0,0 +1,407 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* 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;
|
||||||
|
}
|
694
src/backend/parser/parse_expr.c
Normal file
694
src/backend/parser/parse_expr.c
Normal file
@ -0,0 +1,694 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* 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);
|
||||||
|
}
|
1264
src/backend/parser/parse_func.c
Normal file
1264
src/backend/parser/parse_func.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,259 +1,76 @@
|
|||||||
/*-------------------------------------------------------------------------
|
/*-------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* 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.
|
||||||
RangeTblEntry *
|
* the CALLERS is responsible for freeing the ParseState* returned
|
||||||
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) 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)++,
|
ParseState *
|
||||||
type_id,
|
make_parsestate(void)
|
||||||
(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
|
|
||||||
disallow_setop(char *op, Type optype, Node *operand)
|
|
||||||
{
|
{
|
||||||
if (operand == NULL)
|
ParseState *pstate;
|
||||||
return;
|
|
||||||
|
|
||||||
if (nodeTag(operand) == T_Iter)
|
pstate = malloc(sizeof(ParseState));
|
||||||
{
|
pstate->p_last_resno = 1;
|
||||||
elog(NOTICE, "An operand to the '%s' operator returns a set of %s,",
|
pstate->p_rtable = NIL;
|
||||||
op, tname(optype));
|
pstate->p_numAgg = 0;
|
||||||
elog(WARN, "but '%s' takes single values, not sets.",
|
pstate->p_aggs = NIL;
|
||||||
op);
|
pstate->p_is_insert = false;
|
||||||
}
|
pstate->p_insert_columns = NIL;
|
||||||
|
pstate->p_is_update = false;
|
||||||
|
pstate->p_is_rule = false;
|
||||||
|
pstate->p_in_where_clause = false;
|
||||||
|
pstate->p_target_relation = NULL;
|
||||||
|
pstate->p_target_rangetblentry = NULL;
|
||||||
|
|
||||||
|
return (pstate);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Node *
|
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,
|
|||||||
if (tree != NULL)
|
if (tree != NULL)
|
||||||
{
|
{
|
||||||
result = tree;
|
result = tree;
|
||||||
true_type = get_id_type(true_typeId);
|
true_type = typeidType(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,
|
|||||||
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_retinfunc(true_typeId);
|
infunc = typeidRetinfunc(true_typeId);
|
||||||
con = makeNode(Const);
|
con = makeNode(Const);
|
||||||
con->consttype = true_typeId;
|
con->consttype = true_typeId;
|
||||||
con->constlen = tlen(true_type);
|
con->constlen = typeLen(true_type);
|
||||||
con->constvalue = (Datum) fmgr(infunc,
|
con->constvalue = (Datum) fmgr(infunc,
|
||||||
val,
|
val,
|
||||||
get_typelem(true_typeId),
|
typeidTypElem(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,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
|||||||
CONVERTABLE_TYPE(rtypeId) && nodeTag(rtree) == T_Const &&
|
CONVERTABLE_TYPE(rtypeId) && nodeTag(rtree) == T_Const &&
|
||||||
!((Const *) rtree)->constiscast)
|
!((Const *) rtree)->constiscast)
|
||||||
{
|
{
|
||||||
outfunc = typeid_get_retoutfunc(rtypeId);
|
outfunc = typeidRetoutfunc(rtypeId);
|
||||||
infunc = typeid_get_retinfunc(ltypeId);
|
infunc = typeidRetinfunc(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_type(rtypeId);
|
newtype = typeidType(rtypeId);
|
||||||
((Const *) rtree)->constlen = tlen(newtype);
|
((Const *) rtree)->constlen = typeLen(newtype);
|
||||||
((Const *) rtree)->constbyval = tbyval(newtype);
|
((Const *) rtree)->constbyval = typeByVal(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_retoutfunc(ltypeId);
|
outfunc = typeidRetoutfunc(ltypeId);
|
||||||
infunc = typeid_get_retinfunc(rtypeId);
|
infunc = typeidRetinfunc(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_type(ltypeId);
|
newtype = typeidType(ltypeId);
|
||||||
((Const *) ltree)->constlen = tlen(newtype);
|
((Const *) ltree)->constlen = typeLen(newtype);
|
||||||
((Const *) ltree)->constbyval = tbyval(newtype);
|
((Const *) ltree)->constbyval = typeByVal(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)
|
|||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
switch (nodeTag(value))
|
switch (nodeTag(value))
|
||||||
{
|
{
|
||||||
case T_Integer:
|
case T_Integer:
|
||||||
tp = type("int4");
|
tp = typeidType(INT4OID);
|
||||||
val = Int32GetDatum(intVal(value));
|
val = Int32GetDatum(intVal(value));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -675,7 +473,7 @@ make_const(Value *value)
|
|||||||
{
|
{
|
||||||
float64 dummy;
|
float64 dummy;
|
||||||
|
|
||||||
tp = type("float8");
|
tp = typeidType(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)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case T_String:
|
case T_String:
|
||||||
tp = type("unknown"); /* unknown for now, will be type
|
tp = typeidType(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)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
con = makeConst(typeid(tp),
|
con = makeConst(typeTypeId(tp),
|
||||||
tlen(tp),
|
typeLen(tp),
|
||||||
val,
|
val,
|
||||||
false,
|
false,
|
||||||
tbyval(tp),
|
typeByVal(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);
|
|
||||||
}
|
|
613
src/backend/parser/parse_oper.c
Normal file
613
src/backend/parser/parse_oper.c
Normal file
@ -0,0 +1,613 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* 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));
|
||||||
|
}
|
||||||
|
|
480
src/backend/parser/parse_relation.c
Normal file
480
src/backend/parser/parse_relation.c
Normal file
@ -0,0 +1,480 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* 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);
|
||||||
|
}
|
679
src/backend/parser/parse_target.c
Normal file
679
src/backend/parser/parse_target.c
Normal file
@ -0,0 +1,679 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* 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?";
|
||||||
|
}
|
319
src/backend/parser/parse_type.c
Normal file
319
src/backend/parser/parse_type.c
Normal file
@ -0,0 +1,319 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* 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
|
@ -6,7 +6,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/parser/parser.c,v 1.28 1997/11/20 23:22:24 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/parser/parser.c,v 1.29 1997/11/25 22:05:52 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -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
|
|||||||
define_sets(Node *clause)
|
define_sets(Node *clause)
|
||||||
{
|
{
|
||||||
Oid setoid;
|
Oid setoid;
|
||||||
Type t = type("oid");
|
Type t = typeidType(OIDOID);
|
||||||
Oid typeoid = typeid(t);
|
Oid typeoid = typeTypeId(t);
|
||||||
Size oidsize = tlen(t);
|
Size oidsize = typeLen(t);
|
||||||
bool oidbyval = tbyval(t);
|
bool oidbyval = typeByVal(t);
|
||||||
|
|
||||||
if (clause == NULL)
|
if (clause == NULL)
|
||||||
{
|
{
|
||||||
@ -125,11 +136,11 @@ define_sets(Node *clause)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setoid = SetDefine(((Const *) clause)->constvalue,
|
setoid = SetDefine(((Const *) clause)->constvalue,
|
||||||
get_id_typname(((Const *) clause)->consttype));
|
typeidTypeName(((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_constbyval((Const) clause, oidbyval);
|
set_constypeByVal((Const) clause, oidbyval);
|
||||||
}
|
}
|
||||||
else if (IsA(clause, Iter))
|
else if (IsA(clause, Iter))
|
||||||
{
|
{
|
||||||
@ -173,6 +184,5 @@ define_sets(Node *clause)
|
|||||||
define_sets(get_rightop(clause));
|
define_sets(get_rightop(clause));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -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 @@
|
|||||||
|
|
||||||
#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"
|
||||||
|
@ -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 @@
|
|||||||
#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,
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
event_attno = varattno(event_relation, eslot_string);
|
event_attno = attnameAttNum(event_relation, eslot_string);
|
||||||
event_attype = att_typeid(event_relation, event_attno);
|
event_attype = attnumTypeId(event_relation, event_attno);
|
||||||
}
|
}
|
||||||
heap_close(event_relation);
|
heap_close(event_relation);
|
||||||
|
|
||||||
|
@ -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 @@
|
|||||||
#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);
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.54 1997/11/10 15:24:55 thomas Exp $
|
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.55 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 @@
|
|||||||
|
|
||||||
#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[])
|
|||||||
if (IsUnderPostmaster == false)
|
if (IsUnderPostmaster == false)
|
||||||
{
|
{
|
||||||
puts("\nPOSTGRES backend interactive interface");
|
puts("\nPOSTGRES backend interactive interface");
|
||||||
puts("$Revision: 1.54 $ $Date: 1997/11/10 15:24:55 $");
|
puts("$Revision: 1.55 $ $Date: 1997/11/25 22:06:14 $");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
|
@ -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"
|
||||||
|
@ -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);
|
||||||
|
@ -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 @@
|
|||||||
/*
|
/*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#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);
|
||||||
|
|
||||||
|
19
src/include/parser/analyze.h
Normal file
19
src/include/parser/analyze.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* 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 */
|
@ -1,54 +0,0 @@
|
|||||||
/*-------------------------------------------------------------------------
|
|
||||||
*
|
|
||||||
* 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 */
|
|
38
src/include/parser/parse_agg.h
Normal file
38
src/include/parser/parse_agg.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* 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 */
|
||||||
|
|
39
src/include/parser/parse_clause.h
Normal file
39
src/include/parser/parse_clause.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* 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 */
|
||||||
|
|
34
src/include/parser/parse_expr.h
Normal file
34
src/include/parser/parse_expr.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* 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 */
|
||||||
|
|
97
src/include/parser/parse_func.h
Normal file
97
src/include/parser/parse_func.h
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* 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 */
|
||||||
|
|
67
src/include/parser/parse_node.h
Normal file
67
src/include/parser/parse_node.h
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* parse_node.h
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Copyright (c) 1994, Regents of the University of California
|
||||||
|
*
|
||||||
|
* $Id: parse_node.h,v 1.1 1997/11/25 22:06:57 momjian Exp $
|
||||||
|
*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
#ifndef PARSE_NODE_H
|
||||||
|
#define PARSE_NODE_H
|
||||||
|
|
||||||
|
#include <nodes/nodes.h>
|
||||||
|
#include <nodes/pg_list.h>
|
||||||
|
#include <nodes/primnodes.h>
|
||||||
|
#include <nodes/parsenodes.h>
|
||||||
|
#include <parser/parse_type.h>
|
||||||
|
#include <utils/rel.h>
|
||||||
|
|
||||||
|
typedef struct QueryTreeList
|
||||||
|
{
|
||||||
|
int len; /* number of queries */
|
||||||
|
Query **qtrees;
|
||||||
|
} QueryTreeList;
|
||||||
|
|
||||||
|
/* state information used during parse analysis */
|
||||||
|
typedef struct ParseState
|
||||||
|
{
|
||||||
|
int p_last_resno;
|
||||||
|
List *p_rtable;
|
||||||
|
int p_numAgg;
|
||||||
|
List *p_aggs;
|
||||||
|
bool p_is_insert;
|
||||||
|
List *p_insert_columns;
|
||||||
|
bool p_is_update;
|
||||||
|
bool p_is_rule;
|
||||||
|
bool p_in_where_clause;
|
||||||
|
Relation p_target_relation;
|
||||||
|
RangeTblEntry *p_target_rangetblentry;
|
||||||
|
} 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);
|
||||||
|
|
||||||
|
Const *make_const(Value *value);
|
||||||
|
|
||||||
|
#endif /* PARSE_NODE_H */
|
50
src/include/parser/parse_oper.h
Normal file
50
src/include/parser/parse_oper.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* 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 */
|
@ -1,70 +0,0 @@
|
|||||||
/*-------------------------------------------------------------------------
|
|
||||||
*
|
|
||||||
* 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 */
|
|
56
src/include/parser/parse_relation.h
Normal file
56
src/include/parser/parse_relation.h
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* 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 */
|
@ -1,34 +0,0 @@
|
|||||||
/*-------------------------------------------------------------------------
|
|
||||||
*
|
|
||||||
* parse_state.h--
|
|
||||||
*
|
|
||||||
* Copyright (c) 1994, Regents of the University of California
|
|
||||||
*
|
|
||||||
* $Id: parse_state.h,v 1.8 1997/09/08 21:53:40 momjian Exp $
|
|
||||||
*
|
|
||||||
*-------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef PARSE_STATE_H
|
|
||||||
#define PARSE_STATE_H
|
|
||||||
|
|
||||||
#include <nodes/parsenodes.h>
|
|
||||||
#include <utils/rel.h>
|
|
||||||
|
|
||||||
/* state information used during parse analysis */
|
|
||||||
typedef struct ParseState
|
|
||||||
{
|
|
||||||
int p_last_resno;
|
|
||||||
List *p_rtable;
|
|
||||||
int p_numAgg;
|
|
||||||
List *p_aggs;
|
|
||||||
bool p_is_insert;
|
|
||||||
List *p_insert_columns;
|
|
||||||
bool p_is_update;
|
|
||||||
bool p_is_rule;
|
|
||||||
Relation p_target_relation;
|
|
||||||
RangeTblEntry *p_target_rangetblentry;
|
|
||||||
} ParseState;
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* PARSE_QUERY_H */
|
|
39
src/include/parser/parse_target.h
Normal file
39
src/include/parser/parse_target.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* 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 */
|
||||||
|
|
37
src/include/parser/parse_type.h
Normal file
37
src/include/parser/parse_type.h
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* 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 */
|
21
src/include/parser/parser.h
Normal file
21
src/include/parser/parser.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* 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 */
|
||||||
|
|
@ -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 @@
|
|||||||
#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 *
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#!/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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user