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:
46
src/backend/parser/Makefile.inc
Normal file
46
src/backend/parser/Makefile.inc
Normal 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
2467
src/backend/parser/analyze.c
Normal file
File diff suppressed because it is too large
Load Diff
1470
src/backend/parser/catalog_utils.c
Normal file
1470
src/backend/parser/catalog_utils.c
Normal file
File diff suppressed because it is too large
Load Diff
64
src/backend/parser/catalog_utils.h
Normal file
64
src/backend/parser/catalog_utils.h
Normal 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 */
|
259
src/backend/parser/dbcommands.c
Normal file
259
src/backend/parser/dbcommands.c
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
28
src/backend/parser/dbcommands.h
Normal file
28
src/backend/parser/dbcommands.h
Normal 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
2113
src/backend/parser/gram.y
Normal file
File diff suppressed because it is too large
Load Diff
179
src/backend/parser/keywords.c
Normal file
179
src/backend/parser/keywords.c
Normal 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);
|
||||
}
|
25
src/backend/parser/keywords.h
Normal file
25
src/backend/parser/keywords.h
Normal 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 */
|
653
src/backend/parser/parse_query.c
Normal file
653
src/backend/parser/parse_query.c
Normal 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];
|
||||
}
|
||||
|
72
src/backend/parser/parse_query.h
Normal file
72
src/backend/parser/parse_query.h
Normal 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 */
|
27
src/backend/parser/parse_state.h
Normal file
27
src/backend/parser/parse_state.h
Normal 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
449
src/backend/parser/parser.c
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
|
80
src/backend/parser/parsetree.h
Normal file
80
src/backend/parser/parsetree.h
Normal 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
255
src/backend/parser/scan.l
Normal 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 */
|
||||
|
148
src/backend/parser/scansup.c
Normal file
148
src/backend/parser/scansup.c
Normal 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;
|
||||
}
|
||||
|
17
src/backend/parser/scansup.h
Normal file
17
src/backend/parser/scansup.h
Normal 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);
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user