1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-30 11:03:19 +03:00

Postgres95 1.01 Distribution - Virgin Sources

This commit is contained in:
Marc G. Fournier
1996-07-09 06:22:35 +00:00
commit d31084e9d1
868 changed files with 242656 additions and 0 deletions

View File

@ -0,0 +1,46 @@
#-------------------------------------------------------------------------
#
# Makefile.inc--
# Makefile for the parser module
#
# Copyright (c) 1994, Regents of the University of California
#
#
# IDENTIFICATION
# $Header: /cvsroot/pgsql/src/backend/parser/Attic/Makefile.inc,v 1.1.1.1 1996/07/09 06:21:39 scrappy Exp $
#
#-------------------------------------------------------------------------
VPATH:= $(VPATH):$(CURDIR)/parser
#PARSEYACCS= gram.c parse.h
PARSEYACCS= gram.c
$(PARSEYACCS): gram.y
cd $(objdir); \
$(YACC) $(YFLAGS) $<; \
mv y.tab.c gram.c; \
mv y.tab.h parse.h
$(objdir)/gram.o: gram.c
$(cc_inobjdir)
scan.c: scan.l
cd $(objdir); $(LEX) $<; mv lex.yy.c scan.c
$(objdir)/scan.o: scan.c
$(cc_inobjdir)
SRCS_PARSER+= analyze.c catalog_utils.c dbcommands.c gram.c \
keywords.c parser.c parse_query.c scan.c scansup.c
CLEANFILES+= scan.c ${PARSEYACCS}
POSTGRES_DEPEND+= scan.c $(PARSEYACCS)
HEADERS+= catalog_utils.h io.h parse_query.h parsetree.h \
dbcommands.h keywords.h

2467
src/backend/parser/analyze.c Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,64 @@
/*-------------------------------------------------------------------------
*
* catalog_utils.h--
*
*
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: catalog_utils.h,v 1.1.1.1 1996/07/09 06:21:40 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef CATALOG_UTILS_H
#define CATALOG_UTILS_H
#include "postgres.h"
#include "access/htup.h"
#include "utils/rel.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "utils/syscache.h"
typedef HeapTuple Type;
typedef HeapTuple Operator;
extern Oid typeid_get_relid();
extern bool check_typeid(long id);
extern Type get_id_type(long id);
extern char *get_id_typname(long 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, int arg1, int arg2);
extern Operator right_oper(char *op, int arg);
extern Operator left_oper(char *op, int 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 *outstr(char *typename, char *value);
extern char *instr2(Type tp, char *string, int typlen);
extern char *instr1(TypeTupleForm 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(int type_id);
extern Oid typeid_get_relid(int type_id);
extern Oid get_typrelid(Type typ);
extern Oid get_typelem(Oid type_id);
extern char FindDelimiter(char *typename);
extern void op_error(char *op, int arg1, int arg2);
extern void func_error(char *caller, char *funcname, int nargs, int *argtypes);
#endif /* CATALOG_UTILS_H */

View File

@ -0,0 +1,259 @@
/*-------------------------------------------------------------------------
*
* dbcommands.c--
*
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/Attic/dbcommands.c,v 1.1.1.1 1996/07/09 06:21:40 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include <stdio.h>
#include <signal.h>
#include "postgres.h"
#include "miscadmin.h" /* for DataDir */
#include "access/heapam.h"
#include "access/htup.h"
#include "access/relscan.h"
#include "utils/rel.h"
#include "utils/elog.h"
#include "catalog/catname.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_user.h"
#include "catalog/pg_database.h"
#include "utils/syscache.h"
#include "parser/dbcommands.h"
#include "tcop/tcopprot.h"
#include "storage/bufmgr.h"
#include "storage/lmgr.h"
/* non-export function prototypes */
static void check_permissions(char *command, char *dbname,
Oid *dbIdP, Oid *userIdP);
static HeapTuple get_pg_dbtup(char *command, char *dbname, Relation dbrel);
void
createdb(char *dbname)
{
Oid db_id, user_id;
char buf[512];
/*
* If this call returns, the database does not exist and we're allowed
* to create databases.
*/
check_permissions("createdb", dbname, &db_id, &user_id);
/* close virtual file descriptors so we can do system() calls */
closeAllVfds();
sprintf(buf, "mkdir %s%cbase%c%s", DataDir, SEP_CHAR, SEP_CHAR, dbname);
system(buf);
sprintf(buf, "%s %s%cbase%ctemplate1%c* %s%cbase%c%s",
COPY_CMD, DataDir, SEP_CHAR, SEP_CHAR, SEP_CHAR, DataDir,
SEP_CHAR, SEP_CHAR, dbname);
system(buf);
/* sprintf(buf, "insert into pg_database (datname, datdba, datpath) \
values (\'%s\'::char16, \'%d\'::oid, \'%s\'::text);",
dbname, user_id, dbname);
*/
sprintf(buf, "insert into pg_database (datname, datdba, datpath) \
values (\'%s\', \'%d\', \'%s\');",
dbname, user_id, dbname);
pg_eval(buf, (char **) NULL, (Oid *) NULL, 0);
}
void
destroydb(char *dbname)
{
Oid user_id, db_id;
char buf[512];
/*
* If this call returns, the database exists and we're allowed to
* remove it.
*/
check_permissions("destroydb", dbname, &db_id, &user_id);
if (!OidIsValid(db_id)) {
elog(FATAL, "impossible: pg_database instance with invalid OID.");
}
/* stop the vacuum daemon */
stop_vacuum(dbname);
/* remove the pg_database tuple FIRST,
this may fail due to permissions problems*/
sprintf(buf, "delete from pg_database where pg_database.oid = \'%d\'::oid",
db_id);
pg_eval(buf, (char **) NULL, (Oid *) NULL, 0);
/* remove the data directory. If the DELETE above failed, this will
not be reached */
sprintf(buf, "rm -r %s/base/%s", DataDir, dbname);
system(buf);
/* drop pages for this database that are in the shared buffer cache */
DropBuffers(db_id);
}
static HeapTuple
get_pg_dbtup(char *command, char *dbname, Relation dbrel)
{
HeapTuple dbtup;
HeapTuple tup;
Buffer buf;
HeapScanDesc scan;
ScanKeyData scanKey;
ScanKeyEntryInitialize(&scanKey, 0, Anum_pg_database_datname,
NameEqualRegProcedure, NameGetDatum(dbname));
scan = heap_beginscan(dbrel, 0, NowTimeQual, 1, &scanKey);
if (!HeapScanIsValid(scan))
elog(WARN, "%s: cannot begin scan of pg_database.", command);
/*
* since we want to return the tuple out of this proc, and we're
* going to close the relation, copy the tuple and return the copy.
*/
tup = heap_getnext(scan, 0, &buf);
if (HeapTupleIsValid(tup)) {
dbtup = heap_copytuple(tup);
ReleaseBuffer(buf);
} else
dbtup = tup;
heap_endscan(scan);
return (dbtup);
}
/*
* check_permissions() -- verify that the user is permitted to do this.
*
* If the user is not allowed to carry out this operation, this routine
* elog(WARN, ...)s, which will abort the xact. As a side effect, the
* user's pg_user tuple OID is returned in userIdP and the target database's
* OID is returned in dbIdP.
*/
static void
check_permissions(char *command,
char *dbname,
Oid *dbIdP,
Oid *userIdP)
{
Relation dbrel;
HeapTuple dbtup, utup;
Oid dbowner;
char use_createdb;
bool dbfound;
bool use_super;
char *userName;
userName = GetPgUserName();
utup = SearchSysCacheTuple(USENAME, PointerGetDatum(userName),
0,0,0);
*userIdP = ((Form_pg_user)GETSTRUCT(utup))->usesysid;
use_super = ((Form_pg_user)GETSTRUCT(utup))->usesuper;
use_createdb = ((Form_pg_user)GETSTRUCT(utup))->usecreatedb;
/* Check to make sure user has permission to use createdb */
if (!use_createdb) {
elog(WARN, "user \"%-.*s\" is not allowed to create/destroy databases",
NAMEDATALEN, userName);
}
/* Make sure we are not mucking with the template database */
if (!strcmp(dbname, "template1")) {
elog(WARN, "%s cannot be executed on the template database.", command);
}
/* Check to make sure database is not the currently open database */
if (!strcmp(dbname, GetDatabaseName())) {
elog(WARN, "%s cannot be executed on an open database", command);
}
/* Check to make sure database is owned by this user */
/*
* need the reldesc to get the database owner out of dbtup
* and to set a write lock on it.
*/
dbrel = heap_openr(DatabaseRelationName);
if (!RelationIsValid(dbrel))
elog(FATAL, "%s: cannot open relation \"%-.*s\"",
command, DatabaseRelationName);
/*
* Acquire a write lock on pg_database from the beginning to avoid
* upgrading a read lock to a write lock. Upgrading causes long delays
* when multiple 'createdb's or 'destroydb's are run simult. -mer 7/3/91
*/
RelationSetLockForWrite(dbrel);
dbtup = get_pg_dbtup(command, dbname, dbrel);
dbfound = HeapTupleIsValid(dbtup);
if (dbfound) {
dbowner = (Oid) heap_getattr(dbtup, InvalidBuffer,
Anum_pg_database_datdba,
RelationGetTupleDescriptor(dbrel),
(char *) NULL);
*dbIdP = dbtup->t_oid;
} else {
*dbIdP = InvalidOid;
}
heap_close(dbrel);
/*
* Now be sure that the user is allowed to do this.
*/
if (dbfound && !strcmp(command, "createdb")) {
elog(WARN, "createdb: database %s already exists.", dbname);
} else if (!dbfound && !strcmp(command, "destroydb")) {
elog(WARN, "destroydb: database %s does not exist.", dbname);
} else if (dbfound && !strcmp(command, "destroydb")
&& dbowner != *userIdP && use_super == false) {
elog(WARN, "%s: database %s is not owned by you.", command, dbname);
}
}
/*
* stop_vacuum() -- stop the vacuum daemon on the database, if one is
* running.
*/
void
stop_vacuum(char *dbname)
{
char filename[256];
FILE *fp;
int pid;
sprintf(filename, "%s%cbase%c%s%c%s.vacuum", DataDir, SEP_CHAR, SEP_CHAR,
dbname, SEP_CHAR, dbname);
if ((fp = fopen(filename, "r")) != (FILE *) NULL) {
fscanf(fp, "%d", &pid);
fclose(fp);
if (kill(pid, SIGKILLDAEMON1) < 0) {
elog(WARN, "can't kill vacuum daemon (pid %d) on %s",
pid, dbname);
}
}
}

