Break parser functions into smaller files, group together.
This commit is contained in:
parent
3aff4011c7
commit
4a5b781d71
@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* 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
|
||||
* some of the executor utility code such as "ExecTypeFromTL" should be
|
||||
@ -20,8 +20,9 @@
|
||||
|
||||
#include <postgres.h>
|
||||
|
||||
#include <parser/catalog_utils.h>
|
||||
#include <catalog/pg_type.h>
|
||||
#include <nodes/parsenodes.h>
|
||||
#include <parser/parse_type.h>
|
||||
#include <utils/builtins.h>
|
||||
#include <utils/fcache.h>
|
||||
#include <utils/syscache.h>
|
||||
@ -377,10 +378,10 @@ TupleDescInitEntry(TupleDesc desc,
|
||||
*/
|
||||
if (attisset)
|
||||
{
|
||||
Type t = type("oid");
|
||||
Type t = typeidType(OIDOID);
|
||||
|
||||
att->attlen = tlen(t);
|
||||
att->attbyval = tbyval(t);
|
||||
att->attlen = typeLen(t);
|
||||
att->attbyval = typeByVal(t);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -410,12 +411,12 @@ TupleDescMakeSelfReference(TupleDesc desc,
|
||||
char *relname)
|
||||
{
|
||||
AttributeTupleForm att;
|
||||
Type t = type("oid");
|
||||
Type t = typeidType(OIDOID);
|
||||
|
||||
att = desc->attrs[attnum - 1];
|
||||
att->atttypid = TypeShellMake(relname);
|
||||
att->attlen = tlen(t);
|
||||
att->attbyval = tbyval(t);
|
||||
att->attlen = typeLen(t);
|
||||
att->attbyval = typeByVal(t);
|
||||
att->attnelems = 0;
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* 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
|
||||
* heap_creatr() - Create an uncataloged heap relation
|
||||
@ -42,11 +42,12 @@
|
||||
#include <catalog/pg_attrdef.h>
|
||||
#include <catalog/pg_relcheck.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/lmgr.h>
|
||||
#include <storage/smgr.h>
|
||||
#include <parser/catalog_utils.h>
|
||||
#include <parser/parse_query.h>
|
||||
#include <rewrite/rewriteRemove.h>
|
||||
#include <utils/builtins.h>
|
||||
#include <utils/mcxt.h>
|
||||
@ -722,8 +723,8 @@ addNewRelationType(char *typeName, Oid new_rel_oid)
|
||||
*/
|
||||
new_type_oid = TypeCreate(typeName, /* type name */
|
||||
new_rel_oid, /* relation oid */
|
||||
tlen(type("oid")), /* internal size */
|
||||
tlen(type("oid")), /* external size */
|
||||
typeLen(typeidType(OIDOID)), /* internal size */
|
||||
typeLen(typeidType(OIDOID)), /* external size */
|
||||
'c', /* type-type (catalog) */
|
||||
',', /* default array delimiter */
|
||||
"int4in", /* input procedure */
|
||||
|
@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* 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
|
||||
@ -30,26 +30,27 @@
|
||||
#include <fmgr.h>
|
||||
#include <access/genam.h>
|
||||
#include <access/heapam.h>
|
||||
#include <storage/lmgr.h>
|
||||
#include <miscadmin.h>
|
||||
#include <access/istrat.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 <catalog/catname.h>
|
||||
#include <catalog/catalog.h>
|
||||
#include <catalog/indexing.h>
|
||||
#include <catalog/heap.h>
|
||||
#include <catalog/index.h>
|
||||
#include <catalog/pg_type.h>
|
||||
#include <executor/executor.h>
|
||||
#include <miscadmin.h>
|
||||
#include <optimizer/clauses.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
|
||||
#include <regex/utils.h>
|
||||
|
@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* 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
|
||||
* these routines moved here from commands/define.c and somewhat cleaned up.
|
||||
@ -20,9 +20,10 @@
|
||||
#include <utils/syscache.h>
|
||||
#include <utils/tqual.h>
|
||||
#include <access/heapam.h>
|
||||
#include <parser/catalog_utils.h>
|
||||
#include <catalog/catname.h>
|
||||
#include <catalog/pg_operator.h>
|
||||
#include <catalog/pg_type.h>
|
||||
#include <parser/parse_oper.h>
|
||||
#include <storage/bufmgr.h>
|
||||
#include <fmgr.h>
|
||||
#include <miscadmin.h>
|
||||
|
@ -7,28 +7,28 @@
|
||||
*
|
||||
*
|
||||
* 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 <fmgr.h>
|
||||
#include <miscadmin.h>
|
||||
#include <utils/syscache.h>
|
||||
#include <catalog/pg_proc.h>
|
||||
#include <access/heapam.h>
|
||||
#include <access/relscan.h>
|
||||
#include <fmgr.h>
|
||||
#include <utils/builtins.h>
|
||||
#include <utils/sets.h>
|
||||
#include <catalog/catname.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 <parser/catalog_utils.h>
|
||||
#include <utils/builtins.h>
|
||||
#include <utils/sets.h>
|
||||
#include <utils/lsyscache.h>
|
||||
#include <optimizer/internal.h>
|
||||
#include <optimizer/planner.h>
|
||||
#include <utils/lsyscache.h>
|
||||
#include <miscadmin.h>
|
||||
#ifndef HAVE_MEMMOVE
|
||||
#include <regex/utils.h>
|
||||
#else
|
||||
@ -200,7 +200,7 @@ ProcedureCreate(char *procedureName,
|
||||
if (parameterCount == 1 &&
|
||||
(toid = TypeGet(strVal(lfirst(argList)), &defined)) &&
|
||||
defined &&
|
||||
(relid = typeid_get_relid(toid)) != 0 &&
|
||||
(relid = typeidTypeRelid(toid)) != 0 &&
|
||||
get_attnum(relid, procedureName) != InvalidAttrNumber)
|
||||
elog(WARN, "method %s already an attribute of type %s",
|
||||
procedureName, strVal(lfirst(argList)));
|
||||
|
@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* 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/tqual.h>
|
||||
#include <fmgr.h>
|
||||
#include <parser/catalog_utils.h>
|
||||
#include <catalog/catname.h>
|
||||
#include <catalog/indexing.h>
|
||||
#include <catalog/pg_type.h>
|
||||
#include <parser/parse_func.h>
|
||||
#include <storage/lmgr.h>
|
||||
#include <miscadmin.h>
|
||||
#ifndef HAVE_MEMMOVE
|
||||
|
@ -10,7 +10,7 @@
|
||||
*
|
||||
*
|
||||
* 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
|
||||
* At the point the version is defined, 2 physical relations are created
|
||||
@ -30,6 +30,7 @@
|
||||
#include <utils/builtins.h>
|
||||
#include <commands/version.h>
|
||||
#include <access/xact.h> /* for GetCurrentXactStartTime */
|
||||
#include <parser/parse_node.h>
|
||||
#include <tcop/tcopprot.h>
|
||||
|
||||
#define MAX_QUERY_LEN 1024
|
||||
|
@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* 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 <parser/catalog_utils.h>
|
||||
#include <parser/parse_query.h> /* for MakeTimeRange() */
|
||||
#include <nodes/plannodes.h>
|
||||
#include <tcop/tcopprot.h>
|
||||
#include <lib/stringinfo.h>
|
||||
#include <commands/explain.h>
|
||||
#include <parser/parse_node.h>
|
||||
#include <optimizer/planner.h>
|
||||
#include <access/xact.h>
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* 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 <commands/recipe.h>
|
||||
#include <libpq/libpq-be.h>
|
||||
#include <parser/parse_node.h>
|
||||
#include <utils/builtins.h>
|
||||
#include <utils/relcache.h> /* for RelationNameGetRelation */
|
||||
#include <parser/parse_query.h>
|
||||
#include <rewrite/rewriteHandler.h>
|
||||
#include <rewrite/rewriteManip.h>
|
||||
#include <tcop/pquery.h>
|
||||
@ -488,7 +488,7 @@ tg_replaceNumberedParam(Node *expression,
|
||||
* "result" attribute from the tee relation
|
||||
*/
|
||||
|
||||
isRel = (typeid_get_relid(p->paramtype) != 0);
|
||||
isRel = (typeidTypeRelid(p->paramtype) != 0);
|
||||
if (isRel)
|
||||
{
|
||||
newVar = makeVar(rt_ind,
|
||||
|
@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* 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_operator.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 <fmgr.h>
|
||||
#ifndef HAVE_MEMMOVE
|
||||
|
@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* 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_type.h>
|
||||
#include <catalog/pg_operator.h>
|
||||
#include <parser/parse_oper.h>
|
||||
#include <storage/smgr.h>
|
||||
#include <storage/lmgr.h>
|
||||
#include <utils/inval.h>
|
||||
@ -44,7 +45,6 @@
|
||||
#include <utils/syscache.h>
|
||||
#include <utils/builtins.h>
|
||||
#include <commands/vacuum.h>
|
||||
#include <parser/catalog_utils.h>
|
||||
#include <storage/bufpage.h>
|
||||
#include "storage/shmem.h"
|
||||
#ifndef HAVE_GETRUSAGE
|
||||
|
@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* 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 <utils/builtins.h>
|
||||
#include <nodes/relation.h>
|
||||
#include <parser/catalog_utils.h>
|
||||
#include <parser/parse_query.h>
|
||||
#include <parser/parse_relation.h>
|
||||
#include <parser/parse_type.h>
|
||||
#include <rewrite/rewriteDefine.h>
|
||||
#include <rewrite/rewriteHandler.h>
|
||||
#include <rewrite/rewriteManip.h>
|
||||
@ -72,7 +72,7 @@ DefineVirtualRelation(char *relname, List *tlist)
|
||||
entry = lfirst(t);
|
||||
res = entry->resdom;
|
||||
resname = res->resname;
|
||||
restypename = tname(get_id_type(res->restype));
|
||||
restypename = typeidTypeName(res->restype);
|
||||
|
||||
typename = makeNode(TypeName);
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
||||
*
|
||||
*
|
||||
* 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
|
||||
|
||||
#include "access/tupdesc.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "parser/parse_type.h"
|
||||
#include "storage/bufmgr.h"
|
||||
#include "utils/palloc.h"
|
||||
#include "utils/lsyscache.h"
|
||||
#include "storage/bufmgr.h"
|
||||
#include "parser/catalog_utils.h"
|
||||
#include "catalog/pg_type.h"
|
||||
|
||||
static TupleTableSlot *NodeGetResultTupleSlot(Plan *node);
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* 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 "catalog/pg_proc.h"
|
||||
#include "parser/parse_query.h"
|
||||
#include "tcop/pquery.h"
|
||||
#include "tcop/tcopprot.h"
|
||||
#include "tcop/utility.h"
|
||||
|
@ -23,12 +23,12 @@
|
||||
#include "access/heapam.h"
|
||||
#include "catalog/pg_aggregate.h"
|
||||
#include "catalog/catalog.h"
|
||||
#include "parser/parse_type.h"
|
||||
#include "executor/executor.h"
|
||||
#include "executor/nodeAgg.h"
|
||||
#include "storage/bufmgr.h"
|
||||
#include "utils/palloc.h"
|
||||
#include "utils/syscache.h"
|
||||
#include "parser/catalog_utils.h"
|
||||
|
||||
/*
|
||||
* AggFuncInfo -
|
||||
@ -172,7 +172,7 @@ ExecAgg(Agg *node)
|
||||
if (!HeapTupleIsValid(aggTuple))
|
||||
elog(WARN, "ExecAgg: cache lookup failed for aggregate \"%s\"(%s)",
|
||||
aggname,
|
||||
tname(get_id_type(agg->basetype)));
|
||||
typeidTypeName(agg->basetype));
|
||||
aggp = (Form_pg_aggregate) GETSTRUCT(aggTuple);
|
||||
|
||||
xfn1_oid = aggp->aggtransfn1;
|
||||
|
@ -6,6 +6,7 @@
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include "executor/spi.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "access/printtup.h"
|
||||
#include "fmgr.h"
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* 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/primnodes.h"
|
||||
#include "nodes/relation.h"
|
||||
#include "parser/parse_query.h"
|
||||
|
||||
#include "utils/syscache.h"
|
||||
#include "utils/builtins.h" /* for namecpy */
|
||||
|
@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* 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
|
||||
* AUTHOR DATE MAJOR EVENT
|
||||
@ -26,11 +26,11 @@
|
||||
#include "nodes/parsenodes.h"
|
||||
#include "nodes/print.h"
|
||||
#include "parser/parsetree.h"
|
||||
#include "parser/catalog_utils.h"
|
||||
#include "access/heapam.h"
|
||||
#include "utils/lsyscache.h"
|
||||
#include "nodes/nodes.h"
|
||||
#include "nodes/plannodes.h"
|
||||
#include "parser/parse_relation.h"
|
||||
#include "optimizer/clauses.h"
|
||||
|
||||
static char *plannode_type(Plan *p);
|
||||
@ -194,7 +194,7 @@ print_expr(Node *expr, List *rtable)
|
||||
r = heap_openr(relname);
|
||||
if (rt->refname)
|
||||
relname = rt->refname; /* table renamed */
|
||||
attname = getAttrName(r, var->varattno);
|
||||
attname = attnumAttName(r, var->varattno);
|
||||
heap_close(r);
|
||||
}
|
||||
break;
|
||||
|
@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* 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))
|
||||
{
|
||||
if (typeid_get_relid(get_paramtype((Param) clause)))
|
||||
if (typeidTypeRelid(get_paramtype((Param) clause)))
|
||||
{
|
||||
/* 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);
|
||||
heap_close(rd);
|
||||
}
|
||||
@ -659,7 +659,7 @@ xfunc_width(LispValue clause)
|
||||
else
|
||||
{
|
||||
/* Param node returns a base type */
|
||||
retval = tlen(get_id_type(get_paramtype((Param) clause)));
|
||||
retval = typeLen(typeidType(get_paramtype((Param) clause)));
|
||||
}
|
||||
goto exit;
|
||||
}
|
||||
@ -1324,9 +1324,9 @@ xfunc_func_width(RegProcedure funcid, LispValue args)
|
||||
proc = (Form_pg_proc) GETSTRUCT(tupl);
|
||||
|
||||
/* 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);
|
||||
heap_close(rd);
|
||||
goto exit;
|
||||
|
@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* 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/builtins.h"
|
||||
|
||||
#include "parser/parse_query.h"
|
||||
#include "optimizer/clauseinfo.h"
|
||||
#include "optimizer/clauses.h"
|
||||
#include "optimizer/planmain.h"
|
||||
|
@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* 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/parsenodes.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/lsyscache.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 */
|
||||
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);
|
||||
|
||||
/*
|
||||
@ -318,21 +317,21 @@ pg_checkretval(Oid rettype, QueryTreeList *queryTreeList)
|
||||
* final query had better be a retrieve.
|
||||
*/
|
||||
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
|
||||
* 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)
|
||||
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;
|
||||
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 */
|
||||
return;
|
||||
@ -358,16 +357,16 @@ pg_checkretval(Oid rettype, QueryTreeList *queryTreeList)
|
||||
* declared return type, and be sure that attributes 1 .. n in the
|
||||
* target list match the declared types.
|
||||
*/
|
||||
reln = heap_open(get_typrelid(typ));
|
||||
reln = heap_open(typeTypeRelid(typ));
|
||||
|
||||
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;
|
||||
relnatts = reln->rd_rel->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 */
|
||||
for (i = 1; i <= relnatts; i++)
|
||||
@ -397,14 +396,14 @@ pg_checkretval(Oid rettype, QueryTreeList *queryTreeList)
|
||||
else if (IsA(thenode, Func))
|
||||
tletype = (Oid) get_functype((Func *) thenode);
|
||||
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
|
||||
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
|
||||
/* reach right in there, why don't you? */
|
||||
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);
|
||||
|
@ -7,13 +7,14 @@
|
||||
*
|
||||
*
|
||||
* 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 "postgres.h"
|
||||
|
||||
#include "catalog/pg_type.h"
|
||||
#include "nodes/pg_list.h"
|
||||
#include "nodes/relation.h"
|
||||
#include "nodes/primnodes.h"
|
||||
@ -24,9 +25,9 @@
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/lsyscache.h"
|
||||
#include "utils/palloc.h"
|
||||
#include "parser/parse_type.h"
|
||||
|
||||
#include "parser/parsetree.h" /* for getrelid() */
|
||||
#include "parser/catalog_utils.h"
|
||||
|
||||
#include "optimizer/internal.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);
|
||||
if (attisset)
|
||||
{
|
||||
typlen = tlen(type("oid"));
|
||||
typlen = typeLen(typeidType(OIDOID));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* 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/relation.h"
|
||||
|
||||
#include "parser/parse_query.h"
|
||||
#include "parser/parsetree.h"
|
||||
|
||||
#include "utils/elog.h"
|
||||
|
@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* 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 "nodes/makefuncs.h"
|
||||
#include "parser/catalog_utils.h"
|
||||
|
||||
static Node *flatten_tlistentry(Node *tlistentry, List *flat_tlist);
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
# Makefile for parser
|
||||
#
|
||||
# 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
|
||||
|
||||
|
||||
OBJS= analyze.o catalog_utils.o gram.o \
|
||||
keywords.o parser.o parse_query.o scan.o scansup.o
|
||||
OBJS= analyze.o gram.o keywords.o parser.o parse_agg.o parse_clause.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
|
||||
|
||||
|
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
|
||||
* $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
|
||||
* AUTHOR DATE MAJOR EVENT
|
||||
@ -39,8 +39,6 @@
|
||||
#include "nodes/parsenodes.h"
|
||||
#include "nodes/print.h"
|
||||
#include "parser/gramparse.h"
|
||||
#include "parser/catalog_utils.h"
|
||||
#include "parser/parse_query.h"
|
||||
#include "utils/acl.h"
|
||||
#include "catalog/catname.h"
|
||||
#include "utils/elog.h"
|
||||
@ -49,8 +47,11 @@
|
||||
static char saved_relname[NAMEDATALEN]; /* need this for complex attributes */
|
||||
static bool QueryIsRule = FALSE;
|
||||
static Node *saved_In_Expr;
|
||||
static Oid *param_type_info;
|
||||
static int pfunc_num_args;
|
||||
extern List *parsetree;
|
||||
|
||||
|
||||
/*
|
||||
* 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
|
||||
@ -64,6 +65,9 @@ static List *makeConstantList( A_Const *node);
|
||||
static char *FlattenStringList(List *list);
|
||||
static char *fmtId(char *rawid);
|
||||
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 */
|
||||
#if defined(yywrap)
|
||||
@ -2324,7 +2328,7 @@ Typename: Array opt_array_bounds
|
||||
* emp(name=text,mgr=emp)
|
||||
*/
|
||||
$$->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
|
||||
* contain one element.)
|
||||
*/
|
||||
@ -3690,4 +3694,24 @@ printf("fmtId- %sconvert %s to %s\n", ((cp == rawid)? "do not ": ""), rawid, cp)
|
||||
#endif
|
||||
|
||||
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
|
||||
* $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/parsenodes.h"
|
||||
#include "parse.h"
|
||||
#include "utils/elog.h"
|
||||
#include "parser/keywords.h"
|
||||
#include "utils/elog.h"
|
||||
|
||||
/*
|
||||
* 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--
|
||||
* take an "optimizable" stmt and make the query tree that
|
||||
* the planner requires.
|
||||
* parse_node.c--
|
||||
* various routines that make nodes for query plans
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* 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 <string.h>
|
||||
#include "postgres.h"
|
||||
|
||||
#include "postgres.h"
|
||||
#include "fmgr.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/syscache.h"
|
||||
|
||||
#ifdef 0
|
||||
#include "access/tupmacs.h"
|
||||
#include "utils/elog.h"
|
||||
#include "utils/palloc.h"
|
||||
#include "utils/acl.h" /* for ACL_NO_PRIV_WARNING */
|
||||
#include "utils/rel.h" /* Relation stuff */
|
||||
|
||||
#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/primnodes.h"
|
||||
#include "nodes/parsenodes.h"
|
||||
#include "nodes/makefuncs.h"
|
||||
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* returns range entry if found, else NULL
|
||||
* make_parsestate() --
|
||||
* allocate and initialize a new ParseState.
|
||||
* the CALLERS is responsible for freeing the ParseState* returned
|
||||
*
|
||||
*/
|
||||
RangeTblEntry *
|
||||
colnameRangeTableEntry(ParseState *pstate, char *colname)
|
||||
|
||||
ParseState *
|
||||
make_parsestate(void)
|
||||
{
|
||||
List *et;
|
||||
List *rtable;
|
||||
RangeTblEntry *rte_result;
|
||||
ParseState *pstate;
|
||||
|
||||
if (pstate->p_is_rule)
|
||||
rtable = lnext(lnext(pstate->p_rtable));
|
||||
else
|
||||
rtable = pstate->p_rtable;
|
||||
pstate = malloc(sizeof(ParseState));
|
||||
pstate->p_last_resno = 1;
|
||||
pstate->p_rtable = NIL;
|
||||
pstate->p_numAgg = 0;
|
||||
pstate->p_aggs = NIL;
|
||||
pstate->p_is_insert = false;
|
||||
pstate->p_insert_columns = NIL;
|
||||
pstate->p_is_update = false;
|
||||
pstate->p_is_rule = false;
|
||||
pstate->p_in_where_clause = false;
|
||||
pstate->p_target_relation = NULL;
|
||||
pstate->p_target_rangetblentry = NULL;
|
||||
|
||||
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;
|
||||
return (pstate);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)++,
|
||||
type_id,
|
||||
(Size) type_len,
|
||||
attrname,
|
||||
(Index) 0,
|
||||
(Oid) 0,
|
||||
0);
|
||||
te->expr = (Node *) varnode;
|
||||
if (te_head == NIL)
|
||||
te_head = te_tail = lcons(te, NIL);
|
||||
else
|
||||
te_tail = lappend(te_tail, te);
|
||||
}
|
||||
|
||||
heap_close(rdesc);
|
||||
return (te_head);
|
||||
}
|
||||
|
||||
static void
|
||||
disallow_setop(char *op, Type optype, Node *operand)
|
||||
{
|
||||
if (operand == NULL)
|
||||
return;
|
||||
|
||||
if (nodeTag(operand) == T_Iter)
|
||||
{
|
||||
elog(NOTICE, "An operand to the '%s' operator returns a set of %s,",
|
||||
op, tname(optype));
|
||||
elog(WARN, "but '%s' takes single values, not sets.",
|
||||
op);
|
||||
}
|
||||
}
|
||||
|
||||
static Node *
|
||||
Node *
|
||||
make_operand(char *opname,
|
||||
Node *tree,
|
||||
Oid orig_typeId,
|
||||
@ -267,7 +84,7 @@ make_operand(char *opname,
|
||||
if (tree != NULL)
|
||||
{
|
||||
result = tree;
|
||||
true_type = get_id_type(true_typeId);
|
||||
true_type = typeidType(true_typeId);
|
||||
disallow_setop(opname, true_type, result);
|
||||
if (true_typeId != orig_typeId)
|
||||
{ /* must coerce */
|
||||
@ -276,13 +93,13 @@ make_operand(char *opname,
|
||||
Assert(nodeTag(result) == T_Const);
|
||||
val = (Datum) textout((struct varlena *)
|
||||
con->constvalue);
|
||||
infunc = typeid_get_retinfunc(true_typeId);
|
||||
infunc = typeidRetinfunc(true_typeId);
|
||||
con = makeNode(Const);
|
||||
con->consttype = true_typeId;
|
||||
con->constlen = tlen(true_type);
|
||||
con->constlen = typeLen(true_type);
|
||||
con->constvalue = (Datum) fmgr(infunc,
|
||||
val,
|
||||
get_typelem(true_typeId),
|
||||
typeidTypElem(true_typeId),
|
||||
-1 /* for varchar() type */ );
|
||||
con->constisnull = false;
|
||||
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 *
|
||||
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 &&
|
||||
!((Const *) rtree)->constiscast)
|
||||
{
|
||||
outfunc = typeid_get_retoutfunc(rtypeId);
|
||||
infunc = typeid_get_retinfunc(ltypeId);
|
||||
outfunc = typeidRetoutfunc(rtypeId);
|
||||
infunc = typeidRetinfunc(ltypeId);
|
||||
outstr = (char *) fmgr(outfunc, ((Const *) rtree)->constvalue);
|
||||
((Const *) rtree)->constvalue = (Datum) fmgr(infunc, outstr);
|
||||
pfree(outstr);
|
||||
((Const *) rtree)->consttype = rtypeId = ltypeId;
|
||||
newtype = get_id_type(rtypeId);
|
||||
((Const *) rtree)->constlen = tlen(newtype);
|
||||
((Const *) rtree)->constbyval = tbyval(newtype);
|
||||
newtype = typeidType(rtypeId);
|
||||
((Const *) rtree)->constlen = typeLen(newtype);
|
||||
((Const *) rtree)->constbyval = typeByVal(newtype);
|
||||
}
|
||||
|
||||
if (CONVERTABLE_TYPE(rtypeId) && nodeTag(rtree) != T_Const &&
|
||||
CONVERTABLE_TYPE(ltypeId) && nodeTag(ltree) == T_Const &&
|
||||
!((Const *) ltree)->constiscast)
|
||||
{
|
||||
outfunc = typeid_get_retoutfunc(ltypeId);
|
||||
infunc = typeid_get_retinfunc(rtypeId);
|
||||
outfunc = typeidRetoutfunc(ltypeId);
|
||||
infunc = typeidRetinfunc(rtypeId);
|
||||
outstr = (char *) fmgr(outfunc, ((Const *) ltree)->constvalue);
|
||||
((Const *) ltree)->constvalue = (Datum) fmgr(infunc, outstr);
|
||||
pfree(outstr);
|
||||
((Const *) ltree)->consttype = ltypeId = rtypeId;
|
||||
newtype = get_id_type(ltypeId);
|
||||
((Const *) ltree)->constlen = tlen(newtype);
|
||||
((Const *) ltree)->constbyval = tbyval(newtype);
|
||||
newtype = typeidType(ltypeId);
|
||||
((Const *) ltree)->constlen = typeLen(newtype);
|
||||
((Const *) ltree)->constbyval = typeByVal(newtype);
|
||||
}
|
||||
|
||||
temp = oper(opname, ltypeId, rtypeId, false);
|
||||
@ -426,38 +258,6 @@ make_op(char *opname, Node *ltree, Node *rtree)
|
||||
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 *
|
||||
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);
|
||||
|
||||
attid = nf_varattno(rd, attrname);
|
||||
if (attid == InvalidAttrNumber)
|
||||
elog(WARN, "Invalid attribute %s\n", attrname);
|
||||
vartypeid = att_typeid(rd, attid);
|
||||
attid = attnameAttNum(rd, attrname); /* could elog(WARN) */
|
||||
vartypeid = attnumTypeId(rd, attid);
|
||||
|
||||
varnode = makeVar(vnum, attid, vartypeid, vnum, attid);
|
||||
|
||||
@ -667,7 +465,7 @@ make_const(Value *value)
|
||||
switch (nodeTag(value))
|
||||
{
|
||||
case T_Integer:
|
||||
tp = type("int4");
|
||||
tp = typeidType(INT4OID);
|
||||
val = Int32GetDatum(intVal(value));
|
||||
break;
|
||||
|
||||
@ -675,7 +473,7 @@ make_const(Value *value)
|
||||
{
|
||||
float64 dummy;
|
||||
|
||||
tp = type("float8");
|
||||
tp = typeidType(FLOAT8OID);
|
||||
|
||||
dummy = (float64) palloc(sizeof(float64data));
|
||||
*dummy = floatVal(value);
|
||||
@ -685,7 +483,7 @@ make_const(Value *value)
|
||||
break;
|
||||
|
||||
case T_String:
|
||||
tp = type("unknown"); /* unknown for now, will be type
|
||||
tp = typeidType(UNKNOWNOID); /* unknown for now, will be type
|
||||
* coerced */
|
||||
val = PointerGetDatum(textin(strVal(value)));
|
||||
break;
|
||||
@ -702,111 +500,14 @@ make_const(Value *value)
|
||||
}
|
||||
}
|
||||
|
||||
con = makeConst(typeid(tp),
|
||||
tlen(tp),
|
||||
con = makeConst(typeTypeId(tp),
|
||||
typeLen(tp),
|
||||
val,
|
||||
false,
|
||||
tbyval(tp),
|
||||
typeByVal(tp),
|
||||
false, /* not a set */
|
||||
false);
|
||||
|
||||
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
|
||||
* $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 "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/parse_query.h"
|
||||
#include "utils/palloc.h"
|
||||
#endif
|
||||
|
||||
char *parseString; /* the char* which holds the string to be
|
||||
* parsed */
|
||||
@ -103,10 +114,10 @@ static void
|
||||
define_sets(Node *clause)
|
||||
{
|
||||
Oid setoid;
|
||||
Type t = type("oid");
|
||||
Oid typeoid = typeid(t);
|
||||
Size oidsize = tlen(t);
|
||||
bool oidbyval = tbyval(t);
|
||||
Type t = typeidType(OIDOID);
|
||||
Oid typeoid = typeTypeId(t);
|
||||
Size oidsize = typeLen(t);
|
||||
bool oidbyval = typeByVal(t);
|
||||
|
||||
if (clause == NULL)
|
||||
{
|
||||
@ -125,11 +136,11 @@ define_sets(Node *clause)
|
||||
return;
|
||||
}
|
||||
setoid = SetDefine(((Const *) clause)->constvalue,
|
||||
get_id_typname(((Const *) clause)->consttype));
|
||||
typeidTypeName(((Const *) clause)->consttype));
|
||||
set_constvalue((Const) clause, setoid);
|
||||
set_consttype((Const) clause, typeoid);
|
||||
set_constlen((Const) clause, oidsize);
|
||||
set_constbyval((Const) clause, oidbyval);
|
||||
set_constypeByVal((Const) clause, oidbyval);
|
||||
}
|
||||
else if (IsA(clause, Iter))
|
||||
{
|
||||
@ -173,6 +184,5 @@ define_sets(Node *clause)
|
||||
define_sets(get_rightop(clause));
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* 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 <string.h>
|
||||
#include "c.h"
|
||||
#include "postgres.h"
|
||||
#include "miscadmin.h"
|
||||
#include "utils/elog.h"
|
||||
|
@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* 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 "nodes/pg_list.h" /* for Lisp support */
|
||||
#include "nodes/parsenodes.h"
|
||||
#include "parser/catalog_utils.h"
|
||||
#include "parser/parse_relation.h"
|
||||
|
||||
#include "rewrite/locks.h"
|
||||
#include "rewrite/rewriteDefine.h"
|
||||
#include "rewrite/rewriteRemove.h"
|
||||
@ -107,7 +108,7 @@ InsertRule(char *rulname,
|
||||
if (evslot == NULL)
|
||||
evslot_index = -1;
|
||||
else
|
||||
evslot_index = varattno(eventrel, (char *) evslot);
|
||||
evslot_index = attnameAttNum(eventrel, (char *) evslot);
|
||||
heap_close(eventrel);
|
||||
|
||||
if (evinstead)
|
||||
@ -221,8 +222,8 @@ DefineQueryRewrite(RuleStmt *stmt)
|
||||
}
|
||||
else
|
||||
{
|
||||
event_attno = varattno(event_relation, eslot_string);
|
||||
event_attype = att_typeid(event_relation, event_attno);
|
||||
event_attno = attnameAttNum(event_relation, eslot_string);
|
||||
event_attype = attnumTypeId(event_relation, event_attno);
|
||||
}
|
||||
heap_close(event_relation);
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* 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
|
||||
* See acl.h.
|
||||
@ -31,10 +31,12 @@
|
||||
#include "catalog/pg_operator.h"
|
||||
#include "catalog/pg_aggregate.h"
|
||||
#include "catalog/pg_proc.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "catalog/pg_user.h"
|
||||
#include "parser/parse_agg.h"
|
||||
#include "parser/parse_func.h"
|
||||
#include "utils/syscache.h"
|
||||
#include "utils/tqual.h"
|
||||
#include "parser/catalog_utils.h"
|
||||
#include "fmgr.h"
|
||||
|
||||
static int32 aclcheck(Acl *acl, AclId id, AclIdType idtype, AclMode mode);
|
||||
|
@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* 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
|
||||
* this is the "main" module of the postgres backend and
|
||||
@ -45,11 +45,10 @@
|
||||
|
||||
#include "lib/dllist.h"
|
||||
|
||||
#include "parser/catalog_utils.h"
|
||||
#include "parser/parse_query.h" /* for MakeTimeRange() */
|
||||
#include "commands/async.h"
|
||||
#include "tcop/tcopprot.h" /* where declarations for this file go */
|
||||
#include "optimizer/planner.h"
|
||||
#include "parser/parser.h"
|
||||
|
||||
#include "tcop/tcopprot.h"
|
||||
#include "tcop/tcopdebug.h"
|
||||
@ -1341,7 +1340,7 @@ PostgresMain(int argc, char *argv[])
|
||||
if (IsUnderPostmaster == false)
|
||||
{
|
||||
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/plannodes.h"
|
||||
#include "catalog/pg_proc.h"
|
||||
#include "parser/parse_query.h"
|
||||
#include "tcop/pquery.h"
|
||||
#include "tcop/tcopprot.h"
|
||||
#include "tcop/utility.h"
|
||||
|
@ -6,13 +6,16 @@
|
||||
*
|
||||
* 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
|
||||
#define NODEFUNCS_H
|
||||
|
||||
#include <nodes/nodes.h>
|
||||
#include <nodes/primnodes.h>
|
||||
|
||||
extern bool single_node(Node *node);
|
||||
extern bool var_is_outer(Var *var);
|
||||
extern bool var_is_rel(Var *var);
|
||||
|
@ -6,7 +6,7 @@
|
||||
*
|
||||
* 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 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
|
||||
*
|
||||
* $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
|
||||
* This file was created so that other c files could get the two
|
||||
@ -19,7 +19,7 @@
|
||||
#define TCOPPROT_H
|
||||
|
||||
#include <executor/execdesc.h>
|
||||
#include <parser/parse_query.h>
|
||||
#include <parser/parse_node.h>
|
||||
|
||||
#ifndef BOOTSTRAP_INCLUDE
|
||||
extern List *
|
||||
|
@ -1,6 +1,8 @@
|
||||
#!/bin/sh
|
||||
# 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`
|
||||
do
|
||||
|
Loading…
x
Reference in New Issue
Block a user