View File

@ -0,0 +1,28 @@
/*-------------------------------------------------------------------------
*
* dbcommands.h--
*
*
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: dbcommands.h,v 1.1.1.1 1996/07/09 06:21:40 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef DBCOMMANDS_H
#define DBCOMMANDS_H
/*
* Originally from tmp/daemon.h. The functions declared in daemon.h does not
* exist; hence removed. -- AY 7/29/94
*/
#define SIGKILLDAEMON1 SIGINT
#define SIGKILLDAEMON2 SIGTERM
extern void createdb(char *dbname);
extern void destroydb(char *dbname);
void stop_vacuum(char *dbname);
#endif /* DBCOMMANDS_H */

2113
src/backend/parser/gram.y Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,179 @@
/*-------------------------------------------------------------------------
*
* keywords.c--
* lexical token lookup for reserved words in postgres SQL
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.1.1.1 1996/07/09 06:21:40 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include <ctype.h>
#include <string.h>
#include "postgres.h"
#include "nodes/pg_list.h"
#include "nodes/parsenodes.h"
#include "parse.h"
#include "utils/elog.h"
#include "parser/keywords.h"
#include "parser/dbcommands.h" /* createdb, destroydb stop_vacuum */
/*
* List of (keyword-name, keyword-token-value) pairs.
*
* !!WARNING!!: This list must be sorted, because binary
* search is used to locate entries.
*/
static ScanKeyword ScanKeywords[] = {
/* name value */
{ "abort", ABORT_TRANS },
{ "acl", ACL },
{ "add", ADD },
{ "after", AFTER },
{ "aggregate", AGGREGATE },
{ "all", ALL },
{ "alter", ALTER },
{ "and", AND },
{ "append", APPEND },
{ "archIve", ARCHIVE }, /* XXX crooked: I < _ */
{ "arch_store", ARCH_STORE },
{ "archive", ARCHIVE }, /* XXX crooked: i > _ */
{ "as", AS },
{ "asc", ASC },
{ "backward", BACKWARD },
{ "before", BEFORE },
{ "begin", BEGIN_TRANS },
{ "binary", BINARY },
{ "by", BY },
{ "cast", CAST },
{ "change", CHANGE },
{ "close", CLOSE },
{ "cluster", CLUSTER },
{ "column", COLUMN },
{ "commit", COMMIT },
{ "copy", COPY },
{ "create", CREATE },
{ "current", CURRENT },
{ "cursor", CURSOR },
{ "database", DATABASE },
{ "declare", DECLARE },
{ "delete", DELETE },
{ "delimiters", DELIMITERS },
{ "desc", DESC },
{ "distinct", DISTINCT },
{ "do", DO },
{ "drop", DROP },
{ "end", END_TRANS },
{ "execute", EXECUTE },
{ "explain", EXPLAIN },
{ "extend", EXTEND },
{ "fetch", FETCH },
{ "for", FOR },
{ "forward", FORWARD },
{ "from", FROM },
{ "function", FUNCTION },
{ "grant", GRANT },
{ "group", GROUP },
{ "having", HAVING },
{ "heavy", HEAVY },
{ "in", IN },
{ "index", INDEX },
{ "inherits", INHERITS },
{ "insert", INSERT },
{ "instead", INSTEAD },
{ "into", INTO },
{ "isnull", ISNULL },
{ "language", LANGUAGE },
{ "light", LIGHT },
{ "like", LIKE },
{ "listen", LISTEN },
{ "load", LOAD },
{ "merge", MERGE },
{ "move", MOVE },
{ "new", NEW },
{ "none", NONE },
{ "not", NOT },
{ "nothing", NOTHING },
{ "notify", NOTIFY },
{ "notnull", NOTNULL },
{ "null", PNULL },
{ "on", ON },
{ "operator", OPERATOR },
{ "option", OPTION },
{ "or", OR },
{ "order", ORDER },
{ "privileges", PRIVILEGES },
{ "public", PUBLIC },
{ "purge", PURGE },
{ "recipe", RECIPE },
{ "rename", RENAME },
{ "replace", REPLACE },
{ "retrieve", RETRIEVE },
{ "returns", RETURNS },
{ "revoke", REVOKE },
{ "rollback", ROLLBACK },
{ "rule", RULE },
{ "select", SELECT },
{ "set", SET },
{ "setof", SETOF },
{ "stdin", STDIN },
{ "stdout", STDOUT },
{ "store", STORE },
{ "table", TABLE },
{ "to", TO },
{ "transaction", TRANSACTION },
{ "type", P_TYPE },
{ "update", UPDATE },
{ "using", USING },
{ "vacuum", VACUUM },
{ "values", VALUES },
{ "version", VERSION },
{ "view", VIEW },
{ "where", WHERE },
{ "with", WITH },
{ "work", WORK },
};
ScanKeyword *
ScanKeywordLookup(char *text)
{
ScanKeyword *low = &ScanKeywords[0];
ScanKeyword *high = endof(ScanKeywords) - 1;
ScanKeyword *middle;
int difference;
while (low <= high) {
middle = low + (high - low) / 2;
/* keywords case-insensitive (for SQL) -- ay 8/94 */
difference = strcasecmp(middle->name, text);
if (difference == 0)
return (middle);
else if (difference < 0)
low = middle + 1;
else
high = middle - 1;
}
return (NULL);
}
char*
AtomValueGetString(int atomval)
{
ScanKeyword *low = &ScanKeywords[0];
ScanKeyword *high = endof(ScanKeywords) - 1;
int keyword_list_length = (high-low);
int i;
for (i=0; i < keyword_list_length ; i++ )
if (ScanKeywords[i].value == atomval )
return(ScanKeywords[i].name);
elog(WARN,"AtomGetString called with bogus atom # : %d", atomval );
return(NULL);
}

View File

@ -0,0 +1,25 @@
/*-------------------------------------------------------------------------
*
* keywords.h--
* string,atom lookup thingy, reduces strcmp traffic greatly
* in the bowels of the system. Look for actual defs in lib/C/atoms.c
*
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: keywords.h,v 1.1.1.1 1996/07/09 06:21:40 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef KEYWORDS_H
#define KEYWORDS_H
typedef struct ScanKeyword {
char *name;
int value;
} ScanKeyword;
extern ScanKeyword *ScanKeywordLookup(char *text);
extern char* AtomValueGetString(int atomval);
#endif /* KEYWORDS_H */

View File

@ -0,0 +1,653 @@
/*-------------------------------------------------------------------------
*
* parse_query.c--
* take an "optimizable" stmt and make the query tree that
* the planner requires.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/Attic/parse_query.c,v 1.1.1.1 1996/07/09 06:21:40 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include <ctype.h>
#include <string.h>
#include "postgres.h"
#include "access/heapam.h"
#include "utils/tqual.h"
#include "access/tupmacs.h"
#include "utils/builtins.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_utils.h"
#include "parser/parse_query.h"
/* #include "parser/io.h" */
#include "utils/lsyscache.h"
#include "nodes/pg_list.h"
#include "nodes/primnodes.h"
#include "nodes/parsenodes.h"
#include "nodes/makefuncs.h"
Oid *param_type_info;
int pfunc_num_args;
extern int Quiet;
/* given range variable, return id of variable; position starts with 1 */
int
RangeTablePosn(List *rtable, char *rangevar)
{
int index;
List *temp;
index = 1;
/* temp = pstate->p_rtable; */
temp = rtable;
while (temp != NIL) {
RangeTblEntry *rt_entry = lfirst(temp);
if (!strcmp(rt_entry->refname, rangevar))
return index;
temp = lnext(temp);
index++;
}
return(0);
}
char*
VarnoGetRelname(ParseState *pstate, int vnum)
{
int i;
List *temp = pstate->p_rtable;
for( i = 1; i < vnum ; i++)
temp = lnext(temp);
return(((RangeTblEntry*)lfirst(temp))->relname);
}
RangeTblEntry *
makeRangeTableEntry(char *relname,
bool inh,
TimeRange *timeRange,
char *refname)
{
Relation relation;
RangeTblEntry *ent = makeNode(RangeTblEntry);
ent->relname = pstrdup(relname);
ent->refname = refname;
relation = heap_openr(ent->relname);
if (relation == NULL) {
elog(WARN,"%s: %s",
relname, ACL_NO_PRIV_WARNING);
}
/*
* Flags - zero or more from archive,inheritance,union,version
* or recursive (transitive closure)
* [we don't support them all -- ay 9/94 ]
*/
ent->inh = inh;
ent->timeRange = timeRange;
/* RelOID */
ent->relid = RelationGetRelationId(relation);
/*
* close the relation we're done with it for now.
*/
heap_close(relation);
return ent;
}
/*
* expandAll -
* makes a list of attributes
* assumes reldesc caching works
*/
List *
expandAll(ParseState* pstate, char *relname, int *this_resno)
{
Relation rdesc;
List *tall = NIL;
Var *varnode;
int i, maxattrs, first_resno;
int type_id, type_len, vnum;
char *physical_relname;
first_resno = *this_resno;
/* printf("\nExpanding %.*s.all\n", NAMEDATALEN, relname); */
vnum = RangeTablePosn(pstate->p_rtable, relname);
if ( vnum == 0 ) {
pstate->p_rtable = lappend(pstate->p_rtable,
makeRangeTableEntry(relname, FALSE, NULL,
relname));
vnum = RangeTablePosn(pstate->p_rtable, relname);
}
physical_relname = VarnoGetRelname(pstate, vnum);
rdesc = heap_openr(physical_relname);
if (rdesc == NULL ) {
elog(WARN,"Unable to expand all -- heap_openr failed on %s",
physical_relname);
return NIL;
}
maxattrs = RelationGetNumberOfAttributes(rdesc);
for ( i = maxattrs-1 ; i > -1 ; --i ) {
char *attrname;
TargetEntry *rte = makeNode(TargetEntry);
attrname = pstrdup ((rdesc->rd_att->attrs[i]->attname).data);
varnode = (Var*)make_var(pstate, relname, attrname, &type_id);
type_len = (int)tlen(get_id_type(type_id));
/* Even if the elements making up a set are complex, the
* set itself is not. */
rte->resdom = makeResdom((AttrNumber) i + first_resno,
(Oid)type_id,
(Size)type_len,
attrname,
(Index)0,
(Oid)0,
0);
rte->expr = (Node *)varnode;
tall = lcons(rte, tall);
}
/*
* Close the reldesc - we're done with it now
*/
heap_close(rdesc);
*this_resno = first_resno + maxattrs;
return(tall);
}
TimeQual
makeTimeRange(char *datestring1,
char *datestring2,
int timecode) /* 0 = snapshot , 1 = timerange */
{
TimeQual qual;
AbsoluteTime t1,t2;
switch (timecode) {
case 0:
if (datestring1 == NULL) {
elog(WARN, "MakeTimeRange: bad snapshot arg");
}
t1 = nabstimein(datestring1);
if (!AbsoluteTimeIsValid(t1)) {
elog(WARN, "bad snapshot time: \"%s\"",
datestring1);
}
qual = TimeFormSnapshotTimeQual(t1);
break;
case 1:
if (datestring1 == NULL) {
t1 = NOSTART_ABSTIME;
} else {
t1 = nabstimein(datestring1);
if (!AbsoluteTimeIsValid(t1)) {
elog(WARN,
"bad range start time: \"%s\"",
datestring1);
}
}
if (datestring2 == NULL) {
t2 = NOEND_ABSTIME;
} else {
t2 = nabstimein(datestring2);
if (!AbsoluteTimeIsValid(t2)) {
elog(WARN,
"bad range end time: \"%s\"",
datestring2);
}
}
qual = TimeFormRangedTimeQual(t1,t2);
break;
default:
elog(WARN, "MakeTimeRange: internal parser error");
}
return qual;
}
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 *
make_operand(char *opname,
Node *tree,
int orig_typeId,
int true_typeId)
{
Node *result;
Type true_type;
Datum val;
Oid infunc;
if (tree != NULL) {
result = tree;
true_type = get_id_type(true_typeId);
disallow_setop(opname, true_type, result);
if (true_typeId != orig_typeId) { /* must coerce */
Const *con= (Const *)result;
Assert(nodeTag(result)==T_Const);
val = (Datum)textout((struct varlena *)
con->constvalue);
infunc = typeid_get_retinfunc(true_typeId);
con = makeNode(Const);
con->consttype = true_typeId;
con->constlen = tlen(true_type);
con->constvalue = (Datum)fmgr(infunc,
val,
get_typelem(true_typeId),
-1 /* for varchar() type */);
con->constisnull = false;
con->constbyval = true;
con->constisset = false;
result = (Node *)con;
}
}else {
Const *con= makeNode(Const);
con->consttype = true_typeId;
con->constlen = 0;
con->constvalue = (Datum)(struct varlena *)NULL;
con->constisnull = true;
con->constbyval = true;
con->constisset = false;
result = (Node *)con;
}
return result;
}
Expr *
make_op(char *opname, Node *ltree, Node *rtree)
{
int ltypeId, rtypeId;
Operator temp;
OperatorTupleForm opform;
Oper *newop;
Node *left, *right;
Expr *result;
if (rtree == NULL) {
/* right operator */
ltypeId = (ltree==NULL) ? UNKNOWNOID : exprType(ltree);
temp = right_oper(opname, ltypeId);
opform = (OperatorTupleForm) GETSTRUCT(temp);
left = make_operand(opname, ltree, ltypeId, opform->oprleft);
right = NULL;
}else if (ltree == NULL) {
/* left operator */
rtypeId = (rtree==NULL) ? UNKNOWNOID : exprType(rtree);
temp = left_oper(opname, rtypeId);
opform = (OperatorTupleForm) GETSTRUCT(temp);
right = make_operand(opname, rtree, rtypeId, opform->oprright);
left = NULL;
}else {
/* binary operator */
ltypeId = (ltree==NULL) ? UNKNOWNOID : exprType(ltree);
rtypeId = (rtree==NULL) ? UNKNOWNOID : exprType(rtree);
temp = oper(opname, ltypeId, rtypeId);
opform = (OperatorTupleForm) GETSTRUCT(temp);
left = make_operand(opname, ltree, ltypeId, opform->oprleft);
right = make_operand(opname, rtree, rtypeId, opform->oprright);
}
newop = makeOper(oprid(temp), /* opno */
InvalidOid, /* opid */
opform->oprresult, /* operator result type */
0,
NULL);
result = makeNode(Expr);
result->typeOid = opform->oprresult;
result->opType = OP_EXPR;
result->oper = (Node *)newop;
if (!left) {
result->args = lcons(right, NIL);
} else if (!right) {
result->args = lcons(left, NIL);
} else {
result->args = lcons(left, lcons(right, NIL));
}
return result;
}
int
find_atttype(Oid relid, char *attrname)
{
int attid, 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 *relname, char *attrname, int *type_id)
{
Var *varnode;
int vnum, attid, vartypeid;
Relation rd;
vnum = RangeTablePosn(pstate->p_rtable, relname);
if (vnum == 0) {
pstate->p_rtable =
lappend(pstate->p_rtable,
makeRangeTableEntry(relname, FALSE,
NULL, relname));
vnum = RangeTablePosn (pstate->p_rtable, relname);
relname = VarnoGetRelname(pstate, vnum);
} else {
relname = VarnoGetRelname(pstate, vnum);
}
rd = heap_openr(relname);
/* relid = RelationGetRelationId(rd); */
attid = nf_varattno(rd, (char *) attrname);
if (attid == InvalidAttrNumber)
elog(WARN, "Invalid attribute %s\n", attrname);
vartypeid = att_typeid(rd, attid);
varnode = makeVar(vnum, attid, vartypeid, vnum, attid);
/*
* close relation we're done with it now
*/
heap_close(rd);
*type_id = vartypeid;
return varnode;
}
/*
* make_array_ref() -- Make an array reference node.
*
* Array references can hang off of arbitrary nested dot (or
* function invocation) expressions. This routine takes a
* tree generated by ParseFunc() and an array index and
* generates a new array reference tree. We do some simple
* typechecking to be sure the dereference is valid in the
* type system, but we don't do any bounds checking here.
*
* indirection is a list of A_Indices
*/
ArrayRef *
make_array_ref(Node *expr,
List *indirection)
{
Oid typearray;
HeapTuple type_tuple;
TypeTupleForm type_struct_array, type_struct_element;
ArrayRef *aref;
int reftype;
List *upperIndexpr=NIL;
List *lowerIndexpr=NIL;
typearray = (Oid) exprType(expr);
type_tuple = SearchSysCacheTuple(TYPOID,
ObjectIdGetDatum(typearray),
0,0,0);
if (!HeapTupleIsValid(type_tuple))
elog(WARN, "make_array_ref: Cache lookup failed for type %d\n",
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, "make_array_ref: type %s is not an array",
(Name)&(type_struct_array->typname.data[0]));
}
/* get the type tuple for the element type */
type_tuple = SearchSysCacheTuple(TYPOID,
ObjectIdGetDatum(type_struct_array->typelem),
0,0,0);
if (!HeapTupleIsValid(type_tuple))
elog(WARN, "make_array_ref: Cache lookup failed for type %d\n",
typearray);
type_struct_element = (TypeTupleForm) GETSTRUCT(type_tuple);
while(indirection!=NIL) {
A_Indices *ind = lfirst(indirection);
if (ind->lidx) {
/* XXX assumes all lower indices non null in this case
*/
lowerIndexpr = lappend(lowerIndexpr, ind->lidx);
}
upperIndexpr = lappend(upperIndexpr, ind->uidx);
indirection = lnext(indirection);
}
aref = makeNode(ArrayRef);
aref->refattrlength = type_struct_array->typlen;
aref->refelemlength = type_struct_element->typlen;
aref->refelemtype = type_struct_array->typelem;
aref->refelembyval = type_struct_element->typbyval;
aref->refupperindexpr = upperIndexpr;
aref->reflowerindexpr = lowerIndexpr;
aref->refexpr = expr;
aref->refassgnexpr = NULL;
if (lowerIndexpr == NIL) /* accessing a single array element */
reftype = aref->refelemtype;
else /* request to clip a part of the array, the result is another array */
reftype = typearray;
/* we change it to reflect the true type; since the original refelemtype
* doesn't seem to get used anywhere. - ay 10/94
*/
aref->refelemtype = reftype;
return aref;
}
ArrayRef *
make_array_set(Expr *target_expr,
List *upperIndexpr,
List *lowerIndexpr,
Expr *expr)
{
Oid typearray;
HeapTuple type_tuple;
TypeTupleForm type_struct_array;
TypeTupleForm type_struct_element;
ArrayRef *aref;
int reftype;
typearray = exprType((Node*)target_expr);
type_tuple = SearchSysCacheTuple(TYPOID,
ObjectIdGetDatum(typearray),
0,0,0);
if (!HeapTupleIsValid(type_tuple))
elog(WARN, "make_array_ref: Cache lookup failed for type %d\n",
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, "make_array_ref: type %s is not an array",
(Name)&(type_struct_array->typname.data[0]));
}
/* get the type tuple for the element type */
type_tuple = SearchSysCacheTuple(TYPOID,
ObjectIdGetDatum(type_struct_array->typelem),
0,0,0);
if (!HeapTupleIsValid(type_tuple))
elog(WARN, "make_array_ref: Cache lookup failed for type %d\n",
typearray);
type_struct_element = (TypeTupleForm) GETSTRUCT(type_tuple);
aref = makeNode(ArrayRef);
aref->refattrlength = type_struct_array->typlen;
aref->refelemlength = type_struct_element->typlen;
aref->refelemtype = type_struct_array->typelem;
aref->refelembyval = type_struct_element->typbyval;
aref->refupperindexpr = upperIndexpr;
aref->reflowerindexpr = lowerIndexpr;
aref->refexpr = (Node*)target_expr;
aref->refassgnexpr = (Node*)expr;
if (lowerIndexpr == NIL) /* accessing a single array element */
reftype = aref->refelemtype;
else /* request to set a part of the array, by another array */
reftype = typearray;
aref->refelemtype = reftype;
return aref;
}
/*
*
* make_const -
*
* - takes a lispvalue, (as returned to the yacc routine by the lexer)
* extracts the type, and makes the appropriate type constant
* by invoking the (c-callable) lisp routine c-make-const
* via the lisp_call() mechanism
*
* eventually, produces a "const" lisp-struct as per nodedefs.cl
*/
Const *
make_const(Value *value)
{
Type tp;
Datum val;
Const *con;
switch(nodeTag(value)) {
case T_Integer:
tp = type("int4");
val = Int32GetDatum(intVal(value));
break;
case T_Float:
{
float32 dummy;
tp = type("float4");
dummy = (float32)palloc(sizeof(float32data));
*dummy = floatVal(value);
val = Float32GetDatum(dummy);
}
break;
case T_String:
tp = type("unknown"); /* unknown for now, will be type coerced */
val = PointerGetDatum(textin(strVal(value)));
break;
case T_Null:
default:
{
if (nodeTag(value)!=T_Null)
elog(NOTICE,"unknown type : %d\n", nodeTag(value));
/* null const */
con = makeConst(0, 0, (Datum)NULL, TRUE, 0, FALSE);
return NULL /*con*/;
}
}
con = makeConst(typeid(tp),
tlen(tp),
val,
FALSE,
tbyval(tp),
FALSE); /* not a set */
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];
}

View File

@ -0,0 +1,72 @@
/*-------------------------------------------------------------------------
*
* parse_query.h--
* prototypes for parse_query.c.
*
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: parse_query.h,v 1.1.1.1 1996/07/09 06:21:40 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef PARSE_QUERY_H
#define PARSE_QUERY_H
#include "nodes/pg_list.h"
#include "nodes/parsenodes.h"
#include "parser/catalog_utils.h"
#include "parser/parse_state.h"
typedef struct QueryTreeList {
int len; /* number of queries */
Query** qtrees;
} QueryTreeList;
extern int RangeTablePosn(List *rtable, char *rangevar);
extern char *VarnoGetRelname(ParseState *pstate, int vnum);
extern RangeTblEntry *makeRangeTableEntry(char *relname, bool inh,
TimeRange *timeRange, char *refname);
extern List *expandAll(ParseState *pstate, char *relname, int *this_resno);
extern TimeQual makeTimeRange(char *datestring1, char *datestring2,
int timecode);
extern Expr *make_op(char *opname, Node *ltree, Node *rtree);
extern int find_atttype(Oid relid, char *attrname);
extern Var *make_var(ParseState *pstate,
char *relname, char *attrname, int *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);
/* parser.c (was ylib.c) */
extern QueryTreeList *parser(char *str, Oid *typev, int nargs);
extern Node *parser_typecast(Value *expr, TypeName *typename, int typlen);
extern Node *parser_typecast2(Node *expr, int exprType, Type tp, int typlen);
extern Aggreg *ParseAgg(char *aggname, Oid basetype, Node *target);
/*
* analyze.c
*/
#if 0
extern List *p_rtable;
extern int NumLevels;
#endif
Oid exprType(Node *expr);
ParseState* makeParseState();
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((Oid)type) ? true : false)
#endif /* PARSE_QUERY_H */

View File

@ -0,0 +1,27 @@
/*-------------------------------------------------------------------------
*
* parse_state.h--
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: parse_state.h,v 1.1.1.1 1996/07/09 06:21:40 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef PARSE_STATE_H
#define PARSE_STATE_H
/* state information used during parse analysis */
typedef struct ParseState {
int p_last_resno;
List *p_target_resnos;
Relation parser_current_rel;
List *p_rtable;
int p_query_is_rule;
int p_numAgg;
List *p_aggs;
} ParseState;
#endif /*PARSE_QUERY_H*/

449
src/backend/parser/parser.c Normal file
View File

@ -0,0 +1,449 @@
/*-------------------------------------------------------------------------
*
* ylib.c--
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parser.c,v 1.1.1.1 1996/07/09 06:21:40 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include <string.h>
#include <stdio.h>
#ifndef WIN32
#include <pwd.h>
#endif /*WIN32 */
#include <sys/param.h> /* for MAXPATHLEN */
#include "utils/elog.h"
#include "parser/catalog_utils.h"
#include "nodes/pg_list.h"
#include "utils/exc.h"
#include "utils/excid.h"
#include "utils/palloc.h"
#include "catalog/pg_aggregate.h"
#include "catalog/pg_type.h"
#include "nodes/primnodes.h"
#include "nodes/plannodes.h"
#include "nodes/execnodes.h"
#include "nodes/relation.h"
#include "parser/parse_query.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "access/heapam.h"
#include "nodes/makefuncs.h"
#include "optimizer/clauses.h"
char *parseString; /* the char* which holds the string to be parsed */
char *parseCh; /* a pointer used during parsing to walk down ParseString*/
List *parsetree = NIL;
static void fixupsets();
static void define_sets();
/*
* parser-- returns a list of parse trees
*
* CALLER is responsible for free'ing the list returned
*/
QueryTreeList *
parser(char *str, Oid *typev, int nargs)
{
QueryTreeList* queryList;
int yyresult;
#if defined(FLEX_SCANNER)
extern void DeleteBuffer(void);
#endif /* FLEX_SCANNER */
init_io();
/* Set things up to read from the string, if there is one */
if (strlen(str) != 0) {
parseString = (char *) palloc(strlen(str) + 1);
memmove(parseString,str,strlen(str)+1);
}
parser_init(typev, nargs);
yyresult = yyparse();
#if defined(FLEX_SCANNER)
DeleteBuffer();
#endif /* FLEX_SCANNER */
clearerr(stdin);
if (yyresult) { /* error */
return((QueryTreeList*)NULL);
}
queryList = parse_analyze(parsetree);
#ifdef SETS_FIXED
/* Fixing up sets calls the parser, so it reassigns the global
* variable parsetree. So save the real parsetree.
*/
savetree = parsetree;
foreach (parse, savetree) { /* savetree is really a list of parses */
/* find set definitions embedded in query */
fixupsets((Query *)lfirst(parse));
}
return savetree;
#endif
return queryList;
}
static void
fixupsets(Query *parse)
{
if (parse == NULL)
return;
if (parse->commandType==CMD_UTILITY) /* utility */
return;
if (parse->commandType!=CMD_INSERT)
return;
define_sets(parse);
}
/* Recursively find all of the Consts in the parsetree. Some of
* these may represent a set. The value of the Const will be the
* query (a string) which defines the set. Call SetDefine to define
* the set, and store the OID of the new set in the Const instead.
*/
static void
define_sets(Node *clause)
{
#ifdef SETS_FIXED
Oid setoid;
Type t = type("oid");
Oid typeoid = typeid(t);
Size oidsize = tlen(t);
bool oidbyval = tbyval(t);
if (clause==NULL) {
return;
} else if (IsA(clause,LispList)) {
define_sets(lfirst(clause));
define_sets(lnext(clause));
} else if (IsA(clause,Const)) {
if (get_constisnull((Const)clause) ||
!get_constisset((Const)clause)) {
return;
}
setoid = SetDefine(((Const*)clause)->constvalue,
get_id_typname(((Const*)clause)->consttype));
set_constvalue((Const)clause, setoid);
set_consttype((Const)clause,typeoid);
set_constlen((Const)clause,oidsize);
set_constbyval((Const)clause,oidbyval);
} else if ( IsA(clause,Iter) ) {
define_sets(((Iter*)clause)->iterexpr);
} else if (single_node (clause)) {
return;
} else if (or_clause(clause)) {
List *temp;
/* mapcan */
foreach (temp, ((Expr*)clause)->args) {
define_sets(lfirst(temp));
}
} else if (is_funcclause (clause)) {
List *temp;
/* mapcan */
foreach(temp, ((Expr*)clause)->args) {
define_sets(lfirst(temp));
}
} else if (IsA(clause,ArrayRef)) {
define_sets(((ArrayRef*)clause)->refassgnexpr);
} else if (not_clause (clause)) {
define_sets (get_notclausearg (clause));
} else if (is_opclause (clause)) {
define_sets(get_leftop (clause));
define_sets(get_rightop (clause));
}
#endif
}
#define PSIZE(PTR) (*((int32 *)(PTR) - 1))
Node *
parser_typecast(Value *expr, TypeName *typename, int typlen)
{
/* check for passing non-ints */
Const *adt;
Datum lcp;
Type tp;
char type_string[16];
int32 len;
char *cp = NULL;
char *const_string;
bool string_palloced = false;
switch(nodeTag(expr)) {
case T_String:
const_string = DatumGetPointer(expr->val.str);
break;
case T_Integer:
const_string = (char *) palloc(256);
string_palloced = true;
sprintf(const_string, "%ld", expr->val.ival);
break;
default:
elog(WARN,
"parser_typecast: cannot cast this expression to type \"%s\"",
typename->name);
}
if (typename->arrayBounds != NIL) {
sprintf(type_string,"_%s", typename->name);
tp = (Type) type(type_string);
} else {
tp = (Type) type(typename->name);
}
len = tlen(tp);
#if 0 /* fix me */
switch ( CInteger(lfirst(expr)) ) {
case 23: /* int4 */
const_string = (char *) palloc(256);
string_palloced = true;
sprintf(const_string,"%d", ((Const*)lnext(expr))->constvalue);
break;
case 19: /* char16 */
const_string = (char *) palloc(256);
string_palloced = true;
sprintf(const_string,"%s", ((Const*)lnext(expr))->constvalue);
break;
case 18: /* char */
const_string = (char *) palloc(256);
string_palloced = true;
sprintf(const_string,"%c", ((Const)lnext(expr))->constvalue);
break;
case 701:/* float8 */
const_string = (char *) palloc(256);
string_palloced = true;
sprintf(const_string,"%f", ((Const)lnext(expr))->constvalue);
break;
case 25: /* text */
const_string = DatumGetPointer(((Const)lnext(expr))->constvalue);
const_string = (char *) textout((struct varlena *)const_string);
break;
case 705: /* unknown */
const_string = DatumGetPointer(((Const)lnext(expr))->constvalue);
const_string = (char *) textout((struct varlena *)const_string);
break;
default:
elog(WARN,"unknown type %d", CInteger(lfirst(expr)));
}
#endif
cp = instr2 (tp, const_string, typlen);
if (!tbyvalue(tp)) {
if (len >= 0 && len != PSIZE(cp)) {
char *pp;
pp = (char *) palloc(len);
memmove(pp, cp, len);
cp = pp;
}
lcp = PointerGetDatum(cp);
} else {
switch(len) {
case 1:
lcp = Int8GetDatum(cp);
break;
case 2:
lcp = Int16GetDatum(cp);
break;
case 4:
lcp = Int32GetDatum(cp);
break;
default:
lcp = PointerGetDatum(cp);
break;
}
}
adt = makeConst(typeid(tp),
len,
(Datum)lcp ,
0,
tbyvalue(tp),
0 /* not a set */);
if (string_palloced)
pfree(const_string);
return (Node*)adt;
}
Node *
parser_typecast2(Node *expr, int exprType, Type tp, int typlen)
{
/* check for passing non-ints */
Const *adt;
Datum lcp;
int32 len = tlen(tp);
char *cp = NULL;
char *const_string;
bool string_palloced = false;
Assert(IsA(expr,Const));
switch (exprType) {
case 23: /* int4 */
const_string = (char *) palloc(256);
string_palloced = true;
sprintf(const_string,"%d",
(int) ((Const*)expr)->constvalue);
break;
case 19: /* char16 */
const_string = (char *) palloc(256);
string_palloced = true;
sprintf(const_string,"%s",
(char*) ((Const*)expr)->constvalue);
break;
case 18: /* char */
const_string = (char *) palloc(256);
string_palloced = true;
sprintf(const_string,"%c",
(char) ((Const*)expr)->constvalue);
break;
case 700: /* float4 */
{
float32 floatVal =
DatumGetFloat32(((Const*)expr)->constvalue);
const_string = (char *) palloc(256);
string_palloced = true;
sprintf(const_string,"%f", *floatVal);
break;
}
case 701:/* float8 */
{
float64 floatVal =
DatumGetFloat64(((Const*)expr)->constvalue);
const_string = (char *) palloc(256);
string_palloced = true;
sprintf(const_string,"%f", *floatVal);
break;
}
case 25: /* text */
const_string =
DatumGetPointer(((Const*)expr)->constvalue );
const_string = (char *) textout((struct varlena *)const_string);
break;
case 705: /* unknown */
const_string =
DatumGetPointer(((Const*)expr)->constvalue );
const_string = (char *) textout((struct varlena *)const_string);
break;
default:
elog(WARN,"unknown type%d ",exprType);
}
cp = instr2 (tp, const_string, typlen);
if (!tbyvalue(tp)) {
if (len >= 0 && len != PSIZE(cp)) {
char *pp;
pp = (char *) palloc(len);
memmove(pp, cp, len);
cp = pp;
}
lcp = PointerGetDatum(cp);
} else {
switch(len) {
case 1:
lcp = Int8GetDatum(cp);
break;
case 2:
lcp = Int16GetDatum(cp);
break;
case 4:
lcp = Int32GetDatum(cp);
break;
default:
lcp = PointerGetDatum(cp);
break;
}
}
adt = makeConst((Oid)typeid(tp),
(Size)len,
(Datum)lcp,
0,
0 /*was omitted*/,
0 /* not a set */);
/*
printf("adt %s : %d %d %d\n",CString(expr),typeid(tp) ,
len,cp);
*/
if (string_palloced) pfree(const_string);
return ((Node*) adt);
}
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)
elog(WARN, "parser: aggregate can only be applied on an attribute");
/* only aggregates with transfn1 need a base type */
if (OidIsValid(xfn1)) {
basetype = aggform->aggbasetype;
vartype = ((Var*)target)->vartype;
if (basetype != vartype) {
Type tp1, tp2, get_id_type();
tp1 = get_id_type(basetype);
tp2 = get_id_type(vartype);
elog(NOTICE, "Aggregate type mismatch:");
elog(WARN, "%s works on %s, not %s", aggname,
tname(tp1), tname(tp2));
}
}
aggreg = makeNode(Aggreg);
aggreg->aggname = pstrdup(aggname);
aggreg->basetype = aggform->aggbasetype;
aggreg->aggtype = fintype;
aggreg->target = target;
return aggreg;
}

View File

@ -0,0 +1,80 @@
/*-------------------------------------------------------------------------
*
* parsetree.h--
* Routines to access various components and subcomponents of
* parse trees.
*
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: parsetree.h,v 1.1.1.1 1996/07/09 06:21:41 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef PARSETREE_H
#define PARSETREE_H /* include once only */
/* ----------------
* need pg_list.h for definitions of CAR(), etc. macros
* ----------------
*/
#include "nodes/pg_list.h"
#include "nodes/parsenodes.h"
/* ----------------
* range table macros
*
* parse tree:
* (root targetlist qual)
* ^^^^
* parse root:
* (numlevels cmdtype resrel rangetable priority ruleinfo nestdotinfo)
* ^^^^^^^^^^
* range table:
* (rtentry ...)
*
* rtentry:
* note: this might be wrong, I don't understand how
* rt_time / rt_archive_time work together. anyways it
* looks something like:
*
* (relname ? relid timestuff flags rulelocks)
* or (new/cur relname relid timestuff flags rulelocks)
*
* someone who knows more should correct this -cim 6/9/91
* ----------------
*/
#define rt_relname(rt_entry) \
((!strcmp(((rt_entry)->refname),"*CURRENT*") ||\
!strcmp(((rt_entry)->refname),"*NEW*")) ? ((rt_entry)->refname) : \
((char *)(rt_entry)->relname))
/*
* rt_fetch
* rt_store
*
* Access and (destructively) replace rangetable entries.
*
*/
#define rt_fetch(rangetable_index, rangetable) \
((RangeTblEntry*)nth((rangetable_index)-1, rangetable))
#define rt_store(rangetable_index, rangetable, rt) \
set_nth(rangetable, (rangetable_index)-1, rt)
/*
* getrelid
* getrelname
*
* Given the range index of a relation, return the corresponding
* relation id or relation name.
*/
#define getrelid(rangeindex,rangetable) \
((RangeTblEntry*)nth((rangeindex)-1, rangetable))->relid
#define getrelname(rangeindex, rangetable) \
rt_relname((RangeTblEntry*)nth((rangeindex)-1, rangetable))
#endif /* PARSETREE_H */

255
src/backend/parser/scan.l Normal file
View File

@ -0,0 +1,255 @@
%{
/*-------------------------------------------------------------------------
*
* scan.l--
* lexical scanner for POSTGRES
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/scan.l,v 1.1.1.1 1996/07/09 06:21:41 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include <ctype.h>
#ifndef WIN32
#include <unistd.h>
#endif /* WIN32 */
#ifndef __linux__
#include <math.h>
#else
#include <stdlib.h>
#endif /* __linux__ */
#include <string.h>
#include "postgres.h"
#include "miscadmin.h"
#include "nodes/pg_list.h"
#include "nodes/parsenodes.h"
#include "parser/keywords.h"
#include "parser/scansup.h"
#include "parse.h"
#include "utils/elog.h"
#include "utils/palloc.h"
extern char *parseString;
extern char *parseCh;
/* some versions of lex define this as a macro */
#if defined(yywrap)
#undef yywrap
#endif /* yywrap */
#if defined(FLEX_SCANNER)
/* MAX_PARSE_BUFFER is defined in miscadmin.h */
#define YYLMAX MAX_PARSE_BUFFER
extern int myinput(char* buf, int max);
#undef YY_INPUT
#define YY_INPUT(buf,result,max) {result = myinput(buf,max);}
#else
#undef input
int input();
#undef unput
void unput(char);
#endif /* FLEX_SCANNER */
extern YYSTYPE yylval;
%}
digit [0-9]
letter [_A-Za-z]
letter_or_digit [_A-Za-z0-9]
identifier {letter}{letter_or_digit}*
self [,()\[\].;$\:\+\-\*\/\<\>\=\|]
op_and_self [\~\!\@\#\%\^\&\|\`\?\$\:\+\-\*\/\<\>\=]
op_only [\~\!\@\#\%\^\&\`\?]
operator ({op_and_self}{op_and_self}+)|{op_only}+
/* we used to allow double-quoted strings, but SQL doesn't */
/* so we won't either*/
quote '
integer -?{digit}+
real -?{digit}+\.{digit}+([Ee][-+]?{digit}+)?
param \${integer}
comment "--".*\n
space [ \t\n\f]
other .
%%
{comment} { /* ignore */ }
"::" { return TYPECAST; }
{self} { return (yytext[0]); }
{operator} {
yylval.str = pstrdup((char*)yytext);
return (Op);
}
{param} { yylval.ival = atoi((char*)&yytext[1]);
return (PARAM);
}
{integer} {
yylval.ival = atoi((char*)yytext);
return (ICONST);
}
{real} {
yylval.dval = atof((char*)yytext);
return (FCONST);
}
{quote} {
char literal[MAX_PARSE_BUFFER];
int i = 0;
int c = 0;
/* quote_seen can be either \ or ' because
we handle both cases of \' and '' for
quoting quotes*/
int quote_seen = 0;
while (i < MAX_PARSE_BUFFER - 1) {
c = input();
if (quote_seen != 0) {
if (quote_seen == '\'' &&
c != '\'') {
/* a non-quote follows a single quote */
/* so we've hit the end of the literal */
if (c != '\0' && c != EOF)
unput(c); /* put back the extra char we read*/
i = i - 1;
break; /* break out of the while loop */
}
/* if we reach here, we're still in */
/* the string literal */
literal[i++] = c;
quote_seen = 0;
continue;
}
if (c == '\0' || c == EOF) {
elog(WARN,"unterminated quoted string literal");
/* not reached */
}
literal[i++] = c;
if (c == '\'' || c == '\\')
quote_seen = c;
}
if ( i == MAX_PARSE_BUFFER - 1) {
elog (WARN, "unterminated quote string. parse buffer of %d chars exceeded", MAX_PARSE_BUFFER);
/* not reached */
}
literal[i] = '\0';
yylval.str = pstrdup(scanstr(literal));
return (SCONST);
}
{identifier} {
ScanKeyword *keyword;
keyword = ScanKeywordLookup((char*)yytext);
if (keyword != NULL) {
return (keyword->value);
} else {
yylval.str = pstrdup((char*)yytext);
return (IDENT);
}
}
{space} { /* ignore */ }
{other} { return (yytext[0]); }
%%
void yyerror(char message[])
{
elog(WARN, "parser: %s at or near \"%s\"\n", message, yytext);
}
int yywrap()
{
return(1);
}
/*
init_io:
called by postgres before any actual parsing is done
*/
void
init_io()
{
/* it's important to set this to NULL
because input()/myinput() checks the non-nullness of parseCh
to know when to pass the string to lex/flex */
parseCh = NULL;
#if defined(FLEX_SCANNER)
if (YY_CURRENT_BUFFER)
yy_flush_buffer(YY_CURRENT_BUFFER);
#endif /* FLEX_SCANNER */
BEGIN INITIAL;
}
#if !defined(FLEX_SCANNER)
/* get lex input from a string instead of from stdin */
int
input()
{
if (parseCh == NULL) {
parseCh = parseString;
return(*parseCh++);
} else if (*parseCh == '\0') {
return(0);
} else {
return(*parseCh++);
}
}
/* undo lex input from a string instead of from stdin */
void
unput(char c)
{
if (parseCh == NULL) {
elog(FATAL, "Unput() failed.\n");
} else if (c != 0) {
*--parseCh = c;
}
}
#endif /* !defined(FLEX_SCANNER) */
#ifdef FLEX_SCANNER
/* input routine for flex to read input from a string instead of a file */
int
myinput(char* buf, int max)
{
int len, copylen;
if (parseCh == NULL) {
len = strlen(parseString);
if (len >= max)
copylen = max - 1;
else
copylen = len;
if (copylen > 0)
memcpy(buf, parseString, copylen);
buf[copylen] = '\0';
parseCh = parseString;
return copylen;
} else {
return 0; /* end of string */
}
}
char*
CurScan(void)
{
/*
return (InputFrag ? InputFrag : parseCh) +
(yy_c_buf_p - &yy_current_buffer->yy_ch_buf[yy_n_chars]);
*/
}
#endif /* FLEX_SCANNER */

View File

@ -0,0 +1,148 @@
/*-------------------------------------------------------------------------
*
* scansup.c--
* support routines for the lex/flex scanner, used by both the normal
* backend as well as the bootstrap backend
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/scansup.c,v 1.1.1.1 1996/07/09 06:21:41 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include <ctype.h>
#include <string.h>
#include "c.h"
#include "postgres.h"
#include "miscadmin.h"
#include "utils/elog.h"
#include "parser/scansup.h"
/*
* Scanner error handler.
*/
static void
serror(char *str)
{
elog(WARN, "*** scanner error: %s\n", str);
}
/* ----------------
* scanstr
*
* if the string passed in has escaped codes, map the escape codes to actual
* chars
*
* also, remove leading and ending quotes '"' if any
*
* the string passed in must be non-null
*
* the string returned is a pointer to static storage and should NOT
* be freed by the CALLER.
* ----------------
*/
char*
scanstr(char *s)
{
static char newStr[MAX_PARSE_BUFFER];
int len, i, start, j;
char delimiter;
if (s == NULL || s[0] == '\0')
return s;
len = strlen(s);
start = 0;
/* remove leading and trailing quotes, if any */
/* the normal backend lexer only accepts single quotes, but the
bootstrap lexer accepts double quotes */
delimiter = 0;
if (s[0] == '"' || s[0] == '\''){
delimiter = s[0];
start = 1;
}
if (delimiter != 0) {
if (s[len-1] == delimiter)
len = len - 1;
else
serror("mismatched quote delimiters");
}
for (i = start, j = 0; i < len ; i++) {
if (s[i] == '\'') {
i = i + 1;
if (s[i] == '\'')
newStr[j] = '\'';
}
else {
if (s[i] == '\\') {
i = i + 1;
switch (s[i]) {
case '\\':
newStr[j] = '\\';
break;
case 'b':
newStr[j] = '\b';
break;
case 'f':
newStr[j] = '\f';
break;
case 'n':
newStr[j] = '\n';
break;
case 'r':
newStr[j] = '\r';
break;
case 't':
newStr[j] = '\t';
break;
case '"':
newStr[j] = '"';
break;
case '\'':
newStr[j] = '\'';
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
{
char octal[4];
int k;
long octVal;
for (k=0;
s[i+k] >= '0' && s[i+k] <= '7' && k < 3;
k++)
octal[k] = s[i+k];
i += k-1;
octal[3] = '\0';
octVal = strtol(octal,0,8);
/* elog (NOTICE, "octal = %s octVal = %d, %od", octal, octVal, octVal);*/
if (octVal <= 0377) {
newStr[j] = ((char)octVal);
break;
}
}
default:
elog (WARN, "Bad escape sequence, s[i] = %d", s[i]);
} /* switch */
} /* s[i] == '\\' */
else
newStr[j] = s[i];
}
j++;
}
newStr[j] = '\0';
return newStr;
}

View File

@ -0,0 +1,17 @@
/*-------------------------------------------------------------------------
*
* scansup.h--
* scanner support routines. used by both the bootstrap lexer
* as well as the normal lexer
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: scansup.h,v 1.1.1.1 1996/07/09 06:21:41 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
extern char* scanstr(char *s);