2000-01-17 01:14:49 +01:00
|
|
|
%{
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1996-11-28 06:46:08 +01:00
|
|
|
/*#define YYDEBUG 1*/
|
1996-07-09 08:22:35 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
1997-09-01 08:00:35 +02:00
|
|
|
*
|
1999-02-14 00:22:53 +01:00
|
|
|
* gram.y
|
1997-09-08 05:20:18 +02:00
|
|
|
* POSTGRES SQL YACC rules/actions
|
1997-09-01 08:00:35 +02:00
|
|
|
*
|
2000-01-26 06:58:53 +01:00
|
|
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2000-01-26 06:58:53 +01:00
|
|
|
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.135 2000/01/26 05:56:41 momjian Exp $
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
* HISTORY
|
1997-09-08 05:20:18 +02:00
|
|
|
* AUTHOR DATE MAJOR EVENT
|
|
|
|
* Andrew Yu Sept, 1994 POSTQUEL to SQL conversion
|
|
|
|
* Andrew Yu Oct, 1994 lispy code conversion
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
* NOTES
|
1997-09-08 05:20:18 +02:00
|
|
|
* CAPITALS are used to represent terminal symbols.
|
|
|
|
* non-capitals are used to represent non-terminals.
|
1997-10-25 07:56:41 +02:00
|
|
|
* SQL92-specific syntax is separated from plain SQL/Postgres syntax
|
|
|
|
* to help isolate the non-extensible portions of the parser.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1997-09-08 05:20:18 +02:00
|
|
|
* if you use list, make sure the datum is a node so that the printing
|
|
|
|
* routines work
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
* WARNING
|
1997-09-08 05:20:18 +02:00
|
|
|
* sometimes we assign constants to makeStrings. Make sure we don't free
|
|
|
|
* those.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
#include <ctype.h>
|
1996-11-08 21:46:33 +01:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
#include "postgres.h"
|
1999-07-03 02:33:04 +02:00
|
|
|
#include "access/htup.h"
|
1999-07-16 07:00:38 +02:00
|
|
|
#include "access/xact.h"
|
|
|
|
#include "catalog/catname.h"
|
|
|
|
#include "catalog/pg_type.h"
|
1996-07-09 08:22:35 +02:00
|
|
|
#include "nodes/parsenodes.h"
|
1997-09-13 05:15:46 +02:00
|
|
|
#include "nodes/print.h"
|
1999-07-16 07:00:38 +02:00
|
|
|
#include "parser/analyze.h"
|
1996-11-08 21:46:33 +01:00
|
|
|
#include "parser/gramparse.h"
|
1997-12-05 00:07:23 +01:00
|
|
|
#include "parser/parse_type.h"
|
1999-07-16 07:00:38 +02:00
|
|
|
#include "storage/bufpage.h"
|
1998-12-18 10:10:39 +01:00
|
|
|
#include "storage/lmgr.h"
|
1999-07-16 07:00:38 +02:00
|
|
|
#include "utils/acl.h"
|
1998-12-30 20:56:35 +01:00
|
|
|
#include "utils/numeric.h"
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1998-07-26 06:31:41 +02:00
|
|
|
#ifdef MULTIBYTE
|
2000-01-23 09:16:37 +01:00
|
|
|
#include "miscadmin.h"
|
1998-07-24 05:32:46 +02:00
|
|
|
#include "mb/pg_wchar.h"
|
|
|
|
#endif
|
|
|
|
|
1999-11-15 03:00:15 +01:00
|
|
|
extern List *parsetree; /* final parse result is delivered here */
|
|
|
|
|
1996-11-28 06:46:08 +01:00
|
|
|
static char saved_relname[NAMEDATALEN]; /* need this for complex attributes */
|
1996-07-09 08:22:35 +02:00
|
|
|
static bool QueryIsRule = FALSE;
|
1997-11-25 23:07:18 +01:00
|
|
|
static Oid *param_type_info;
|
|
|
|
static int pfunc_num_args;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-11-25 23:07:18 +01:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*
|
1997-09-08 05:20:18 +02:00
|
|
|
* If you need access to certain yacc-generated variables and find that
|
1996-07-09 08:22:35 +02:00
|
|
|
* they're static by default, uncomment the next line. (this is not a
|
|
|
|
* problem, yet.)
|
|
|
|
*/
|
|
|
|
/*#define __YYSCLASS*/
|
|
|
|
|
1998-02-11 05:09:54 +01:00
|
|
|
static char *xlateSqlFunc(char *);
|
1996-07-09 08:22:35 +02:00
|
|
|
static char *xlateSqlType(char *);
|
1996-11-30 04:38:09 +01:00
|
|
|
static Node *makeA_Expr(int oper, char *opname, Node *lexpr, Node *rexpr);
|
2000-01-17 01:14:49 +01:00
|
|
|
static Node *makeTypeCast(Node *arg, TypeName *typename);
|
1998-01-17 06:01:34 +01:00
|
|
|
static Node *makeRowExpr(char *opr, List *largs, List *rargs);
|
1998-10-08 20:30:52 +02:00
|
|
|
static void mapTargetColumns(List *source, List *target);
|
1997-11-25 23:07:18 +01:00
|
|
|
static void param_type_init(Oid *typev, int nargs);
|
1999-03-18 22:39:56 +01:00
|
|
|
static Node *doNegate(Node *n);
|
1997-11-25 23:07:18 +01:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/* old versions of flex define this as a macro */
|
|
|
|
#if defined(yywrap)
|
|
|
|
#undef yywrap
|
|
|
|
#endif /* yywrap */
|
|
|
|
%}
|
|
|
|
|
|
|
|
|
1997-09-08 05:20:18 +02:00
|
|
|
%union
|
|
|
|
{
|
|
|
|
double dval;
|
|
|
|
int ival;
|
|
|
|
char chr;
|
|
|
|
char *str;
|
|
|
|
bool boolean;
|
|
|
|
List *list;
|
|
|
|
Node *node;
|
|
|
|
Value *value;
|
|
|
|
|
|
|
|
Attr *attr;
|
|
|
|
|
|
|
|
TypeName *typnam;
|
|
|
|
DefElem *defelt;
|
|
|
|
SortGroupBy *sortgroupby;
|
1999-02-23 08:42:41 +01:00
|
|
|
JoinExpr *joinexpr;
|
1997-09-08 05:20:18 +02:00
|
|
|
IndexElem *ielem;
|
|
|
|
RangeVar *range;
|
|
|
|
RelExpr *relexp;
|
|
|
|
A_Indices *aind;
|
|
|
|
ResTarget *target;
|
|
|
|
ParamNo *paramno;
|
|
|
|
|
|
|
|
VersionStmt *vstmt;
|
|
|
|
DefineStmt *dstmt;
|
|
|
|
RuleStmt *rstmt;
|
1998-01-09 21:06:08 +01:00
|
|
|
InsertStmt *astmt;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
1997-09-01 08:00:35 +02:00
|
|
|
%type <node> stmt,
|
2000-01-16 21:05:00 +01:00
|
|
|
AlterTableStmt, ClosePortalStmt,
|
1999-12-10 04:56:14 +01:00
|
|
|
CopyStmt, CreateStmt, CreateAsStmt, CreateSeqStmt, DefineStmt, DropStmt,
|
This patch implements ORACLE's COMMENT SQL command.
>From the ORACLE 7 SQL Language Reference Manual:
-----------------------------------------------------
COMMENT
Purpose:
To add a comment about a table, view, snapshot, or
column into the data dictionary.
Prerequisites:
The table, view, or snapshot must be in your own
schema
or you must have COMMENT ANY TABLE system privilege.
Syntax:
COMMENT ON [ TABLE table ] |
[ COLUMN table.column] IS 'text'
You can effectively drop a comment from the database
by setting it to the empty string ''.
-----------------------------------------------------
Example:
COMMENT ON TABLE workorders IS
'Maintains base records for workorder information';
COMMENT ON COLUMN workorders.hours IS
'Number of hours the engineer worked on the task';
to drop a comment:
COMMENT ON COLUMN workorders.hours IS '';
The current patch will simply perform the insert into
pg_description, as per the TODO. And, of course, when
the table is dropped, any comments relating to it
or any of its attributes are also dropped. I haven't
looked at the ODBC source yet, but I do know from
an ODBC client standpoint that the standard does
support the notion of table and column comments.
Hopefully the ODBC driver is already fetching these
values from pg_description, but if not, it should be
trivial.
Hope this makes the grade,
Mike Mascari
(mascarim@yahoo.com)
1999-10-15 03:49:49 +02:00
|
|
|
TruncateStmt, CommentStmt,
|
1997-09-08 05:20:18 +02:00
|
|
|
ExtendStmt, FetchStmt, GrantStmt, CreateTrigStmt, DropTrigStmt,
|
1997-10-28 16:11:45 +01:00
|
|
|
CreatePLangStmt, DropPLangStmt,
|
1998-08-25 23:37:08 +02:00
|
|
|
IndexStmt, ListenStmt, UnlistenStmt, LockStmt, OptimizableStmt,
|
1999-03-07 04:34:11 +01:00
|
|
|
ProcedureStmt, RemoveAggrStmt, RemoveOperStmt,
|
1997-11-21 19:12:58 +01:00
|
|
|
RemoveFuncStmt, RemoveStmt,
|
1997-09-08 05:20:18 +02:00
|
|
|
RenameStmt, RevokeStmt, RuleStmt, TransactionStmt, ViewStmt, LoadStmt,
|
1999-12-10 04:56:14 +01:00
|
|
|
CreatedbStmt, DropdbStmt, VacuumStmt, CursorStmt, SubSelect,
|
1999-02-23 08:42:41 +01:00
|
|
|
UpdateStmt, InsertStmt, select_clause, SelectStmt, NotifyStmt, DeleteStmt,
|
Hi!
INTERSECT and EXCEPT is available for postgresql-v6.4!
The patch against v6.4 is included at the end of the current text
(in uuencoded form!)
I also included the text of my Master's Thesis. (a postscript
version). I hope that you find something of it useful and would be
happy if parts of it find their way into the PostgreSQL documentation
project (If so, tell me, then I send the sources of the document!)
The contents of the document are:
-) The first chapter might be of less interest as it gives only an
overview on SQL.
-) The second chapter gives a description on much of PostgreSQL's
features (like user defined types etc. and how to use these features)
-) The third chapter starts with an overview of PostgreSQL's internal
structure with focus on the stages a query has to pass (i.e. parser,
planner/optimizer, executor). Then a detailed description of the
implementation of the Having clause and the Intersect/Except logic is
given.
Originally I worked on v6.3.2 but never found time enough to prepare
and post a patch. Now I applied the changes to v6.4 to get Intersect
and Except working with the new version. Chapter 3 of my documentation
deals with the changes against v6.3.2, so keep that in mind when
comparing the parts of the code printed there with the patched sources
of v6.4.
Here are some remarks on the patch. There are some things that have
still to be done but at the moment I don't have time to do them
myself. (I'm doing my military service at the moment) Sorry for that
:-(
-) I used a rewrite technique for the implementation of the Except/Intersect
logic which rewrites the query to a semantically equivalent query before
it is handed to the rewrite system (for views, rules etc.), planner,
executor etc.
-) In v6.3.2 the types of the attributes of two select statements
connected by the UNION keyword had to match 100%. In v6.4 the types
only need to be familiar (i.e. int and float can be mixed). Since this
feature did not exist when I worked on Intersect/Except it
does not work correctly for Except/Intersect queries WHEN USED IN
COMBINATION WITH UNIONS! (i.e. sometimes the wrong type is used for the
resulting table. This is because until now the types of the attributes of
the first select statement have been used for the resulting table.
When Intersects and/or Excepts are used in combination with Unions it
might happen, that the first select statement of the original query
appears at another position in the query which will be executed. The reason
for this is the technique used for the implementation of
Except/Intersect which does a query rewrite!)
NOTE: It is NOT broken for pure UNION queries and pure INTERSECT/EXCEPT
queries!!!
-) I had to add the field intersect_clause to some data structures
but did not find time to implement printfuncs for the new field.
This does NOT break the debug modes but when an Except/Intersect
is used the query debug output will be the already rewritten query.
-) Massive changes to the grammar rules for SELECT and INSERT statements
have been necessary (see comments in gram.y and documentation for
deatails) in order to be able to use mixed queries like
(SELECT ... UNION (SELECT ... EXCEPT SELECT)) INTERSECT SELECT...;
-) When using UNION/EXCEPT/INTERSECT you will get:
NOTICE: equal: "Don't know if nodes of type xxx are equal".
I did not have time to add comparsion support for all the needed nodes,
but the default behaviour of the function equal met my requirements.
I did not dare to supress this message!
That's the reason why the regression test for union will fail: These
messages are also included in the union.out file!
-) Somebody of you changed the union_planner() function for v6.4
(I copied the targetlist to new_tlist and that was removed and
replaced by a cleanup of the original targetlist). These chnages
violated some having queries executed against views so I changed
it back again. I did not have time to examine the differences between the
two versions but now it works :-)
If you want to find out, try the file queries/view_having.sql on
both versions and compare the results . Two queries won't produce a
correct result with your version.
regards
Stefan
1999-01-18 01:10:17 +01:00
|
|
|
ClusterStmt, ExplainStmt, VariableSetStmt, VariableShowStmt, VariableResetStmt,
|
1999-09-29 18:06:40 +02:00
|
|
|
CreateUserStmt, AlterUserStmt, DropUserStmt, RuleActionStmt,
|
1999-10-07 06:23:24 +02:00
|
|
|
RuleActionStmtOrEmpty, ConstraintsSetStmt,
|
1999-12-16 18:24:19 +01:00
|
|
|
CreateGroupStmt, AlterGroupStmt, DropGroupStmt
|
1997-09-08 05:20:18 +02:00
|
|
|
|
2000-01-16 21:05:00 +01:00
|
|
|
%type <node> alter_column_action
|
|
|
|
%type <ival> drop_behavior
|
|
|
|
|
2000-01-13 19:26:18 +01:00
|
|
|
%type <str> createdb_opt_location
|
|
|
|
%type <ival> createdb_opt_encoding
|
1997-11-07 08:02:10 +01:00
|
|
|
|
1999-05-12 09:22:52 +02:00
|
|
|
%type <ival> opt_lock, lock_type
|
|
|
|
%type <boolean> opt_lmode
|
1998-12-18 10:10:39 +01:00
|
|
|
|
2000-01-14 23:11:38 +01:00
|
|
|
%type <ival> user_createdb_clause, user_createuser_clause
|
1999-05-12 09:22:52 +02:00
|
|
|
%type <str> user_passwd_clause
|
1999-11-30 04:57:29 +01:00
|
|
|
%type <ival> sysid_clause
|
1999-05-12 09:22:52 +02:00
|
|
|
%type <str> user_valid_clause
|
2000-01-14 23:11:38 +01:00
|
|
|
%type <list> user_list, user_group_clause, users_in_new_group_clause
|
1997-12-04 01:28:15 +01:00
|
|
|
|
1999-05-12 09:22:52 +02:00
|
|
|
%type <boolean> TriggerActionTime, TriggerForSpec, PLangTrusted
|
1997-09-01 08:00:35 +02:00
|
|
|
|
1999-09-29 18:06:40 +02:00
|
|
|
%type <str> OptConstrFromTable
|
|
|
|
|
1997-10-25 07:56:41 +02:00
|
|
|
%type <str> TriggerEvents, TriggerFuncArg
|
1997-09-01 08:00:35 +02:00
|
|
|
|
1999-12-14 01:08:21 +01:00
|
|
|
%type <str> relation_name, copy_file_name, copy_delimiter, copy_null, def_name,
|
1997-09-08 05:20:18 +02:00
|
|
|
database_name, access_method_clause, access_method, attr_name,
|
1999-03-07 04:34:11 +01:00
|
|
|
class, index_name, name, func_name, file_name, aggr_argtype
|
1997-08-21 03:34:44 +02:00
|
|
|
|
2000-01-18 20:08:13 +01:00
|
|
|
%type <str> opt_id,
|
1997-11-21 19:12:58 +01:00
|
|
|
all_Op, MathOp, opt_name, opt_unique,
|
1999-02-02 04:45:56 +01:00
|
|
|
OptUseOp, opt_class, SpecialRuleRelation
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2000-01-13 19:26:18 +01:00
|
|
|
%type <str> opt_level, opt_encoding
|
1997-09-08 05:20:18 +02:00
|
|
|
%type <str> privileges, operation_commalist, grantee
|
|
|
|
%type <chr> operation, TriggerOneEvent
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1996-12-20 21:33:12 +01:00
|
|
|
%type <list> stmtblock, stmtmulti,
|
1999-02-02 04:45:56 +01:00
|
|
|
result, relation_name_list, OptTableElementList,
|
1997-12-05 00:07:23 +01:00
|
|
|
OptInherit, definition,
|
I have been working with user defined types and user defined c
functions. One problem that I have encountered with the function
manager is that it does not allow the user to define type conversion
functions that convert between user types. For instance if mytype1,
mytype2, and mytype3 are three Postgresql user types, and if I wish to
define Postgresql conversion functions like
I run into problems, because the Postgresql dynamic loader would look
for a single link symbol, mytype3, for both pieces of object code. If
I just change the name of one of the Postgresql functions (to make the
symbols distinct), the automatic type conversion that Postgresql uses,
for example, when matching operators to arguments no longer finds the
type conversion function.
The solution that I propose, and have implemented in the attatched
patch extends the CREATE FUNCTION syntax as follows. In the first case
above I use the link symbol mytype2_to_mytype3 for the link object
that implements the first conversion function, and define the
Postgresql operator with the following syntax
The patch includes changes to the parser to include the altered
syntax, changes to the ProcedureStmt node in nodes/parsenodes.h,
changes to commands/define.c to handle the extra information in the AS
clause, and changes to utils/fmgr/dfmgr.c that alter the way that the
dynamic loader figures out what link symbol to use. I store the
string for the link symbol in the prosrc text attribute of the pg_proc
table which is currently unused in rows that reference dynamically
loaded
functions.
Bernie Frankpitt
1999-09-28 06:34:56 +02:00
|
|
|
opt_with, func_args, func_args_list, func_as,
|
1999-10-07 06:23:24 +02:00
|
|
|
oper_argtypes, RuleActionList, RuleActionMulti,
|
1997-09-08 05:20:18 +02:00
|
|
|
opt_column_list, columnList, opt_va_list, va_list,
|
|
|
|
sort_clause, sortby_list, index_params, index_list, name_list,
|
1999-07-17 00:29:42 +02:00
|
|
|
from_clause, from_expr, table_list, opt_array_bounds,
|
|
|
|
expr_list, attrs, target_list, update_target_list,
|
1999-02-08 15:14:32 +01:00
|
|
|
def_list, opt_indirection, group_clause, TriggerFuncArgs,
|
|
|
|
opt_select_limit
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1998-02-11 05:09:54 +01:00
|
|
|
%type <node> func_return
|
|
|
|
%type <boolean> set_opt
|
|
|
|
|
1999-05-12 09:22:52 +02:00
|
|
|
%type <boolean> TriggerForOpt, TriggerForType, OptTemp, OptTempType, OptTempScope
|
1998-02-11 05:09:54 +01:00
|
|
|
|
1999-02-23 08:42:41 +01:00
|
|
|
%type <list> for_update_clause, update_list
|
1999-11-15 03:00:15 +01:00
|
|
|
%type <boolean> opt_all
|
1998-03-18 17:50:25 +01:00
|
|
|
%type <boolean> opt_table
|
1998-07-25 02:17:30 +02:00
|
|
|
%type <boolean> opt_trans
|
1997-09-01 08:00:35 +02:00
|
|
|
|
1999-02-23 08:42:41 +01:00
|
|
|
%type <list> join_clause_with_union, join_clause, join_list, join_qual, using_list
|
|
|
|
%type <node> join_expr, using_expr
|
|
|
|
%type <str> join_outer
|
|
|
|
%type <ival> join_type
|
|
|
|
|
1997-09-01 08:00:35 +02:00
|
|
|
%type <list> extract_list, position_list
|
|
|
|
%type <list> substr_list, substr_from, substr_for, trim_list
|
1997-10-25 07:56:41 +02:00
|
|
|
%type <list> opt_interval
|
1997-09-01 08:00:35 +02:00
|
|
|
|
1999-10-30 01:52:22 +02:00
|
|
|
%type <boolean> opt_inh_star, opt_binary, opt_using, opt_instead,
|
|
|
|
opt_with_copy, index_opt_unique, opt_verbose, opt_analyze
|
1999-05-20 14:12:55 +02:00
|
|
|
%type <boolean> opt_cursor
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2000-01-18 20:08:13 +01:00
|
|
|
%type <ival> copy_dirn, def_type, direction, remove_type,
|
1999-10-26 05:12:39 +02:00
|
|
|
opt_column, event, comment_type, comment_cl,
|
|
|
|
comment_ag, comment_fn, comment_op, comment_tg
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-11-21 19:12:58 +01:00
|
|
|
%type <ival> fetch_how_many
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1999-02-08 15:14:32 +01:00
|
|
|
%type <node> select_limit_value, select_offset_value
|
|
|
|
|
1997-04-02 06:01:03 +02:00
|
|
|
%type <list> OptSeqList
|
|
|
|
%type <defelt> OptSeqElem
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
%type <dstmt> def_rest
|
|
|
|
%type <astmt> insert_rest
|
|
|
|
|
1997-12-05 00:07:23 +01:00
|
|
|
%type <node> OptTableElement, ConstraintElem
|
2000-01-16 21:05:00 +01:00
|
|
|
%type <node> columnDef
|
1996-07-09 08:22:35 +02:00
|
|
|
%type <defelt> def_elem
|
1997-09-01 08:00:35 +02:00
|
|
|
%type <node> def_arg, columnElem, where_clause,
|
1999-11-20 22:39:36 +01:00
|
|
|
a_expr, a_expr_or_null, b_expr, com_expr, AexprConst,
|
1999-07-28 19:39:38 +02:00
|
|
|
in_expr, having_clause
|
1999-10-04 01:55:40 +02:00
|
|
|
%type <list> row_descriptor, row_list, in_expr_nodes
|
1997-12-23 20:47:32 +01:00
|
|
|
%type <node> row_expr
|
1998-12-04 16:34:49 +01:00
|
|
|
%type <node> case_expr, case_arg, when_clause, case_default
|
|
|
|
%type <list> when_clause_list
|
1998-05-10 01:22:15 +02:00
|
|
|
%type <ival> sub_type
|
1997-12-23 20:47:32 +01:00
|
|
|
%type <list> OptCreateAs, CreateAsList
|
|
|
|
%type <node> CreateAsElement
|
1998-07-08 16:04:11 +02:00
|
|
|
%type <value> NumericOnly, FloatOnly, IntegerOnly
|
1996-07-09 08:22:35 +02:00
|
|
|
%type <attr> event_object, attr
|
1997-09-08 05:20:18 +02:00
|
|
|
%type <sortgroupby> sortby
|
1996-07-09 08:22:35 +02:00
|
|
|
%type <ielem> index_elem, func_index
|
1999-02-23 08:42:41 +01:00
|
|
|
%type <range> table_expr
|
1996-07-09 08:22:35 +02:00
|
|
|
%type <relexp> relation_expr
|
1999-07-17 00:29:42 +02:00
|
|
|
%type <target> target_el, update_target_el
|
1997-09-08 05:20:18 +02:00
|
|
|
%type <paramno> ParamNo
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1999-07-17 00:29:42 +02:00
|
|
|
%type <typnam> Typename, opt_type, SimpleTypename,
|
|
|
|
Generic, Numeric, Character, Datetime
|
1998-02-11 05:09:54 +01:00
|
|
|
%type <str> generic, numeric, character, datetime
|
1998-04-08 08:39:01 +02:00
|
|
|
%type <str> extract_arg
|
1997-10-25 07:56:41 +02:00
|
|
|
%type <str> opt_charset, opt_collate
|
1998-12-30 20:56:35 +01:00
|
|
|
%type <str> opt_float
|
|
|
|
%type <ival> opt_numeric, opt_decimal
|
1997-10-25 07:56:41 +02:00
|
|
|
%type <boolean> opt_varying, opt_timezone
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
%type <ival> Iconst
|
1999-10-26 18:32:46 +02:00
|
|
|
%type <str> Sconst, comment_text
|
1998-02-11 05:09:54 +01:00
|
|
|
%type <str> UserId, var_value, zone_value
|
1997-10-25 07:56:41 +02:00
|
|
|
%type <str> ColId, ColLabel
|
1998-02-11 05:09:54 +01:00
|
|
|
%type <str> TypeId
|
1997-10-25 07:56:41 +02:00
|
|
|
|
1997-12-05 00:07:23 +01:00
|
|
|
%type <node> TableConstraint
|
1999-12-10 08:37:35 +01:00
|
|
|
%type <list> ColPrimaryKey, ColConstraintList
|
1997-12-05 00:07:23 +01:00
|
|
|
%type <node> ColConstraint, ColConstraintElem
|
1999-12-06 19:02:47 +01:00
|
|
|
%type <ival> key_actions, key_action, key_reference
|
|
|
|
%type <str> key_match
|
|
|
|
%type <ival> ConstraintAttributeSpec, ConstraintDeferrabilitySpec,
|
|
|
|
ConstraintTimeSpec
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1999-09-29 18:06:40 +02:00
|
|
|
%type <list> constraints_set_list
|
|
|
|
%type <list> constraints_set_namelist
|
|
|
|
%type <boolean> constraints_set_mode
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*
|
|
|
|
* If you make any token changes, remember to:
|
1997-09-08 05:20:18 +02:00
|
|
|
* - use "yacc -d" and update parse.h
|
|
|
|
* - update the keyword table in parser/keywords.c
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
|
1997-10-25 07:56:41 +02:00
|
|
|
/* Reserved word tokens
|
|
|
|
* SQL92 syntax has many type-specific constructs.
|
|
|
|
* So, go ahead and make these types reserved words,
|
|
|
|
* and call-out the syntax explicitly.
|
|
|
|
* This gets annoying when trying to also retain Postgres' nice
|
|
|
|
* type-extensible features, but we don't really have a choice.
|
|
|
|
* - thomas 1997-10-11
|
2000-01-17 01:14:49 +01:00
|
|
|
* NOTE: Whenever possible, try to add new keywords to the ColId list,
|
|
|
|
* or failing that, at least to the ColLabel list.
|
1997-10-25 07:56:41 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
/* Keywords (in SQL92 reserved words) */
|
1998-09-30 07:47:57 +02:00
|
|
|
%token ABSOLUTE, ACTION, ADD, ALL, ALTER, AND, ANY, AS, ASC,
|
1997-10-25 07:56:41 +02:00
|
|
|
BEGIN_TRANS, BETWEEN, BOTH, BY,
|
1998-12-04 16:34:49 +01:00
|
|
|
CASCADE, CASE, CAST, CHAR, CHARACTER, CHECK, CLOSE,
|
1999-05-12 09:22:52 +02:00
|
|
|
COALESCE, COLLATE, COLUMN, COMMIT,
|
1999-09-29 18:06:40 +02:00
|
|
|
CONSTRAINT, CONSTRAINTS, CREATE, CROSS, CURRENT, CURRENT_DATE,
|
|
|
|
CURRENT_TIME, CURRENT_TIMESTAMP, CURRENT_USER, CURSOR,
|
1997-10-25 07:56:41 +02:00
|
|
|
DAY_P, DECIMAL, DECLARE, DEFAULT, DELETE, DESC, DISTINCT, DOUBLE, DROP,
|
Hi!
INTERSECT and EXCEPT is available for postgresql-v6.4!
The patch against v6.4 is included at the end of the current text
(in uuencoded form!)
I also included the text of my Master's Thesis. (a postscript
version). I hope that you find something of it useful and would be
happy if parts of it find their way into the PostgreSQL documentation
project (If so, tell me, then I send the sources of the document!)
The contents of the document are:
-) The first chapter might be of less interest as it gives only an
overview on SQL.
-) The second chapter gives a description on much of PostgreSQL's
features (like user defined types etc. and how to use these features)
-) The third chapter starts with an overview of PostgreSQL's internal
structure with focus on the stages a query has to pass (i.e. parser,
planner/optimizer, executor). Then a detailed description of the
implementation of the Having clause and the Intersect/Except logic is
given.
Originally I worked on v6.3.2 but never found time enough to prepare
and post a patch. Now I applied the changes to v6.4 to get Intersect
and Except working with the new version. Chapter 3 of my documentation
deals with the changes against v6.3.2, so keep that in mind when
comparing the parts of the code printed there with the patched sources
of v6.4.
Here are some remarks on the patch. There are some things that have
still to be done but at the moment I don't have time to do them
myself. (I'm doing my military service at the moment) Sorry for that
:-(
-) I used a rewrite technique for the implementation of the Except/Intersect
logic which rewrites the query to a semantically equivalent query before
it is handed to the rewrite system (for views, rules etc.), planner,
executor etc.
-) In v6.3.2 the types of the attributes of two select statements
connected by the UNION keyword had to match 100%. In v6.4 the types
only need to be familiar (i.e. int and float can be mixed). Since this
feature did not exist when I worked on Intersect/Except it
does not work correctly for Except/Intersect queries WHEN USED IN
COMBINATION WITH UNIONS! (i.e. sometimes the wrong type is used for the
resulting table. This is because until now the types of the attributes of
the first select statement have been used for the resulting table.
When Intersects and/or Excepts are used in combination with Unions it
might happen, that the first select statement of the original query
appears at another position in the query which will be executed. The reason
for this is the technique used for the implementation of
Except/Intersect which does a query rewrite!)
NOTE: It is NOT broken for pure UNION queries and pure INTERSECT/EXCEPT
queries!!!
-) I had to add the field intersect_clause to some data structures
but did not find time to implement printfuncs for the new field.
This does NOT break the debug modes but when an Except/Intersect
is used the query debug output will be the already rewritten query.
-) Massive changes to the grammar rules for SELECT and INSERT statements
have been necessary (see comments in gram.y and documentation for
deatails) in order to be able to use mixed queries like
(SELECT ... UNION (SELECT ... EXCEPT SELECT)) INTERSECT SELECT...;
-) When using UNION/EXCEPT/INTERSECT you will get:
NOTICE: equal: "Don't know if nodes of type xxx are equal".
I did not have time to add comparsion support for all the needed nodes,
but the default behaviour of the function equal met my requirements.
I did not dare to supress this message!
That's the reason why the regression test for union will fail: These
messages are also included in the union.out file!
-) Somebody of you changed the union_planner() function for v6.4
(I copied the targetlist to new_tlist and that was removed and
replaced by a cleanup of the original targetlist). These chnages
violated some having queries executed against views so I changed
it back again. I did not have time to examine the differences between the
two versions but now it works :-)
If you want to find out, try the file queries/view_having.sql on
both versions and compare the results . Two queries won't produce a
correct result with your version.
regards
Stefan
1999-01-18 01:10:17 +01:00
|
|
|
ELSE, END_TRANS, EXCEPT, EXECUTE, EXISTS, EXTRACT,
|
1998-09-30 07:47:57 +02:00
|
|
|
FALSE_P, FETCH, FLOAT, FOR, FOREIGN, FROM, FULL,
|
1999-05-12 09:22:52 +02:00
|
|
|
GLOBAL, GRANT, GROUP, HAVING, HOUR_P,
|
Hi!
INTERSECT and EXCEPT is available for postgresql-v6.4!
The patch against v6.4 is included at the end of the current text
(in uuencoded form!)
I also included the text of my Master's Thesis. (a postscript
version). I hope that you find something of it useful and would be
happy if parts of it find their way into the PostgreSQL documentation
project (If so, tell me, then I send the sources of the document!)
The contents of the document are:
-) The first chapter might be of less interest as it gives only an
overview on SQL.
-) The second chapter gives a description on much of PostgreSQL's
features (like user defined types etc. and how to use these features)
-) The third chapter starts with an overview of PostgreSQL's internal
structure with focus on the stages a query has to pass (i.e. parser,
planner/optimizer, executor). Then a detailed description of the
implementation of the Having clause and the Intersect/Except logic is
given.
Originally I worked on v6.3.2 but never found time enough to prepare
and post a patch. Now I applied the changes to v6.4 to get Intersect
and Except working with the new version. Chapter 3 of my documentation
deals with the changes against v6.3.2, so keep that in mind when
comparing the parts of the code printed there with the patched sources
of v6.4.
Here are some remarks on the patch. There are some things that have
still to be done but at the moment I don't have time to do them
myself. (I'm doing my military service at the moment) Sorry for that
:-(
-) I used a rewrite technique for the implementation of the Except/Intersect
logic which rewrites the query to a semantically equivalent query before
it is handed to the rewrite system (for views, rules etc.), planner,
executor etc.
-) In v6.3.2 the types of the attributes of two select statements
connected by the UNION keyword had to match 100%. In v6.4 the types
only need to be familiar (i.e. int and float can be mixed). Since this
feature did not exist when I worked on Intersect/Except it
does not work correctly for Except/Intersect queries WHEN USED IN
COMBINATION WITH UNIONS! (i.e. sometimes the wrong type is used for the
resulting table. This is because until now the types of the attributes of
the first select statement have been used for the resulting table.
When Intersects and/or Excepts are used in combination with Unions it
might happen, that the first select statement of the original query
appears at another position in the query which will be executed. The reason
for this is the technique used for the implementation of
Except/Intersect which does a query rewrite!)
NOTE: It is NOT broken for pure UNION queries and pure INTERSECT/EXCEPT
queries!!!
-) I had to add the field intersect_clause to some data structures
but did not find time to implement printfuncs for the new field.
This does NOT break the debug modes but when an Except/Intersect
is used the query debug output will be the already rewritten query.
-) Massive changes to the grammar rules for SELECT and INSERT statements
have been necessary (see comments in gram.y and documentation for
deatails) in order to be able to use mixed queries like
(SELECT ... UNION (SELECT ... EXCEPT SELECT)) INTERSECT SELECT...;
-) When using UNION/EXCEPT/INTERSECT you will get:
NOTICE: equal: "Don't know if nodes of type xxx are equal".
I did not have time to add comparsion support for all the needed nodes,
but the default behaviour of the function equal met my requirements.
I did not dare to supress this message!
That's the reason why the regression test for union will fail: These
messages are also included in the union.out file!
-) Somebody of you changed the union_planner() function for v6.4
(I copied the targetlist to new_tlist and that was removed and
replaced by a cleanup of the original targetlist). These chnages
violated some having queries executed against views so I changed
it back again. I did not have time to examine the differences between the
two versions but now it works :-)
If you want to find out, try the file queries/view_having.sql on
both versions and compare the results . Two queries won't produce a
correct result with your version.
regards
Stefan
1999-01-18 01:10:17 +01:00
|
|
|
IN, INNER_P, INSENSITIVE, INSERT, INTERSECT, INTERVAL, INTO, IS,
|
|
|
|
ISOLATION, JOIN, KEY, LANGUAGE, LEADING, LEFT, LEVEL, LIKE, LOCAL,
|
1998-07-24 05:32:46 +02:00
|
|
|
MATCH, MINUTE_P, MONTH_P, NAMES,
|
1998-12-04 16:34:49 +01:00
|
|
|
NATIONAL, NATURAL, NCHAR, NEXT, NO, NOT, NULLIF, NULL_P, NUMERIC,
|
1998-09-13 06:19:33 +02:00
|
|
|
OF, ON, ONLY, OPTION, OR, ORDER, OUTER_P,
|
|
|
|
PARTIAL, POSITION, PRECISION, PRIMARY, PRIOR, PRIVILEGES, PROCEDURE, PUBLIC,
|
|
|
|
READ, REFERENCES, RELATIVE, REVOKE, RIGHT, ROLLBACK,
|
|
|
|
SCROLL, SECOND_P, SELECT, SET, SUBSTRING,
|
1999-04-19 18:00:18 +02:00
|
|
|
TABLE, TEMP, TEMPORARY, THEN, TIME, TIMESTAMP, TIMEZONE_HOUR,
|
|
|
|
TIMEZONE_MINUTE, TO, TRAILING, TRANSACTION, TRIM, TRUE_P,
|
1998-05-10 01:22:15 +02:00
|
|
|
UNION, UNIQUE, UPDATE, USER, USING,
|
1998-02-01 20:43:54 +01:00
|
|
|
VALUES, VARCHAR, VARYING, VIEW,
|
1998-12-04 16:34:49 +01:00
|
|
|
WHEN, WHERE, WITH, WORK, YEAR_P, ZONE
|
1997-10-25 07:56:41 +02:00
|
|
|
|
1999-11-30 04:57:29 +01:00
|
|
|
|
1997-10-25 07:56:41 +02:00
|
|
|
/* Keywords (in SQL3 reserved words) */
|
1999-09-29 18:06:40 +02:00
|
|
|
%token DEFERRABLE, DEFERRED,
|
|
|
|
IMMEDIATE, INITIALLY,
|
|
|
|
PENDANT,
|
|
|
|
RESTRICT,
|
|
|
|
TRIGGER
|
1997-10-25 07:56:41 +02:00
|
|
|
|
|
|
|
/* Keywords (in SQL92 non-reserved words) */
|
1999-05-12 09:22:52 +02:00
|
|
|
%token COMMITTED, SERIALIZABLE, TYPE_P
|
1997-10-25 07:56:41 +02:00
|
|
|
|
1998-09-30 07:47:57 +02:00
|
|
|
/* Keywords for Postgres support (not in SQL92 reserved words)
|
|
|
|
*
|
|
|
|
* The CREATEDB and CREATEUSER tokens should go away
|
|
|
|
* when some sort of pg_privileges relation is introduced.
|
|
|
|
* - Todd A. Brandys 1998-01-01?
|
|
|
|
*/
|
1999-05-12 09:22:52 +02:00
|
|
|
%token ABORT_TRANS, ACCESS, AFTER, AGGREGATE, ANALYZE,
|
|
|
|
BACKWARD, BEFORE, BINARY,
|
This patch implements ORACLE's COMMENT SQL command.
>From the ORACLE 7 SQL Language Reference Manual:
-----------------------------------------------------
COMMENT
Purpose:
To add a comment about a table, view, snapshot, or
column into the data dictionary.
Prerequisites:
The table, view, or snapshot must be in your own
schema
or you must have COMMENT ANY TABLE system privilege.
Syntax:
COMMENT ON [ TABLE table ] |
[ COLUMN table.column] IS 'text'
You can effectively drop a comment from the database
by setting it to the empty string ''.
-----------------------------------------------------
Example:
COMMENT ON TABLE workorders IS
'Maintains base records for workorder information';
COMMENT ON COLUMN workorders.hours IS
'Number of hours the engineer worked on the task';
to drop a comment:
COMMENT ON COLUMN workorders.hours IS '';
The current patch will simply perform the insert into
pg_description, as per the TODO. And, of course, when
the table is dropped, any comments relating to it
or any of its attributes are also dropped. I haven't
looked at the ODBC source yet, but I do know from
an ODBC client standpoint that the standard does
support the notion of table and column comments.
Hopefully the ODBC driver is already fetching these
values from pg_description, but if not, it should be
trivial.
Hope this makes the grade,
Mike Mascari
(mascarim@yahoo.com)
1999-10-15 03:49:49 +02:00
|
|
|
CACHE, CLUSTER, COMMENT, COPY, CREATEDB, CREATEUSER, CYCLE,
|
1999-05-12 09:22:52 +02:00
|
|
|
DATABASE, DELIMITERS, DO,
|
|
|
|
EACH, ENCODING, EXCLUSIVE, EXPLAIN, EXTEND,
|
1997-11-21 19:12:58 +01:00
|
|
|
FORWARD, FUNCTION, HANDLER,
|
1998-03-18 17:50:25 +01:00
|
|
|
INCREMENT, INDEX, INHERITS, INSTEAD, ISNULL,
|
1999-02-08 15:14:32 +01:00
|
|
|
LANCOMPILER, LIMIT, LISTEN, LOAD, LOCATION, LOCK_P,
|
1999-05-12 09:22:52 +02:00
|
|
|
MAXVALUE, MINVALUE, MODE, MOVE,
|
1998-09-30 07:47:57 +02:00
|
|
|
NEW, NOCREATEDB, NOCREATEUSER, NONE, NOTHING, NOTIFY, NOTNULL,
|
1999-02-08 15:14:32 +01:00
|
|
|
OFFSET, OIDS, OPERATOR, PASSWORD, PROCEDURAL,
|
1999-03-18 23:01:56 +01:00
|
|
|
RENAME, RESET, RETURNS, ROW, RULE,
|
1999-11-30 04:57:29 +01:00
|
|
|
SEQUENCE, SERIAL, SETOF, SHARE, SHOW, START, STATEMENT, STDIN, STDOUT, SYSID,
|
1999-09-23 19:03:39 +02:00
|
|
|
TRUNCATE, TRUSTED,
|
1998-09-30 07:47:57 +02:00
|
|
|
UNLISTEN, UNTIL, VACUUM, VALID, VERBOSE, VERSION
|
1997-12-04 01:28:15 +01:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/* Special keywords, not in the query language - see the "lex" file */
|
1997-09-01 08:00:35 +02:00
|
|
|
%token <str> IDENT, SCONST, Op
|
1996-07-09 08:22:35 +02:00
|
|
|
%token <ival> ICONST, PARAM
|
|
|
|
%token <dval> FCONST
|
|
|
|
|
1997-09-13 05:15:46 +02:00
|
|
|
/* these are not real. they are here so that they get generated as #define's*/
|
1997-09-08 05:20:18 +02:00
|
|
|
%token OP
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
/* precedence */
|
1997-10-25 07:56:41 +02:00
|
|
|
%left OR
|
|
|
|
%left AND
|
|
|
|
%right NOT
|
|
|
|
%right '='
|
1998-01-01 06:44:54 +01:00
|
|
|
%nonassoc '<' '>'
|
1997-10-25 07:56:41 +02:00
|
|
|
%nonassoc LIKE
|
|
|
|
%nonassoc BETWEEN
|
|
|
|
%nonassoc IN
|
1999-03-17 22:02:57 +01:00
|
|
|
%left Op /* multi-character ops and user-defined operators */
|
1997-10-25 07:56:41 +02:00
|
|
|
%nonassoc NOTNULL
|
|
|
|
%nonassoc ISNULL
|
1999-03-20 00:48:50 +01:00
|
|
|
%nonassoc NULL_P
|
1997-10-25 07:56:41 +02:00
|
|
|
%nonassoc IS
|
|
|
|
%left '+' '-'
|
1999-07-09 23:59:59 +02:00
|
|
|
%left '*' '/' '%'
|
|
|
|
%left '^'
|
1997-10-25 07:56:41 +02:00
|
|
|
%left '|' /* this is the relation union op, not logical or */
|
|
|
|
/* Unary Operators */
|
|
|
|
%right ':'
|
|
|
|
%left ';' /* end of statement or natural log */
|
|
|
|
%right UMINUS
|
|
|
|
%left '.'
|
|
|
|
%left '[' ']'
|
1999-12-10 04:01:05 +01:00
|
|
|
%left TYPECAST
|
Hi!
INTERSECT and EXCEPT is available for postgresql-v6.4!
The patch against v6.4 is included at the end of the current text
(in uuencoded form!)
I also included the text of my Master's Thesis. (a postscript
version). I hope that you find something of it useful and would be
happy if parts of it find their way into the PostgreSQL documentation
project (If so, tell me, then I send the sources of the document!)
The contents of the document are:
-) The first chapter might be of less interest as it gives only an
overview on SQL.
-) The second chapter gives a description on much of PostgreSQL's
features (like user defined types etc. and how to use these features)
-) The third chapter starts with an overview of PostgreSQL's internal
structure with focus on the stages a query has to pass (i.e. parser,
planner/optimizer, executor). Then a detailed description of the
implementation of the Having clause and the Intersect/Except logic is
given.
Originally I worked on v6.3.2 but never found time enough to prepare
and post a patch. Now I applied the changes to v6.4 to get Intersect
and Except working with the new version. Chapter 3 of my documentation
deals with the changes against v6.3.2, so keep that in mind when
comparing the parts of the code printed there with the patched sources
of v6.4.
Here are some remarks on the patch. There are some things that have
still to be done but at the moment I don't have time to do them
myself. (I'm doing my military service at the moment) Sorry for that
:-(
-) I used a rewrite technique for the implementation of the Except/Intersect
logic which rewrites the query to a semantically equivalent query before
it is handed to the rewrite system (for views, rules etc.), planner,
executor etc.
-) In v6.3.2 the types of the attributes of two select statements
connected by the UNION keyword had to match 100%. In v6.4 the types
only need to be familiar (i.e. int and float can be mixed). Since this
feature did not exist when I worked on Intersect/Except it
does not work correctly for Except/Intersect queries WHEN USED IN
COMBINATION WITH UNIONS! (i.e. sometimes the wrong type is used for the
resulting table. This is because until now the types of the attributes of
the first select statement have been used for the resulting table.
When Intersects and/or Excepts are used in combination with Unions it
might happen, that the first select statement of the original query
appears at another position in the query which will be executed. The reason
for this is the technique used for the implementation of
Except/Intersect which does a query rewrite!)
NOTE: It is NOT broken for pure UNION queries and pure INTERSECT/EXCEPT
queries!!!
-) I had to add the field intersect_clause to some data structures
but did not find time to implement printfuncs for the new field.
This does NOT break the debug modes but when an Except/Intersect
is used the query debug output will be the already rewritten query.
-) Massive changes to the grammar rules for SELECT and INSERT statements
have been necessary (see comments in gram.y and documentation for
deatails) in order to be able to use mixed queries like
(SELECT ... UNION (SELECT ... EXCEPT SELECT)) INTERSECT SELECT...;
-) When using UNION/EXCEPT/INTERSECT you will get:
NOTICE: equal: "Don't know if nodes of type xxx are equal".
I did not have time to add comparsion support for all the needed nodes,
but the default behaviour of the function equal met my requirements.
I did not dare to supress this message!
That's the reason why the regression test for union will fail: These
messages are also included in the union.out file!
-) Somebody of you changed the union_planner() function for v6.4
(I copied the targetlist to new_tlist and that was removed and
replaced by a cleanup of the original targetlist). These chnages
violated some having queries executed against views so I changed
it back again. I did not have time to examine the differences between the
two versions but now it works :-)
If you want to find out, try the file queries/view_having.sql on
both versions and compare the results . Two queries won't produce a
correct result with your version.
regards
Stefan
1999-01-18 01:10:17 +01:00
|
|
|
%left UNION INTERSECT EXCEPT
|
1996-07-09 08:22:35 +02:00
|
|
|
%%
|
|
|
|
|
1999-10-05 20:14:31 +02:00
|
|
|
/*
|
|
|
|
* Handle comment-only lines, and ;; SELECT * FROM pg_class ;;;
|
|
|
|
* psql already handles such cases, but other interfaces don't.
|
|
|
|
* bjm 1999/10/05
|
|
|
|
*/
|
|
|
|
stmtblock: stmtmulti
|
1997-09-08 05:20:18 +02:00
|
|
|
{ parsetree = $1; }
|
|
|
|
;
|
1996-12-20 21:33:12 +01:00
|
|
|
|
1999-10-07 06:23:24 +02:00
|
|
|
/* the thrashing around here is to discard "empty" statements... */
|
1999-05-22 07:06:43 +02:00
|
|
|
stmtmulti: stmtmulti ';' stmt
|
1999-10-07 06:23:24 +02:00
|
|
|
{ if ($3 != (Node *)NULL)
|
1999-10-05 20:14:31 +02:00
|
|
|
$$ = lappend($1, $3);
|
|
|
|
else
|
|
|
|
$$ = $1;
|
|
|
|
}
|
1999-05-22 07:06:43 +02:00
|
|
|
| stmt
|
1999-10-07 06:23:24 +02:00
|
|
|
{ if ($1 != (Node *)NULL)
|
1999-10-05 20:14:31 +02:00
|
|
|
$$ = lcons($1,NIL);
|
|
|
|
else
|
1999-10-07 06:23:24 +02:00
|
|
|
$$ = NIL;
|
1999-10-05 20:14:31 +02:00
|
|
|
}
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2000-01-16 21:05:00 +01:00
|
|
|
stmt : AlterTableStmt
|
1999-12-16 18:24:19 +01:00
|
|
|
| AlterGroupStmt
|
1997-12-04 01:28:15 +01:00
|
|
|
| AlterUserStmt
|
1997-09-08 05:20:18 +02:00
|
|
|
| ClosePortalStmt
|
|
|
|
| CopyStmt
|
|
|
|
| CreateStmt
|
1997-12-23 20:47:32 +01:00
|
|
|
| CreateAsStmt
|
1999-12-16 18:24:19 +01:00
|
|
|
| CreateGroupStmt
|
1997-09-08 05:20:18 +02:00
|
|
|
| CreateSeqStmt
|
1997-10-28 16:11:45 +01:00
|
|
|
| CreatePLangStmt
|
1997-09-08 05:20:18 +02:00
|
|
|
| CreateTrigStmt
|
1997-12-04 01:28:15 +01:00
|
|
|
| CreateUserStmt
|
1997-09-08 05:20:18 +02:00
|
|
|
| ClusterStmt
|
|
|
|
| DefineStmt
|
1999-12-10 04:56:14 +01:00
|
|
|
| DropStmt
|
1999-09-23 19:03:39 +02:00
|
|
|
| TruncateStmt
|
This patch implements ORACLE's COMMENT SQL command.
>From the ORACLE 7 SQL Language Reference Manual:
-----------------------------------------------------
COMMENT
Purpose:
To add a comment about a table, view, snapshot, or
column into the data dictionary.
Prerequisites:
The table, view, or snapshot must be in your own
schema
or you must have COMMENT ANY TABLE system privilege.
Syntax:
COMMENT ON [ TABLE table ] |
[ COLUMN table.column] IS 'text'
You can effectively drop a comment from the database
by setting it to the empty string ''.
-----------------------------------------------------
Example:
COMMENT ON TABLE workorders IS
'Maintains base records for workorder information';
COMMENT ON COLUMN workorders.hours IS
'Number of hours the engineer worked on the task';
to drop a comment:
COMMENT ON COLUMN workorders.hours IS '';
The current patch will simply perform the insert into
pg_description, as per the TODO. And, of course, when
the table is dropped, any comments relating to it
or any of its attributes are also dropped. I haven't
looked at the ODBC source yet, but I do know from
an ODBC client standpoint that the standard does
support the notion of table and column comments.
Hopefully the ODBC driver is already fetching these
values from pg_description, but if not, it should be
trivial.
Hope this makes the grade,
Mike Mascari
(mascarim@yahoo.com)
1999-10-15 03:49:49 +02:00
|
|
|
| CommentStmt
|
1999-12-16 18:24:19 +01:00
|
|
|
| DropGroupStmt
|
1997-10-28 16:11:45 +01:00
|
|
|
| DropPLangStmt
|
1997-09-08 05:20:18 +02:00
|
|
|
| DropTrigStmt
|
1997-12-04 01:28:15 +01:00
|
|
|
| DropUserStmt
|
1997-09-08 05:20:18 +02:00
|
|
|
| ExtendStmt
|
|
|
|
| ExplainStmt
|
|
|
|
| FetchStmt
|
|
|
|
| GrantStmt
|
|
|
|
| IndexStmt
|
|
|
|
| ListenStmt
|
1998-08-25 23:37:08 +02:00
|
|
|
| UnlistenStmt
|
1998-01-23 00:05:18 +01:00
|
|
|
| LockStmt
|
1997-09-08 05:20:18 +02:00
|
|
|
| ProcedureStmt
|
|
|
|
| RemoveAggrStmt
|
|
|
|
| RemoveOperStmt
|
|
|
|
| RemoveFuncStmt
|
|
|
|
| RemoveStmt
|
|
|
|
| RenameStmt
|
|
|
|
| RevokeStmt
|
|
|
|
| OptimizableStmt
|
|
|
|
| RuleStmt
|
|
|
|
| TransactionStmt
|
|
|
|
| ViewStmt
|
|
|
|
| LoadStmt
|
|
|
|
| CreatedbStmt
|
1999-12-10 04:56:14 +01:00
|
|
|
| DropdbStmt
|
1997-09-08 05:20:18 +02:00
|
|
|
| VacuumStmt
|
|
|
|
| VariableSetStmt
|
|
|
|
| VariableShowStmt
|
|
|
|
| VariableResetStmt
|
1999-09-29 18:06:40 +02:00
|
|
|
| ConstraintsSetStmt
|
1999-10-05 20:14:31 +02:00
|
|
|
| /*EMPTY*/
|
1999-10-07 06:23:24 +02:00
|
|
|
{ $$ = (Node *)NULL; }
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
1997-04-02 20:24:52 +02:00
|
|
|
|
1997-12-04 01:28:15 +01:00
|
|
|
/*****************************************************************************
|
|
|
|
*
|
1997-12-16 16:50:54 +01:00
|
|
|
* Create a new Postgres DBMS user
|
1997-12-04 01:28:15 +01:00
|
|
|
*
|
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
|
1999-11-30 04:57:29 +01:00
|
|
|
CreateUserStmt: CREATE USER UserId
|
|
|
|
user_createdb_clause user_createuser_clause user_group_clause
|
|
|
|
user_valid_clause
|
1997-12-16 16:50:54 +01:00
|
|
|
{
|
|
|
|
CreateUserStmt *n = makeNode(CreateUserStmt);
|
|
|
|
n->user = $3;
|
1999-11-30 04:57:29 +01:00
|
|
|
n->sysid = -1;
|
|
|
|
n->password = NULL;
|
2000-01-14 23:11:38 +01:00
|
|
|
n->createdb = $4 == +1 ? true : false;
|
|
|
|
n->createuser = $5 == +1 ? true : false;
|
1999-11-30 04:57:29 +01:00
|
|
|
n->groupElts = $6;
|
|
|
|
n->validUntil = $7;
|
1997-12-16 16:50:54 +01:00
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
1999-11-30 04:57:29 +01:00
|
|
|
| CREATE USER UserId WITH sysid_clause user_passwd_clause
|
|
|
|
user_createdb_clause user_createuser_clause user_group_clause
|
|
|
|
user_valid_clause
|
|
|
|
{
|
|
|
|
CreateUserStmt *n = makeNode(CreateUserStmt);
|
|
|
|
n->user = $3;
|
|
|
|
n->sysid = $5;
|
|
|
|
n->password = $6;
|
2000-01-14 23:11:38 +01:00
|
|
|
n->createdb = $7 == +1 ? true : false;
|
|
|
|
n->createuser = $8 == +1 ? true : false;
|
1999-11-30 04:57:29 +01:00
|
|
|
n->groupElts = $9;
|
|
|
|
n->validUntil = $10;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
1997-12-16 16:50:54 +01:00
|
|
|
;
|
1997-12-04 01:28:15 +01:00
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
*
|
|
|
|
* Alter a postresql DBMS user
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
|
1999-11-30 04:57:29 +01:00
|
|
|
AlterUserStmt: ALTER USER UserId user_createdb_clause
|
2000-01-14 23:11:38 +01:00
|
|
|
user_createuser_clause user_valid_clause
|
1997-12-16 16:50:54 +01:00
|
|
|
{
|
|
|
|
AlterUserStmt *n = makeNode(AlterUserStmt);
|
|
|
|
n->user = $3;
|
1999-11-30 04:57:29 +01:00
|
|
|
n->password = NULL;
|
|
|
|
n->createdb = $4;
|
|
|
|
n->createuser = $5;
|
2000-01-14 23:11:38 +01:00
|
|
|
n->validUntil = $6;
|
1999-11-30 04:57:29 +01:00
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
2000-01-14 23:11:38 +01:00
|
|
|
| ALTER USER UserId WITH PASSWORD Sconst
|
1999-11-30 04:57:29 +01:00
|
|
|
user_createdb_clause
|
2000-01-14 23:11:38 +01:00
|
|
|
user_createuser_clause user_valid_clause
|
1999-11-30 04:57:29 +01:00
|
|
|
{
|
|
|
|
AlterUserStmt *n = makeNode(AlterUserStmt);
|
|
|
|
n->user = $3;
|
|
|
|
n->password = $6;
|
|
|
|
n->createdb = $7;
|
|
|
|
n->createuser = $8;
|
2000-01-14 23:11:38 +01:00
|
|
|
n->validUntil = $9;
|
1997-12-16 16:50:54 +01:00
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
;
|
1997-12-04 01:28:15 +01:00
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
*
|
|
|
|
* Drop a postresql DBMS user
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
|
2000-01-14 23:11:38 +01:00
|
|
|
DropUserStmt: DROP USER user_list
|
1997-12-16 16:50:54 +01:00
|
|
|
{
|
|
|
|
DropUserStmt *n = makeNode(DropUserStmt);
|
2000-01-14 23:11:38 +01:00
|
|
|
n->users = $3;
|
1997-12-16 16:50:54 +01:00
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
2000-01-14 23:11:38 +01:00
|
|
|
user_passwd_clause: PASSWORD Sconst { $$ = $2; }
|
1999-11-30 04:57:29 +01:00
|
|
|
| /*EMPTY*/ { $$ = NULL; }
|
1997-12-16 16:50:54 +01:00
|
|
|
;
|
|
|
|
|
2000-01-14 23:11:38 +01:00
|
|
|
sysid_clause: SYSID Iconst
|
|
|
|
{
|
|
|
|
if ($2 <= 0)
|
|
|
|
elog(ERROR, "sysid must be positive");
|
|
|
|
$$ = $2;
|
|
|
|
}
|
1999-11-30 04:57:29 +01:00
|
|
|
| /*EMPTY*/ { $$ = -1; }
|
|
|
|
;
|
|
|
|
|
2000-01-14 23:11:38 +01:00
|
|
|
user_createdb_clause: CREATEDB { $$ = +1; }
|
|
|
|
| NOCREATEDB { $$ = -1; }
|
|
|
|
| /*EMPTY*/ { $$ = 0; }
|
1997-12-16 16:50:54 +01:00
|
|
|
;
|
|
|
|
|
2000-01-14 23:11:38 +01:00
|
|
|
user_createuser_clause: CREATEUSER { $$ = +1; }
|
|
|
|
| NOCREATEUSER { $$ = -1; }
|
|
|
|
| /*EMPTY*/ { $$ = 0; }
|
1997-12-16 16:50:54 +01:00
|
|
|
;
|
|
|
|
|
2000-01-14 23:11:38 +01:00
|
|
|
user_list: user_list ',' UserId
|
1997-12-16 16:50:54 +01:00
|
|
|
{
|
|
|
|
$$ = lcons((void*)makeString($3), $1);
|
|
|
|
}
|
1998-02-11 05:09:54 +01:00
|
|
|
| UserId
|
1997-12-16 16:50:54 +01:00
|
|
|
{
|
|
|
|
$$ = lcons((void*)makeString($1), NIL);
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
2000-01-14 23:11:38 +01:00
|
|
|
user_group_clause: IN GROUP user_list { $$ = $3; }
|
1999-12-16 18:24:19 +01:00
|
|
|
| /*EMPTY*/ { $$ = NULL; }
|
1997-12-16 16:50:54 +01:00
|
|
|
;
|
|
|
|
|
|
|
|
user_valid_clause: VALID UNTIL SCONST { $$ = $3; }
|
|
|
|
| /*EMPTY*/ { $$ = NULL; }
|
|
|
|
;
|
1997-10-25 07:56:41 +02:00
|
|
|
|
1999-12-16 18:24:19 +01:00
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
*
|
|
|
|
* Create a postresql group
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
CreateGroupStmt: CREATE GROUP UserId
|
|
|
|
{
|
|
|
|
CreateGroupStmt *n = makeNode(CreateGroupStmt);
|
|
|
|
n->name = $3;
|
|
|
|
n->sysid = -1;
|
|
|
|
n->initUsers = NULL;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
CREATE GROUP UserId WITH sysid_clause users_in_new_group_clause
|
|
|
|
{
|
|
|
|
CreateGroupStmt *n = makeNode(CreateGroupStmt);
|
|
|
|
n->name = $3;
|
|
|
|
n->sysid = $5;
|
|
|
|
n->initUsers = $6;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
2000-01-14 23:11:38 +01:00
|
|
|
users_in_new_group_clause: USER user_list { $$ = $2; }
|
1999-12-16 18:24:19 +01:00
|
|
|
| /* EMPTY */ { $$ = NULL; }
|
|
|
|
;
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
*
|
|
|
|
* Alter a postresql group
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
|
2000-01-14 23:11:38 +01:00
|
|
|
AlterGroupStmt: ALTER GROUP UserId ADD USER user_list
|
1999-12-16 18:24:19 +01:00
|
|
|
{
|
|
|
|
AlterGroupStmt *n = makeNode(AlterGroupStmt);
|
|
|
|
n->name = $3;
|
|
|
|
n->sysid = -1;
|
|
|
|
n->action = +1;
|
|
|
|
n->listUsers = $6;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
|
|
2000-01-14 23:11:38 +01:00
|
|
|
ALTER GROUP UserId DROP USER user_list
|
1999-12-16 18:24:19 +01:00
|
|
|
{
|
|
|
|
AlterGroupStmt *n = makeNode(AlterGroupStmt);
|
|
|
|
n->name = $3;
|
|
|
|
n->sysid = -1;
|
|
|
|
n->action = -1;
|
|
|
|
n->listUsers = $6;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
*
|
|
|
|
* Drop a postresql group
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
DropGroupStmt: DROP GROUP UserId
|
|
|
|
{
|
|
|
|
DropGroupStmt *n = makeNode(DropGroupStmt);
|
|
|
|
n->name = $3;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
|
|
|
|
1997-04-02 20:24:52 +02:00
|
|
|
/*****************************************************************************
|
1997-09-01 08:00:35 +02:00
|
|
|
*
|
1997-04-02 20:24:52 +02:00
|
|
|
* Set PG internal variable
|
1997-09-18 05:46:18 +02:00
|
|
|
* SET name TO 'var_value'
|
1997-10-25 07:56:41 +02:00
|
|
|
* Include SQL92 syntax (thomas 1997-10-22):
|
|
|
|
* SET TIME ZONE 'var_value'
|
1997-09-01 08:00:35 +02:00
|
|
|
*
|
1997-04-02 20:24:52 +02:00
|
|
|
*****************************************************************************/
|
|
|
|
|
1997-10-25 07:56:41 +02:00
|
|
|
VariableSetStmt: SET ColId TO var_value
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
VariableSetStmt *n = makeNode(VariableSetStmt);
|
|
|
|
n->name = $2;
|
|
|
|
n->value = $4;
|
|
|
|
$$ = (Node *) n;
|
|
|
|
}
|
1997-11-07 08:02:10 +01:00
|
|
|
| SET ColId '=' var_value
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
VariableSetStmt *n = makeNode(VariableSetStmt);
|
|
|
|
n->name = $2;
|
|
|
|
n->value = $4;
|
|
|
|
$$ = (Node *) n;
|
|
|
|
}
|
1997-11-07 08:02:10 +01:00
|
|
|
| SET TIME ZONE zone_value
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
VariableSetStmt *n = makeNode(VariableSetStmt);
|
|
|
|
n->name = "timezone";
|
|
|
|
n->value = $4;
|
|
|
|
$$ = (Node *) n;
|
|
|
|
}
|
1999-05-12 09:22:52 +02:00
|
|
|
| SET TRANSACTION ISOLATION LEVEL opt_level
|
1998-12-18 10:10:39 +01:00
|
|
|
{
|
|
|
|
VariableSetStmt *n = makeNode(VariableSetStmt);
|
|
|
|
n->name = "XactIsoLevel";
|
|
|
|
n->value = $5;
|
|
|
|
$$ = (Node *) n;
|
|
|
|
}
|
2000-01-13 19:26:18 +01:00
|
|
|
| SET NAMES opt_encoding
|
1998-07-24 05:32:46 +02:00
|
|
|
{
|
1999-08-18 15:04:45 +02:00
|
|
|
#ifdef MULTIBYTE
|
1998-07-24 05:32:46 +02:00
|
|
|
VariableSetStmt *n = makeNode(VariableSetStmt);
|
|
|
|
n->name = "client_encoding";
|
|
|
|
n->value = $3;
|
|
|
|
$$ = (Node *) n;
|
|
|
|
#else
|
2000-01-13 19:26:18 +01:00
|
|
|
elog(ERROR, "SET NAMES is not supported.");
|
1998-07-24 05:32:46 +02:00
|
|
|
#endif
|
|
|
|
}
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
|
|
|
|
1999-05-12 09:22:52 +02:00
|
|
|
opt_level: READ COMMITTED { $$ = "committed"; }
|
|
|
|
| SERIALIZABLE { $$ = "serializable"; }
|
|
|
|
;
|
|
|
|
|
1997-09-18 05:46:18 +02:00
|
|
|
var_value: Sconst { $$ = $1; }
|
1997-11-07 08:02:10 +01:00
|
|
|
| DEFAULT { $$ = NULL; }
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
|
|
|
|
1997-09-18 05:46:18 +02:00
|
|
|
zone_value: Sconst { $$ = $1; }
|
1997-11-07 08:02:10 +01:00
|
|
|
| DEFAULT { $$ = NULL; }
|
1998-04-08 08:39:01 +02:00
|
|
|
| LOCAL { $$ = NULL; }
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
1997-09-01 08:00:35 +02:00
|
|
|
|
2000-01-13 19:26:18 +01:00
|
|
|
opt_encoding: Sconst { $$ = $1; }
|
|
|
|
| DEFAULT { $$ = NULL; }
|
|
|
|
| /*EMPTY*/ { $$ = NULL; }
|
|
|
|
;
|
|
|
|
|
1997-10-25 07:56:41 +02:00
|
|
|
VariableShowStmt: SHOW ColId
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
VariableShowStmt *n = makeNode(VariableShowStmt);
|
|
|
|
n->name = $2;
|
|
|
|
$$ = (Node *) n;
|
|
|
|
}
|
1997-10-30 17:39:27 +01:00
|
|
|
| SHOW TIME ZONE
|
|
|
|
{
|
|
|
|
VariableShowStmt *n = makeNode(VariableShowStmt);
|
|
|
|
n->name = "timezone";
|
|
|
|
$$ = (Node *) n;
|
|
|
|
}
|
1998-12-18 10:10:39 +01:00
|
|
|
| SHOW TRANSACTION ISOLATION LEVEL
|
|
|
|
{
|
|
|
|
VariableShowStmt *n = makeNode(VariableShowStmt);
|
|
|
|
n->name = "XactIsoLevel";
|
|
|
|
$$ = (Node *) n;
|
|
|
|
}
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
|
|
|
|
1997-10-25 07:56:41 +02:00
|
|
|
VariableResetStmt: RESET ColId
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
VariableResetStmt *n = makeNode(VariableResetStmt);
|
|
|
|
n->name = $2;
|
|
|
|
$$ = (Node *) n;
|
|
|
|
}
|
1997-10-30 17:39:27 +01:00
|
|
|
| RESET TIME ZONE
|
|
|
|
{
|
|
|
|
VariableResetStmt *n = makeNode(VariableResetStmt);
|
|
|
|
n->name = "timezone";
|
|
|
|
$$ = (Node *) n;
|
|
|
|
}
|
1998-12-18 10:10:39 +01:00
|
|
|
| RESET TRANSACTION ISOLATION LEVEL
|
|
|
|
{
|
|
|
|
VariableResetStmt *n = makeNode(VariableResetStmt);
|
|
|
|
n->name = "XactIsoLevel";
|
|
|
|
$$ = (Node *) n;
|
|
|
|
}
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
To: Thomas Lockhart <Thomas.G.Lockhart@jpl.nasa.gov>
Subject: Re: [PATCHES] SET DateStyle patches
On Tue, 22 Apr 1997, Thomas Lockhart wrote:
> Some more patches! These (try to) finish implementing SET variable TO value
> for "DateStyle" (changed the name from simply "date" to be more descriptive).
> This is based on code from Martin and Bruce (?), which was easy to modify.
> The syntax is
>
> SET DateStyle TO 'iso'
> SET DateStyle TO 'postgres'
> SET DateStyle TO 'sql'
> SET DateStyle TO 'european'
> SET DateStyle TO 'noneuropean'
> SET DateStyle TO 'us' (same as "noneuropean")
> SET DateStyle TO 'default' (current same as "postgres,us")
>
> ("european" is just compared for the first 4 characters, and "noneuropean"
> is compared for the first 7 to allow less typing).
>
> Multiple arguments are allowed, so SET datestyle TO 'sql,euro' is valid.
>
> My mods also try to implement "SHOW variable" and "RESET variable", but
> that part just core dumps at the moment. I would guess that my errors
> are obvious to someone who knows what they are doing with the parser stuff,
> so if someone (Bruce and/or Martin??) could have it do the right thing
> we will have a more complete set of what we need.
>
> Also, I would like to have a floating point precision global variable to
> implement "SET precision TO 10" and perhaps "SET precision TO 10,2" for
> float8 and float4, but I don't know how to do that for integer types rather
> than strings. If someone is fixing the SHOW and RESET code, perhaps they can
> add some hooks for me to do the floats while they are at it.
>
> I've left some remnants of variable structures in the source code which
> I did not use in the interests of getting something working for v6.1.
> We'll have time to clean things up for the next release...
1997-04-23 05:18:27 +02:00
|
|
|
|
1997-10-25 07:56:41 +02:00
|
|
|
|
1999-09-29 18:06:40 +02:00
|
|
|
ConstraintsSetStmt: SET CONSTRAINTS constraints_set_list constraints_set_mode
|
|
|
|
{
|
|
|
|
ConstraintsSetStmt *n = makeNode(ConstraintsSetStmt);
|
|
|
|
n->constraints = $3;
|
|
|
|
n->deferred = $4;
|
|
|
|
$$ = (Node *) n;
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
|
|
|
|
|
|
|
constraints_set_list: ALL
|
|
|
|
{
|
|
|
|
$$ = NIL;
|
|
|
|
}
|
|
|
|
| constraints_set_namelist
|
|
|
|
{
|
|
|
|
$$ = $1;
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
|
|
|
|
|
|
|
constraints_set_namelist: IDENT
|
|
|
|
{
|
|
|
|
$$ = lappend(NIL, $1);
|
|
|
|
}
|
|
|
|
| constraints_set_namelist ',' IDENT
|
|
|
|
{
|
|
|
|
$$ = lappend($1, $3);
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
|
|
|
|
|
|
|
constraints_set_mode: DEFERRED
|
|
|
|
{
|
|
|
|
$$ = true;
|
|
|
|
}
|
|
|
|
| IMMEDIATE
|
|
|
|
{
|
|
|
|
$$ = false;
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*****************************************************************************
|
|
|
|
*
|
2000-01-16 21:05:00 +01:00
|
|
|
* ALTER TABLE variations
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
|
2000-01-16 21:05:00 +01:00
|
|
|
AlterTableStmt:
|
|
|
|
/* ALTER TABLE <name> ADD [COLUMN] <coldef> */
|
|
|
|
ALTER TABLE relation_name opt_inh_star ADD opt_column columnDef
|
|
|
|
{
|
|
|
|
AlterTableStmt *n = makeNode(AlterTableStmt);
|
|
|
|
n->subtype = 'A';
|
|
|
|
n->relname = $3;
|
|
|
|
n->inh = $4;
|
|
|
|
n->def = $7;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
/* ALTER TABLE <name> ALTER [COLUMN] <colname> {SET DEFAULT <expr>|DROP DEFAULT} */
|
|
|
|
| ALTER TABLE relation_name opt_inh_star ALTER opt_column ColId alter_column_action
|
|
|
|
{
|
|
|
|
AlterTableStmt *n = makeNode(AlterTableStmt);
|
|
|
|
n->subtype = 'T';
|
|
|
|
n->relname = $3;
|
|
|
|
n->inh = $4;
|
|
|
|
n->name = $7;
|
|
|
|
n->def = $8;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
/* ALTER TABLE <name> DROP [COLUMN] <name> {RESTRICT|CASCADE} */
|
2000-01-22 15:20:56 +01:00
|
|
|
| ALTER TABLE relation_name opt_inh_star DROP opt_column ColId /* drop_behavior */
|
2000-01-16 21:05:00 +01:00
|
|
|
{
|
|
|
|
AlterTableStmt *n = makeNode(AlterTableStmt);
|
|
|
|
n->subtype = 'D';
|
|
|
|
n->relname = $3;
|
|
|
|
n->inh = $4;
|
|
|
|
n->name = $7;
|
2000-01-22 15:20:56 +01:00
|
|
|
/* n->behavior = $8; */
|
2000-01-16 21:05:00 +01:00
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
/* ALTER TABLE <name> ADD CONSTRAINT ... */
|
|
|
|
| ALTER TABLE relation_name opt_inh_star ADD TableConstraint
|
|
|
|
{
|
|
|
|
AlterTableStmt *n = makeNode(AlterTableStmt);
|
2000-01-18 07:12:03 +01:00
|
|
|
n->subtype = 'C';
|
2000-01-16 21:05:00 +01:00
|
|
|
n->relname = $3;
|
|
|
|
n->inh = $4;
|
|
|
|
n->def = $6;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
/* ALTER TABLE <name> DROP CONSTRAINT <name> {RESTRICT|CASCADE} */
|
|
|
|
| ALTER TABLE relation_name opt_inh_star DROP CONSTRAINT name drop_behavior
|
|
|
|
{
|
|
|
|
AlterTableStmt *n = makeNode(AlterTableStmt);
|
2000-01-19 00:30:24 +01:00
|
|
|
n->subtype = 'X';
|
2000-01-16 21:05:00 +01:00
|
|
|
n->relname = $3;
|
|
|
|
n->inh = $4;
|
|
|
|
n->name = $7;
|
|
|
|
n->behavior = $8;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
|
|
|
alter_column_action:
|
|
|
|
SET DEFAULT a_expr_or_null { $$ = $3; }
|
|
|
|
| DROP DEFAULT { $$ = NULL; }
|
|
|
|
;
|
|
|
|
|
|
|
|
drop_behavior: CASCADE { $$ = CASCADE; }
|
|
|
|
| RESTRICT { $$ = RESTRICT; }
|
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-18 05:46:18 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
/*****************************************************************************
|
1997-09-01 08:00:35 +02:00
|
|
|
*
|
1997-09-08 05:20:18 +02:00
|
|
|
* QUERY :
|
|
|
|
* close <optname>
|
1997-09-01 08:00:35 +02:00
|
|
|
*
|
1996-07-09 08:22:35 +02:00
|
|
|
*****************************************************************************/
|
|
|
|
|
1997-09-01 08:00:35 +02:00
|
|
|
ClosePortalStmt: CLOSE opt_id
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
ClosePortalStmt *n = makeNode(ClosePortalStmt);
|
|
|
|
n->portalname = $2;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1999-07-17 00:29:42 +02:00
|
|
|
opt_id: ColId { $$ = $1; }
|
|
|
|
| /*EMPTY*/ { $$ = NULL; }
|
|
|
|
;
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
*
|
1997-09-08 05:20:18 +02:00
|
|
|
* QUERY :
|
|
|
|
* COPY [BINARY] <relname> FROM/TO
|
|
|
|
* [USING DELIMITERS <delimiter>]
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
|
1999-12-14 01:08:21 +01:00
|
|
|
CopyStmt: COPY opt_binary relation_name opt_with_copy copy_dirn copy_file_name copy_delimiter copy_null
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
CopyStmt *n = makeNode(CopyStmt);
|
|
|
|
n->binary = $2;
|
|
|
|
n->relname = $3;
|
|
|
|
n->oids = $4;
|
|
|
|
n->direction = $5;
|
|
|
|
n->filename = $6;
|
|
|
|
n->delimiter = $7;
|
1999-12-14 01:08:21 +01:00
|
|
|
n->null_print = $8;
|
1997-09-08 05:20:18 +02:00
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
|
|
|
copy_dirn: TO
|
|
|
|
{ $$ = TO; }
|
1997-11-07 08:02:10 +01:00
|
|
|
| FROM
|
1997-09-08 05:20:18 +02:00
|
|
|
{ $$ = FROM; }
|
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-01 08:00:35 +02:00
|
|
|
/*
|
1996-07-09 08:22:35 +02:00
|
|
|
* copy_file_name NULL indicates stdio is used. Whether stdin or stdout is
|
|
|
|
* used depends on the direction. (It really doesn't make sense to copy from
|
1997-09-08 05:20:18 +02:00
|
|
|
* stdout. We silently correct the "typo". - AY 9/94
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
1997-09-08 05:20:18 +02:00
|
|
|
copy_file_name: Sconst { $$ = $1; }
|
|
|
|
| STDIN { $$ = NULL; }
|
|
|
|
| STDOUT { $$ = NULL; }
|
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-11-07 08:02:10 +01:00
|
|
|
opt_binary: BINARY { $$ = TRUE; }
|
|
|
|
| /*EMPTY*/ { $$ = FALSE; }
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-08 05:20:18 +02:00
|
|
|
opt_with_copy: WITH OIDS { $$ = TRUE; }
|
1997-12-16 16:50:54 +01:00
|
|
|
| /*EMPTY*/ { $$ = FALSE; }
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
1996-08-24 22:49:41 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*
|
|
|
|
* the default copy delimiter is tab but the user can configure it
|
|
|
|
*/
|
1999-10-30 01:52:22 +02:00
|
|
|
copy_delimiter: opt_using DELIMITERS Sconst { $$ = $3; }
|
1997-12-16 16:50:54 +01:00
|
|
|
| /*EMPTY*/ { $$ = "\t"; }
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1999-10-30 01:52:22 +02:00
|
|
|
opt_using: USING { $$ = TRUE; }
|
|
|
|
| /*EMPTY*/ { $$ = TRUE; }
|
|
|
|
;
|
|
|
|
|
1999-12-14 01:08:21 +01:00
|
|
|
copy_null: WITH NULL_P AS Sconst { $$ = $4; }
|
|
|
|
| /*EMPTY*/ { $$ = "\\N"; }
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
*
|
1997-09-08 05:20:18 +02:00
|
|
|
* QUERY :
|
|
|
|
* CREATE relname
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
|
1999-02-02 04:45:56 +01:00
|
|
|
CreateStmt: CREATE OptTemp TABLE relation_name '(' OptTableElementList ')'
|
1998-09-30 07:47:57 +02:00
|
|
|
OptInherit
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
CreateStmt *n = makeNode(CreateStmt);
|
1999-02-02 04:45:56 +01:00
|
|
|
n->istemp = $2;
|
|
|
|
n->relname = $4;
|
|
|
|
n->tableElts = $6;
|
|
|
|
n->inhRelnames = $8;
|
1997-12-05 00:07:23 +01:00
|
|
|
n->constraints = NIL;
|
1997-09-08 05:20:18 +02:00
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
1999-05-12 09:22:52 +02:00
|
|
|
OptTemp: OptTempType { $$ = $1; }
|
|
|
|
| OptTempScope OptTempType { $$ = $2; }
|
|
|
|
;
|
|
|
|
|
|
|
|
OptTempType: TEMP { $$ = TRUE; }
|
1999-04-19 18:00:18 +02:00
|
|
|
| TEMPORARY { $$ = TRUE; }
|
1999-02-02 04:45:56 +01:00
|
|
|
| /*EMPTY*/ { $$ = FALSE; }
|
|
|
|
;
|
|
|
|
|
1999-05-12 09:22:52 +02:00
|
|
|
OptTempScope: GLOBAL
|
|
|
|
{
|
|
|
|
elog(ERROR, "GLOBAL TEMPORARY TABLE is not currently supported");
|
|
|
|
$$ = TRUE;
|
|
|
|
}
|
|
|
|
| LOCAL
|
|
|
|
{
|
|
|
|
$$ = FALSE;
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
1997-12-05 00:07:23 +01:00
|
|
|
OptTableElementList: OptTableElementList ',' OptTableElement
|
1998-04-08 08:39:01 +02:00
|
|
|
{
|
|
|
|
if ($3 != NULL)
|
|
|
|
$$ = lappend($1, $3);
|
|
|
|
else
|
|
|
|
$$ = $1;
|
|
|
|
}
|
|
|
|
| OptTableElement
|
|
|
|
{
|
|
|
|
if ($1 != NULL)
|
|
|
|
$$ = lcons($1, NIL);
|
|
|
|
else
|
|
|
|
$$ = NULL;
|
|
|
|
}
|
1997-12-05 00:07:23 +01:00
|
|
|
| /*EMPTY*/ { $$ = NULL; }
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-12-05 00:07:23 +01:00
|
|
|
OptTableElement: columnDef { $$ = $1; }
|
|
|
|
| TableConstraint { $$ = $1; }
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1999-12-10 08:37:35 +01:00
|
|
|
columnDef: ColId Typename ColConstraintList
|
1997-12-05 00:07:23 +01:00
|
|
|
{
|
|
|
|
ColumnDef *n = makeNode(ColumnDef);
|
|
|
|
n->colname = $1;
|
|
|
|
n->typename = $2;
|
1999-10-04 01:55:40 +02:00
|
|
|
n->raw_default = NULL;
|
|
|
|
n->cooked_default = NULL;
|
1997-12-05 00:07:23 +01:00
|
|
|
n->is_not_null = FALSE;
|
|
|
|
n->constraints = $3;
|
1998-08-25 17:04:24 +02:00
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
1998-09-16 16:29:35 +02:00
|
|
|
| ColId SERIAL ColPrimaryKey
|
1998-08-25 17:04:24 +02:00
|
|
|
{
|
|
|
|
ColumnDef *n = makeNode(ColumnDef);
|
|
|
|
n->colname = $1;
|
|
|
|
n->typename = makeNode(TypeName);
|
|
|
|
n->typename->name = xlateSqlType("integer");
|
2000-01-20 03:24:50 +01:00
|
|
|
n->typename->typmod = -1;
|
1999-10-04 01:55:40 +02:00
|
|
|
n->raw_default = NULL;
|
|
|
|
n->cooked_default = NULL;
|
1998-08-25 17:04:24 +02:00
|
|
|
n->is_not_null = TRUE;
|
|
|
|
n->is_sequence = TRUE;
|
1998-09-16 16:29:35 +02:00
|
|
|
n->constraints = $3;
|
1998-08-25 17:04:24 +02:00
|
|
|
|
1997-12-05 00:07:23 +01:00
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
1999-12-10 08:37:35 +01:00
|
|
|
ColConstraintList: ColConstraintList ColConstraint
|
1998-05-10 01:22:15 +02:00
|
|
|
{
|
|
|
|
if ($2 != NULL)
|
|
|
|
$$ = lappend($1, $2);
|
|
|
|
else
|
|
|
|
$$ = $1;
|
|
|
|
}
|
1999-12-10 08:37:35 +01:00
|
|
|
| /*EMPTY*/
|
|
|
|
{ $$ = NIL; }
|
1997-12-16 16:50:54 +01:00
|
|
|
;
|
|
|
|
|
1998-09-16 16:29:35 +02:00
|
|
|
ColPrimaryKey: PRIMARY KEY
|
|
|
|
{
|
|
|
|
Constraint *n = makeNode(Constraint);
|
|
|
|
n->contype = CONSTR_PRIMARY;
|
|
|
|
n->name = NULL;
|
1999-10-04 01:55:40 +02:00
|
|
|
n->raw_expr = NULL;
|
|
|
|
n->cooked_expr = NULL;
|
1998-09-16 16:29:35 +02:00
|
|
|
n->keys = NULL;
|
|
|
|
$$ = lcons((Node *)n, NIL);
|
|
|
|
}
|
|
|
|
| /*EMPTY*/ { $$ = NULL; }
|
|
|
|
;
|
|
|
|
|
1997-12-05 00:07:23 +01:00
|
|
|
ColConstraint:
|
|
|
|
CONSTRAINT name ColConstraintElem
|
|
|
|
{
|
1999-12-06 19:02:47 +01:00
|
|
|
switch (nodeTag($3))
|
|
|
|
{
|
|
|
|
case T_Constraint:
|
|
|
|
{
|
|
|
|
Constraint *n = (Constraint *)$3;
|
|
|
|
if (n != NULL) n->name = $2;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case T_FkConstraint:
|
|
|
|
{
|
|
|
|
FkConstraint *n = (FkConstraint *)$3;
|
|
|
|
if (n != NULL) n->constr_name = $2;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
$$ = $3;
|
1997-12-05 00:07:23 +01:00
|
|
|
}
|
|
|
|
| ColConstraintElem
|
|
|
|
{ $$ = $1; }
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1999-11-20 22:39:36 +01:00
|
|
|
/*
|
|
|
|
* DEFAULT NULL is already the default for Postgres.
|
1999-10-04 01:55:40 +02:00
|
|
|
* But define it here and carry it forward into the system
|
1998-09-16 16:29:35 +02:00
|
|
|
* to make it explicit.
|
|
|
|
* - thomas 1998-09-13
|
1999-11-20 22:39:36 +01:00
|
|
|
*
|
1999-02-23 08:42:41 +01:00
|
|
|
* WITH NULL and NULL are not SQL92-standard syntax elements,
|
|
|
|
* so leave them out. Use DEFAULT NULL to explicitly indicate
|
|
|
|
* that a column may have that value. WITH NULL leads to
|
|
|
|
* shift/reduce conflicts with WITH TIME ZONE anyway.
|
|
|
|
* - thomas 1999-01-08
|
1999-11-20 22:39:36 +01:00
|
|
|
*
|
1999-10-04 01:55:40 +02:00
|
|
|
* DEFAULT expression must be b_expr not a_expr to prevent shift/reduce
|
|
|
|
* conflict on NOT (since NOT might start a subsequent NOT NULL constraint,
|
|
|
|
* or be part of a_expr NOT LIKE or similar constructs).
|
1998-09-13 06:19:33 +02:00
|
|
|
*/
|
1999-10-04 01:55:40 +02:00
|
|
|
ColConstraintElem: CHECK '(' a_expr ')'
|
1997-12-05 00:07:23 +01:00
|
|
|
{
|
|
|
|
Constraint *n = makeNode(Constraint);
|
|
|
|
n->contype = CONSTR_CHECK;
|
|
|
|
n->name = NULL;
|
1999-10-04 01:55:40 +02:00
|
|
|
n->raw_expr = $3;
|
|
|
|
n->cooked_expr = NULL;
|
1997-12-05 00:07:23 +01:00
|
|
|
n->keys = NULL;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
1998-09-16 16:29:35 +02:00
|
|
|
| DEFAULT NULL_P
|
|
|
|
{
|
|
|
|
Constraint *n = makeNode(Constraint);
|
|
|
|
n->contype = CONSTR_DEFAULT;
|
|
|
|
n->name = NULL;
|
1999-10-04 01:55:40 +02:00
|
|
|
n->raw_expr = NULL;
|
|
|
|
n->cooked_expr = NULL;
|
1998-09-16 16:29:35 +02:00
|
|
|
n->keys = NULL;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
1999-10-04 01:55:40 +02:00
|
|
|
| DEFAULT b_expr
|
1997-12-05 00:07:23 +01:00
|
|
|
{
|
|
|
|
Constraint *n = makeNode(Constraint);
|
|
|
|
n->contype = CONSTR_DEFAULT;
|
|
|
|
n->name = NULL;
|
1999-10-04 01:55:40 +02:00
|
|
|
n->raw_expr = $2;
|
|
|
|
n->cooked_expr = NULL;
|
1997-12-05 00:07:23 +01:00
|
|
|
n->keys = NULL;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
| NOT NULL_P
|
|
|
|
{
|
|
|
|
Constraint *n = makeNode(Constraint);
|
|
|
|
n->contype = CONSTR_NOTNULL;
|
|
|
|
n->name = NULL;
|
1999-10-04 01:55:40 +02:00
|
|
|
n->raw_expr = NULL;
|
|
|
|
n->cooked_expr = NULL;
|
1997-12-05 00:07:23 +01:00
|
|
|
n->keys = NULL;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
| UNIQUE
|
|
|
|
{
|
|
|
|
Constraint *n = makeNode(Constraint);
|
|
|
|
n->contype = CONSTR_UNIQUE;
|
|
|
|
n->name = NULL;
|
1999-10-04 01:55:40 +02:00
|
|
|
n->raw_expr = NULL;
|
|
|
|
n->cooked_expr = NULL;
|
1997-12-05 00:07:23 +01:00
|
|
|
n->keys = NULL;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
| PRIMARY KEY
|
|
|
|
{
|
|
|
|
Constraint *n = makeNode(Constraint);
|
|
|
|
n->contype = CONSTR_PRIMARY;
|
|
|
|
n->name = NULL;
|
1999-10-04 01:55:40 +02:00
|
|
|
n->raw_expr = NULL;
|
|
|
|
n->cooked_expr = NULL;
|
1997-12-05 00:07:23 +01:00
|
|
|
n->keys = NULL;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
1999-12-06 19:02:47 +01:00
|
|
|
| REFERENCES ColId opt_column_list key_match key_actions
|
1997-12-05 00:07:23 +01:00
|
|
|
{
|
1999-12-06 19:02:47 +01:00
|
|
|
/* XXX
|
|
|
|
* Need ConstraintAttributeSpec as $6 -- Jan
|
|
|
|
*/
|
|
|
|
FkConstraint *n = makeNode(FkConstraint);
|
|
|
|
n->constr_name = NULL;
|
|
|
|
n->pktable_name = $2;
|
|
|
|
n->fk_attrs = NIL;
|
|
|
|
n->pk_attrs = $3;
|
|
|
|
n->match_type = $4;
|
|
|
|
n->actions = $5;
|
|
|
|
n->deferrable = true;
|
|
|
|
n->initdeferred = false;
|
|
|
|
/*
|
|
|
|
n->deferrable = ($6 & 1) != 0;
|
|
|
|
n->initdeferred = ($6 & 2) != 0;
|
|
|
|
*/
|
|
|
|
$$ = (Node *)n;
|
1997-12-05 00:07:23 +01:00
|
|
|
}
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
1997-08-20 03:12:38 +02:00
|
|
|
|
1997-12-05 00:07:23 +01:00
|
|
|
/* ConstraintElem specifies constraint syntax which is not embedded into
|
|
|
|
* a column definition. ColConstraintElem specifies the embedded form.
|
|
|
|
* - thomas 1997-12-03
|
|
|
|
*/
|
|
|
|
TableConstraint: CONSTRAINT name ConstraintElem
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
1999-12-06 19:02:47 +01:00
|
|
|
switch (nodeTag($3))
|
|
|
|
{
|
|
|
|
case T_Constraint:
|
|
|
|
{
|
|
|
|
Constraint *n = (Constraint *)$3;
|
|
|
|
if (n != NULL) n->name = $2;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case T_FkConstraint:
|
|
|
|
{
|
|
|
|
FkConstraint *n = (FkConstraint *)$3;
|
|
|
|
if (n != NULL) n->constr_name = $2;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
$$ = $3;
|
1997-09-08 05:20:18 +02:00
|
|
|
}
|
1997-12-05 00:07:23 +01:00
|
|
|
| ConstraintElem
|
|
|
|
{ $$ = $1; }
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
|
|
|
|
1999-10-04 01:55:40 +02:00
|
|
|
ConstraintElem: CHECK '(' a_expr ')'
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
1997-12-05 00:07:23 +01:00
|
|
|
Constraint *n = makeNode(Constraint);
|
|
|
|
n->contype = CONSTR_CHECK;
|
|
|
|
n->name = NULL;
|
1999-10-04 01:55:40 +02:00
|
|
|
n->raw_expr = $3;
|
|
|
|
n->cooked_expr = NULL;
|
1997-12-05 00:07:23 +01:00
|
|
|
$$ = (Node *)n;
|
1997-09-08 05:20:18 +02:00
|
|
|
}
|
1997-10-25 07:56:41 +02:00
|
|
|
| UNIQUE '(' columnList ')'
|
1997-12-05 00:07:23 +01:00
|
|
|
{
|
|
|
|
Constraint *n = makeNode(Constraint);
|
|
|
|
n->contype = CONSTR_UNIQUE;
|
|
|
|
n->name = NULL;
|
1999-10-04 01:55:40 +02:00
|
|
|
n->raw_expr = NULL;
|
|
|
|
n->cooked_expr = NULL;
|
1997-12-05 00:07:23 +01:00
|
|
|
n->keys = $3;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
1997-10-25 07:56:41 +02:00
|
|
|
| PRIMARY KEY '(' columnList ')'
|
1997-12-05 00:07:23 +01:00
|
|
|
{
|
|
|
|
Constraint *n = makeNode(Constraint);
|
|
|
|
n->contype = CONSTR_PRIMARY;
|
|
|
|
n->name = NULL;
|
1999-10-04 01:55:40 +02:00
|
|
|
n->raw_expr = NULL;
|
|
|
|
n->cooked_expr = NULL;
|
1997-12-05 00:07:23 +01:00
|
|
|
n->keys = $4;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
1999-12-06 19:02:47 +01:00
|
|
|
| FOREIGN KEY '(' columnList ')' REFERENCES ColId opt_column_list key_match key_actions ConstraintAttributeSpec
|
|
|
|
{
|
|
|
|
FkConstraint *n = makeNode(FkConstraint);
|
|
|
|
n->constr_name = NULL;
|
|
|
|
n->pktable_name = $7;
|
|
|
|
n->fk_attrs = $4;
|
|
|
|
n->pk_attrs = $8;
|
|
|
|
n->match_type = $9;
|
|
|
|
n->actions = $10;
|
|
|
|
n->deferrable = ($11 & 1) != 0;
|
|
|
|
n->initdeferred = ($11 & 2) != 0;
|
|
|
|
$$ = (Node *)n;
|
1998-04-08 08:39:01 +02:00
|
|
|
}
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1999-12-06 19:02:47 +01:00
|
|
|
key_match: MATCH FULL
|
|
|
|
{
|
|
|
|
$$ = "FULL";
|
|
|
|
}
|
|
|
|
| MATCH PARTIAL
|
|
|
|
{
|
|
|
|
elog(ERROR, "FOREIGN KEY match type PARTIAL not implemented yet");
|
|
|
|
$$ = "PARTIAL";
|
|
|
|
}
|
|
|
|
| /*EMPTY*/
|
|
|
|
{
|
|
|
|
elog(ERROR, "FOREIGN KEY match type UNSPECIFIED not implemented yet");
|
|
|
|
$$ = "UNSPECIFIED";
|
|
|
|
}
|
1997-10-25 07:56:41 +02:00
|
|
|
;
|
|
|
|
|
1999-12-06 19:02:47 +01:00
|
|
|
key_actions: key_action key_action { $$ = $1 | $2; }
|
|
|
|
| key_action { $$ = $1; }
|
|
|
|
| /*EMPTY*/ { $$ = 0; }
|
1997-10-25 07:56:41 +02:00
|
|
|
;
|
|
|
|
|
1999-12-06 19:02:47 +01:00
|
|
|
key_action: ON DELETE key_reference { $$ = $3 << FKCONSTR_ON_DELETE_SHIFT; }
|
|
|
|
| ON UPDATE key_reference { $$ = $3 << FKCONSTR_ON_UPDATE_SHIFT; }
|
1997-10-25 07:56:41 +02:00
|
|
|
;
|
|
|
|
|
1999-12-06 19:02:47 +01:00
|
|
|
key_reference: NO ACTION { $$ = FKCONSTR_ON_KEY_NOACTION; }
|
|
|
|
| RESTRICT { $$ = FKCONSTR_ON_KEY_RESTRICT; }
|
|
|
|
| CASCADE { $$ = FKCONSTR_ON_KEY_CASCADE; }
|
|
|
|
| SET NULL_P { $$ = FKCONSTR_ON_KEY_SETNULL; }
|
|
|
|
| SET DEFAULT { $$ = FKCONSTR_ON_KEY_SETDEFAULT; }
|
1997-10-25 07:56:41 +02:00
|
|
|
;
|
|
|
|
|
1997-12-05 00:07:23 +01:00
|
|
|
OptInherit: INHERITS '(' relation_name_list ')' { $$ = $3; }
|
|
|
|
| /*EMPTY*/ { $$ = NIL; }
|
|
|
|
;
|
|
|
|
|
1999-11-15 03:00:15 +01:00
|
|
|
/*
|
|
|
|
* Note: CREATE TABLE ... AS SELECT ... is just another spelling for
|
|
|
|
* SELECT ... INTO.
|
|
|
|
*/
|
|
|
|
|
|
|
|
CreateAsStmt: CREATE OptTemp TABLE relation_name OptCreateAs AS SelectStmt
|
1997-12-23 20:47:32 +01:00
|
|
|
{
|
1999-02-02 04:45:56 +01:00
|
|
|
SelectStmt *n = (SelectStmt *)$7;
|
|
|
|
if ($5 != NIL)
|
|
|
|
mapTargetColumns($5, n->targetList);
|
1999-11-15 03:00:15 +01:00
|
|
|
if (n->into != NULL)
|
|
|
|
elog(ERROR,"CREATE TABLE/AS SELECT may not specify INTO");
|
1999-02-02 04:45:56 +01:00
|
|
|
n->istemp = $2;
|
|
|
|
n->into = $4;
|
1997-12-23 20:47:32 +01:00
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
|
|
|
OptCreateAs: '(' CreateAsList ')' { $$ = $2; }
|
|
|
|
| /*EMPTY*/ { $$ = NULL; }
|
|
|
|
;
|
|
|
|
|
|
|
|
CreateAsList: CreateAsList ',' CreateAsElement { $$ = lappend($1, $3); }
|
|
|
|
| CreateAsElement { $$ = lcons($1, NIL); }
|
|
|
|
;
|
|
|
|
|
|
|
|
CreateAsElement: ColId
|
|
|
|
{
|
|
|
|
ColumnDef *n = makeNode(ColumnDef);
|
|
|
|
n->colname = $1;
|
|
|
|
n->typename = NULL;
|
1999-10-04 01:55:40 +02:00
|
|
|
n->raw_default = NULL;
|
|
|
|
n->cooked_default = NULL;
|
1997-12-23 20:47:32 +01:00
|
|
|
n->is_not_null = FALSE;
|
|
|
|
n->constraints = NULL;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
1997-09-13 05:15:46 +02:00
|
|
|
|
1997-04-02 06:01:03 +02:00
|
|
|
/*****************************************************************************
|
|
|
|
*
|
1997-09-08 05:20:18 +02:00
|
|
|
* QUERY :
|
|
|
|
* CREATE SEQUENCE seqname
|
1997-04-02 06:01:03 +02:00
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
|
1998-03-18 17:50:25 +01:00
|
|
|
CreateSeqStmt: CREATE SEQUENCE relation_name OptSeqList
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
CreateSeqStmt *n = makeNode(CreateSeqStmt);
|
|
|
|
n->seqname = $3;
|
|
|
|
n->options = $4;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
;
|
1997-04-02 06:01:03 +02:00
|
|
|
|
1998-03-18 17:50:25 +01:00
|
|
|
OptSeqList: OptSeqList OptSeqElem
|
1997-09-08 05:20:18 +02:00
|
|
|
{ $$ = lappend($1, $2); }
|
1998-03-18 17:50:25 +01:00
|
|
|
| { $$ = NIL; }
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
|
|
|
|
1998-03-18 17:50:25 +01:00
|
|
|
OptSeqElem: CACHE IntegerOnly
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
$$ = makeNode(DefElem);
|
1998-03-18 17:50:25 +01:00
|
|
|
$$->defname = "cache";
|
1997-09-08 05:20:18 +02:00
|
|
|
$$->arg = (Node *)$2;
|
|
|
|
}
|
1998-03-18 17:50:25 +01:00
|
|
|
| CYCLE
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
$$ = makeNode(DefElem);
|
1998-03-18 17:50:25 +01:00
|
|
|
$$->defname = "cycle";
|
1997-09-08 05:20:18 +02:00
|
|
|
$$->arg = (Node *)NULL;
|
|
|
|
}
|
1998-03-18 17:50:25 +01:00
|
|
|
| INCREMENT IntegerOnly
|
|
|
|
{
|
|
|
|
$$ = makeNode(DefElem);
|
|
|
|
$$->defname = "increment";
|
|
|
|
$$->arg = (Node *)$2;
|
|
|
|
}
|
|
|
|
| MAXVALUE IntegerOnly
|
|
|
|
{
|
|
|
|
$$ = makeNode(DefElem);
|
|
|
|
$$->defname = "maxvalue";
|
|
|
|
$$->arg = (Node *)$2;
|
|
|
|
}
|
|
|
|
| MINVALUE IntegerOnly
|
|
|
|
{
|
|
|
|
$$ = makeNode(DefElem);
|
|
|
|
$$->defname = "minvalue";
|
|
|
|
$$->arg = (Node *)$2;
|
|
|
|
}
|
|
|
|
| START IntegerOnly
|
|
|
|
{
|
|
|
|
$$ = makeNode(DefElem);
|
|
|
|
$$->defname = "start";
|
|
|
|
$$->arg = (Node *)$2;
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
1998-07-08 16:04:11 +02:00
|
|
|
NumericOnly: FloatOnly { $$ = $1; }
|
|
|
|
| IntegerOnly { $$ = $1; }
|
|
|
|
|
|
|
|
FloatOnly: FCONST
|
|
|
|
{
|
|
|
|
$$ = makeFloat($1);
|
|
|
|
}
|
|
|
|
| '-' FCONST
|
|
|
|
{
|
|
|
|
$$ = makeFloat($2);
|
|
|
|
$$->val.dval = - $$->val.dval;
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
1998-03-18 17:50:25 +01:00
|
|
|
IntegerOnly: Iconst
|
|
|
|
{
|
|
|
|
$$ = makeInteger($1);
|
|
|
|
}
|
|
|
|
| '-' Iconst
|
|
|
|
{
|
|
|
|
$$ = makeInteger($2);
|
|
|
|
$$->val.ival = - $$->val.ival;
|
|
|
|
}
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
1997-04-02 06:01:03 +02:00
|
|
|
|
1997-10-28 16:11:45 +01:00
|
|
|
/*****************************************************************************
|
|
|
|
*
|
|
|
|
* QUERIES :
|
|
|
|
* CREATE PROCEDURAL LANGUAGE ...
|
|
|
|
* DROP PROCEDURAL LANGUAGE ...
|
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
|
1997-11-07 08:02:10 +01:00
|
|
|
CreatePLangStmt: CREATE PLangTrusted PROCEDURAL LANGUAGE Sconst
|
1997-10-28 16:11:45 +01:00
|
|
|
HANDLER def_name LANCOMPILER Sconst
|
|
|
|
{
|
|
|
|
CreatePLangStmt *n = makeNode(CreatePLangStmt);
|
|
|
|
n->plname = $5;
|
|
|
|
n->plhandler = $7;
|
|
|
|
n->plcompiler = $9;
|
|
|
|
n->pltrusted = $2;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
|
|
|
PLangTrusted: TRUSTED { $$ = TRUE; }
|
|
|
|
| { $$ = FALSE; }
|
|
|
|
|
1997-11-07 08:02:10 +01:00
|
|
|
DropPLangStmt: DROP PROCEDURAL LANGUAGE Sconst
|
1997-10-28 16:11:45 +01:00
|
|
|
{
|
|
|
|
DropPLangStmt *n = makeNode(DropPLangStmt);
|
|
|
|
n->plname = $4;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
;
|
1997-04-02 06:01:03 +02:00
|
|
|
|
1997-09-04 15:24:26 +02:00
|
|
|
/*****************************************************************************
|
|
|
|
*
|
1997-09-08 05:20:18 +02:00
|
|
|
* QUERIES :
|
|
|
|
* CREATE TRIGGER ...
|
|
|
|
* DROP TRIGGER ...
|
1997-09-04 15:24:26 +02:00
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
|
1997-11-07 08:02:10 +01:00
|
|
|
CreateTrigStmt: CREATE TRIGGER name TriggerActionTime TriggerEvents ON
|
1997-09-08 05:20:18 +02:00
|
|
|
relation_name TriggerForSpec EXECUTE PROCEDURE
|
|
|
|
name '(' TriggerFuncArgs ')'
|
|
|
|
{
|
|
|
|
CreateTrigStmt *n = makeNode(CreateTrigStmt);
|
|
|
|
n->trigname = $3;
|
|
|
|
n->relname = $7;
|
|
|
|
n->funcname = $11;
|
|
|
|
n->args = $13;
|
|
|
|
n->before = $4;
|
|
|
|
n->row = $8;
|
|
|
|
memcpy (n->actions, $5, 4);
|
1999-09-29 18:06:40 +02:00
|
|
|
n->lang = NULL; /* unused */
|
|
|
|
n->text = NULL; /* unused */
|
|
|
|
n->attr = NULL; /* unused */
|
|
|
|
n->when = NULL; /* unused */
|
|
|
|
|
|
|
|
n->isconstraint = false;
|
|
|
|
n->deferrable = false;
|
|
|
|
n->initdeferred = false;
|
|
|
|
n->constrrelname = NULL;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
| CREATE CONSTRAINT TRIGGER name AFTER TriggerOneEvent ON
|
|
|
|
relation_name OptConstrFromTable
|
1999-12-06 19:02:47 +01:00
|
|
|
ConstraintAttributeSpec
|
1999-09-29 18:06:40 +02:00
|
|
|
FOR EACH ROW EXECUTE PROCEDURE name '(' TriggerFuncArgs ')'
|
|
|
|
{
|
|
|
|
CreateTrigStmt *n = makeNode(CreateTrigStmt);
|
|
|
|
n->trigname = $4;
|
|
|
|
n->relname = $8;
|
1999-12-06 19:02:47 +01:00
|
|
|
n->funcname = $16;
|
|
|
|
n->args = $18;
|
1999-09-29 18:06:40 +02:00
|
|
|
n->before = false;
|
|
|
|
n->row = true;
|
|
|
|
n->actions[0] = $6;
|
|
|
|
n->actions[1] = '\0';
|
|
|
|
n->lang = NULL; /* unused */
|
|
|
|
n->text = NULL; /* unused */
|
|
|
|
n->attr = NULL; /* unused */
|
|
|
|
n->when = NULL; /* unused */
|
|
|
|
|
|
|
|
n->isconstraint = true;
|
1999-12-06 19:02:47 +01:00
|
|
|
n->deferrable = ($10 & 1) != 0;
|
|
|
|
n->initdeferred = ($10 & 2) != 0;
|
1999-09-29 18:06:40 +02:00
|
|
|
|
|
|
|
n->constrrelname = $9;
|
1997-09-08 05:20:18 +02:00
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
1998-02-11 05:09:54 +01:00
|
|
|
TriggerActionTime: BEFORE { $$ = TRUE; }
|
|
|
|
| AFTER { $$ = FALSE; }
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
|
|
|
|
|
|
|
TriggerEvents: TriggerOneEvent
|
1998-02-11 05:09:54 +01:00
|
|
|
{
|
|
|
|
char *e = palloc (4);
|
|
|
|
e[0] = $1; e[1] = 0; $$ = e;
|
|
|
|
}
|
|
|
|
| TriggerOneEvent OR TriggerOneEvent
|
|
|
|
{
|
|
|
|
char *e = palloc (4);
|
|
|
|
e[0] = $1; e[1] = $3; e[2] = 0; $$ = e;
|
|
|
|
}
|
|
|
|
| TriggerOneEvent OR TriggerOneEvent OR TriggerOneEvent
|
|
|
|
{
|
|
|
|
char *e = palloc (4);
|
|
|
|
e[0] = $1; e[1] = $3; e[2] = $5; e[3] = 0;
|
|
|
|
$$ = e;
|
|
|
|
}
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
|
|
|
|
1998-02-11 05:09:54 +01:00
|
|
|
TriggerOneEvent: INSERT { $$ = 'i'; }
|
|
|
|
| DELETE { $$ = 'd'; }
|
|
|
|
| UPDATE { $$ = 'u'; }
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
|
|
|
|
1998-02-11 05:09:54 +01:00
|
|
|
TriggerForSpec: FOR TriggerForOpt TriggerForType
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
1998-02-11 05:09:54 +01:00
|
|
|
$$ = $3;
|
1997-09-08 05:20:18 +02:00
|
|
|
}
|
|
|
|
;
|
1997-09-04 15:24:26 +02:00
|
|
|
|
1998-02-11 05:09:54 +01:00
|
|
|
TriggerForOpt: EACH { $$ = TRUE; }
|
|
|
|
| /*EMPTY*/ { $$ = FALSE; }
|
|
|
|
;
|
|
|
|
|
|
|
|
TriggerForType: ROW { $$ = TRUE; }
|
|
|
|
| STATEMENT { $$ = FALSE; }
|
|
|
|
;
|
|
|
|
|
1997-11-07 08:02:10 +01:00
|
|
|
TriggerFuncArgs: TriggerFuncArg
|
1997-09-08 05:20:18 +02:00
|
|
|
{ $$ = lcons($1, NIL); }
|
1998-02-11 05:09:54 +01:00
|
|
|
| TriggerFuncArgs ',' TriggerFuncArg
|
1997-09-08 05:20:18 +02:00
|
|
|
{ $$ = lappend($1, $3); }
|
1998-02-11 05:09:54 +01:00
|
|
|
| /*EMPTY*/
|
1997-11-07 08:02:10 +01:00
|
|
|
{ $$ = NIL; }
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
|
|
|
|
1997-11-07 08:02:10 +01:00
|
|
|
TriggerFuncArg: ICONST
|
1998-02-11 05:09:54 +01:00
|
|
|
{
|
|
|
|
char *s = (char *) palloc (256);
|
|
|
|
sprintf (s, "%d", $1);
|
|
|
|
$$ = s;
|
|
|
|
}
|
|
|
|
| FCONST
|
|
|
|
{
|
|
|
|
char *s = (char *) palloc (256);
|
|
|
|
sprintf (s, "%g", $1);
|
|
|
|
$$ = s;
|
|
|
|
}
|
|
|
|
| Sconst { $$ = $1; }
|
|
|
|
| IDENT { $$ = $1; }
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
1997-09-04 15:24:26 +02:00
|
|
|
|
1999-09-29 18:06:40 +02:00
|
|
|
OptConstrFromTable: /* Empty */
|
|
|
|
{
|
|
|
|
$$ = "";
|
|
|
|
}
|
|
|
|
| FROM relation_name
|
|
|
|
{
|
|
|
|
$$ = $2;
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
1999-12-06 19:02:47 +01:00
|
|
|
ConstraintAttributeSpec: /* Empty */
|
|
|
|
{ $$ = 0; }
|
|
|
|
| ConstraintDeferrabilitySpec
|
|
|
|
{ $$ = $1; }
|
|
|
|
| ConstraintDeferrabilitySpec ConstraintTimeSpec
|
|
|
|
{
|
|
|
|
if ($1 == 0 && $2 != 0)
|
|
|
|
elog(ERROR, "INITIALLY DEFERRED constraint must be DEFERRABLE");
|
|
|
|
$$ = $1 | $2;
|
|
|
|
}
|
|
|
|
| ConstraintTimeSpec
|
|
|
|
{
|
|
|
|
if ($1 != 0)
|
|
|
|
$$ = 3;
|
|
|
|
else
|
1999-09-29 18:06:40 +02:00
|
|
|
$$ = 0;
|
1999-12-06 19:02:47 +01:00
|
|
|
}
|
|
|
|
| ConstraintTimeSpec ConstraintDeferrabilitySpec
|
|
|
|
{
|
|
|
|
if ($2 == 0 && $1 != 0)
|
|
|
|
elog(ERROR, "INITIALLY DEFERRED constraint must be DEFERRABLE");
|
|
|
|
$$ = $1 | $2;
|
|
|
|
}
|
1999-09-29 18:06:40 +02:00
|
|
|
;
|
|
|
|
|
1999-12-06 19:02:47 +01:00
|
|
|
ConstraintDeferrabilitySpec: NOT DEFERRABLE
|
|
|
|
{ $$ = 0; }
|
|
|
|
| DEFERRABLE
|
|
|
|
{ $$ = 1; }
|
|
|
|
;
|
|
|
|
|
|
|
|
ConstraintTimeSpec: INITIALLY IMMEDIATE
|
|
|
|
{ $$ = 0; }
|
1999-09-29 18:06:40 +02:00
|
|
|
| INITIALLY DEFERRED
|
1999-12-06 19:02:47 +01:00
|
|
|
{ $$ = 2; }
|
1999-09-29 18:06:40 +02:00
|
|
|
;
|
1999-12-10 04:01:05 +01:00
|
|
|
|
1999-09-29 18:06:40 +02:00
|
|
|
|
1998-02-11 05:09:54 +01:00
|
|
|
DropTrigStmt: DROP TRIGGER name ON relation_name
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
DropTrigStmt *n = makeNode(DropTrigStmt);
|
|
|
|
n->trigname = $3;
|
|
|
|
n->relname = $5;
|
|
|
|
$$ = (Node *) n;
|
|
|
|
}
|
|
|
|
;
|
1997-09-04 15:24:26 +02:00
|
|
|
|
1997-10-25 07:56:41 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*****************************************************************************
|
|
|
|
*
|
1997-09-08 05:20:18 +02:00
|
|
|
* QUERY :
|
|
|
|
* define (type,operator,aggregate)
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
DefineStmt: CREATE def_type def_rest
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
$3->defType = $2;
|
|
|
|
$$ = (Node *)$3;
|
|
|
|
}
|
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-01 08:00:35 +02:00
|
|
|
def_rest: def_name definition
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
$$ = makeNode(DefineStmt);
|
|
|
|
$$->defname = $1;
|
|
|
|
$$->definition = $2;
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
1997-09-13 05:15:46 +02:00
|
|
|
def_type: OPERATOR { $$ = OPERATOR; }
|
1997-12-05 00:07:23 +01:00
|
|
|
| TYPE_P { $$ = TYPE_P; }
|
1997-11-07 08:02:10 +01:00
|
|
|
| AGGREGATE { $$ = AGGREGATE; }
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-13 05:15:46 +02:00
|
|
|
def_name: PROCEDURE { $$ = "procedure"; }
|
1997-11-07 08:02:10 +01:00
|
|
|
| JOIN { $$ = "join"; }
|
|
|
|
| ColId { $$ = $1; }
|
1999-11-20 22:39:36 +01:00
|
|
|
| all_Op { $$ = $1; }
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-13 05:15:46 +02:00
|
|
|
definition: '(' def_list ')' { $$ = $2; }
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-13 05:15:46 +02:00
|
|
|
def_list: def_elem { $$ = lcons($1, NIL); }
|
1997-11-07 08:02:10 +01:00
|
|
|
| def_list ',' def_elem { $$ = lappend($1, $3); }
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
def_elem: def_name '=' def_arg
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
$$ = makeNode(DefElem);
|
|
|
|
$$->defname = $1;
|
|
|
|
$$->arg = (Node *)$3;
|
|
|
|
}
|
1997-11-07 08:02:10 +01:00
|
|
|
| def_name
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
$$ = makeNode(DefElem);
|
|
|
|
$$->defname = $1;
|
|
|
|
$$->arg = (Node *)NULL;
|
|
|
|
}
|
1997-11-07 08:02:10 +01:00
|
|
|
| DEFAULT '=' def_arg
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
$$ = makeNode(DefElem);
|
1997-09-13 05:15:46 +02:00
|
|
|
$$->defname = "default";
|
1997-09-08 05:20:18 +02:00
|
|
|
$$->arg = (Node *)$3;
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
1997-10-25 07:56:41 +02:00
|
|
|
def_arg: ColId { $$ = (Node *)makeString($1); }
|
|
|
|
| all_Op { $$ = (Node *)makeString($1); }
|
1998-07-08 16:04:11 +02:00
|
|
|
| NumericOnly { $$ = (Node *)$1; }
|
1997-10-25 07:56:41 +02:00
|
|
|
| Sconst { $$ = (Node *)makeString($1); }
|
|
|
|
| SETOF ColId
|
1997-09-13 05:15:46 +02:00
|
|
|
{
|
|
|
|
TypeName *n = makeNode(TypeName);
|
|
|
|
n->name = $2;
|
|
|
|
n->setof = TRUE;
|
|
|
|
n->arrayBounds = NULL;
|
1998-02-10 05:02:59 +01:00
|
|
|
n->typmod = -1;
|
1997-09-13 05:15:46 +02:00
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
*
|
1997-09-08 05:20:18 +02:00
|
|
|
* QUERY:
|
1999-12-10 04:56:14 +01:00
|
|
|
* drop <relname1> [, <relname2> .. <relnameN> ]
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
|
1999-12-10 04:56:14 +01:00
|
|
|
DropStmt: DROP TABLE relation_name_list
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
1999-12-10 04:56:14 +01:00
|
|
|
DropStmt *n = makeNode(DropStmt);
|
1997-09-08 05:20:18 +02:00
|
|
|
n->relNames = $3;
|
1997-09-13 05:15:46 +02:00
|
|
|
n->sequence = FALSE;
|
1997-09-08 05:20:18 +02:00
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
1997-10-25 07:56:41 +02:00
|
|
|
| DROP SEQUENCE relation_name_list
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
1999-12-10 04:56:14 +01:00
|
|
|
DropStmt *n = makeNode(DropStmt);
|
1997-09-08 05:20:18 +02:00
|
|
|
n->relNames = $3;
|
1997-09-13 05:15:46 +02:00
|
|
|
n->sequence = TRUE;
|
1997-09-08 05:20:18 +02:00
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1999-09-23 19:03:39 +02:00
|
|
|
/*****************************************************************************
|
|
|
|
*
|
|
|
|
* QUERY:
|
|
|
|
* truncate table relname
|
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
TruncateStmt: TRUNCATE TABLE relation_name
|
|
|
|
{
|
|
|
|
TruncateStmt *n = makeNode(TruncateStmt);
|
|
|
|
n->relName = $3;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
This patch implements ORACLE's COMMENT SQL command.
>From the ORACLE 7 SQL Language Reference Manual:
-----------------------------------------------------
COMMENT
Purpose:
To add a comment about a table, view, snapshot, or
column into the data dictionary.
Prerequisites:
The table, view, or snapshot must be in your own
schema
or you must have COMMENT ANY TABLE system privilege.
Syntax:
COMMENT ON [ TABLE table ] |
[ COLUMN table.column] IS 'text'
You can effectively drop a comment from the database
by setting it to the empty string ''.
-----------------------------------------------------
Example:
COMMENT ON TABLE workorders IS
'Maintains base records for workorder information';
COMMENT ON COLUMN workorders.hours IS
'Number of hours the engineer worked on the task';
to drop a comment:
COMMENT ON COLUMN workorders.hours IS '';
The current patch will simply perform the insert into
pg_description, as per the TODO. And, of course, when
the table is dropped, any comments relating to it
or any of its attributes are also dropped. I haven't
looked at the ODBC source yet, but I do know from
an ODBC client standpoint that the standard does
support the notion of table and column comments.
Hopefully the ODBC driver is already fetching these
values from pg_description, but if not, it should be
trivial.
Hope this makes the grade,
Mike Mascari
(mascarim@yahoo.com)
1999-10-15 03:49:49 +02:00
|
|
|
/*****************************************************************************
|
|
|
|
*
|
1999-10-26 05:12:39 +02:00
|
|
|
* The COMMENT ON statement can take different forms based upon the type of
|
|
|
|
* the object associated with the comment. The form of the statement is:
|
|
|
|
*
|
|
|
|
* COMMENT ON [ [ DATABASE | INDEX | RULE | SEQUENCE | TABLE | TYPE | VIEW ]
|
|
|
|
* <objname> | AGGREGATE <aggname> <aggtype> | FUNCTION
|
|
|
|
* <funcname> (arg1, arg2, ...) | OPERATOR <op>
|
|
|
|
* (leftoperand_typ rightoperand_typ) | TRIGGER <triggername> ON
|
|
|
|
* <relname> ] IS 'text'
|
This patch implements ORACLE's COMMENT SQL command.
>From the ORACLE 7 SQL Language Reference Manual:
-----------------------------------------------------
COMMENT
Purpose:
To add a comment about a table, view, snapshot, or
column into the data dictionary.
Prerequisites:
The table, view, or snapshot must be in your own
schema
or you must have COMMENT ANY TABLE system privilege.
Syntax:
COMMENT ON [ TABLE table ] |
[ COLUMN table.column] IS 'text'
You can effectively drop a comment from the database
by setting it to the empty string ''.
-----------------------------------------------------
Example:
COMMENT ON TABLE workorders IS
'Maintains base records for workorder information';
COMMENT ON COLUMN workorders.hours IS
'Number of hours the engineer worked on the task';
to drop a comment:
COMMENT ON COLUMN workorders.hours IS '';
The current patch will simply perform the insert into
pg_description, as per the TODO. And, of course, when
the table is dropped, any comments relating to it
or any of its attributes are also dropped. I haven't
looked at the ODBC source yet, but I do know from
an ODBC client standpoint that the standard does
support the notion of table and column comments.
Hopefully the ODBC driver is already fetching these
values from pg_description, but if not, it should be
trivial.
Hope this makes the grade,
Mike Mascari
(mascarim@yahoo.com)
1999-10-15 03:49:49 +02:00
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
|
1999-10-26 18:32:46 +02:00
|
|
|
CommentStmt: COMMENT ON comment_type name IS comment_text
|
1999-10-26 05:12:39 +02:00
|
|
|
{
|
|
|
|
CommentStmt *n = makeNode(CommentStmt);
|
|
|
|
n->objtype = $3;
|
|
|
|
n->objname = $4;
|
|
|
|
n->objproperty = NULL;
|
|
|
|
n->objlist = NULL;
|
|
|
|
n->comment = $6;
|
|
|
|
$$ = (Node *) n;
|
|
|
|
}
|
1999-10-26 18:32:46 +02:00
|
|
|
| COMMENT ON comment_cl relation_name '.' attr_name IS comment_text
|
This patch implements ORACLE's COMMENT SQL command.
>From the ORACLE 7 SQL Language Reference Manual:
-----------------------------------------------------
COMMENT
Purpose:
To add a comment about a table, view, snapshot, or
column into the data dictionary.
Prerequisites:
The table, view, or snapshot must be in your own
schema
or you must have COMMENT ANY TABLE system privilege.
Syntax:
COMMENT ON [ TABLE table ] |
[ COLUMN table.column] IS 'text'
You can effectively drop a comment from the database
by setting it to the empty string ''.
-----------------------------------------------------
Example:
COMMENT ON TABLE workorders IS
'Maintains base records for workorder information';
COMMENT ON COLUMN workorders.hours IS
'Number of hours the engineer worked on the task';
to drop a comment:
COMMENT ON COLUMN workorders.hours IS '';
The current patch will simply perform the insert into
pg_description, as per the TODO. And, of course, when
the table is dropped, any comments relating to it
or any of its attributes are also dropped. I haven't
looked at the ODBC source yet, but I do know from
an ODBC client standpoint that the standard does
support the notion of table and column comments.
Hopefully the ODBC driver is already fetching these
values from pg_description, but if not, it should be
trivial.
Hope this makes the grade,
Mike Mascari
(mascarim@yahoo.com)
1999-10-15 03:49:49 +02:00
|
|
|
{
|
|
|
|
CommentStmt *n = makeNode(CommentStmt);
|
1999-10-26 05:12:39 +02:00
|
|
|
n->objtype = $3;
|
|
|
|
n->objname = $4;
|
|
|
|
n->objproperty = $6;
|
|
|
|
n->objlist = NULL;
|
This patch implements ORACLE's COMMENT SQL command.
>From the ORACLE 7 SQL Language Reference Manual:
-----------------------------------------------------
COMMENT
Purpose:
To add a comment about a table, view, snapshot, or
column into the data dictionary.
Prerequisites:
The table, view, or snapshot must be in your own
schema
or you must have COMMENT ANY TABLE system privilege.
Syntax:
COMMENT ON [ TABLE table ] |
[ COLUMN table.column] IS 'text'
You can effectively drop a comment from the database
by setting it to the empty string ''.
-----------------------------------------------------
Example:
COMMENT ON TABLE workorders IS
'Maintains base records for workorder information';
COMMENT ON COLUMN workorders.hours IS
'Number of hours the engineer worked on the task';
to drop a comment:
COMMENT ON COLUMN workorders.hours IS '';
The current patch will simply perform the insert into
pg_description, as per the TODO. And, of course, when
the table is dropped, any comments relating to it
or any of its attributes are also dropped. I haven't
looked at the ODBC source yet, but I do know from
an ODBC client standpoint that the standard does
support the notion of table and column comments.
Hopefully the ODBC driver is already fetching these
values from pg_description, but if not, it should be
trivial.
Hope this makes the grade,
Mike Mascari
(mascarim@yahoo.com)
1999-10-15 03:49:49 +02:00
|
|
|
n->comment = $8;
|
|
|
|
$$ = (Node *) n;
|
|
|
|
}
|
1999-10-26 18:32:46 +02:00
|
|
|
| COMMENT ON comment_ag name aggr_argtype IS comment_text
|
1999-10-26 05:12:39 +02:00
|
|
|
{
|
This patch implements ORACLE's COMMENT SQL command.
>From the ORACLE 7 SQL Language Reference Manual:
-----------------------------------------------------
COMMENT
Purpose:
To add a comment about a table, view, snapshot, or
column into the data dictionary.
Prerequisites:
The table, view, or snapshot must be in your own
schema
or you must have COMMENT ANY TABLE system privilege.
Syntax:
COMMENT ON [ TABLE table ] |
[ COLUMN table.column] IS 'text'
You can effectively drop a comment from the database
by setting it to the empty string ''.
-----------------------------------------------------
Example:
COMMENT ON TABLE workorders IS
'Maintains base records for workorder information';
COMMENT ON COLUMN workorders.hours IS
'Number of hours the engineer worked on the task';
to drop a comment:
COMMENT ON COLUMN workorders.hours IS '';
The current patch will simply perform the insert into
pg_description, as per the TODO. And, of course, when
the table is dropped, any comments relating to it
or any of its attributes are also dropped. I haven't
looked at the ODBC source yet, but I do know from
an ODBC client standpoint that the standard does
support the notion of table and column comments.
Hopefully the ODBC driver is already fetching these
values from pg_description, but if not, it should be
trivial.
Hope this makes the grade,
Mike Mascari
(mascarim@yahoo.com)
1999-10-15 03:49:49 +02:00
|
|
|
CommentStmt *n = makeNode(CommentStmt);
|
1999-10-26 05:12:39 +02:00
|
|
|
n->objtype = $3;
|
|
|
|
n->objname = $4;
|
|
|
|
n->objproperty = $5;
|
|
|
|
n->objlist = NULL;
|
|
|
|
n->comment = $7;
|
|
|
|
$$ = (Node *) n;
|
|
|
|
}
|
1999-10-26 18:32:46 +02:00
|
|
|
| COMMENT ON comment_fn func_name func_args IS comment_text
|
1999-10-26 05:12:39 +02:00
|
|
|
{
|
|
|
|
CommentStmt *n = makeNode(CommentStmt);
|
|
|
|
n->objtype = $3;
|
|
|
|
n->objname = $4;
|
|
|
|
n->objproperty = NULL;
|
|
|
|
n->objlist = $5;
|
|
|
|
n->comment = $7;
|
|
|
|
$$ = (Node *) n;
|
|
|
|
}
|
1999-10-26 18:32:46 +02:00
|
|
|
| COMMENT ON comment_op all_Op '(' oper_argtypes ')' IS comment_text
|
1999-10-26 05:12:39 +02:00
|
|
|
{
|
|
|
|
CommentStmt *n = makeNode(CommentStmt);
|
|
|
|
n->objtype = $3;
|
|
|
|
n->objname = $4;
|
|
|
|
n->objproperty = NULL;
|
|
|
|
n->objlist = $6;
|
|
|
|
n->comment = $9;
|
This patch implements ORACLE's COMMENT SQL command.
>From the ORACLE 7 SQL Language Reference Manual:
-----------------------------------------------------
COMMENT
Purpose:
To add a comment about a table, view, snapshot, or
column into the data dictionary.
Prerequisites:
The table, view, or snapshot must be in your own
schema
or you must have COMMENT ANY TABLE system privilege.
Syntax:
COMMENT ON [ TABLE table ] |
[ COLUMN table.column] IS 'text'
You can effectively drop a comment from the database
by setting it to the empty string ''.
-----------------------------------------------------
Example:
COMMENT ON TABLE workorders IS
'Maintains base records for workorder information';
COMMENT ON COLUMN workorders.hours IS
'Number of hours the engineer worked on the task';
to drop a comment:
COMMENT ON COLUMN workorders.hours IS '';
The current patch will simply perform the insert into
pg_description, as per the TODO. And, of course, when
the table is dropped, any comments relating to it
or any of its attributes are also dropped. I haven't
looked at the ODBC source yet, but I do know from
an ODBC client standpoint that the standard does
support the notion of table and column comments.
Hopefully the ODBC driver is already fetching these
values from pg_description, but if not, it should be
trivial.
Hope this makes the grade,
Mike Mascari
(mascarim@yahoo.com)
1999-10-15 03:49:49 +02:00
|
|
|
$$ = (Node *) n;
|
|
|
|
}
|
1999-10-26 18:32:46 +02:00
|
|
|
| COMMENT ON comment_tg name ON relation_name IS comment_text
|
1999-10-26 05:12:39 +02:00
|
|
|
{
|
|
|
|
CommentStmt *n = makeNode(CommentStmt);
|
|
|
|
n->objtype = $3;
|
|
|
|
n->objname = $4;
|
|
|
|
n->objproperty = $6;
|
|
|
|
n->objlist = NULL;
|
|
|
|
n->comment = $8;
|
|
|
|
$$ = (Node *) n;
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
|
|
|
comment_type: DATABASE { $$ = DATABASE; }
|
|
|
|
| INDEX { $$ = INDEX; }
|
|
|
|
| RULE { $$ = RULE; }
|
|
|
|
| SEQUENCE { $$ = SEQUENCE; }
|
|
|
|
| TABLE { $$ = TABLE; }
|
|
|
|
| TYPE_P { $$ = TYPE_P; }
|
|
|
|
| VIEW { $$ = VIEW; }
|
|
|
|
;
|
|
|
|
|
|
|
|
comment_cl: COLUMN { $$ = COLUMN; }
|
|
|
|
;
|
|
|
|
|
|
|
|
comment_ag: AGGREGATE { $$ = AGGREGATE; }
|
|
|
|
;
|
|
|
|
|
|
|
|
comment_fn: FUNCTION { $$ = FUNCTION; }
|
|
|
|
;
|
|
|
|
|
|
|
|
comment_op: OPERATOR { $$ = OPERATOR; }
|
|
|
|
;
|
|
|
|
|
|
|
|
comment_tg: TRIGGER { $$ = TRIGGER; }
|
1999-10-26 18:32:46 +02:00
|
|
|
;
|
This patch implements ORACLE's COMMENT SQL command.
>From the ORACLE 7 SQL Language Reference Manual:
-----------------------------------------------------
COMMENT
Purpose:
To add a comment about a table, view, snapshot, or
column into the data dictionary.
Prerequisites:
The table, view, or snapshot must be in your own
schema
or you must have COMMENT ANY TABLE system privilege.
Syntax:
COMMENT ON [ TABLE table ] |
[ COLUMN table.column] IS 'text'
You can effectively drop a comment from the database
by setting it to the empty string ''.
-----------------------------------------------------
Example:
COMMENT ON TABLE workorders IS
'Maintains base records for workorder information';
COMMENT ON COLUMN workorders.hours IS
'Number of hours the engineer worked on the task';
to drop a comment:
COMMENT ON COLUMN workorders.hours IS '';
The current patch will simply perform the insert into
pg_description, as per the TODO. And, of course, when
the table is dropped, any comments relating to it
or any of its attributes are also dropped. I haven't
looked at the ODBC source yet, but I do know from
an ODBC client standpoint that the standard does
support the notion of table and column comments.
Hopefully the ODBC driver is already fetching these
values from pg_description, but if not, it should be
trivial.
Hope this makes the grade,
Mike Mascari
(mascarim@yahoo.com)
1999-10-15 03:49:49 +02:00
|
|
|
|
1999-10-26 18:32:46 +02:00
|
|
|
comment_text: Sconst { $$ = $1; }
|
1999-12-10 04:01:05 +01:00
|
|
|
| NULL_P { $$ = NULL; }
|
1999-10-26 18:32:46 +02:00
|
|
|
;
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*****************************************************************************
|
|
|
|
*
|
1997-09-08 05:20:18 +02:00
|
|
|
* QUERY:
|
1998-09-13 06:19:33 +02:00
|
|
|
* fetch/move [forward | backward] [ # | all ] [ in <portalname> ]
|
|
|
|
* fetch [ forward | backward | absolute | relative ]
|
|
|
|
* [ # | all | next | prior ] [ [ in | from ] <portalname> ]
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
|
2000-01-18 20:08:13 +01:00
|
|
|
FetchStmt: FETCH direction fetch_how_many from_in name
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
FetchStmt *n = makeNode(FetchStmt);
|
1998-09-13 06:19:33 +02:00
|
|
|
if ($2 == RELATIVE)
|
|
|
|
{
|
|
|
|
if ($3 == 0)
|
|
|
|
elog(ERROR,"FETCH/RELATIVE at current position is not supported");
|
|
|
|
$2 = FORWARD;
|
|
|
|
}
|
|
|
|
if ($3 < 0)
|
|
|
|
{
|
|
|
|
$3 = -$3;
|
|
|
|
$2 = (($2 == FORWARD)? BACKWARD: FORWARD);
|
|
|
|
}
|
1997-09-08 05:20:18 +02:00
|
|
|
n->direction = $2;
|
|
|
|
n->howMany = $3;
|
2000-01-18 20:08:13 +01:00
|
|
|
n->portalname = $5;
|
|
|
|
n->ismove = false;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
| FETCH fetch_how_many from_in name
|
|
|
|
{
|
|
|
|
FetchStmt *n = makeNode(FetchStmt);
|
|
|
|
if ($2 < 0)
|
|
|
|
{
|
|
|
|
n->howMany = -$2;
|
|
|
|
n->direction = BACKWARD;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
n->direction = FORWARD;
|
|
|
|
n->howMany = $2;
|
|
|
|
}
|
1997-09-08 05:20:18 +02:00
|
|
|
n->portalname = $4;
|
1997-09-29 07:59:16 +02:00
|
|
|
n->ismove = false;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
2000-01-18 20:08:13 +01:00
|
|
|
| FETCH direction from_in name
|
|
|
|
{
|
|
|
|
FetchStmt *n = makeNode(FetchStmt);
|
|
|
|
if ($2 == RELATIVE)
|
|
|
|
{
|
|
|
|
$2 = FORWARD;
|
|
|
|
}
|
|
|
|
n->direction = $2;
|
|
|
|
n->howMany = 1;
|
|
|
|
n->portalname = $4;
|
|
|
|
n->ismove = false;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
| FETCH from_in name
|
|
|
|
{
|
|
|
|
FetchStmt *n = makeNode(FetchStmt);
|
|
|
|
n->direction = FORWARD;
|
|
|
|
n->howMany = 1;
|
|
|
|
n->portalname = $3;
|
|
|
|
n->ismove = false;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
| FETCH name
|
|
|
|
{
|
|
|
|
FetchStmt *n = makeNode(FetchStmt);
|
|
|
|
n->direction = FORWARD;
|
|
|
|
n->howMany = 1;
|
|
|
|
n->portalname = $2;
|
|
|
|
n->ismove = false;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
|
|
|
|
| MOVE direction fetch_how_many from_in name
|
1997-09-29 07:59:16 +02:00
|
|
|
{
|
|
|
|
FetchStmt *n = makeNode(FetchStmt);
|
1998-09-13 06:19:33 +02:00
|
|
|
if ($3 < 0)
|
|
|
|
{
|
|
|
|
$3 = -$3;
|
|
|
|
$2 = (($2 == FORWARD)? BACKWARD: FORWARD);
|
|
|
|
}
|
1997-09-29 07:59:16 +02:00
|
|
|
n->direction = $2;
|
|
|
|
n->howMany = $3;
|
2000-01-18 20:08:13 +01:00
|
|
|
n->portalname = $5;
|
|
|
|
n->ismove = TRUE;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
| MOVE fetch_how_many from_in name
|
|
|
|
{
|
|
|
|
FetchStmt *n = makeNode(FetchStmt);
|
|
|
|
if ($2 < 0)
|
|
|
|
{
|
|
|
|
n->howMany = -$2;
|
|
|
|
n->direction = BACKWARD;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
n->direction = FORWARD;
|
|
|
|
n->howMany = $2;
|
|
|
|
}
|
1997-09-29 07:59:16 +02:00
|
|
|
n->portalname = $4;
|
1997-11-17 17:37:24 +01:00
|
|
|
n->ismove = TRUE;
|
1997-09-08 05:20:18 +02:00
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
2000-01-18 20:08:13 +01:00
|
|
|
| MOVE direction from_in name
|
|
|
|
{
|
|
|
|
FetchStmt *n = makeNode(FetchStmt);
|
|
|
|
n->direction = $2;
|
|
|
|
n->howMany = 1;
|
|
|
|
n->portalname = $4;
|
|
|
|
n->ismove = TRUE;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
| MOVE from_in name
|
|
|
|
{
|
|
|
|
FetchStmt *n = makeNode(FetchStmt);
|
|
|
|
n->direction = FORWARD;
|
|
|
|
n->howMany = 1;
|
|
|
|
n->portalname = $3;
|
|
|
|
n->ismove = TRUE;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
| MOVE name
|
|
|
|
{
|
|
|
|
FetchStmt *n = makeNode(FetchStmt);
|
|
|
|
n->direction = FORWARD;
|
|
|
|
n->howMany = 1;
|
|
|
|
n->portalname = $2;
|
|
|
|
n->ismove = TRUE;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
|
|
|
|
2000-01-18 20:08:13 +01:00
|
|
|
direction: FORWARD { $$ = FORWARD; }
|
1998-09-13 06:19:33 +02:00
|
|
|
| BACKWARD { $$ = BACKWARD; }
|
|
|
|
| RELATIVE { $$ = RELATIVE; }
|
|
|
|
| ABSOLUTE
|
|
|
|
{
|
|
|
|
elog(NOTICE,"FETCH/ABSOLUTE not supported, using RELATIVE");
|
|
|
|
$$ = RELATIVE;
|
|
|
|
}
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1998-09-13 06:19:33 +02:00
|
|
|
fetch_how_many: Iconst { $$ = $1; }
|
|
|
|
| '-' Iconst { $$ = - $2; }
|
1997-12-16 16:50:54 +01:00
|
|
|
| ALL { $$ = 0; /* 0 means fetch all tuples*/ }
|
1998-09-13 06:19:33 +02:00
|
|
|
| NEXT { $$ = 1; }
|
|
|
|
| PRIOR { $$ = -1; }
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2000-01-18 20:08:13 +01:00
|
|
|
from_in: IN
|
|
|
|
| FROM
|
|
|
|
;
|
1997-09-29 07:59:16 +02:00
|
|
|
|
1997-10-25 07:56:41 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*****************************************************************************
|
|
|
|
*
|
1997-09-08 05:20:18 +02:00
|
|
|
* QUERY:
|
|
|
|
* GRANT [privileges] ON [relation_name_list] TO [GROUP] grantee
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
|
1997-10-25 07:56:41 +02:00
|
|
|
GrantStmt: GRANT privileges ON relation_name_list TO grantee opt_with_grant
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
$$ = (Node*)makeAclStmt($2,$4,$6,'+');
|
|
|
|
}
|
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
privileges: ALL PRIVILEGES
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
$$ = aclmakepriv("rwaR",0);
|
|
|
|
}
|
|
|
|
| ALL
|
|
|
|
{
|
|
|
|
$$ = aclmakepriv("rwaR",0);
|
|
|
|
}
|
|
|
|
| operation_commalist
|
|
|
|
{
|
|
|
|
$$ = $1;
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
1997-10-25 07:56:41 +02:00
|
|
|
operation_commalist: operation
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
$$ = aclmakepriv("",$1);
|
|
|
|
}
|
|
|
|
| operation_commalist ',' operation
|
|
|
|
{
|
|
|
|
$$ = aclmakepriv($1,$3);
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
1997-10-25 07:56:41 +02:00
|
|
|
operation: SELECT
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
$$ = ACL_MODE_RD_CHR;
|
|
|
|
}
|
|
|
|
| INSERT
|
|
|
|
{
|
|
|
|
$$ = ACL_MODE_AP_CHR;
|
|
|
|
}
|
|
|
|
| UPDATE
|
|
|
|
{
|
|
|
|
$$ = ACL_MODE_WR_CHR;
|
|
|
|
}
|
|
|
|
| DELETE
|
|
|
|
{
|
|
|
|
$$ = ACL_MODE_WR_CHR;
|
|
|
|
}
|
1997-10-25 07:56:41 +02:00
|
|
|
| RULE
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
$$ = ACL_MODE_RU_CHR;
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
|
|
|
grantee: PUBLIC
|
|
|
|
{
|
|
|
|
$$ = aclmakeuser("A","");
|
|
|
|
}
|
1997-10-25 07:56:41 +02:00
|
|
|
| GROUP ColId
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
$$ = aclmakeuser("G",$2);
|
|
|
|
}
|
1997-10-25 07:56:41 +02:00
|
|
|
| ColId
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
$$ = aclmakeuser("U",$1);
|
|
|
|
}
|
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-10-25 07:56:41 +02:00
|
|
|
opt_with_grant: WITH GRANT OPTION
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
yyerror("WITH GRANT OPTION is not supported. Only relation owners can set privileges");
|
1997-10-25 07:56:41 +02:00
|
|
|
}
|
|
|
|
| /*EMPTY*/
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
|
|
|
|
1997-10-25 07:56:41 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*****************************************************************************
|
|
|
|
*
|
1997-09-08 05:20:18 +02:00
|
|
|
* QUERY:
|
|
|
|
* REVOKE [privileges] ON [relation_name] FROM [user]
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
|
1997-11-07 08:02:10 +01:00
|
|
|
RevokeStmt: REVOKE privileges ON relation_name_list FROM grantee
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
$$ = (Node*)makeAclStmt($2,$4,$6,'-');
|
|
|
|
}
|
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-10-25 07:56:41 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*****************************************************************************
|
|
|
|
*
|
1997-09-08 05:20:18 +02:00
|
|
|
* QUERY:
|
1997-11-21 19:12:58 +01:00
|
|
|
* create index <indexname> on <relname>
|
1997-09-08 05:20:18 +02:00
|
|
|
* using <access> "(" (<col> with <op>)+ ")" [with
|
|
|
|
* <target_list>]
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1997-09-08 05:20:18 +02:00
|
|
|
* [where <qual>] is not supported anymore
|
1996-07-09 08:22:35 +02:00
|
|
|
*****************************************************************************/
|
|
|
|
|
1997-09-08 05:20:18 +02:00
|
|
|
IndexStmt: CREATE index_opt_unique INDEX index_name ON relation_name
|
|
|
|
access_method_clause '(' index_params ')' opt_with
|
|
|
|
{
|
|
|
|
/* should check that access_method is valid,
|
|
|
|
etc ... but doesn't */
|
|
|
|
IndexStmt *n = makeNode(IndexStmt);
|
|
|
|
n->unique = $2;
|
|
|
|
n->idxname = $4;
|
|
|
|
n->relname = $6;
|
|
|
|
n->accessMethod = $7;
|
|
|
|
n->indexParams = $9;
|
|
|
|
n->withClause = $11;
|
|
|
|
n->whereClause = NULL;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
1997-10-25 07:56:41 +02:00
|
|
|
index_opt_unique: UNIQUE { $$ = TRUE; }
|
|
|
|
| /*EMPTY*/ { $$ = FALSE; }
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
|
|
|
|
1997-10-25 07:56:41 +02:00
|
|
|
access_method_clause: USING access_method { $$ = $2; }
|
|
|
|
| /*EMPTY*/ { $$ = "btree"; }
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
1996-08-15 09:42:52 +02:00
|
|
|
|
1997-10-25 07:56:41 +02:00
|
|
|
index_params: index_list { $$ = $1; }
|
|
|
|
| func_index { $$ = lcons($1,NIL); }
|
|
|
|
;
|
|
|
|
|
|
|
|
index_list: index_list ',' index_elem { $$ = lappend($1, $3); }
|
|
|
|
| index_elem { $$ = lcons($1, NIL); }
|
|
|
|
;
|
|
|
|
|
1998-02-11 05:09:54 +01:00
|
|
|
func_index: func_name '(' name_list ')' opt_type opt_class
|
1997-10-25 07:56:41 +02:00
|
|
|
{
|
|
|
|
$$ = makeNode(IndexElem);
|
|
|
|
$$->name = $1;
|
|
|
|
$$->args = $3;
|
|
|
|
$$->class = $6;
|
1998-08-26 07:22:58 +02:00
|
|
|
$$->typename = $5;
|
1997-10-25 07:56:41 +02:00
|
|
|
}
|
|
|
|
;
|
|
|
|
|
|
|
|
index_elem: attr_name opt_type opt_class
|
|
|
|
{
|
|
|
|
$$ = makeNode(IndexElem);
|
|
|
|
$$->name = $1;
|
|
|
|
$$->args = NIL;
|
|
|
|
$$->class = $3;
|
1998-08-26 07:22:58 +02:00
|
|
|
$$->typename = $2;
|
1997-10-25 07:56:41 +02:00
|
|
|
}
|
|
|
|
;
|
|
|
|
|
1997-12-16 16:50:54 +01:00
|
|
|
opt_type: ':' Typename { $$ = $2; }
|
|
|
|
| FOR Typename { $$ = $2; }
|
|
|
|
| /*EMPTY*/ { $$ = NULL; }
|
1997-10-25 07:56:41 +02:00
|
|
|
;
|
|
|
|
|
|
|
|
/* opt_class "WITH class" conflicts with preceeding opt_type
|
|
|
|
* for Typename of "TIMESTAMP WITH TIME ZONE"
|
|
|
|
* So, remove "WITH class" from the syntax. OK??
|
|
|
|
* - thomas 1997-10-12
|
1997-11-07 08:02:10 +01:00
|
|
|
* | WITH class { $$ = $2; }
|
1997-10-25 07:56:41 +02:00
|
|
|
*/
|
|
|
|
opt_class: class { $$ = $1; }
|
1997-11-07 08:02:10 +01:00
|
|
|
| USING class { $$ = $2; }
|
1997-10-25 07:56:41 +02:00
|
|
|
| /*EMPTY*/ { $$ = NULL; }
|
|
|
|
;
|
|
|
|
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*****************************************************************************
|
|
|
|
*
|
1997-09-08 05:20:18 +02:00
|
|
|
* QUERY:
|
|
|
|
* extend index <indexname> [where <qual>]
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
ExtendStmt: EXTEND INDEX index_name where_clause
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
ExtendStmt *n = makeNode(ExtendStmt);
|
|
|
|
n->idxname = $3;
|
|
|
|
n->whereClause = $4;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
*
|
1997-09-08 05:20:18 +02:00
|
|
|
* QUERY:
|
|
|
|
* execute recipe <recipeName>
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
|
1999-03-07 04:34:11 +01:00
|
|
|
/* NOT USED
|
1997-09-01 08:00:35 +02:00
|
|
|
RecipeStmt: EXECUTE RECIPE recipe_name
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
RecipeStmt *n;
|
|
|
|
if (!IsTransactionBlock())
|
1998-01-09 21:06:08 +01:00
|
|
|
elog(ERROR,"EXECUTE RECIPE may only be used in begin/end transaction blocks");
|
1997-09-08 05:20:18 +02:00
|
|
|
|
|
|
|
n = makeNode(RecipeStmt);
|
|
|
|
n->recipeName = $3;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
;
|
1999-03-07 04:34:11 +01:00
|
|
|
*/
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
*
|
1997-09-08 05:20:18 +02:00
|
|
|
* QUERY:
|
|
|
|
* define function <fname>
|
|
|
|
* (language = <lang>, returntype = <typename>
|
|
|
|
* [, arch_pct = <percentage | pre-defined>]
|
|
|
|
* [, disk_pct = <percentage | pre-defined>]
|
|
|
|
* [, byte_pct = <percentage | pre-defined>]
|
|
|
|
* [, perbyte_cpu = <int | pre-defined>]
|
|
|
|
* [, percall_cpu = <int | pre-defined>]
|
|
|
|
* [, iscachable])
|
|
|
|
* [arg is (<type-1> { , <type-n>})]
|
|
|
|
* as <filename or code in language as appropriate>
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
|
1998-02-11 05:09:54 +01:00
|
|
|
ProcedureStmt: CREATE FUNCTION func_name func_args
|
I have been working with user defined types and user defined c
functions. One problem that I have encountered with the function
manager is that it does not allow the user to define type conversion
functions that convert between user types. For instance if mytype1,
mytype2, and mytype3 are three Postgresql user types, and if I wish to
define Postgresql conversion functions like
I run into problems, because the Postgresql dynamic loader would look
for a single link symbol, mytype3, for both pieces of object code. If
I just change the name of one of the Postgresql functions (to make the
symbols distinct), the automatic type conversion that Postgresql uses,
for example, when matching operators to arguments no longer finds the
type conversion function.
The solution that I propose, and have implemented in the attatched
patch extends the CREATE FUNCTION syntax as follows. In the first case
above I use the link symbol mytype2_to_mytype3 for the link object
that implements the first conversion function, and define the
Postgresql operator with the following syntax
The patch includes changes to the parser to include the altered
syntax, changes to the ProcedureStmt node in nodes/parsenodes.h,
changes to commands/define.c to handle the extra information in the AS
clause, and changes to utils/fmgr/dfmgr.c that alter the way that the
dynamic loader figures out what link symbol to use. I store the
string for the link symbol in the prosrc text attribute of the pg_proc
table which is currently unused in rows that reference dynamically
loaded
functions.
Bernie Frankpitt
1999-09-28 06:34:56 +02:00
|
|
|
RETURNS func_return opt_with AS func_as LANGUAGE Sconst
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
ProcedureStmt *n = makeNode(ProcedureStmt);
|
|
|
|
n->funcname = $3;
|
|
|
|
n->defArgs = $4;
|
1998-02-11 05:09:54 +01:00
|
|
|
n->returnType = $6;
|
1997-09-08 05:20:18 +02:00
|
|
|
n->withClause = $7;
|
|
|
|
n->as = $9;
|
|
|
|
n->language = $11;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
};
|
|
|
|
|
|
|
|
opt_with: WITH definition { $$ = $2; }
|
1998-02-11 05:09:54 +01:00
|
|
|
| /*EMPTY*/ { $$ = NIL; }
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
|
|
|
|
1998-02-11 05:09:54 +01:00
|
|
|
func_args: '(' func_args_list ')' { $$ = $2; }
|
1997-11-07 08:02:10 +01:00
|
|
|
| '(' ')' { $$ = NIL; }
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1998-02-11 05:09:54 +01:00
|
|
|
func_args_list: TypeId
|
|
|
|
{ $$ = lcons(makeString($1),NIL); }
|
|
|
|
| func_args_list ',' TypeId
|
|
|
|
{ $$ = lappend($1,makeString($3)); }
|
|
|
|
;
|
|
|
|
|
I have been working with user defined types and user defined c
functions. One problem that I have encountered with the function
manager is that it does not allow the user to define type conversion
functions that convert between user types. For instance if mytype1,
mytype2, and mytype3 are three Postgresql user types, and if I wish to
define Postgresql conversion functions like
I run into problems, because the Postgresql dynamic loader would look
for a single link symbol, mytype3, for both pieces of object code. If
I just change the name of one of the Postgresql functions (to make the
symbols distinct), the automatic type conversion that Postgresql uses,
for example, when matching operators to arguments no longer finds the
type conversion function.
The solution that I propose, and have implemented in the attatched
patch extends the CREATE FUNCTION syntax as follows. In the first case
above I use the link symbol mytype2_to_mytype3 for the link object
that implements the first conversion function, and define the
Postgresql operator with the following syntax
The patch includes changes to the parser to include the altered
syntax, changes to the ProcedureStmt node in nodes/parsenodes.h,
changes to commands/define.c to handle the extra information in the AS
clause, and changes to utils/fmgr/dfmgr.c that alter the way that the
dynamic loader figures out what link symbol to use. I store the
string for the link symbol in the prosrc text attribute of the pg_proc
table which is currently unused in rows that reference dynamically
loaded
functions.
Bernie Frankpitt
1999-09-28 06:34:56 +02:00
|
|
|
func_as: Sconst
|
|
|
|
{ $$ = lcons(makeString($1),NIL); }
|
|
|
|
| Sconst ',' Sconst
|
|
|
|
{ $$ = lappend(lcons(makeString($1),NIL), makeString($3)); }
|
|
|
|
;
|
|
|
|
|
1998-02-11 05:09:54 +01:00
|
|
|
func_return: set_opt TypeId
|
|
|
|
{
|
|
|
|
TypeName *n = makeNode(TypeName);
|
|
|
|
n->name = $2;
|
|
|
|
n->setof = $1;
|
|
|
|
n->arrayBounds = NULL;
|
2000-01-20 03:24:50 +01:00
|
|
|
n->typmod = -1;
|
1998-02-11 05:09:54 +01:00
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
|
|
|
set_opt: SETOF { $$ = TRUE; }
|
|
|
|
| /*EMPTY*/ { $$ = FALSE; }
|
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
*
|
1997-09-08 05:20:18 +02:00
|
|
|
* QUERY:
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1997-09-08 05:20:18 +02:00
|
|
|
* remove function <funcname>
|
|
|
|
* (REMOVE FUNCTION "funcname" (arg1, arg2, ...))
|
|
|
|
* remove aggregate <aggname>
|
|
|
|
* (REMOVE AGGREGATE "aggname" "aggtype")
|
|
|
|
* remove operator <opname>
|
|
|
|
* (REMOVE OPERATOR "opname" (leftoperand_typ rightoperand_typ))
|
|
|
|
* remove type <typename>
|
|
|
|
* (REMOVE TYPE "typename")
|
|
|
|
* remove rule <rulename>
|
|
|
|
* (REMOVE RULE "rulename")
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
RemoveStmt: DROP remove_type name
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
RemoveStmt *n = makeNode(RemoveStmt);
|
|
|
|
n->removeType = $2;
|
|
|
|
n->name = $3;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
1997-12-05 00:07:23 +01:00
|
|
|
remove_type: TYPE_P { $$ = TYPE_P; }
|
1997-11-07 08:02:10 +01:00
|
|
|
| INDEX { $$ = INDEX; }
|
|
|
|
| RULE { $$ = RULE; }
|
|
|
|
| VIEW { $$ = VIEW; }
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1998-02-11 05:09:54 +01:00
|
|
|
|
1997-05-22 02:17:24 +02:00
|
|
|
RemoveAggrStmt: DROP AGGREGATE name aggr_argtype
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
RemoveAggrStmt *n = makeNode(RemoveAggrStmt);
|
|
|
|
n->aggname = $3;
|
|
|
|
n->aggtype = $4;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
|
|
|
aggr_argtype: name { $$ = $1; }
|
1997-11-07 08:02:10 +01:00
|
|
|
| '*' { $$ = NULL; }
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
1997-05-22 02:17:24 +02:00
|
|
|
|
1998-02-11 05:09:54 +01:00
|
|
|
|
|
|
|
RemoveFuncStmt: DROP FUNCTION func_name func_args
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
RemoveFuncStmt *n = makeNode(RemoveFuncStmt);
|
|
|
|
n->funcname = $3;
|
1998-02-11 05:09:54 +01:00
|
|
|
n->args = $4;
|
1997-09-08 05:20:18 +02:00
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
RemoveOperStmt: DROP OPERATOR all_Op '(' oper_argtypes ')'
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
RemoveOperStmt *n = makeNode(RemoveOperStmt);
|
|
|
|
n->opname = $3;
|
|
|
|
n->args = $5;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-08 05:20:18 +02:00
|
|
|
oper_argtypes: name
|
|
|
|
{
|
1998-01-09 21:06:08 +01:00
|
|
|
elog(ERROR,"parser: argument type missing (use NONE for unary operators)");
|
1997-09-08 05:20:18 +02:00
|
|
|
}
|
|
|
|
| name ',' name
|
|
|
|
{ $$ = makeList(makeString($1), makeString($3), -1); }
|
|
|
|
| NONE ',' name /* left unary */
|
|
|
|
{ $$ = makeList(NULL, makeString($3), -1); }
|
|
|
|
| name ',' NONE /* right unary */
|
|
|
|
{ $$ = makeList(makeString($1), NULL, -1); }
|
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-10-25 07:56:41 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*****************************************************************************
|
|
|
|
*
|
1997-09-08 05:20:18 +02:00
|
|
|
* QUERY:
|
|
|
|
* rename <attrname1> in <relname> [*] to <attrname2>
|
|
|
|
* rename <relname1> to <relname2>
|
1997-09-01 08:00:35 +02:00
|
|
|
*
|
1996-07-09 08:22:35 +02:00
|
|
|
*****************************************************************************/
|
|
|
|
|
1997-09-01 08:00:35 +02:00
|
|
|
RenameStmt: ALTER TABLE relation_name opt_inh_star
|
1997-09-08 05:20:18 +02:00
|
|
|
RENAME opt_column opt_name TO name
|
|
|
|
{
|
|
|
|
RenameStmt *n = makeNode(RenameStmt);
|
|
|
|
n->relname = $3;
|
|
|
|
n->inh = $4;
|
|
|
|
n->column = $7;
|
|
|
|
n->newname = $9;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
|
|
|
opt_name: name { $$ = $1; }
|
1997-11-07 08:02:10 +01:00
|
|
|
| /*EMPTY*/ { $$ = NULL; }
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
|
|
|
|
|
|
|
opt_column: COLUMN { $$ = COLUMN; }
|
|
|
|
| /*EMPTY*/ { $$ = 0; }
|
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************
|
1997-09-01 08:00:35 +02:00
|
|
|
*
|
1997-09-08 05:20:18 +02:00
|
|
|
* QUERY: Define Rewrite Rule , Define Tuple Rule
|
|
|
|
* Define Rule <old rules >
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1997-09-08 05:20:18 +02:00
|
|
|
* only rewrite rule is supported -- ay 9/94
|
1997-09-01 08:00:35 +02:00
|
|
|
*
|
1996-07-09 08:22:35 +02:00
|
|
|
*****************************************************************************/
|
|
|
|
|
1997-09-01 08:00:35 +02:00
|
|
|
RuleStmt: CREATE RULE name AS
|
1997-09-08 05:20:18 +02:00
|
|
|
{ QueryIsRule=TRUE; }
|
|
|
|
ON event TO event_object where_clause
|
1999-02-07 20:02:20 +01:00
|
|
|
DO opt_instead RuleActionList
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
RuleStmt *n = makeNode(RuleStmt);
|
|
|
|
n->rulename = $3;
|
|
|
|
n->event = $7;
|
|
|
|
n->object = $9;
|
|
|
|
n->whereClause = $10;
|
|
|
|
n->instead = $12;
|
|
|
|
n->actions = $13;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
1999-02-07 20:02:20 +01:00
|
|
|
RuleActionList: NOTHING { $$ = NIL; }
|
|
|
|
| SelectStmt { $$ = lcons($1, NIL); }
|
|
|
|
| RuleActionStmt { $$ = lcons($1, NIL); }
|
1999-10-07 06:23:24 +02:00
|
|
|
| '[' RuleActionMulti ']' { $$ = $2; }
|
|
|
|
| '(' RuleActionMulti ')' { $$ = $2; }
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
1997-09-01 08:00:35 +02:00
|
|
|
|
1999-10-07 06:23:24 +02:00
|
|
|
/* the thrashing around here is to discard "empty" statements... */
|
|
|
|
RuleActionMulti: RuleActionMulti ';' RuleActionStmtOrEmpty
|
|
|
|
{ if ($3 != (Node *)NULL)
|
|
|
|
$$ = lappend($1, $3);
|
|
|
|
else
|
|
|
|
$$ = $1;
|
|
|
|
}
|
|
|
|
| RuleActionStmtOrEmpty
|
|
|
|
{ if ($1 != (Node *)NULL)
|
|
|
|
$$ = lcons($1,NIL);
|
|
|
|
else
|
|
|
|
$$ = NIL;
|
|
|
|
}
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
1997-09-01 08:00:35 +02:00
|
|
|
|
1999-02-07 20:02:20 +01:00
|
|
|
RuleActionStmt: InsertStmt
|
|
|
|
| UpdateStmt
|
|
|
|
| DeleteStmt
|
|
|
|
| NotifyStmt
|
|
|
|
;
|
|
|
|
|
1999-10-07 06:23:24 +02:00
|
|
|
RuleActionStmtOrEmpty: RuleActionStmt
|
|
|
|
| /*EMPTY*/
|
|
|
|
{ $$ = (Node *)NULL; }
|
|
|
|
;
|
|
|
|
|
1997-11-07 08:02:10 +01:00
|
|
|
event_object: relation_name '.' attr_name
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
$$ = makeNode(Attr);
|
|
|
|
$$->relname = $1;
|
|
|
|
$$->paramNo = NULL;
|
|
|
|
$$->attrs = lcons(makeString($3), NIL);
|
|
|
|
$$->indirection = NIL;
|
|
|
|
}
|
|
|
|
| relation_name
|
|
|
|
{
|
|
|
|
$$ = makeNode(Attr);
|
|
|
|
$$->relname = $1;
|
|
|
|
$$->paramNo = NULL;
|
|
|
|
$$->attrs = NIL;
|
|
|
|
$$->indirection = NIL;
|
|
|
|
}
|
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
/* change me to select, update, etc. some day */
|
1997-09-08 05:20:18 +02:00
|
|
|
event: SELECT { $$ = CMD_SELECT; }
|
|
|
|
| UPDATE { $$ = CMD_UPDATE; }
|
|
|
|
| DELETE { $$ = CMD_DELETE; }
|
|
|
|
| INSERT { $$ = CMD_INSERT; }
|
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-08 05:20:18 +02:00
|
|
|
opt_instead: INSTEAD { $$ = TRUE; }
|
1998-03-18 17:50:25 +01:00
|
|
|
| /*EMPTY*/ { $$ = FALSE; }
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
*
|
1997-09-08 05:20:18 +02:00
|
|
|
* QUERY:
|
|
|
|
* NOTIFY <relation_name> can appear both in rule bodies and
|
|
|
|
* as a query-level command
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
|
1997-11-07 08:02:10 +01:00
|
|
|
NotifyStmt: NOTIFY relation_name
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
NotifyStmt *n = makeNode(NotifyStmt);
|
|
|
|
n->relname = $2;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-11-07 08:02:10 +01:00
|
|
|
ListenStmt: LISTEN relation_name
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
ListenStmt *n = makeNode(ListenStmt);
|
|
|
|
n->relname = $2;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
1996-07-09 08:22:35 +02:00
|
|
|
;
|
|
|
|
|
1998-08-25 23:37:08 +02:00
|
|
|
UnlistenStmt: UNLISTEN relation_name
|
|
|
|
{
|
|
|
|
UnlistenStmt *n = makeNode(UnlistenStmt);
|
|
|
|
n->relname = $2;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
1998-10-09 09:06:37 +02:00
|
|
|
| UNLISTEN '*'
|
|
|
|
{
|
|
|
|
UnlistenStmt *n = makeNode(UnlistenStmt);
|
|
|
|
n->relname = "*";
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
1998-08-25 23:37:08 +02:00
|
|
|
;
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
*
|
1997-09-08 05:20:18 +02:00
|
|
|
* Transactions:
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1997-09-08 05:20:18 +02:00
|
|
|
* abort transaction
|
|
|
|
* (ABORT)
|
|
|
|
* begin transaction
|
|
|
|
* (BEGIN)
|
|
|
|
* end transaction
|
|
|
|
* (END)
|
1997-09-01 08:00:35 +02:00
|
|
|
*
|
1996-07-09 08:22:35 +02:00
|
|
|
*****************************************************************************/
|
|
|
|
|
1998-07-25 02:17:30 +02:00
|
|
|
TransactionStmt: ABORT_TRANS opt_trans
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
TransactionStmt *n = makeNode(TransactionStmt);
|
|
|
|
n->command = ABORT_TRANS;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
1998-07-25 02:17:30 +02:00
|
|
|
| BEGIN_TRANS opt_trans
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
TransactionStmt *n = makeNode(TransactionStmt);
|
|
|
|
n->command = BEGIN_TRANS;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
1998-07-25 02:17:30 +02:00
|
|
|
| COMMIT opt_trans
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
TransactionStmt *n = makeNode(TransactionStmt);
|
|
|
|
n->command = END_TRANS;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
1998-07-25 02:17:30 +02:00
|
|
|
| END_TRANS opt_trans
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
TransactionStmt *n = makeNode(TransactionStmt);
|
|
|
|
n->command = END_TRANS;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
1998-07-25 02:17:30 +02:00
|
|
|
| ROLLBACK opt_trans
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
TransactionStmt *n = makeNode(TransactionStmt);
|
|
|
|
n->command = ABORT_TRANS;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
1998-07-25 02:17:30 +02:00
|
|
|
;
|
1997-09-08 05:20:18 +02:00
|
|
|
|
1998-07-26 03:18:09 +02:00
|
|
|
opt_trans: WORK { $$ = TRUE; }
|
|
|
|
| TRANSACTION { $$ = TRUE; }
|
|
|
|
| /*EMPTY*/ { $$ = TRUE; }
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
*
|
1997-09-08 05:20:18 +02:00
|
|
|
* QUERY:
|
|
|
|
* define view <viewname> '('target-list ')' [where <quals> ]
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
|
1998-01-09 21:06:08 +01:00
|
|
|
ViewStmt: CREATE VIEW name AS SelectStmt
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
ViewStmt *n = makeNode(ViewStmt);
|
|
|
|
n->viewname = $3;
|
|
|
|
n->query = (Query *)$5;
|
1998-01-11 21:02:32 +01:00
|
|
|
if (((SelectStmt *)n->query)->sortClause != NULL)
|
|
|
|
elog(ERROR,"Order by and Distinct on views is not implemented.");
|
1998-01-09 22:26:12 +01:00
|
|
|
if (((SelectStmt *)n->query)->unionClause != NULL)
|
1998-01-09 21:06:08 +01:00
|
|
|
elog(ERROR,"Views on unions not implemented.");
|
1999-01-05 16:46:25 +01:00
|
|
|
if (((SelectStmt *)n->query)->forUpdate != NULL)
|
|
|
|
elog(ERROR, "SELECT FOR UPDATE is not allowed in CREATE VIEW");
|
1997-09-08 05:20:18 +02:00
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
*
|
1997-09-08 05:20:18 +02:00
|
|
|
* QUERY:
|
|
|
|
* load "filename"
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
|
1997-11-07 08:02:10 +01:00
|
|
|
LoadStmt: LOAD file_name
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
LoadStmt *n = makeNode(LoadStmt);
|
|
|
|
n->filename = $2;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
*
|
2000-01-13 19:26:18 +01:00
|
|
|
* CREATE DATABASE
|
|
|
|
*
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
|
2000-01-13 19:26:18 +01:00
|
|
|
CreatedbStmt: CREATE DATABASE database_name WITH createdb_opt_location createdb_opt_encoding
|
|
|
|
{
|
|
|
|
CreatedbStmt *n;
|
|
|
|
|
|
|
|
if ($5 == NULL && $6 == -1)
|
|
|
|
elog(ERROR, "CREATE DATABASE WITH requires at least one option.");
|
|
|
|
|
|
|
|
n = makeNode(CreatedbStmt);
|
1997-09-08 05:20:18 +02:00
|
|
|
n->dbname = $3;
|
1998-07-24 05:32:46 +02:00
|
|
|
n->dbpath = $5;
|
1998-07-26 06:31:41 +02:00
|
|
|
#ifdef MULTIBYTE
|
2000-01-13 19:26:18 +01:00
|
|
|
n->encoding = $6;
|
1998-07-24 05:32:46 +02:00
|
|
|
#else
|
1998-08-24 03:14:24 +02:00
|
|
|
n->encoding = 0;
|
1998-07-24 05:32:46 +02:00
|
|
|
#endif
|
1997-09-08 05:20:18 +02:00
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
1998-07-24 05:32:46 +02:00
|
|
|
| CREATE DATABASE database_name
|
|
|
|
{
|
|
|
|
CreatedbStmt *n = makeNode(CreatedbStmt);
|
|
|
|
n->dbname = $3;
|
|
|
|
n->dbpath = NULL;
|
1998-07-26 06:31:41 +02:00
|
|
|
#ifdef MULTIBYTE
|
1998-07-24 05:32:46 +02:00
|
|
|
n->encoding = GetTemplateEncoding();
|
1998-08-24 03:14:24 +02:00
|
|
|
#else
|
|
|
|
n->encoding = 0;
|
1998-07-24 05:32:46 +02:00
|
|
|
#endif
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
2000-01-13 19:26:18 +01:00
|
|
|
createdb_opt_location: LOCATION '=' Sconst { $$ = $3; }
|
|
|
|
| LOCATION '=' DEFAULT { $$ = NULL; }
|
1997-11-07 08:02:10 +01:00
|
|
|
| /*EMPTY*/ { $$ = NULL; }
|
|
|
|
;
|
|
|
|
|
2000-01-13 19:26:18 +01:00
|
|
|
createdb_opt_encoding:
|
|
|
|
ENCODING '=' Sconst
|
|
|
|
{
|
|
|
|
#ifdef MULTIBYTE
|
|
|
|
int i;
|
|
|
|
i = pg_char_to_encoding($3);
|
|
|
|
if (i == -1)
|
|
|
|
elog(ERROR, "%s is not a valid encoding name.", $3);
|
|
|
|
$$ = i;
|
|
|
|
#else
|
2000-01-23 09:16:37 +01:00
|
|
|
elog(ERROR, "Multi-byte support is not enabled");
|
2000-01-13 19:26:18 +01:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
| ENCODING '=' Iconst
|
|
|
|
{
|
|
|
|
#ifdef MULTIBYTE
|
|
|
|
if (!pg_get_encent_by_encoding($3))
|
|
|
|
elog(ERROR, "%d is not a valid encoding code.", $3);
|
|
|
|
$$ = $3;
|
|
|
|
#else
|
2000-01-23 09:16:37 +01:00
|
|
|
elog(ERROR, "Multi-byte support is not enabled");
|
2000-01-13 19:26:18 +01:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
| ENCODING '=' DEFAULT
|
|
|
|
{
|
|
|
|
#ifdef MULTIBYTE
|
|
|
|
$$ = GetTemplateEncoding();
|
|
|
|
#else
|
|
|
|
$$ = -1;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
| /*EMPTY*/
|
|
|
|
{
|
|
|
|
#ifdef MULTIBYTE
|
|
|
|
$$ = GetTemplateEncoding();
|
|
|
|
#else
|
|
|
|
$$= -1;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1998-07-24 05:32:46 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*****************************************************************************
|
|
|
|
*
|
2000-01-13 19:26:18 +01:00
|
|
|
* DROP DATABASE
|
|
|
|
*
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
|
1999-12-10 04:56:14 +01:00
|
|
|
DropdbStmt: DROP DATABASE database_name
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
1999-12-10 04:56:14 +01:00
|
|
|
DropdbStmt *n = makeNode(DropdbStmt);
|
1997-09-08 05:20:18 +02:00
|
|
|
n->dbname = $3;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
*
|
1997-09-08 05:20:18 +02:00
|
|
|
* QUERY:
|
|
|
|
* cluster <index_name> on <relation_name>
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
|
1997-09-01 08:00:35 +02:00
|
|
|
ClusterStmt: CLUSTER index_name ON relation_name
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
ClusterStmt *n = makeNode(ClusterStmt);
|
|
|
|
n->relname = $4;
|
|
|
|
n->indexname = $2;
|
|
|
|
$$ = (Node*)n;
|
|
|
|
}
|
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
*
|
1997-09-08 05:20:18 +02:00
|
|
|
* QUERY:
|
|
|
|
* vacuum
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
|
1997-04-23 08:04:46 +02:00
|
|
|
VacuumStmt: VACUUM opt_verbose opt_analyze
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
VacuumStmt *n = makeNode(VacuumStmt);
|
|
|
|
n->verbose = $2;
|
|
|
|
n->analyze = $3;
|
|
|
|
n->vacrel = NULL;
|
|
|
|
n->va_spec = NIL;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
1997-12-02 17:09:15 +01:00
|
|
|
| VACUUM opt_verbose opt_analyze relation_name opt_va_list
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
VacuumStmt *n = makeNode(VacuumStmt);
|
|
|
|
n->verbose = $2;
|
1997-12-02 17:09:15 +01:00
|
|
|
n->analyze = $3;
|
|
|
|
n->vacrel = $4;
|
1997-09-08 05:20:18 +02:00
|
|
|
n->va_spec = $5;
|
|
|
|
if ( $5 != NIL && !$4 )
|
1998-01-09 21:06:08 +01:00
|
|
|
elog(ERROR,"parser: syntax error at or near \"(\"");
|
1997-09-08 05:20:18 +02:00
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
1997-10-25 07:56:41 +02:00
|
|
|
opt_verbose: VERBOSE { $$ = TRUE; }
|
1997-12-16 16:50:54 +01:00
|
|
|
| /*EMPTY*/ { $$ = FALSE; }
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
|
|
|
|
1997-10-25 07:56:41 +02:00
|
|
|
opt_analyze: ANALYZE { $$ = TRUE; }
|
1997-12-16 16:50:54 +01:00
|
|
|
| /*EMPTY*/ { $$ = FALSE; }
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
1997-04-23 08:04:46 +02:00
|
|
|
|
1998-03-18 17:50:25 +01:00
|
|
|
opt_va_list: '(' va_list ')' { $$ = $2; }
|
|
|
|
| /*EMPTY*/ { $$ = NIL; }
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
1997-04-23 08:04:46 +02:00
|
|
|
|
1997-11-07 08:02:10 +01:00
|
|
|
va_list: name
|
1997-09-08 05:20:18 +02:00
|
|
|
{ $$=lcons($1,NIL); }
|
|
|
|
| va_list ',' name
|
|
|
|
{ $$=lappend($1,$3); }
|
|
|
|
;
|
1997-09-01 08:00:35 +02:00
|
|
|
|
1997-10-25 07:56:41 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*****************************************************************************
|
|
|
|
*
|
1997-09-08 05:20:18 +02:00
|
|
|
* QUERY:
|
|
|
|
* EXPLAIN query
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
|
1997-01-16 15:56:59 +01:00
|
|
|
ExplainStmt: EXPLAIN opt_verbose OptimizableStmt
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
ExplainStmt *n = makeNode(ExplainStmt);
|
|
|
|
n->verbose = $2;
|
|
|
|
n->query = (Query*)$3;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-10-25 07:56:41 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*****************************************************************************
|
1997-09-08 05:20:18 +02:00
|
|
|
* *
|
|
|
|
* Optimizable Stmts: *
|
|
|
|
* *
|
|
|
|
* one of the five queries processed by the planner *
|
|
|
|
* *
|
|
|
|
* [ultimately] produces query-trees as specified *
|
|
|
|
* in the query-spec document in ~postgres/ref *
|
|
|
|
* *
|
1996-07-09 08:22:35 +02:00
|
|
|
*****************************************************************************/
|
|
|
|
|
1998-01-09 21:06:08 +01:00
|
|
|
OptimizableStmt: SelectStmt
|
1997-09-08 05:20:18 +02:00
|
|
|
| CursorStmt
|
1998-01-09 21:06:08 +01:00
|
|
|
| UpdateStmt
|
|
|
|
| InsertStmt
|
1997-09-08 05:20:18 +02:00
|
|
|
| NotifyStmt
|
|
|
|
| DeleteStmt /* by default all are $$=$1 */
|
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
*
|
1997-09-08 05:20:18 +02:00
|
|
|
* QUERY:
|
|
|
|
* INSERT STATEMENTS
|
1997-09-01 08:00:35 +02:00
|
|
|
*
|
1996-07-09 08:22:35 +02:00
|
|
|
*****************************************************************************/
|
|
|
|
|
Hi!
INTERSECT and EXCEPT is available for postgresql-v6.4!
The patch against v6.4 is included at the end of the current text
(in uuencoded form!)
I also included the text of my Master's Thesis. (a postscript
version). I hope that you find something of it useful and would be
happy if parts of it find their way into the PostgreSQL documentation
project (If so, tell me, then I send the sources of the document!)
The contents of the document are:
-) The first chapter might be of less interest as it gives only an
overview on SQL.
-) The second chapter gives a description on much of PostgreSQL's
features (like user defined types etc. and how to use these features)
-) The third chapter starts with an overview of PostgreSQL's internal
structure with focus on the stages a query has to pass (i.e. parser,
planner/optimizer, executor). Then a detailed description of the
implementation of the Having clause and the Intersect/Except logic is
given.
Originally I worked on v6.3.2 but never found time enough to prepare
and post a patch. Now I applied the changes to v6.4 to get Intersect
and Except working with the new version. Chapter 3 of my documentation
deals with the changes against v6.3.2, so keep that in mind when
comparing the parts of the code printed there with the patched sources
of v6.4.
Here are some remarks on the patch. There are some things that have
still to be done but at the moment I don't have time to do them
myself. (I'm doing my military service at the moment) Sorry for that
:-(
-) I used a rewrite technique for the implementation of the Except/Intersect
logic which rewrites the query to a semantically equivalent query before
it is handed to the rewrite system (for views, rules etc.), planner,
executor etc.
-) In v6.3.2 the types of the attributes of two select statements
connected by the UNION keyword had to match 100%. In v6.4 the types
only need to be familiar (i.e. int and float can be mixed). Since this
feature did not exist when I worked on Intersect/Except it
does not work correctly for Except/Intersect queries WHEN USED IN
COMBINATION WITH UNIONS! (i.e. sometimes the wrong type is used for the
resulting table. This is because until now the types of the attributes of
the first select statement have been used for the resulting table.
When Intersects and/or Excepts are used in combination with Unions it
might happen, that the first select statement of the original query
appears at another position in the query which will be executed. The reason
for this is the technique used for the implementation of
Except/Intersect which does a query rewrite!)
NOTE: It is NOT broken for pure UNION queries and pure INTERSECT/EXCEPT
queries!!!
-) I had to add the field intersect_clause to some data structures
but did not find time to implement printfuncs for the new field.
This does NOT break the debug modes but when an Except/Intersect
is used the query debug output will be the already rewritten query.
-) Massive changes to the grammar rules for SELECT and INSERT statements
have been necessary (see comments in gram.y and documentation for
deatails) in order to be able to use mixed queries like
(SELECT ... UNION (SELECT ... EXCEPT SELECT)) INTERSECT SELECT...;
-) When using UNION/EXCEPT/INTERSECT you will get:
NOTICE: equal: "Don't know if nodes of type xxx are equal".
I did not have time to add comparsion support for all the needed nodes,
but the default behaviour of the function equal met my requirements.
I did not dare to supress this message!
That's the reason why the regression test for union will fail: These
messages are also included in the union.out file!
-) Somebody of you changed the union_planner() function for v6.4
(I copied the targetlist to new_tlist and that was removed and
replaced by a cleanup of the original targetlist). These chnages
violated some having queries executed against views so I changed
it back again. I did not have time to examine the differences between the
two versions but now it works :-)
If you want to find out, try the file queries/view_having.sql on
both versions and compare the results . Two queries won't produce a
correct result with your version.
regards
Stefan
1999-01-18 01:10:17 +01:00
|
|
|
/* This rule used 'opt_column_list' between 'relation_name' and 'insert_rest'
|
1999-07-20 02:18:01 +02:00
|
|
|
* originally. When the second rule of 'insert_rest' was changed to use the
|
|
|
|
* new 'SelectStmt' rule (for INTERSECT and EXCEPT) it produced a shift/reduce
|
|
|
|
* conflict. So I just changed the rules 'InsertStmt' and 'insert_rest' to
|
|
|
|
* accept the same statements without any shift/reduce conflicts
|
|
|
|
*/
|
|
|
|
InsertStmt: INSERT INTO relation_name insert_rest
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
Hi!
INTERSECT and EXCEPT is available for postgresql-v6.4!
The patch against v6.4 is included at the end of the current text
(in uuencoded form!)
I also included the text of my Master's Thesis. (a postscript
version). I hope that you find something of it useful and would be
happy if parts of it find their way into the PostgreSQL documentation
project (If so, tell me, then I send the sources of the document!)
The contents of the document are:
-) The first chapter might be of less interest as it gives only an
overview on SQL.
-) The second chapter gives a description on much of PostgreSQL's
features (like user defined types etc. and how to use these features)
-) The third chapter starts with an overview of PostgreSQL's internal
structure with focus on the stages a query has to pass (i.e. parser,
planner/optimizer, executor). Then a detailed description of the
implementation of the Having clause and the Intersect/Except logic is
given.
Originally I worked on v6.3.2 but never found time enough to prepare
and post a patch. Now I applied the changes to v6.4 to get Intersect
and Except working with the new version. Chapter 3 of my documentation
deals with the changes against v6.3.2, so keep that in mind when
comparing the parts of the code printed there with the patched sources
of v6.4.
Here are some remarks on the patch. There are some things that have
still to be done but at the moment I don't have time to do them
myself. (I'm doing my military service at the moment) Sorry for that
:-(
-) I used a rewrite technique for the implementation of the Except/Intersect
logic which rewrites the query to a semantically equivalent query before
it is handed to the rewrite system (for views, rules etc.), planner,
executor etc.
-) In v6.3.2 the types of the attributes of two select statements
connected by the UNION keyword had to match 100%. In v6.4 the types
only need to be familiar (i.e. int and float can be mixed). Since this
feature did not exist when I worked on Intersect/Except it
does not work correctly for Except/Intersect queries WHEN USED IN
COMBINATION WITH UNIONS! (i.e. sometimes the wrong type is used for the
resulting table. This is because until now the types of the attributes of
the first select statement have been used for the resulting table.
When Intersects and/or Excepts are used in combination with Unions it
might happen, that the first select statement of the original query
appears at another position in the query which will be executed. The reason
for this is the technique used for the implementation of
Except/Intersect which does a query rewrite!)
NOTE: It is NOT broken for pure UNION queries and pure INTERSECT/EXCEPT
queries!!!
-) I had to add the field intersect_clause to some data structures
but did not find time to implement printfuncs for the new field.
This does NOT break the debug modes but when an Except/Intersect
is used the query debug output will be the already rewritten query.
-) Massive changes to the grammar rules for SELECT and INSERT statements
have been necessary (see comments in gram.y and documentation for
deatails) in order to be able to use mixed queries like
(SELECT ... UNION (SELECT ... EXCEPT SELECT)) INTERSECT SELECT...;
-) When using UNION/EXCEPT/INTERSECT you will get:
NOTICE: equal: "Don't know if nodes of type xxx are equal".
I did not have time to add comparsion support for all the needed nodes,
but the default behaviour of the function equal met my requirements.
I did not dare to supress this message!
That's the reason why the regression test for union will fail: These
messages are also included in the union.out file!
-) Somebody of you changed the union_planner() function for v6.4
(I copied the targetlist to new_tlist and that was removed and
replaced by a cleanup of the original targetlist). These chnages
violated some having queries executed against views so I changed
it back again. I did not have time to examine the differences between the
two versions but now it works :-)
If you want to find out, try the file queries/view_having.sql on
both versions and compare the results . Two queries won't produce a
correct result with your version.
regards
Stefan
1999-01-18 01:10:17 +01:00
|
|
|
$4->relname = $3;
|
1999-07-20 02:18:01 +02:00
|
|
|
$$ = (Node *) $4;
|
1997-09-08 05:20:18 +02:00
|
|
|
}
|
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1999-07-17 00:29:42 +02:00
|
|
|
insert_rest: VALUES '(' target_list ')'
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
1998-01-09 21:06:08 +01:00
|
|
|
$$ = makeNode(InsertStmt);
|
Hi!
INTERSECT and EXCEPT is available for postgresql-v6.4!
The patch against v6.4 is included at the end of the current text
(in uuencoded form!)
I also included the text of my Master's Thesis. (a postscript
version). I hope that you find something of it useful and would be
happy if parts of it find their way into the PostgreSQL documentation
project (If so, tell me, then I send the sources of the document!)
The contents of the document are:
-) The first chapter might be of less interest as it gives only an
overview on SQL.
-) The second chapter gives a description on much of PostgreSQL's
features (like user defined types etc. and how to use these features)
-) The third chapter starts with an overview of PostgreSQL's internal
structure with focus on the stages a query has to pass (i.e. parser,
planner/optimizer, executor). Then a detailed description of the
implementation of the Having clause and the Intersect/Except logic is
given.
Originally I worked on v6.3.2 but never found time enough to prepare
and post a patch. Now I applied the changes to v6.4 to get Intersect
and Except working with the new version. Chapter 3 of my documentation
deals with the changes against v6.3.2, so keep that in mind when
comparing the parts of the code printed there with the patched sources
of v6.4.
Here are some remarks on the patch. There are some things that have
still to be done but at the moment I don't have time to do them
myself. (I'm doing my military service at the moment) Sorry for that
:-(
-) I used a rewrite technique for the implementation of the Except/Intersect
logic which rewrites the query to a semantically equivalent query before
it is handed to the rewrite system (for views, rules etc.), planner,
executor etc.
-) In v6.3.2 the types of the attributes of two select statements
connected by the UNION keyword had to match 100%. In v6.4 the types
only need to be familiar (i.e. int and float can be mixed). Since this
feature did not exist when I worked on Intersect/Except it
does not work correctly for Except/Intersect queries WHEN USED IN
COMBINATION WITH UNIONS! (i.e. sometimes the wrong type is used for the
resulting table. This is because until now the types of the attributes of
the first select statement have been used for the resulting table.
When Intersects and/or Excepts are used in combination with Unions it
might happen, that the first select statement of the original query
appears at another position in the query which will be executed. The reason
for this is the technique used for the implementation of
Except/Intersect which does a query rewrite!)
NOTE: It is NOT broken for pure UNION queries and pure INTERSECT/EXCEPT
queries!!!
-) I had to add the field intersect_clause to some data structures
but did not find time to implement printfuncs for the new field.
This does NOT break the debug modes but when an Except/Intersect
is used the query debug output will be the already rewritten query.
-) Massive changes to the grammar rules for SELECT and INSERT statements
have been necessary (see comments in gram.y and documentation for
deatails) in order to be able to use mixed queries like
(SELECT ... UNION (SELECT ... EXCEPT SELECT)) INTERSECT SELECT...;
-) When using UNION/EXCEPT/INTERSECT you will get:
NOTICE: equal: "Don't know if nodes of type xxx are equal".
I did not have time to add comparsion support for all the needed nodes,
but the default behaviour of the function equal met my requirements.
I did not dare to supress this message!
That's the reason why the regression test for union will fail: These
messages are also included in the union.out file!
-) Somebody of you changed the union_planner() function for v6.4
(I copied the targetlist to new_tlist and that was removed and
replaced by a cleanup of the original targetlist). These chnages
violated some having queries executed against views so I changed
it back again. I did not have time to examine the differences between the
two versions but now it works :-)
If you want to find out, try the file queries/view_having.sql on
both versions and compare the results . Two queries won't produce a
correct result with your version.
regards
Stefan
1999-01-18 01:10:17 +01:00
|
|
|
$$->cols = NULL;
|
1998-01-11 04:41:57 +01:00
|
|
|
$$->unique = NULL;
|
1997-09-08 05:20:18 +02:00
|
|
|
$$->targetList = $3;
|
|
|
|
$$->fromClause = NIL;
|
1998-01-17 05:53:46 +01:00
|
|
|
$$->whereClause = NULL;
|
1998-01-11 04:41:57 +01:00
|
|
|
$$->groupClause = NIL;
|
1998-01-17 05:53:46 +01:00
|
|
|
$$->havingClause = NULL;
|
1998-01-11 04:41:57 +01:00
|
|
|
$$->unionClause = NIL;
|
1997-09-08 05:20:18 +02:00
|
|
|
}
|
1998-09-02 17:47:30 +02:00
|
|
|
| DEFAULT VALUES
|
|
|
|
{
|
|
|
|
$$ = makeNode(InsertStmt);
|
|
|
|
$$->unique = NULL;
|
|
|
|
$$->targetList = NIL;
|
|
|
|
$$->fromClause = NIL;
|
|
|
|
$$->whereClause = NULL;
|
|
|
|
$$->groupClause = NIL;
|
|
|
|
$$->havingClause = NULL;
|
|
|
|
$$->unionClause = NIL;
|
Hi!
INTERSECT and EXCEPT is available for postgresql-v6.4!
The patch against v6.4 is included at the end of the current text
(in uuencoded form!)
I also included the text of my Master's Thesis. (a postscript
version). I hope that you find something of it useful and would be
happy if parts of it find their way into the PostgreSQL documentation
project (If so, tell me, then I send the sources of the document!)
The contents of the document are:
-) The first chapter might be of less interest as it gives only an
overview on SQL.
-) The second chapter gives a description on much of PostgreSQL's
features (like user defined types etc. and how to use these features)
-) The third chapter starts with an overview of PostgreSQL's internal
structure with focus on the stages a query has to pass (i.e. parser,
planner/optimizer, executor). Then a detailed description of the
implementation of the Having clause and the Intersect/Except logic is
given.
Originally I worked on v6.3.2 but never found time enough to prepare
and post a patch. Now I applied the changes to v6.4 to get Intersect
and Except working with the new version. Chapter 3 of my documentation
deals with the changes against v6.3.2, so keep that in mind when
comparing the parts of the code printed there with the patched sources
of v6.4.
Here are some remarks on the patch. There are some things that have
still to be done but at the moment I don't have time to do them
myself. (I'm doing my military service at the moment) Sorry for that
:-(
-) I used a rewrite technique for the implementation of the Except/Intersect
logic which rewrites the query to a semantically equivalent query before
it is handed to the rewrite system (for views, rules etc.), planner,
executor etc.
-) In v6.3.2 the types of the attributes of two select statements
connected by the UNION keyword had to match 100%. In v6.4 the types
only need to be familiar (i.e. int and float can be mixed). Since this
feature did not exist when I worked on Intersect/Except it
does not work correctly for Except/Intersect queries WHEN USED IN
COMBINATION WITH UNIONS! (i.e. sometimes the wrong type is used for the
resulting table. This is because until now the types of the attributes of
the first select statement have been used for the resulting table.
When Intersects and/or Excepts are used in combination with Unions it
might happen, that the first select statement of the original query
appears at another position in the query which will be executed. The reason
for this is the technique used for the implementation of
Except/Intersect which does a query rewrite!)
NOTE: It is NOT broken for pure UNION queries and pure INTERSECT/EXCEPT
queries!!!
-) I had to add the field intersect_clause to some data structures
but did not find time to implement printfuncs for the new field.
This does NOT break the debug modes but when an Except/Intersect
is used the query debug output will be the already rewritten query.
-) Massive changes to the grammar rules for SELECT and INSERT statements
have been necessary (see comments in gram.y and documentation for
deatails) in order to be able to use mixed queries like
(SELECT ... UNION (SELECT ... EXCEPT SELECT)) INTERSECT SELECT...;
-) When using UNION/EXCEPT/INTERSECT you will get:
NOTICE: equal: "Don't know if nodes of type xxx are equal".
I did not have time to add comparsion support for all the needed nodes,
but the default behaviour of the function equal met my requirements.
I did not dare to supress this message!
That's the reason why the regression test for union will fail: These
messages are also included in the union.out file!
-) Somebody of you changed the union_planner() function for v6.4
(I copied the targetlist to new_tlist and that was removed and
replaced by a cleanup of the original targetlist). These chnages
violated some having queries executed against views so I changed
it back again. I did not have time to examine the differences between the
two versions but now it works :-)
If you want to find out, try the file queries/view_having.sql on
both versions and compare the results . Two queries won't produce a
correct result with your version.
regards
Stefan
1999-01-18 01:10:17 +01:00
|
|
|
$$->intersectClause = NIL;
|
1998-09-02 17:47:30 +02:00
|
|
|
}
|
1999-07-20 02:18:01 +02:00
|
|
|
/* We want the full power of SelectStatements including INTERSECT and EXCEPT
|
|
|
|
* for insertion. However, we can't support sort or limit clauses.
|
|
|
|
*/
|
Hi!
INTERSECT and EXCEPT is available for postgresql-v6.4!
The patch against v6.4 is included at the end of the current text
(in uuencoded form!)
I also included the text of my Master's Thesis. (a postscript
version). I hope that you find something of it useful and would be
happy if parts of it find their way into the PostgreSQL documentation
project (If so, tell me, then I send the sources of the document!)
The contents of the document are:
-) The first chapter might be of less interest as it gives only an
overview on SQL.
-) The second chapter gives a description on much of PostgreSQL's
features (like user defined types etc. and how to use these features)
-) The third chapter starts with an overview of PostgreSQL's internal
structure with focus on the stages a query has to pass (i.e. parser,
planner/optimizer, executor). Then a detailed description of the
implementation of the Having clause and the Intersect/Except logic is
given.
Originally I worked on v6.3.2 but never found time enough to prepare
and post a patch. Now I applied the changes to v6.4 to get Intersect
and Except working with the new version. Chapter 3 of my documentation
deals with the changes against v6.3.2, so keep that in mind when
comparing the parts of the code printed there with the patched sources
of v6.4.
Here are some remarks on the patch. There are some things that have
still to be done but at the moment I don't have time to do them
myself. (I'm doing my military service at the moment) Sorry for that
:-(
-) I used a rewrite technique for the implementation of the Except/Intersect
logic which rewrites the query to a semantically equivalent query before
it is handed to the rewrite system (for views, rules etc.), planner,
executor etc.
-) In v6.3.2 the types of the attributes of two select statements
connected by the UNION keyword had to match 100%. In v6.4 the types
only need to be familiar (i.e. int and float can be mixed). Since this
feature did not exist when I worked on Intersect/Except it
does not work correctly for Except/Intersect queries WHEN USED IN
COMBINATION WITH UNIONS! (i.e. sometimes the wrong type is used for the
resulting table. This is because until now the types of the attributes of
the first select statement have been used for the resulting table.
When Intersects and/or Excepts are used in combination with Unions it
might happen, that the first select statement of the original query
appears at another position in the query which will be executed. The reason
for this is the technique used for the implementation of
Except/Intersect which does a query rewrite!)
NOTE: It is NOT broken for pure UNION queries and pure INTERSECT/EXCEPT
queries!!!
-) I had to add the field intersect_clause to some data structures
but did not find time to implement printfuncs for the new field.
This does NOT break the debug modes but when an Except/Intersect
is used the query debug output will be the already rewritten query.
-) Massive changes to the grammar rules for SELECT and INSERT statements
have been necessary (see comments in gram.y and documentation for
deatails) in order to be able to use mixed queries like
(SELECT ... UNION (SELECT ... EXCEPT SELECT)) INTERSECT SELECT...;
-) When using UNION/EXCEPT/INTERSECT you will get:
NOTICE: equal: "Don't know if nodes of type xxx are equal".
I did not have time to add comparsion support for all the needed nodes,
but the default behaviour of the function equal met my requirements.
I did not dare to supress this message!
That's the reason why the regression test for union will fail: These
messages are also included in the union.out file!
-) Somebody of you changed the union_planner() function for v6.4
(I copied the targetlist to new_tlist and that was removed and
replaced by a cleanup of the original targetlist). These chnages
violated some having queries executed against views so I changed
it back again. I did not have time to examine the differences between the
two versions but now it works :-)
If you want to find out, try the file queries/view_having.sql on
both versions and compare the results . Two queries won't produce a
correct result with your version.
regards
Stefan
1999-01-18 01:10:17 +01:00
|
|
|
| SelectStmt
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
1999-07-20 02:18:01 +02:00
|
|
|
SelectStmt *n = (SelectStmt *) $1;
|
|
|
|
if (n->sortClause)
|
|
|
|
elog(ERROR, "INSERT ... SELECT can't have ORDER BY");
|
1998-01-09 21:06:08 +01:00
|
|
|
$$ = makeNode(InsertStmt);
|
1999-07-20 02:18:01 +02:00
|
|
|
$$->cols = NIL;
|
Hi!
INTERSECT and EXCEPT is available for postgresql-v6.4!
The patch against v6.4 is included at the end of the current text
(in uuencoded form!)
I also included the text of my Master's Thesis. (a postscript
version). I hope that you find something of it useful and would be
happy if parts of it find their way into the PostgreSQL documentation
project (If so, tell me, then I send the sources of the document!)
The contents of the document are:
-) The first chapter might be of less interest as it gives only an
overview on SQL.
-) The second chapter gives a description on much of PostgreSQL's
features (like user defined types etc. and how to use these features)
-) The third chapter starts with an overview of PostgreSQL's internal
structure with focus on the stages a query has to pass (i.e. parser,
planner/optimizer, executor). Then a detailed description of the
implementation of the Having clause and the Intersect/Except logic is
given.
Originally I worked on v6.3.2 but never found time enough to prepare
and post a patch. Now I applied the changes to v6.4 to get Intersect
and Except working with the new version. Chapter 3 of my documentation
deals with the changes against v6.3.2, so keep that in mind when
comparing the parts of the code printed there with the patched sources
of v6.4.
Here are some remarks on the patch. There are some things that have
still to be done but at the moment I don't have time to do them
myself. (I'm doing my military service at the moment) Sorry for that
:-(
-) I used a rewrite technique for the implementation of the Except/Intersect
logic which rewrites the query to a semantically equivalent query before
it is handed to the rewrite system (for views, rules etc.), planner,
executor etc.
-) In v6.3.2 the types of the attributes of two select statements
connected by the UNION keyword had to match 100%. In v6.4 the types
only need to be familiar (i.e. int and float can be mixed). Since this
feature did not exist when I worked on Intersect/Except it
does not work correctly for Except/Intersect queries WHEN USED IN
COMBINATION WITH UNIONS! (i.e. sometimes the wrong type is used for the
resulting table. This is because until now the types of the attributes of
the first select statement have been used for the resulting table.
When Intersects and/or Excepts are used in combination with Unions it
might happen, that the first select statement of the original query
appears at another position in the query which will be executed. The reason
for this is the technique used for the implementation of
Except/Intersect which does a query rewrite!)
NOTE: It is NOT broken for pure UNION queries and pure INTERSECT/EXCEPT
queries!!!
-) I had to add the field intersect_clause to some data structures
but did not find time to implement printfuncs for the new field.
This does NOT break the debug modes but when an Except/Intersect
is used the query debug output will be the already rewritten query.
-) Massive changes to the grammar rules for SELECT and INSERT statements
have been necessary (see comments in gram.y and documentation for
deatails) in order to be able to use mixed queries like
(SELECT ... UNION (SELECT ... EXCEPT SELECT)) INTERSECT SELECT...;
-) When using UNION/EXCEPT/INTERSECT you will get:
NOTICE: equal: "Don't know if nodes of type xxx are equal".
I did not have time to add comparsion support for all the needed nodes,
but the default behaviour of the function equal met my requirements.
I did not dare to supress this message!
That's the reason why the regression test for union will fail: These
messages are also included in the union.out file!
-) Somebody of you changed the union_planner() function for v6.4
(I copied the targetlist to new_tlist and that was removed and
replaced by a cleanup of the original targetlist). These chnages
violated some having queries executed against views so I changed
it back again. I did not have time to examine the differences between the
two versions but now it works :-)
If you want to find out, try the file queries/view_having.sql on
both versions and compare the results . Two queries won't produce a
correct result with your version.
regards
Stefan
1999-01-18 01:10:17 +01:00
|
|
|
$$->unique = n->unique;
|
|
|
|
$$->targetList = n->targetList;
|
|
|
|
$$->fromClause = n->fromClause;
|
|
|
|
$$->whereClause = n->whereClause;
|
|
|
|
$$->groupClause = n->groupClause;
|
|
|
|
$$->havingClause = n->havingClause;
|
|
|
|
$$->unionClause = n->unionClause;
|
|
|
|
$$->intersectClause = n->intersectClause;
|
1999-07-20 02:18:01 +02:00
|
|
|
$$->unionall = n->unionall;
|
1999-01-21 17:08:55 +01:00
|
|
|
$$->forUpdate = n->forUpdate;
|
Hi!
INTERSECT and EXCEPT is available for postgresql-v6.4!
The patch against v6.4 is included at the end of the current text
(in uuencoded form!)
I also included the text of my Master's Thesis. (a postscript
version). I hope that you find something of it useful and would be
happy if parts of it find their way into the PostgreSQL documentation
project (If so, tell me, then I send the sources of the document!)
The contents of the document are:
-) The first chapter might be of less interest as it gives only an
overview on SQL.
-) The second chapter gives a description on much of PostgreSQL's
features (like user defined types etc. and how to use these features)
-) The third chapter starts with an overview of PostgreSQL's internal
structure with focus on the stages a query has to pass (i.e. parser,
planner/optimizer, executor). Then a detailed description of the
implementation of the Having clause and the Intersect/Except logic is
given.
Originally I worked on v6.3.2 but never found time enough to prepare
and post a patch. Now I applied the changes to v6.4 to get Intersect
and Except working with the new version. Chapter 3 of my documentation
deals with the changes against v6.3.2, so keep that in mind when
comparing the parts of the code printed there with the patched sources
of v6.4.
Here are some remarks on the patch. There are some things that have
still to be done but at the moment I don't have time to do them
myself. (I'm doing my military service at the moment) Sorry for that
:-(
-) I used a rewrite technique for the implementation of the Except/Intersect
logic which rewrites the query to a semantically equivalent query before
it is handed to the rewrite system (for views, rules etc.), planner,
executor etc.
-) In v6.3.2 the types of the attributes of two select statements
connected by the UNION keyword had to match 100%. In v6.4 the types
only need to be familiar (i.e. int and float can be mixed). Since this
feature did not exist when I worked on Intersect/Except it
does not work correctly for Except/Intersect queries WHEN USED IN
COMBINATION WITH UNIONS! (i.e. sometimes the wrong type is used for the
resulting table. This is because until now the types of the attributes of
the first select statement have been used for the resulting table.
When Intersects and/or Excepts are used in combination with Unions it
might happen, that the first select statement of the original query
appears at another position in the query which will be executed. The reason
for this is the technique used for the implementation of
Except/Intersect which does a query rewrite!)
NOTE: It is NOT broken for pure UNION queries and pure INTERSECT/EXCEPT
queries!!!
-) I had to add the field intersect_clause to some data structures
but did not find time to implement printfuncs for the new field.
This does NOT break the debug modes but when an Except/Intersect
is used the query debug output will be the already rewritten query.
-) Massive changes to the grammar rules for SELECT and INSERT statements
have been necessary (see comments in gram.y and documentation for
deatails) in order to be able to use mixed queries like
(SELECT ... UNION (SELECT ... EXCEPT SELECT)) INTERSECT SELECT...;
-) When using UNION/EXCEPT/INTERSECT you will get:
NOTICE: equal: "Don't know if nodes of type xxx are equal".
I did not have time to add comparsion support for all the needed nodes,
but the default behaviour of the function equal met my requirements.
I did not dare to supress this message!
That's the reason why the regression test for union will fail: These
messages are also included in the union.out file!
-) Somebody of you changed the union_planner() function for v6.4
(I copied the targetlist to new_tlist and that was removed and
replaced by a cleanup of the original targetlist). These chnages
violated some having queries executed against views so I changed
it back again. I did not have time to examine the differences between the
two versions but now it works :-)
If you want to find out, try the file queries/view_having.sql on
both versions and compare the results . Two queries won't produce a
correct result with your version.
regards
Stefan
1999-01-18 01:10:17 +01:00
|
|
|
}
|
1999-07-17 00:29:42 +02:00
|
|
|
| '(' columnList ')' VALUES '(' target_list ')'
|
Hi!
INTERSECT and EXCEPT is available for postgresql-v6.4!
The patch against v6.4 is included at the end of the current text
(in uuencoded form!)
I also included the text of my Master's Thesis. (a postscript
version). I hope that you find something of it useful and would be
happy if parts of it find their way into the PostgreSQL documentation
project (If so, tell me, then I send the sources of the document!)
The contents of the document are:
-) The first chapter might be of less interest as it gives only an
overview on SQL.
-) The second chapter gives a description on much of PostgreSQL's
features (like user defined types etc. and how to use these features)
-) The third chapter starts with an overview of PostgreSQL's internal
structure with focus on the stages a query has to pass (i.e. parser,
planner/optimizer, executor). Then a detailed description of the
implementation of the Having clause and the Intersect/Except logic is
given.
Originally I worked on v6.3.2 but never found time enough to prepare
and post a patch. Now I applied the changes to v6.4 to get Intersect
and Except working with the new version. Chapter 3 of my documentation
deals with the changes against v6.3.2, so keep that in mind when
comparing the parts of the code printed there with the patched sources
of v6.4.
Here are some remarks on the patch. There are some things that have
still to be done but at the moment I don't have time to do them
myself. (I'm doing my military service at the moment) Sorry for that
:-(
-) I used a rewrite technique for the implementation of the Except/Intersect
logic which rewrites the query to a semantically equivalent query before
it is handed to the rewrite system (for views, rules etc.), planner,
executor etc.
-) In v6.3.2 the types of the attributes of two select statements
connected by the UNION keyword had to match 100%. In v6.4 the types
only need to be familiar (i.e. int and float can be mixed). Since this
feature did not exist when I worked on Intersect/Except it
does not work correctly for Except/Intersect queries WHEN USED IN
COMBINATION WITH UNIONS! (i.e. sometimes the wrong type is used for the
resulting table. This is because until now the types of the attributes of
the first select statement have been used for the resulting table.
When Intersects and/or Excepts are used in combination with Unions it
might happen, that the first select statement of the original query
appears at another position in the query which will be executed. The reason
for this is the technique used for the implementation of
Except/Intersect which does a query rewrite!)
NOTE: It is NOT broken for pure UNION queries and pure INTERSECT/EXCEPT
queries!!!
-) I had to add the field intersect_clause to some data structures
but did not find time to implement printfuncs for the new field.
This does NOT break the debug modes but when an Except/Intersect
is used the query debug output will be the already rewritten query.
-) Massive changes to the grammar rules for SELECT and INSERT statements
have been necessary (see comments in gram.y and documentation for
deatails) in order to be able to use mixed queries like
(SELECT ... UNION (SELECT ... EXCEPT SELECT)) INTERSECT SELECT...;
-) When using UNION/EXCEPT/INTERSECT you will get:
NOTICE: equal: "Don't know if nodes of type xxx are equal".
I did not have time to add comparsion support for all the needed nodes,
but the default behaviour of the function equal met my requirements.
I did not dare to supress this message!
That's the reason why the regression test for union will fail: These
messages are also included in the union.out file!
-) Somebody of you changed the union_planner() function for v6.4
(I copied the targetlist to new_tlist and that was removed and
replaced by a cleanup of the original targetlist). These chnages
violated some having queries executed against views so I changed
it back again. I did not have time to examine the differences between the
two versions but now it works :-)
If you want to find out, try the file queries/view_having.sql on
both versions and compare the results . Two queries won't produce a
correct result with your version.
regards
Stefan
1999-01-18 01:10:17 +01:00
|
|
|
{
|
|
|
|
$$ = makeNode(InsertStmt);
|
|
|
|
$$->cols = $2;
|
|
|
|
$$->unique = NULL;
|
|
|
|
$$->targetList = $6;
|
|
|
|
$$->fromClause = NIL;
|
|
|
|
$$->whereClause = NULL;
|
|
|
|
$$->groupClause = NIL;
|
|
|
|
$$->havingClause = NULL;
|
|
|
|
$$->unionClause = NIL;
|
|
|
|
$$->intersectClause = NIL;
|
|
|
|
}
|
|
|
|
| '(' columnList ')' SelectStmt
|
|
|
|
{
|
1999-07-20 02:18:01 +02:00
|
|
|
SelectStmt *n = (SelectStmt *) $4;
|
|
|
|
if (n->sortClause)
|
|
|
|
elog(ERROR, "INSERT ... SELECT can't have ORDER BY");
|
Hi!
INTERSECT and EXCEPT is available for postgresql-v6.4!
The patch against v6.4 is included at the end of the current text
(in uuencoded form!)
I also included the text of my Master's Thesis. (a postscript
version). I hope that you find something of it useful and would be
happy if parts of it find their way into the PostgreSQL documentation
project (If so, tell me, then I send the sources of the document!)
The contents of the document are:
-) The first chapter might be of less interest as it gives only an
overview on SQL.
-) The second chapter gives a description on much of PostgreSQL's
features (like user defined types etc. and how to use these features)
-) The third chapter starts with an overview of PostgreSQL's internal
structure with focus on the stages a query has to pass (i.e. parser,
planner/optimizer, executor). Then a detailed description of the
implementation of the Having clause and the Intersect/Except logic is
given.
Originally I worked on v6.3.2 but never found time enough to prepare
and post a patch. Now I applied the changes to v6.4 to get Intersect
and Except working with the new version. Chapter 3 of my documentation
deals with the changes against v6.3.2, so keep that in mind when
comparing the parts of the code printed there with the patched sources
of v6.4.
Here are some remarks on the patch. There are some things that have
still to be done but at the moment I don't have time to do them
myself. (I'm doing my military service at the moment) Sorry for that
:-(
-) I used a rewrite technique for the implementation of the Except/Intersect
logic which rewrites the query to a semantically equivalent query before
it is handed to the rewrite system (for views, rules etc.), planner,
executor etc.
-) In v6.3.2 the types of the attributes of two select statements
connected by the UNION keyword had to match 100%. In v6.4 the types
only need to be familiar (i.e. int and float can be mixed). Since this
feature did not exist when I worked on Intersect/Except it
does not work correctly for Except/Intersect queries WHEN USED IN
COMBINATION WITH UNIONS! (i.e. sometimes the wrong type is used for the
resulting table. This is because until now the types of the attributes of
the first select statement have been used for the resulting table.
When Intersects and/or Excepts are used in combination with Unions it
might happen, that the first select statement of the original query
appears at another position in the query which will be executed. The reason
for this is the technique used for the implementation of
Except/Intersect which does a query rewrite!)
NOTE: It is NOT broken for pure UNION queries and pure INTERSECT/EXCEPT
queries!!!
-) I had to add the field intersect_clause to some data structures
but did not find time to implement printfuncs for the new field.
This does NOT break the debug modes but when an Except/Intersect
is used the query debug output will be the already rewritten query.
-) Massive changes to the grammar rules for SELECT and INSERT statements
have been necessary (see comments in gram.y and documentation for
deatails) in order to be able to use mixed queries like
(SELECT ... UNION (SELECT ... EXCEPT SELECT)) INTERSECT SELECT...;
-) When using UNION/EXCEPT/INTERSECT you will get:
NOTICE: equal: "Don't know if nodes of type xxx are equal".
I did not have time to add comparsion support for all the needed nodes,
but the default behaviour of the function equal met my requirements.
I did not dare to supress this message!
That's the reason why the regression test for union will fail: These
messages are also included in the union.out file!
-) Somebody of you changed the union_planner() function for v6.4
(I copied the targetlist to new_tlist and that was removed and
replaced by a cleanup of the original targetlist). These chnages
violated some having queries executed against views so I changed
it back again. I did not have time to examine the differences between the
two versions but now it works :-)
If you want to find out, try the file queries/view_having.sql on
both versions and compare the results . Two queries won't produce a
correct result with your version.
regards
Stefan
1999-01-18 01:10:17 +01:00
|
|
|
$$ = makeNode(InsertStmt);
|
|
|
|
$$->cols = $2;
|
|
|
|
$$->unique = n->unique;
|
|
|
|
$$->targetList = n->targetList;
|
|
|
|
$$->fromClause = n->fromClause;
|
|
|
|
$$->whereClause = n->whereClause;
|
|
|
|
$$->groupClause = n->groupClause;
|
|
|
|
$$->havingClause = n->havingClause;
|
|
|
|
$$->unionClause = n->unionClause;
|
|
|
|
$$->intersectClause = n->intersectClause;
|
1999-07-20 02:18:01 +02:00
|
|
|
$$->unionall = n->unionall;
|
|
|
|
$$->forUpdate = n->forUpdate;
|
1997-09-08 05:20:18 +02:00
|
|
|
}
|
|
|
|
;
|
|
|
|
|
1997-11-07 08:02:10 +01:00
|
|
|
opt_column_list: '(' columnList ')' { $$ = $2; }
|
1997-09-08 05:20:18 +02:00
|
|
|
| /*EMPTY*/ { $$ = NIL; }
|
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-01 08:00:35 +02:00
|
|
|
columnList:
|
1997-09-08 05:20:18 +02:00
|
|
|
columnList ',' columnElem
|
|
|
|
{ $$ = lappend($1, $3); }
|
|
|
|
| columnElem
|
|
|
|
{ $$ = lcons($1, NIL); }
|
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-11-07 08:02:10 +01:00
|
|
|
columnElem: ColId opt_indirection
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
Ident *id = makeNode(Ident);
|
|
|
|
id->name = $1;
|
|
|
|
id->indirection = $2;
|
|
|
|
$$ = (Node *)id;
|
|
|
|
}
|
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-10-25 07:56:41 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*****************************************************************************
|
|
|
|
*
|
1997-09-08 05:20:18 +02:00
|
|
|
* QUERY:
|
|
|
|
* DELETE STATEMENTS
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*****************************************************************************/
|
1997-09-01 08:00:35 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
DeleteStmt: DELETE FROM relation_name
|
1997-09-08 05:20:18 +02:00
|
|
|
where_clause
|
|
|
|
{
|
|
|
|
DeleteStmt *n = makeNode(DeleteStmt);
|
|
|
|
n->relname = $3;
|
|
|
|
n->whereClause = $4;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1999-05-17 03:01:06 +02:00
|
|
|
LockStmt: LOCK_P opt_table relation_name opt_lock
|
1998-01-23 00:05:18 +01:00
|
|
|
{
|
1998-12-18 10:10:39 +01:00
|
|
|
LockStmt *n = makeNode(LockStmt);
|
|
|
|
|
|
|
|
n->relname = $3;
|
1999-05-17 03:01:06 +02:00
|
|
|
n->mode = $4;
|
1998-12-18 10:10:39 +01:00
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
1999-05-12 09:22:52 +02:00
|
|
|
;
|
1998-12-18 10:10:39 +01:00
|
|
|
|
1999-05-17 03:01:06 +02:00
|
|
|
opt_lock: IN lock_type MODE { $$ = $2; }
|
1999-05-12 09:22:52 +02:00
|
|
|
| /*EMPTY*/ { $$ = AccessExclusiveLock; }
|
|
|
|
;
|
1998-01-23 00:05:18 +01:00
|
|
|
|
1999-05-12 09:22:52 +02:00
|
|
|
lock_type: SHARE ROW EXCLUSIVE { $$ = ShareRowExclusiveLock; }
|
|
|
|
| ROW opt_lmode { $$ = ($2? RowShareLock: RowExclusiveLock); }
|
|
|
|
| ACCESS opt_lmode { $$ = ($2? AccessShareLock: AccessExclusiveLock); }
|
|
|
|
| opt_lmode { $$ = ($1? ShareLock: ExclusiveLock); }
|
1998-01-23 00:05:18 +01:00
|
|
|
;
|
|
|
|
|
1999-05-12 09:22:52 +02:00
|
|
|
opt_lmode: SHARE { $$ = TRUE; }
|
|
|
|
| EXCLUSIVE { $$ = FALSE; }
|
1998-12-18 10:10:39 +01:00
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1999-05-12 09:22:52 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*****************************************************************************
|
|
|
|
*
|
1997-09-08 05:20:18 +02:00
|
|
|
* QUERY:
|
1998-01-09 21:06:08 +01:00
|
|
|
* UpdateStmt (UPDATE)
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
|
1998-01-09 21:06:08 +01:00
|
|
|
UpdateStmt: UPDATE relation_name
|
1999-07-17 00:29:42 +02:00
|
|
|
SET update_target_list
|
1997-09-08 05:20:18 +02:00
|
|
|
from_clause
|
|
|
|
where_clause
|
|
|
|
{
|
1998-01-09 21:06:08 +01:00
|
|
|
UpdateStmt *n = makeNode(UpdateStmt);
|
1997-09-08 05:20:18 +02:00
|
|
|
n->relname = $2;
|
|
|
|
n->targetList = $4;
|
|
|
|
n->fromClause = $5;
|
|
|
|
n->whereClause = $6;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
;
|
1997-09-01 08:00:35 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
*
|
1997-09-08 05:20:18 +02:00
|
|
|
* QUERY:
|
|
|
|
* CURSOR STATEMENTS
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*****************************************************************************/
|
1999-05-20 14:12:55 +02:00
|
|
|
CursorStmt: DECLARE name opt_cursor CURSOR FOR SelectStmt
|
Hi!
INTERSECT and EXCEPT is available for postgresql-v6.4!
The patch against v6.4 is included at the end of the current text
(in uuencoded form!)
I also included the text of my Master's Thesis. (a postscript
version). I hope that you find something of it useful and would be
happy if parts of it find their way into the PostgreSQL documentation
project (If so, tell me, then I send the sources of the document!)
The contents of the document are:
-) The first chapter might be of less interest as it gives only an
overview on SQL.
-) The second chapter gives a description on much of PostgreSQL's
features (like user defined types etc. and how to use these features)
-) The third chapter starts with an overview of PostgreSQL's internal
structure with focus on the stages a query has to pass (i.e. parser,
planner/optimizer, executor). Then a detailed description of the
implementation of the Having clause and the Intersect/Except logic is
given.
Originally I worked on v6.3.2 but never found time enough to prepare
and post a patch. Now I applied the changes to v6.4 to get Intersect
and Except working with the new version. Chapter 3 of my documentation
deals with the changes against v6.3.2, so keep that in mind when
comparing the parts of the code printed there with the patched sources
of v6.4.
Here are some remarks on the patch. There are some things that have
still to be done but at the moment I don't have time to do them
myself. (I'm doing my military service at the moment) Sorry for that
:-(
-) I used a rewrite technique for the implementation of the Except/Intersect
logic which rewrites the query to a semantically equivalent query before
it is handed to the rewrite system (for views, rules etc.), planner,
executor etc.
-) In v6.3.2 the types of the attributes of two select statements
connected by the UNION keyword had to match 100%. In v6.4 the types
only need to be familiar (i.e. int and float can be mixed). Since this
feature did not exist when I worked on Intersect/Except it
does not work correctly for Except/Intersect queries WHEN USED IN
COMBINATION WITH UNIONS! (i.e. sometimes the wrong type is used for the
resulting table. This is because until now the types of the attributes of
the first select statement have been used for the resulting table.
When Intersects and/or Excepts are used in combination with Unions it
might happen, that the first select statement of the original query
appears at another position in the query which will be executed. The reason
for this is the technique used for the implementation of
Except/Intersect which does a query rewrite!)
NOTE: It is NOT broken for pure UNION queries and pure INTERSECT/EXCEPT
queries!!!
-) I had to add the field intersect_clause to some data structures
but did not find time to implement printfuncs for the new field.
This does NOT break the debug modes but when an Except/Intersect
is used the query debug output will be the already rewritten query.
-) Massive changes to the grammar rules for SELECT and INSERT statements
have been necessary (see comments in gram.y and documentation for
deatails) in order to be able to use mixed queries like
(SELECT ... UNION (SELECT ... EXCEPT SELECT)) INTERSECT SELECT...;
-) When using UNION/EXCEPT/INTERSECT you will get:
NOTICE: equal: "Don't know if nodes of type xxx are equal".
I did not have time to add comparsion support for all the needed nodes,
but the default behaviour of the function equal met my requirements.
I did not dare to supress this message!
That's the reason why the regression test for union will fail: These
messages are also included in the union.out file!
-) Somebody of you changed the union_planner() function for v6.4
(I copied the targetlist to new_tlist and that was removed and
replaced by a cleanup of the original targetlist). These chnages
violated some having queries executed against views so I changed
it back again. I did not have time to examine the differences between the
two versions but now it works :-)
If you want to find out, try the file queries/view_having.sql on
both versions and compare the results . Two queries won't produce a
correct result with your version.
regards
Stefan
1999-01-18 01:10:17 +01:00
|
|
|
{
|
|
|
|
SelectStmt *n;
|
|
|
|
|
|
|
|
n= (SelectStmt *)$6;
|
|
|
|
/* from PORTAL name */
|
|
|
|
/*
|
|
|
|
* 15 august 1991 -- since 3.0 postgres does locking
|
1997-09-08 05:20:18 +02:00
|
|
|
* right, we discovered that portals were violating
|
|
|
|
* locking protocol. portal locks cannot span xacts.
|
|
|
|
* as a short-term fix, we installed the check here.
|
|
|
|
* -- mao
|
|
|
|
*/
|
|
|
|
if (!IsTransactionBlock())
|
1998-01-09 21:06:08 +01:00
|
|
|
elog(ERROR,"Named portals may only be used in begin/end transaction blocks");
|
1997-09-08 05:20:18 +02:00
|
|
|
|
|
|
|
n->portalname = $2;
|
|
|
|
n->binary = $3;
|
1999-05-20 14:12:55 +02:00
|
|
|
if (n->forUpdate != NULL)
|
|
|
|
elog(ERROR,"DECLARE/UPDATE not supported;"
|
|
|
|
" Cursors must be READ ONLY.");
|
1997-09-08 05:20:18 +02:00
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1998-09-13 06:19:33 +02:00
|
|
|
opt_cursor: BINARY { $$ = TRUE; }
|
|
|
|
| INSENSITIVE { $$ = FALSE; }
|
|
|
|
| SCROLL { $$ = FALSE; }
|
|
|
|
| INSENSITIVE SCROLL { $$ = FALSE; }
|
|
|
|
| /*EMPTY*/ { $$ = FALSE; }
|
|
|
|
;
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*****************************************************************************
|
|
|
|
*
|
1997-09-08 05:20:18 +02:00
|
|
|
* QUERY:
|
|
|
|
* SELECT STATEMENTS
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*****************************************************************************/
|
1999-07-20 02:18:01 +02:00
|
|
|
|
|
|
|
/* A complete SELECT statement looks like this. Note sort, for_update,
|
|
|
|
* and limit clauses can only appear once, not in each subselect.
|
Hi!
INTERSECT and EXCEPT is available for postgresql-v6.4!
The patch against v6.4 is included at the end of the current text
(in uuencoded form!)
I also included the text of my Master's Thesis. (a postscript
version). I hope that you find something of it useful and would be
happy if parts of it find their way into the PostgreSQL documentation
project (If so, tell me, then I send the sources of the document!)
The contents of the document are:
-) The first chapter might be of less interest as it gives only an
overview on SQL.
-) The second chapter gives a description on much of PostgreSQL's
features (like user defined types etc. and how to use these features)
-) The third chapter starts with an overview of PostgreSQL's internal
structure with focus on the stages a query has to pass (i.e. parser,
planner/optimizer, executor). Then a detailed description of the
implementation of the Having clause and the Intersect/Except logic is
given.
Originally I worked on v6.3.2 but never found time enough to prepare
and post a patch. Now I applied the changes to v6.4 to get Intersect
and Except working with the new version. Chapter 3 of my documentation
deals with the changes against v6.3.2, so keep that in mind when
comparing the parts of the code printed there with the patched sources
of v6.4.
Here are some remarks on the patch. There are some things that have
still to be done but at the moment I don't have time to do them
myself. (I'm doing my military service at the moment) Sorry for that
:-(
-) I used a rewrite technique for the implementation of the Except/Intersect
logic which rewrites the query to a semantically equivalent query before
it is handed to the rewrite system (for views, rules etc.), planner,
executor etc.
-) In v6.3.2 the types of the attributes of two select statements
connected by the UNION keyword had to match 100%. In v6.4 the types
only need to be familiar (i.e. int and float can be mixed). Since this
feature did not exist when I worked on Intersect/Except it
does not work correctly for Except/Intersect queries WHEN USED IN
COMBINATION WITH UNIONS! (i.e. sometimes the wrong type is used for the
resulting table. This is because until now the types of the attributes of
the first select statement have been used for the resulting table.
When Intersects and/or Excepts are used in combination with Unions it
might happen, that the first select statement of the original query
appears at another position in the query which will be executed. The reason
for this is the technique used for the implementation of
Except/Intersect which does a query rewrite!)
NOTE: It is NOT broken for pure UNION queries and pure INTERSECT/EXCEPT
queries!!!
-) I had to add the field intersect_clause to some data structures
but did not find time to implement printfuncs for the new field.
This does NOT break the debug modes but when an Except/Intersect
is used the query debug output will be the already rewritten query.
-) Massive changes to the grammar rules for SELECT and INSERT statements
have been necessary (see comments in gram.y and documentation for
deatails) in order to be able to use mixed queries like
(SELECT ... UNION (SELECT ... EXCEPT SELECT)) INTERSECT SELECT...;
-) When using UNION/EXCEPT/INTERSECT you will get:
NOTICE: equal: "Don't know if nodes of type xxx are equal".
I did not have time to add comparsion support for all the needed nodes,
but the default behaviour of the function equal met my requirements.
I did not dare to supress this message!
That's the reason why the regression test for union will fail: These
messages are also included in the union.out file!
-) Somebody of you changed the union_planner() function for v6.4
(I copied the targetlist to new_tlist and that was removed and
replaced by a cleanup of the original targetlist). These chnages
violated some having queries executed against views so I changed
it back again. I did not have time to examine the differences between the
two versions but now it works :-)
If you want to find out, try the file queries/view_having.sql on
both versions and compare the results . Two queries won't produce a
correct result with your version.
regards
Stefan
1999-01-18 01:10:17 +01:00
|
|
|
*
|
|
|
|
* The rule returns a SelectStmt Node having the set operations attached to
|
1999-02-23 08:42:41 +01:00
|
|
|
* unionClause and intersectClause (NIL if no set operations were present)
|
|
|
|
*/
|
|
|
|
|
|
|
|
SelectStmt: select_clause sort_clause for_update_clause opt_select_limit
|
Hi!
INTERSECT and EXCEPT is available for postgresql-v6.4!
The patch against v6.4 is included at the end of the current text
(in uuencoded form!)
I also included the text of my Master's Thesis. (a postscript
version). I hope that you find something of it useful and would be
happy if parts of it find their way into the PostgreSQL documentation
project (If so, tell me, then I send the sources of the document!)
The contents of the document are:
-) The first chapter might be of less interest as it gives only an
overview on SQL.
-) The second chapter gives a description on much of PostgreSQL's
features (like user defined types etc. and how to use these features)
-) The third chapter starts with an overview of PostgreSQL's internal
structure with focus on the stages a query has to pass (i.e. parser,
planner/optimizer, executor). Then a detailed description of the
implementation of the Having clause and the Intersect/Except logic is
given.
Originally I worked on v6.3.2 but never found time enough to prepare
and post a patch. Now I applied the changes to v6.4 to get Intersect
and Except working with the new version. Chapter 3 of my documentation
deals with the changes against v6.3.2, so keep that in mind when
comparing the parts of the code printed there with the patched sources
of v6.4.
Here are some remarks on the patch. There are some things that have
still to be done but at the moment I don't have time to do them
myself. (I'm doing my military service at the moment) Sorry for that
:-(
-) I used a rewrite technique for the implementation of the Except/Intersect
logic which rewrites the query to a semantically equivalent query before
it is handed to the rewrite system (for views, rules etc.), planner,
executor etc.
-) In v6.3.2 the types of the attributes of two select statements
connected by the UNION keyword had to match 100%. In v6.4 the types
only need to be familiar (i.e. int and float can be mixed). Since this
feature did not exist when I worked on Intersect/Except it
does not work correctly for Except/Intersect queries WHEN USED IN
COMBINATION WITH UNIONS! (i.e. sometimes the wrong type is used for the
resulting table. This is because until now the types of the attributes of
the first select statement have been used for the resulting table.
When Intersects and/or Excepts are used in combination with Unions it
might happen, that the first select statement of the original query
appears at another position in the query which will be executed. The reason
for this is the technique used for the implementation of
Except/Intersect which does a query rewrite!)
NOTE: It is NOT broken for pure UNION queries and pure INTERSECT/EXCEPT
queries!!!
-) I had to add the field intersect_clause to some data structures
but did not find time to implement printfuncs for the new field.
This does NOT break the debug modes but when an Except/Intersect
is used the query debug output will be the already rewritten query.
-) Massive changes to the grammar rules for SELECT and INSERT statements
have been necessary (see comments in gram.y and documentation for
deatails) in order to be able to use mixed queries like
(SELECT ... UNION (SELECT ... EXCEPT SELECT)) INTERSECT SELECT...;
-) When using UNION/EXCEPT/INTERSECT you will get:
NOTICE: equal: "Don't know if nodes of type xxx are equal".
I did not have time to add comparsion support for all the needed nodes,
but the default behaviour of the function equal met my requirements.
I did not dare to supress this message!
That's the reason why the regression test for union will fail: These
messages are also included in the union.out file!
-) Somebody of you changed the union_planner() function for v6.4
(I copied the targetlist to new_tlist and that was removed and
replaced by a cleanup of the original targetlist). These chnages
violated some having queries executed against views so I changed
it back again. I did not have time to examine the differences between the
two versions but now it works :-)
If you want to find out, try the file queries/view_having.sql on
both versions and compare the results . Two queries won't produce a
correct result with your version.
regards
Stefan
1999-01-18 01:10:17 +01:00
|
|
|
{
|
|
|
|
if IsA($1, SelectStmt)
|
|
|
|
{
|
1999-07-20 02:18:01 +02:00
|
|
|
/* There were no set operations, so just attach the
|
|
|
|
* one-time clauses.
|
|
|
|
*/
|
|
|
|
SelectStmt *n = (SelectStmt *) $1;
|
|
|
|
n->sortClause = $2;
|
|
|
|
n->forUpdate = $3;
|
|
|
|
n->limitOffset = nth(0, $4);
|
|
|
|
n->limitCount = nth(1, $4);
|
|
|
|
$$ = (Node *) n;
|
Hi!
INTERSECT and EXCEPT is available for postgresql-v6.4!
The patch against v6.4 is included at the end of the current text
(in uuencoded form!)
I also included the text of my Master's Thesis. (a postscript
version). I hope that you find something of it useful and would be
happy if parts of it find their way into the PostgreSQL documentation
project (If so, tell me, then I send the sources of the document!)
The contents of the document are:
-) The first chapter might be of less interest as it gives only an
overview on SQL.
-) The second chapter gives a description on much of PostgreSQL's
features (like user defined types etc. and how to use these features)
-) The third chapter starts with an overview of PostgreSQL's internal
structure with focus on the stages a query has to pass (i.e. parser,
planner/optimizer, executor). Then a detailed description of the
implementation of the Having clause and the Intersect/Except logic is
given.
Originally I worked on v6.3.2 but never found time enough to prepare
and post a patch. Now I applied the changes to v6.4 to get Intersect
and Except working with the new version. Chapter 3 of my documentation
deals with the changes against v6.3.2, so keep that in mind when
comparing the parts of the code printed there with the patched sources
of v6.4.
Here are some remarks on the patch. There are some things that have
still to be done but at the moment I don't have time to do them
myself. (I'm doing my military service at the moment) Sorry for that
:-(
-) I used a rewrite technique for the implementation of the Except/Intersect
logic which rewrites the query to a semantically equivalent query before
it is handed to the rewrite system (for views, rules etc.), planner,
executor etc.
-) In v6.3.2 the types of the attributes of two select statements
connected by the UNION keyword had to match 100%. In v6.4 the types
only need to be familiar (i.e. int and float can be mixed). Since this
feature did not exist when I worked on Intersect/Except it
does not work correctly for Except/Intersect queries WHEN USED IN
COMBINATION WITH UNIONS! (i.e. sometimes the wrong type is used for the
resulting table. This is because until now the types of the attributes of
the first select statement have been used for the resulting table.
When Intersects and/or Excepts are used in combination with Unions it
might happen, that the first select statement of the original query
appears at another position in the query which will be executed. The reason
for this is the technique used for the implementation of
Except/Intersect which does a query rewrite!)
NOTE: It is NOT broken for pure UNION queries and pure INTERSECT/EXCEPT
queries!!!
-) I had to add the field intersect_clause to some data structures
but did not find time to implement printfuncs for the new field.
This does NOT break the debug modes but when an Except/Intersect
is used the query debug output will be the already rewritten query.
-) Massive changes to the grammar rules for SELECT and INSERT statements
have been necessary (see comments in gram.y and documentation for
deatails) in order to be able to use mixed queries like
(SELECT ... UNION (SELECT ... EXCEPT SELECT)) INTERSECT SELECT...;
-) When using UNION/EXCEPT/INTERSECT you will get:
NOTICE: equal: "Don't know if nodes of type xxx are equal".
I did not have time to add comparsion support for all the needed nodes,
but the default behaviour of the function equal met my requirements.
I did not dare to supress this message!
That's the reason why the regression test for union will fail: These
messages are also included in the union.out file!
-) Somebody of you changed the union_planner() function for v6.4
(I copied the targetlist to new_tlist and that was removed and
replaced by a cleanup of the original targetlist). These chnages
violated some having queries executed against views so I changed
it back again. I did not have time to examine the differences between the
two versions but now it works :-)
If you want to find out, try the file queries/view_having.sql on
both versions and compare the results . Two queries won't produce a
correct result with your version.
regards
Stefan
1999-01-18 01:10:17 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
1999-07-20 02:18:01 +02:00
|
|
|
/* There were set operations. The root of the operator
|
|
|
|
* tree is delivered by $1, but we must hand back a
|
|
|
|
* SelectStmt node not an A_Expr Node.
|
|
|
|
* So we find the leftmost 'SelectStmt' in the operator
|
|
|
|
* tree $1 (which is the first Select Statement in the
|
|
|
|
* query), which will be the returned node.
|
|
|
|
* Then we attach the whole operator tree to that node's
|
|
|
|
* 'intersectClause', and a list of all 'SelectStmt' Nodes
|
|
|
|
* in the tree to its 'unionClause'. (NOTE that this means
|
|
|
|
* the top node has indirect recursive pointers to itself!
|
|
|
|
* This would cause trouble if we tried copyObject!!)
|
|
|
|
* The intersectClause and unionClause subtrees will be
|
|
|
|
* left untouched by the main parser, and will only be
|
|
|
|
* processed when control gets to the function
|
|
|
|
* Except_Intersect_Rewrite() (in rewriteHandler.c).
|
|
|
|
*/
|
|
|
|
Node *op = (Node *) $1;
|
|
|
|
List *select_list = NIL;
|
|
|
|
SelectStmt *first_select;
|
|
|
|
bool intersect_present = false,
|
|
|
|
unionall_present = false;
|
|
|
|
|
|
|
|
/* Take the operator tree as an argument and create a
|
|
|
|
* list of all SelectStmt Nodes found in the tree.
|
|
|
|
*
|
|
|
|
* If one of the SelectStmt Nodes has the 'unionall' flag
|
|
|
|
* set to true the 'unionall_present' flag is also set to
|
|
|
|
* true.
|
|
|
|
*/
|
|
|
|
create_select_list(op, &select_list, &unionall_present);
|
|
|
|
|
|
|
|
/* Replace all the A_Expr Nodes in the operator tree by
|
|
|
|
* Expr Nodes.
|
|
|
|
*
|
|
|
|
* If an INTERSECT or an EXCEPT is present, the
|
|
|
|
* 'intersect_present' flag is set to true
|
|
|
|
*/
|
|
|
|
op = A_Expr_to_Expr(op, &intersect_present);
|
Hi!
INTERSECT and EXCEPT is available for postgresql-v6.4!
The patch against v6.4 is included at the end of the current text
(in uuencoded form!)
I also included the text of my Master's Thesis. (a postscript
version). I hope that you find something of it useful and would be
happy if parts of it find their way into the PostgreSQL documentation
project (If so, tell me, then I send the sources of the document!)
The contents of the document are:
-) The first chapter might be of less interest as it gives only an
overview on SQL.
-) The second chapter gives a description on much of PostgreSQL's
features (like user defined types etc. and how to use these features)
-) The third chapter starts with an overview of PostgreSQL's internal
structure with focus on the stages a query has to pass (i.e. parser,
planner/optimizer, executor). Then a detailed description of the
implementation of the Having clause and the Intersect/Except logic is
given.
Originally I worked on v6.3.2 but never found time enough to prepare
and post a patch. Now I applied the changes to v6.4 to get Intersect
and Except working with the new version. Chapter 3 of my documentation
deals with the changes against v6.3.2, so keep that in mind when
comparing the parts of the code printed there with the patched sources
of v6.4.
Here are some remarks on the patch. There are some things that have
still to be done but at the moment I don't have time to do them
myself. (I'm doing my military service at the moment) Sorry for that
:-(
-) I used a rewrite technique for the implementation of the Except/Intersect
logic which rewrites the query to a semantically equivalent query before
it is handed to the rewrite system (for views, rules etc.), planner,
executor etc.
-) In v6.3.2 the types of the attributes of two select statements
connected by the UNION keyword had to match 100%. In v6.4 the types
only need to be familiar (i.e. int and float can be mixed). Since this
feature did not exist when I worked on Intersect/Except it
does not work correctly for Except/Intersect queries WHEN USED IN
COMBINATION WITH UNIONS! (i.e. sometimes the wrong type is used for the
resulting table. This is because until now the types of the attributes of
the first select statement have been used for the resulting table.
When Intersects and/or Excepts are used in combination with Unions it
might happen, that the first select statement of the original query
appears at another position in the query which will be executed. The reason
for this is the technique used for the implementation of
Except/Intersect which does a query rewrite!)
NOTE: It is NOT broken for pure UNION queries and pure INTERSECT/EXCEPT
queries!!!
-) I had to add the field intersect_clause to some data structures
but did not find time to implement printfuncs for the new field.
This does NOT break the debug modes but when an Except/Intersect
is used the query debug output will be the already rewritten query.
-) Massive changes to the grammar rules for SELECT and INSERT statements
have been necessary (see comments in gram.y and documentation for
deatails) in order to be able to use mixed queries like
(SELECT ... UNION (SELECT ... EXCEPT SELECT)) INTERSECT SELECT...;
-) When using UNION/EXCEPT/INTERSECT you will get:
NOTICE: equal: "Don't know if nodes of type xxx are equal".
I did not have time to add comparsion support for all the needed nodes,
but the default behaviour of the function equal met my requirements.
I did not dare to supress this message!
That's the reason why the regression test for union will fail: These
messages are also included in the union.out file!
-) Somebody of you changed the union_planner() function for v6.4
(I copied the targetlist to new_tlist and that was removed and
replaced by a cleanup of the original targetlist). These chnages
violated some having queries executed against views so I changed
it back again. I did not have time to examine the differences between the
two versions but now it works :-)
If you want to find out, try the file queries/view_having.sql on
both versions and compare the results . Two queries won't produce a
correct result with your version.
regards
Stefan
1999-01-18 01:10:17 +01:00
|
|
|
|
1999-07-20 02:18:01 +02:00
|
|
|
/* If both flags are set to true we have a UNION ALL
|
|
|
|
* statement mixed up with INTERSECT or EXCEPT
|
|
|
|
* which can not be handled at the moment.
|
|
|
|
*/
|
|
|
|
if (intersect_present && unionall_present)
|
|
|
|
elog(ERROR, "UNION ALL not allowed in mixed set operations");
|
|
|
|
|
|
|
|
/* Get the leftmost SeletStmt Node (which automatically
|
|
|
|
* represents the first Select Statement of the query!)
|
|
|
|
*/
|
|
|
|
first_select = (SelectStmt *) lfirst(select_list);
|
Hi!
INTERSECT and EXCEPT is available for postgresql-v6.4!
The patch against v6.4 is included at the end of the current text
(in uuencoded form!)
I also included the text of my Master's Thesis. (a postscript
version). I hope that you find something of it useful and would be
happy if parts of it find their way into the PostgreSQL documentation
project (If so, tell me, then I send the sources of the document!)
The contents of the document are:
-) The first chapter might be of less interest as it gives only an
overview on SQL.
-) The second chapter gives a description on much of PostgreSQL's
features (like user defined types etc. and how to use these features)
-) The third chapter starts with an overview of PostgreSQL's internal
structure with focus on the stages a query has to pass (i.e. parser,
planner/optimizer, executor). Then a detailed description of the
implementation of the Having clause and the Intersect/Except logic is
given.
Originally I worked on v6.3.2 but never found time enough to prepare
and post a patch. Now I applied the changes to v6.4 to get Intersect
and Except working with the new version. Chapter 3 of my documentation
deals with the changes against v6.3.2, so keep that in mind when
comparing the parts of the code printed there with the patched sources
of v6.4.
Here are some remarks on the patch. There are some things that have
still to be done but at the moment I don't have time to do them
myself. (I'm doing my military service at the moment) Sorry for that
:-(
-) I used a rewrite technique for the implementation of the Except/Intersect
logic which rewrites the query to a semantically equivalent query before
it is handed to the rewrite system (for views, rules etc.), planner,
executor etc.
-) In v6.3.2 the types of the attributes of two select statements
connected by the UNION keyword had to match 100%. In v6.4 the types
only need to be familiar (i.e. int and float can be mixed). Since this
feature did not exist when I worked on Intersect/Except it
does not work correctly for Except/Intersect queries WHEN USED IN
COMBINATION WITH UNIONS! (i.e. sometimes the wrong type is used for the
resulting table. This is because until now the types of the attributes of
the first select statement have been used for the resulting table.
When Intersects and/or Excepts are used in combination with Unions it
might happen, that the first select statement of the original query
appears at another position in the query which will be executed. The reason
for this is the technique used for the implementation of
Except/Intersect which does a query rewrite!)
NOTE: It is NOT broken for pure UNION queries and pure INTERSECT/EXCEPT
queries!!!
-) I had to add the field intersect_clause to some data structures
but did not find time to implement printfuncs for the new field.
This does NOT break the debug modes but when an Except/Intersect
is used the query debug output will be the already rewritten query.
-) Massive changes to the grammar rules for SELECT and INSERT statements
have been necessary (see comments in gram.y and documentation for
deatails) in order to be able to use mixed queries like
(SELECT ... UNION (SELECT ... EXCEPT SELECT)) INTERSECT SELECT...;
-) When using UNION/EXCEPT/INTERSECT you will get:
NOTICE: equal: "Don't know if nodes of type xxx are equal".
I did not have time to add comparsion support for all the needed nodes,
but the default behaviour of the function equal met my requirements.
I did not dare to supress this message!
That's the reason why the regression test for union will fail: These
messages are also included in the union.out file!
-) Somebody of you changed the union_planner() function for v6.4
(I copied the targetlist to new_tlist and that was removed and
replaced by a cleanup of the original targetlist). These chnages
violated some having queries executed against views so I changed
it back again. I did not have time to examine the differences between the
two versions but now it works :-)
If you want to find out, try the file queries/view_having.sql on
both versions and compare the results . Two queries won't produce a
correct result with your version.
regards
Stefan
1999-01-18 01:10:17 +01:00
|
|
|
|
1999-07-20 02:18:01 +02:00
|
|
|
/* Attach the list of all SeletStmt Nodes to unionClause */
|
|
|
|
first_select->unionClause = select_list;
|
Hi!
INTERSECT and EXCEPT is available for postgresql-v6.4!
The patch against v6.4 is included at the end of the current text
(in uuencoded form!)
I also included the text of my Master's Thesis. (a postscript
version). I hope that you find something of it useful and would be
happy if parts of it find their way into the PostgreSQL documentation
project (If so, tell me, then I send the sources of the document!)
The contents of the document are:
-) The first chapter might be of less interest as it gives only an
overview on SQL.
-) The second chapter gives a description on much of PostgreSQL's
features (like user defined types etc. and how to use these features)
-) The third chapter starts with an overview of PostgreSQL's internal
structure with focus on the stages a query has to pass (i.e. parser,
planner/optimizer, executor). Then a detailed description of the
implementation of the Having clause and the Intersect/Except logic is
given.
Originally I worked on v6.3.2 but never found time enough to prepare
and post a patch. Now I applied the changes to v6.4 to get Intersect
and Except working with the new version. Chapter 3 of my documentation
deals with the changes against v6.3.2, so keep that in mind when
comparing the parts of the code printed there with the patched sources
of v6.4.
Here are some remarks on the patch. There are some things that have
still to be done but at the moment I don't have time to do them
myself. (I'm doing my military service at the moment) Sorry for that
:-(
-) I used a rewrite technique for the implementation of the Except/Intersect
logic which rewrites the query to a semantically equivalent query before
it is handed to the rewrite system (for views, rules etc.), planner,
executor etc.
-) In v6.3.2 the types of the attributes of two select statements
connected by the UNION keyword had to match 100%. In v6.4 the types
only need to be familiar (i.e. int and float can be mixed). Since this
feature did not exist when I worked on Intersect/Except it
does not work correctly for Except/Intersect queries WHEN USED IN
COMBINATION WITH UNIONS! (i.e. sometimes the wrong type is used for the
resulting table. This is because until now the types of the attributes of
the first select statement have been used for the resulting table.
When Intersects and/or Excepts are used in combination with Unions it
might happen, that the first select statement of the original query
appears at another position in the query which will be executed. The reason
for this is the technique used for the implementation of
Except/Intersect which does a query rewrite!)
NOTE: It is NOT broken for pure UNION queries and pure INTERSECT/EXCEPT
queries!!!
-) I had to add the field intersect_clause to some data structures
but did not find time to implement printfuncs for the new field.
This does NOT break the debug modes but when an Except/Intersect
is used the query debug output will be the already rewritten query.
-) Massive changes to the grammar rules for SELECT and INSERT statements
have been necessary (see comments in gram.y and documentation for
deatails) in order to be able to use mixed queries like
(SELECT ... UNION (SELECT ... EXCEPT SELECT)) INTERSECT SELECT...;
-) When using UNION/EXCEPT/INTERSECT you will get:
NOTICE: equal: "Don't know if nodes of type xxx are equal".
I did not have time to add comparsion support for all the needed nodes,
but the default behaviour of the function equal met my requirements.
I did not dare to supress this message!
That's the reason why the regression test for union will fail: These
messages are also included in the union.out file!
-) Somebody of you changed the union_planner() function for v6.4
(I copied the targetlist to new_tlist and that was removed and
replaced by a cleanup of the original targetlist). These chnages
violated some having queries executed against views so I changed
it back again. I did not have time to examine the differences between the
two versions but now it works :-)
If you want to find out, try the file queries/view_having.sql on
both versions and compare the results . Two queries won't produce a
correct result with your version.
regards
Stefan
1999-01-18 01:10:17 +01:00
|
|
|
|
1999-07-20 02:18:01 +02:00
|
|
|
/* Attach the whole operator tree to intersectClause */
|
|
|
|
first_select->intersectClause = (List *) op;
|
Hi!
INTERSECT and EXCEPT is available for postgresql-v6.4!
The patch against v6.4 is included at the end of the current text
(in uuencoded form!)
I also included the text of my Master's Thesis. (a postscript
version). I hope that you find something of it useful and would be
happy if parts of it find their way into the PostgreSQL documentation
project (If so, tell me, then I send the sources of the document!)
The contents of the document are:
-) The first chapter might be of less interest as it gives only an
overview on SQL.
-) The second chapter gives a description on much of PostgreSQL's
features (like user defined types etc. and how to use these features)
-) The third chapter starts with an overview of PostgreSQL's internal
structure with focus on the stages a query has to pass (i.e. parser,
planner/optimizer, executor). Then a detailed description of the
implementation of the Having clause and the Intersect/Except logic is
given.
Originally I worked on v6.3.2 but never found time enough to prepare
and post a patch. Now I applied the changes to v6.4 to get Intersect
and Except working with the new version. Chapter 3 of my documentation
deals with the changes against v6.3.2, so keep that in mind when
comparing the parts of the code printed there with the patched sources
of v6.4.
Here are some remarks on the patch. There are some things that have
still to be done but at the moment I don't have time to do them
myself. (I'm doing my military service at the moment) Sorry for that
:-(
-) I used a rewrite technique for the implementation of the Except/Intersect
logic which rewrites the query to a semantically equivalent query before
it is handed to the rewrite system (for views, rules etc.), planner,
executor etc.
-) In v6.3.2 the types of the attributes of two select statements
connected by the UNION keyword had to match 100%. In v6.4 the types
only need to be familiar (i.e. int and float can be mixed). Since this
feature did not exist when I worked on Intersect/Except it
does not work correctly for Except/Intersect queries WHEN USED IN
COMBINATION WITH UNIONS! (i.e. sometimes the wrong type is used for the
resulting table. This is because until now the types of the attributes of
the first select statement have been used for the resulting table.
When Intersects and/or Excepts are used in combination with Unions it
might happen, that the first select statement of the original query
appears at another position in the query which will be executed. The reason
for this is the technique used for the implementation of
Except/Intersect which does a query rewrite!)
NOTE: It is NOT broken for pure UNION queries and pure INTERSECT/EXCEPT
queries!!!
-) I had to add the field intersect_clause to some data structures
but did not find time to implement printfuncs for the new field.
This does NOT break the debug modes but when an Except/Intersect
is used the query debug output will be the already rewritten query.
-) Massive changes to the grammar rules for SELECT and INSERT statements
have been necessary (see comments in gram.y and documentation for
deatails) in order to be able to use mixed queries like
(SELECT ... UNION (SELECT ... EXCEPT SELECT)) INTERSECT SELECT...;
-) When using UNION/EXCEPT/INTERSECT you will get:
NOTICE: equal: "Don't know if nodes of type xxx are equal".
I did not have time to add comparsion support for all the needed nodes,
but the default behaviour of the function equal met my requirements.
I did not dare to supress this message!
That's the reason why the regression test for union will fail: These
messages are also included in the union.out file!
-) Somebody of you changed the union_planner() function for v6.4
(I copied the targetlist to new_tlist and that was removed and
replaced by a cleanup of the original targetlist). These chnages
violated some having queries executed against views so I changed
it back again. I did not have time to examine the differences between the
two versions but now it works :-)
If you want to find out, try the file queries/view_having.sql on
both versions and compare the results . Two queries won't produce a
correct result with your version.
regards
Stefan
1999-01-18 01:10:17 +01:00
|
|
|
|
1999-07-20 02:18:01 +02:00
|
|
|
/* finally attach the sort clause &etc */
|
|
|
|
first_select->sortClause = $2;
|
|
|
|
first_select->forUpdate = $3;
|
|
|
|
first_select->limitOffset = nth(0, $4);
|
|
|
|
first_select->limitCount = nth(1, $4);
|
|
|
|
$$ = (Node *) first_select;
|
Hi!
INTERSECT and EXCEPT is available for postgresql-v6.4!
The patch against v6.4 is included at the end of the current text
(in uuencoded form!)
I also included the text of my Master's Thesis. (a postscript
version). I hope that you find something of it useful and would be
happy if parts of it find their way into the PostgreSQL documentation
project (If so, tell me, then I send the sources of the document!)
The contents of the document are:
-) The first chapter might be of less interest as it gives only an
overview on SQL.
-) The second chapter gives a description on much of PostgreSQL's
features (like user defined types etc. and how to use these features)
-) The third chapter starts with an overview of PostgreSQL's internal
structure with focus on the stages a query has to pass (i.e. parser,
planner/optimizer, executor). Then a detailed description of the
implementation of the Having clause and the Intersect/Except logic is
given.
Originally I worked on v6.3.2 but never found time enough to prepare
and post a patch. Now I applied the changes to v6.4 to get Intersect
and Except working with the new version. Chapter 3 of my documentation
deals with the changes against v6.3.2, so keep that in mind when
comparing the parts of the code printed there with the patched sources
of v6.4.
Here are some remarks on the patch. There are some things that have
still to be done but at the moment I don't have time to do them
myself. (I'm doing my military service at the moment) Sorry for that
:-(
-) I used a rewrite technique for the implementation of the Except/Intersect
logic which rewrites the query to a semantically equivalent query before
it is handed to the rewrite system (for views, rules etc.), planner,
executor etc.
-) In v6.3.2 the types of the attributes of two select statements
connected by the UNION keyword had to match 100%. In v6.4 the types
only need to be familiar (i.e. int and float can be mixed). Since this
feature did not exist when I worked on Intersect/Except it
does not work correctly for Except/Intersect queries WHEN USED IN
COMBINATION WITH UNIONS! (i.e. sometimes the wrong type is used for the
resulting table. This is because until now the types of the attributes of
the first select statement have been used for the resulting table.
When Intersects and/or Excepts are used in combination with Unions it
might happen, that the first select statement of the original query
appears at another position in the query which will be executed. The reason
for this is the technique used for the implementation of
Except/Intersect which does a query rewrite!)
NOTE: It is NOT broken for pure UNION queries and pure INTERSECT/EXCEPT
queries!!!
-) I had to add the field intersect_clause to some data structures
but did not find time to implement printfuncs for the new field.
This does NOT break the debug modes but when an Except/Intersect
is used the query debug output will be the already rewritten query.
-) Massive changes to the grammar rules for SELECT and INSERT statements
have been necessary (see comments in gram.y and documentation for
deatails) in order to be able to use mixed queries like
(SELECT ... UNION (SELECT ... EXCEPT SELECT)) INTERSECT SELECT...;
-) When using UNION/EXCEPT/INTERSECT you will get:
NOTICE: equal: "Don't know if nodes of type xxx are equal".
I did not have time to add comparsion support for all the needed nodes,
but the default behaviour of the function equal met my requirements.
I did not dare to supress this message!
That's the reason why the regression test for union will fail: These
messages are also included in the union.out file!
-) Somebody of you changed the union_planner() function for v6.4
(I copied the targetlist to new_tlist and that was removed and
replaced by a cleanup of the original targetlist). These chnages
violated some having queries executed against views so I changed
it back again. I did not have time to examine the differences between the
two versions but now it works :-)
If you want to find out, try the file queries/view_having.sql on
both versions and compare the results . Two queries won't produce a
correct result with your version.
regards
Stefan
1999-01-18 01:10:17 +01:00
|
|
|
}
|
1999-01-25 13:01:19 +01:00
|
|
|
if (((SelectStmt *)$$)->forUpdate != NULL && QueryIsRule)
|
|
|
|
elog(ERROR, "SELECT FOR UPDATE is not allowed in RULES");
|
Hi!
INTERSECT and EXCEPT is available for postgresql-v6.4!
The patch against v6.4 is included at the end of the current text
(in uuencoded form!)
I also included the text of my Master's Thesis. (a postscript
version). I hope that you find something of it useful and would be
happy if parts of it find their way into the PostgreSQL documentation
project (If so, tell me, then I send the sources of the document!)
The contents of the document are:
-) The first chapter might be of less interest as it gives only an
overview on SQL.
-) The second chapter gives a description on much of PostgreSQL's
features (like user defined types etc. and how to use these features)
-) The third chapter starts with an overview of PostgreSQL's internal
structure with focus on the stages a query has to pass (i.e. parser,
planner/optimizer, executor). Then a detailed description of the
implementation of the Having clause and the Intersect/Except logic is
given.
Originally I worked on v6.3.2 but never found time enough to prepare
and post a patch. Now I applied the changes to v6.4 to get Intersect
and Except working with the new version. Chapter 3 of my documentation
deals with the changes against v6.3.2, so keep that in mind when
comparing the parts of the code printed there with the patched sources
of v6.4.
Here are some remarks on the patch. There are some things that have
still to be done but at the moment I don't have time to do them
myself. (I'm doing my military service at the moment) Sorry for that
:-(
-) I used a rewrite technique for the implementation of the Except/Intersect
logic which rewrites the query to a semantically equivalent query before
it is handed to the rewrite system (for views, rules etc.), planner,
executor etc.
-) In v6.3.2 the types of the attributes of two select statements
connected by the UNION keyword had to match 100%. In v6.4 the types
only need to be familiar (i.e. int and float can be mixed). Since this
feature did not exist when I worked on Intersect/Except it
does not work correctly for Except/Intersect queries WHEN USED IN
COMBINATION WITH UNIONS! (i.e. sometimes the wrong type is used for the
resulting table. This is because until now the types of the attributes of
the first select statement have been used for the resulting table.
When Intersects and/or Excepts are used in combination with Unions it
might happen, that the first select statement of the original query
appears at another position in the query which will be executed. The reason
for this is the technique used for the implementation of
Except/Intersect which does a query rewrite!)
NOTE: It is NOT broken for pure UNION queries and pure INTERSECT/EXCEPT
queries!!!
-) I had to add the field intersect_clause to some data structures
but did not find time to implement printfuncs for the new field.
This does NOT break the debug modes but when an Except/Intersect
is used the query debug output will be the already rewritten query.
-) Massive changes to the grammar rules for SELECT and INSERT statements
have been necessary (see comments in gram.y and documentation for
deatails) in order to be able to use mixed queries like
(SELECT ... UNION (SELECT ... EXCEPT SELECT)) INTERSECT SELECT...;
-) When using UNION/EXCEPT/INTERSECT you will get:
NOTICE: equal: "Don't know if nodes of type xxx are equal".
I did not have time to add comparsion support for all the needed nodes,
but the default behaviour of the function equal met my requirements.
I did not dare to supress this message!
That's the reason why the regression test for union will fail: These
messages are also included in the union.out file!
-) Somebody of you changed the union_planner() function for v6.4
(I copied the targetlist to new_tlist and that was removed and
replaced by a cleanup of the original targetlist). These chnages
violated some having queries executed against views so I changed
it back again. I did not have time to examine the differences between the
two versions but now it works :-)
If you want to find out, try the file queries/view_having.sql on
both versions and compare the results . Two queries won't produce a
correct result with your version.
regards
Stefan
1999-01-18 01:10:17 +01:00
|
|
|
}
|
|
|
|
;
|
|
|
|
|
1999-07-20 02:18:01 +02:00
|
|
|
/* This rule parses Select statements that can appear within set operations,
|
|
|
|
* including UNION, INTERSECT and EXCEPT. '(' and ')' can be used to specify
|
|
|
|
* the ordering of the set operations. Without '(' and ')' we want the
|
Hi!
INTERSECT and EXCEPT is available for postgresql-v6.4!
The patch against v6.4 is included at the end of the current text
(in uuencoded form!)
I also included the text of my Master's Thesis. (a postscript
version). I hope that you find something of it useful and would be
happy if parts of it find their way into the PostgreSQL documentation
project (If so, tell me, then I send the sources of the document!)
The contents of the document are:
-) The first chapter might be of less interest as it gives only an
overview on SQL.
-) The second chapter gives a description on much of PostgreSQL's
features (like user defined types etc. and how to use these features)
-) The third chapter starts with an overview of PostgreSQL's internal
structure with focus on the stages a query has to pass (i.e. parser,
planner/optimizer, executor). Then a detailed description of the
implementation of the Having clause and the Intersect/Except logic is
given.
Originally I worked on v6.3.2 but never found time enough to prepare
and post a patch. Now I applied the changes to v6.4 to get Intersect
and Except working with the new version. Chapter 3 of my documentation
deals with the changes against v6.3.2, so keep that in mind when
comparing the parts of the code printed there with the patched sources
of v6.4.
Here are some remarks on the patch. There are some things that have
still to be done but at the moment I don't have time to do them
myself. (I'm doing my military service at the moment) Sorry for that
:-(
-) I used a rewrite technique for the implementation of the Except/Intersect
logic which rewrites the query to a semantically equivalent query before
it is handed to the rewrite system (for views, rules etc.), planner,
executor etc.
-) In v6.3.2 the types of the attributes of two select statements
connected by the UNION keyword had to match 100%. In v6.4 the types
only need to be familiar (i.e. int and float can be mixed). Since this
feature did not exist when I worked on Intersect/Except it
does not work correctly for Except/Intersect queries WHEN USED IN
COMBINATION WITH UNIONS! (i.e. sometimes the wrong type is used for the
resulting table. This is because until now the types of the attributes of
the first select statement have been used for the resulting table.
When Intersects and/or Excepts are used in combination with Unions it
might happen, that the first select statement of the original query
appears at another position in the query which will be executed. The reason
for this is the technique used for the implementation of
Except/Intersect which does a query rewrite!)
NOTE: It is NOT broken for pure UNION queries and pure INTERSECT/EXCEPT
queries!!!
-) I had to add the field intersect_clause to some data structures
but did not find time to implement printfuncs for the new field.
This does NOT break the debug modes but when an Except/Intersect
is used the query debug output will be the already rewritten query.
-) Massive changes to the grammar rules for SELECT and INSERT statements
have been necessary (see comments in gram.y and documentation for
deatails) in order to be able to use mixed queries like
(SELECT ... UNION (SELECT ... EXCEPT SELECT)) INTERSECT SELECT...;
-) When using UNION/EXCEPT/INTERSECT you will get:
NOTICE: equal: "Don't know if nodes of type xxx are equal".
I did not have time to add comparsion support for all the needed nodes,
but the default behaviour of the function equal met my requirements.
I did not dare to supress this message!
That's the reason why the regression test for union will fail: These
messages are also included in the union.out file!
-) Somebody of you changed the union_planner() function for v6.4
(I copied the targetlist to new_tlist and that was removed and
replaced by a cleanup of the original targetlist). These chnages
violated some having queries executed against views so I changed
it back again. I did not have time to examine the differences between the
two versions but now it works :-)
If you want to find out, try the file queries/view_having.sql on
both versions and compare the results . Two queries won't produce a
correct result with your version.
regards
Stefan
1999-01-18 01:10:17 +01:00
|
|
|
* operations to be left associative.
|
|
|
|
*
|
1999-07-20 02:18:01 +02:00
|
|
|
* Note that sort clauses cannot be included at this level --- a sort clause
|
|
|
|
* can only appear at the end of the complete Select, and it will be handled
|
|
|
|
* by the topmost SelectStmt rule. Likewise FOR UPDATE and LIMIT.
|
Hi!
INTERSECT and EXCEPT is available for postgresql-v6.4!
The patch against v6.4 is included at the end of the current text
(in uuencoded form!)
I also included the text of my Master's Thesis. (a postscript
version). I hope that you find something of it useful and would be
happy if parts of it find their way into the PostgreSQL documentation
project (If so, tell me, then I send the sources of the document!)
The contents of the document are:
-) The first chapter might be of less interest as it gives only an
overview on SQL.
-) The second chapter gives a description on much of PostgreSQL's
features (like user defined types etc. and how to use these features)
-) The third chapter starts with an overview of PostgreSQL's internal
structure with focus on the stages a query has to pass (i.e. parser,
planner/optimizer, executor). Then a detailed description of the
implementation of the Having clause and the Intersect/Except logic is
given.
Originally I worked on v6.3.2 but never found time enough to prepare
and post a patch. Now I applied the changes to v6.4 to get Intersect
and Except working with the new version. Chapter 3 of my documentation
deals with the changes against v6.3.2, so keep that in mind when
comparing the parts of the code printed there with the patched sources
of v6.4.
Here are some remarks on the patch. There are some things that have
still to be done but at the moment I don't have time to do them
myself. (I'm doing my military service at the moment) Sorry for that
:-(
-) I used a rewrite technique for the implementation of the Except/Intersect
logic which rewrites the query to a semantically equivalent query before
it is handed to the rewrite system (for views, rules etc.), planner,
executor etc.
-) In v6.3.2 the types of the attributes of two select statements
connected by the UNION keyword had to match 100%. In v6.4 the types
only need to be familiar (i.e. int and float can be mixed). Since this
feature did not exist when I worked on Intersect/Except it
does not work correctly for Except/Intersect queries WHEN USED IN
COMBINATION WITH UNIONS! (i.e. sometimes the wrong type is used for the
resulting table. This is because until now the types of the attributes of
the first select statement have been used for the resulting table.
When Intersects and/or Excepts are used in combination with Unions it
might happen, that the first select statement of the original query
appears at another position in the query which will be executed. The reason
for this is the technique used for the implementation of
Except/Intersect which does a query rewrite!)
NOTE: It is NOT broken for pure UNION queries and pure INTERSECT/EXCEPT
queries!!!
-) I had to add the field intersect_clause to some data structures
but did not find time to implement printfuncs for the new field.
This does NOT break the debug modes but when an Except/Intersect
is used the query debug output will be the already rewritten query.
-) Massive changes to the grammar rules for SELECT and INSERT statements
have been necessary (see comments in gram.y and documentation for
deatails) in order to be able to use mixed queries like
(SELECT ... UNION (SELECT ... EXCEPT SELECT)) INTERSECT SELECT...;
-) When using UNION/EXCEPT/INTERSECT you will get:
NOTICE: equal: "Don't know if nodes of type xxx are equal".
I did not have time to add comparsion support for all the needed nodes,
but the default behaviour of the function equal met my requirements.
I did not dare to supress this message!
That's the reason why the regression test for union will fail: These
messages are also included in the union.out file!
-) Somebody of you changed the union_planner() function for v6.4
(I copied the targetlist to new_tlist and that was removed and
replaced by a cleanup of the original targetlist). These chnages
violated some having queries executed against views so I changed
it back again. I did not have time to examine the differences between the
two versions but now it works :-)
If you want to find out, try the file queries/view_having.sql on
both versions and compare the results . Two queries won't produce a
correct result with your version.
regards
Stefan
1999-01-18 01:10:17 +01:00
|
|
|
*
|
|
|
|
* The rule builds up an operator tree using A_Expr Nodes. AND Nodes represent
|
1999-07-20 02:18:01 +02:00
|
|
|
* INTERSECTs, OR Nodes represent UNIONs, and AND NOT nodes represent EXCEPTs.
|
Hi!
INTERSECT and EXCEPT is available for postgresql-v6.4!
The patch against v6.4 is included at the end of the current text
(in uuencoded form!)
I also included the text of my Master's Thesis. (a postscript
version). I hope that you find something of it useful and would be
happy if parts of it find their way into the PostgreSQL documentation
project (If so, tell me, then I send the sources of the document!)
The contents of the document are:
-) The first chapter might be of less interest as it gives only an
overview on SQL.
-) The second chapter gives a description on much of PostgreSQL's
features (like user defined types etc. and how to use these features)
-) The third chapter starts with an overview of PostgreSQL's internal
structure with focus on the stages a query has to pass (i.e. parser,
planner/optimizer, executor). Then a detailed description of the
implementation of the Having clause and the Intersect/Except logic is
given.
Originally I worked on v6.3.2 but never found time enough to prepare
and post a patch. Now I applied the changes to v6.4 to get Intersect
and Except working with the new version. Chapter 3 of my documentation
deals with the changes against v6.3.2, so keep that in mind when
comparing the parts of the code printed there with the patched sources
of v6.4.
Here are some remarks on the patch. There are some things that have
still to be done but at the moment I don't have time to do them
myself. (I'm doing my military service at the moment) Sorry for that
:-(
-) I used a rewrite technique for the implementation of the Except/Intersect
logic which rewrites the query to a semantically equivalent query before
it is handed to the rewrite system (for views, rules etc.), planner,
executor etc.
-) In v6.3.2 the types of the attributes of two select statements
connected by the UNION keyword had to match 100%. In v6.4 the types
only need to be familiar (i.e. int and float can be mixed). Since this
feature did not exist when I worked on Intersect/Except it
does not work correctly for Except/Intersect queries WHEN USED IN
COMBINATION WITH UNIONS! (i.e. sometimes the wrong type is used for the
resulting table. This is because until now the types of the attributes of
the first select statement have been used for the resulting table.
When Intersects and/or Excepts are used in combination with Unions it
might happen, that the first select statement of the original query
appears at another position in the query which will be executed. The reason
for this is the technique used for the implementation of
Except/Intersect which does a query rewrite!)
NOTE: It is NOT broken for pure UNION queries and pure INTERSECT/EXCEPT
queries!!!
-) I had to add the field intersect_clause to some data structures
but did not find time to implement printfuncs for the new field.
This does NOT break the debug modes but when an Except/Intersect
is used the query debug output will be the already rewritten query.
-) Massive changes to the grammar rules for SELECT and INSERT statements
have been necessary (see comments in gram.y and documentation for
deatails) in order to be able to use mixed queries like
(SELECT ... UNION (SELECT ... EXCEPT SELECT)) INTERSECT SELECT...;
-) When using UNION/EXCEPT/INTERSECT you will get:
NOTICE: equal: "Don't know if nodes of type xxx are equal".
I did not have time to add comparsion support for all the needed nodes,
but the default behaviour of the function equal met my requirements.
I did not dare to supress this message!
That's the reason why the regression test for union will fail: These
messages are also included in the union.out file!
-) Somebody of you changed the union_planner() function for v6.4
(I copied the targetlist to new_tlist and that was removed and
replaced by a cleanup of the original targetlist). These chnages
violated some having queries executed against views so I changed
it back again. I did not have time to examine the differences between the
two versions but now it works :-)
If you want to find out, try the file queries/view_having.sql on
both versions and compare the results . Two queries won't produce a
correct result with your version.
regards
Stefan
1999-01-18 01:10:17 +01:00
|
|
|
* The SelectStatements to be connected are the left and right arguments to
|
|
|
|
* the A_Expr Nodes.
|
1999-07-20 02:18:01 +02:00
|
|
|
* If no set operations appear in the query, the tree consists only of one
|
|
|
|
* SelectStmt Node.
|
|
|
|
*/
|
1999-02-23 08:42:41 +01:00
|
|
|
select_clause: '(' select_clause ')'
|
Hi!
INTERSECT and EXCEPT is available for postgresql-v6.4!
The patch against v6.4 is included at the end of the current text
(in uuencoded form!)
I also included the text of my Master's Thesis. (a postscript
version). I hope that you find something of it useful and would be
happy if parts of it find their way into the PostgreSQL documentation
project (If so, tell me, then I send the sources of the document!)
The contents of the document are:
-) The first chapter might be of less interest as it gives only an
overview on SQL.
-) The second chapter gives a description on much of PostgreSQL's
features (like user defined types etc. and how to use these features)
-) The third chapter starts with an overview of PostgreSQL's internal
structure with focus on the stages a query has to pass (i.e. parser,
planner/optimizer, executor). Then a detailed description of the
implementation of the Having clause and the Intersect/Except logic is
given.
Originally I worked on v6.3.2 but never found time enough to prepare
and post a patch. Now I applied the changes to v6.4 to get Intersect
and Except working with the new version. Chapter 3 of my documentation
deals with the changes against v6.3.2, so keep that in mind when
comparing the parts of the code printed there with the patched sources
of v6.4.
Here are some remarks on the patch. There are some things that have
still to be done but at the moment I don't have time to do them
myself. (I'm doing my military service at the moment) Sorry for that
:-(
-) I used a rewrite technique for the implementation of the Except/Intersect
logic which rewrites the query to a semantically equivalent query before
it is handed to the rewrite system (for views, rules etc.), planner,
executor etc.
-) In v6.3.2 the types of the attributes of two select statements
connected by the UNION keyword had to match 100%. In v6.4 the types
only need to be familiar (i.e. int and float can be mixed). Since this
feature did not exist when I worked on Intersect/Except it
does not work correctly for Except/Intersect queries WHEN USED IN
COMBINATION WITH UNIONS! (i.e. sometimes the wrong type is used for the
resulting table. This is because until now the types of the attributes of
the first select statement have been used for the resulting table.
When Intersects and/or Excepts are used in combination with Unions it
might happen, that the first select statement of the original query
appears at another position in the query which will be executed. The reason
for this is the technique used for the implementation of
Except/Intersect which does a query rewrite!)
NOTE: It is NOT broken for pure UNION queries and pure INTERSECT/EXCEPT
queries!!!
-) I had to add the field intersect_clause to some data structures
but did not find time to implement printfuncs for the new field.
This does NOT break the debug modes but when an Except/Intersect
is used the query debug output will be the already rewritten query.
-) Massive changes to the grammar rules for SELECT and INSERT statements
have been necessary (see comments in gram.y and documentation for
deatails) in order to be able to use mixed queries like
(SELECT ... UNION (SELECT ... EXCEPT SELECT)) INTERSECT SELECT...;
-) When using UNION/EXCEPT/INTERSECT you will get:
NOTICE: equal: "Don't know if nodes of type xxx are equal".
I did not have time to add comparsion support for all the needed nodes,
but the default behaviour of the function equal met my requirements.
I did not dare to supress this message!
That's the reason why the regression test for union will fail: These
messages are also included in the union.out file!
-) Somebody of you changed the union_planner() function for v6.4
(I copied the targetlist to new_tlist and that was removed and
replaced by a cleanup of the original targetlist). These chnages
violated some having queries executed against views so I changed
it back again. I did not have time to examine the differences between the
two versions but now it works :-)
If you want to find out, try the file queries/view_having.sql on
both versions and compare the results . Two queries won't produce a
correct result with your version.
regards
Stefan
1999-01-18 01:10:17 +01:00
|
|
|
{
|
|
|
|
$$ = $2;
|
|
|
|
}
|
|
|
|
| SubSelect
|
|
|
|
{
|
|
|
|
$$ = $1;
|
|
|
|
}
|
1999-02-23 08:42:41 +01:00
|
|
|
| select_clause EXCEPT select_clause
|
Hi!
INTERSECT and EXCEPT is available for postgresql-v6.4!
The patch against v6.4 is included at the end of the current text
(in uuencoded form!)
I also included the text of my Master's Thesis. (a postscript
version). I hope that you find something of it useful and would be
happy if parts of it find their way into the PostgreSQL documentation
project (If so, tell me, then I send the sources of the document!)
The contents of the document are:
-) The first chapter might be of less interest as it gives only an
overview on SQL.
-) The second chapter gives a description on much of PostgreSQL's
features (like user defined types etc. and how to use these features)
-) The third chapter starts with an overview of PostgreSQL's internal
structure with focus on the stages a query has to pass (i.e. parser,
planner/optimizer, executor). Then a detailed description of the
implementation of the Having clause and the Intersect/Except logic is
given.
Originally I worked on v6.3.2 but never found time enough to prepare
and post a patch. Now I applied the changes to v6.4 to get Intersect
and Except working with the new version. Chapter 3 of my documentation
deals with the changes against v6.3.2, so keep that in mind when
comparing the parts of the code printed there with the patched sources
of v6.4.
Here are some remarks on the patch. There are some things that have
still to be done but at the moment I don't have time to do them
myself. (I'm doing my military service at the moment) Sorry for that
:-(
-) I used a rewrite technique for the implementation of the Except/Intersect
logic which rewrites the query to a semantically equivalent query before
it is handed to the rewrite system (for views, rules etc.), planner,
executor etc.
-) In v6.3.2 the types of the attributes of two select statements
connected by the UNION keyword had to match 100%. In v6.4 the types
only need to be familiar (i.e. int and float can be mixed). Since this
feature did not exist when I worked on Intersect/Except it
does not work correctly for Except/Intersect queries WHEN USED IN
COMBINATION WITH UNIONS! (i.e. sometimes the wrong type is used for the
resulting table. This is because until now the types of the attributes of
the first select statement have been used for the resulting table.
When Intersects and/or Excepts are used in combination with Unions it
might happen, that the first select statement of the original query
appears at another position in the query which will be executed. The reason
for this is the technique used for the implementation of
Except/Intersect which does a query rewrite!)
NOTE: It is NOT broken for pure UNION queries and pure INTERSECT/EXCEPT
queries!!!
-) I had to add the field intersect_clause to some data structures
but did not find time to implement printfuncs for the new field.
This does NOT break the debug modes but when an Except/Intersect
is used the query debug output will be the already rewritten query.
-) Massive changes to the grammar rules for SELECT and INSERT statements
have been necessary (see comments in gram.y and documentation for
deatails) in order to be able to use mixed queries like
(SELECT ... UNION (SELECT ... EXCEPT SELECT)) INTERSECT SELECT...;
-) When using UNION/EXCEPT/INTERSECT you will get:
NOTICE: equal: "Don't know if nodes of type xxx are equal".
I did not have time to add comparsion support for all the needed nodes,
but the default behaviour of the function equal met my requirements.
I did not dare to supress this message!
That's the reason why the regression test for union will fail: These
messages are also included in the union.out file!
-) Somebody of you changed the union_planner() function for v6.4
(I copied the targetlist to new_tlist and that was removed and
replaced by a cleanup of the original targetlist). These chnages
violated some having queries executed against views so I changed
it back again. I did not have time to examine the differences between the
two versions but now it works :-)
If you want to find out, try the file queries/view_having.sql on
both versions and compare the results . Two queries won't produce a
correct result with your version.
regards
Stefan
1999-01-18 01:10:17 +01:00
|
|
|
{
|
|
|
|
$$ = (Node *)makeA_Expr(AND,NULL,$1,
|
|
|
|
makeA_Expr(NOT,NULL,NULL,$3));
|
|
|
|
}
|
1999-11-15 03:00:15 +01:00
|
|
|
| select_clause UNION opt_all select_clause
|
Hi!
INTERSECT and EXCEPT is available for postgresql-v6.4!
The patch against v6.4 is included at the end of the current text
(in uuencoded form!)
I also included the text of my Master's Thesis. (a postscript
version). I hope that you find something of it useful and would be
happy if parts of it find their way into the PostgreSQL documentation
project (If so, tell me, then I send the sources of the document!)
The contents of the document are:
-) The first chapter might be of less interest as it gives only an
overview on SQL.
-) The second chapter gives a description on much of PostgreSQL's
features (like user defined types etc. and how to use these features)
-) The third chapter starts with an overview of PostgreSQL's internal
structure with focus on the stages a query has to pass (i.e. parser,
planner/optimizer, executor). Then a detailed description of the
implementation of the Having clause and the Intersect/Except logic is
given.
Originally I worked on v6.3.2 but never found time enough to prepare
and post a patch. Now I applied the changes to v6.4 to get Intersect
and Except working with the new version. Chapter 3 of my documentation
deals with the changes against v6.3.2, so keep that in mind when
comparing the parts of the code printed there with the patched sources
of v6.4.
Here are some remarks on the patch. There are some things that have
still to be done but at the moment I don't have time to do them
myself. (I'm doing my military service at the moment) Sorry for that
:-(
-) I used a rewrite technique for the implementation of the Except/Intersect
logic which rewrites the query to a semantically equivalent query before
it is handed to the rewrite system (for views, rules etc.), planner,
executor etc.
-) In v6.3.2 the types of the attributes of two select statements
connected by the UNION keyword had to match 100%. In v6.4 the types
only need to be familiar (i.e. int and float can be mixed). Since this
feature did not exist when I worked on Intersect/Except it
does not work correctly for Except/Intersect queries WHEN USED IN
COMBINATION WITH UNIONS! (i.e. sometimes the wrong type is used for the
resulting table. This is because until now the types of the attributes of
the first select statement have been used for the resulting table.
When Intersects and/or Excepts are used in combination with Unions it
might happen, that the first select statement of the original query
appears at another position in the query which will be executed. The reason
for this is the technique used for the implementation of
Except/Intersect which does a query rewrite!)
NOTE: It is NOT broken for pure UNION queries and pure INTERSECT/EXCEPT
queries!!!
-) I had to add the field intersect_clause to some data structures
but did not find time to implement printfuncs for the new field.
This does NOT break the debug modes but when an Except/Intersect
is used the query debug output will be the already rewritten query.
-) Massive changes to the grammar rules for SELECT and INSERT statements
have been necessary (see comments in gram.y and documentation for
deatails) in order to be able to use mixed queries like
(SELECT ... UNION (SELECT ... EXCEPT SELECT)) INTERSECT SELECT...;
-) When using UNION/EXCEPT/INTERSECT you will get:
NOTICE: equal: "Don't know if nodes of type xxx are equal".
I did not have time to add comparsion support for all the needed nodes,
but the default behaviour of the function equal met my requirements.
I did not dare to supress this message!
That's the reason why the regression test for union will fail: These
messages are also included in the union.out file!
-) Somebody of you changed the union_planner() function for v6.4
(I copied the targetlist to new_tlist and that was removed and
replaced by a cleanup of the original targetlist). These chnages
violated some having queries executed against views so I changed
it back again. I did not have time to examine the differences between the
two versions but now it works :-)
If you want to find out, try the file queries/view_having.sql on
both versions and compare the results . Two queries won't produce a
correct result with your version.
regards
Stefan
1999-01-18 01:10:17 +01:00
|
|
|
{
|
|
|
|
if (IsA($4, SelectStmt))
|
|
|
|
{
|
|
|
|
SelectStmt *n = (SelectStmt *)$4;
|
|
|
|
n->unionall = $3;
|
1999-07-20 02:18:01 +02:00
|
|
|
/* NOTE: if UNION ALL appears with a parenthesized set
|
|
|
|
* operation to its right, the ALL is silently discarded.
|
|
|
|
* Should we generate an error instead? I think it may
|
|
|
|
* be OK since ALL with UNION to its right is ignored
|
|
|
|
* anyway...
|
|
|
|
*/
|
Hi!
INTERSECT and EXCEPT is available for postgresql-v6.4!
The patch against v6.4 is included at the end of the current text
(in uuencoded form!)
I also included the text of my Master's Thesis. (a postscript
version). I hope that you find something of it useful and would be
happy if parts of it find their way into the PostgreSQL documentation
project (If so, tell me, then I send the sources of the document!)
The contents of the document are:
-) The first chapter might be of less interest as it gives only an
overview on SQL.
-) The second chapter gives a description on much of PostgreSQL's
features (like user defined types etc. and how to use these features)
-) The third chapter starts with an overview of PostgreSQL's internal
structure with focus on the stages a query has to pass (i.e. parser,
planner/optimizer, executor). Then a detailed description of the
implementation of the Having clause and the Intersect/Except logic is
given.
Originally I worked on v6.3.2 but never found time enough to prepare
and post a patch. Now I applied the changes to v6.4 to get Intersect
and Except working with the new version. Chapter 3 of my documentation
deals with the changes against v6.3.2, so keep that in mind when
comparing the parts of the code printed there with the patched sources
of v6.4.
Here are some remarks on the patch. There are some things that have
still to be done but at the moment I don't have time to do them
myself. (I'm doing my military service at the moment) Sorry for that
:-(
-) I used a rewrite technique for the implementation of the Except/Intersect
logic which rewrites the query to a semantically equivalent query before
it is handed to the rewrite system (for views, rules etc.), planner,
executor etc.
-) In v6.3.2 the types of the attributes of two select statements
connected by the UNION keyword had to match 100%. In v6.4 the types
only need to be familiar (i.e. int and float can be mixed). Since this
feature did not exist when I worked on Intersect/Except it
does not work correctly for Except/Intersect queries WHEN USED IN
COMBINATION WITH UNIONS! (i.e. sometimes the wrong type is used for the
resulting table. This is because until now the types of the attributes of
the first select statement have been used for the resulting table.
When Intersects and/or Excepts are used in combination with Unions it
might happen, that the first select statement of the original query
appears at another position in the query which will be executed. The reason
for this is the technique used for the implementation of
Except/Intersect which does a query rewrite!)
NOTE: It is NOT broken for pure UNION queries and pure INTERSECT/EXCEPT
queries!!!
-) I had to add the field intersect_clause to some data structures
but did not find time to implement printfuncs for the new field.
This does NOT break the debug modes but when an Except/Intersect
is used the query debug output will be the already rewritten query.
-) Massive changes to the grammar rules for SELECT and INSERT statements
have been necessary (see comments in gram.y and documentation for
deatails) in order to be able to use mixed queries like
(SELECT ... UNION (SELECT ... EXCEPT SELECT)) INTERSECT SELECT...;
-) When using UNION/EXCEPT/INTERSECT you will get:
NOTICE: equal: "Don't know if nodes of type xxx are equal".
I did not have time to add comparsion support for all the needed nodes,
but the default behaviour of the function equal met my requirements.
I did not dare to supress this message!
That's the reason why the regression test for union will fail: These
messages are also included in the union.out file!
-) Somebody of you changed the union_planner() function for v6.4
(I copied the targetlist to new_tlist and that was removed and
replaced by a cleanup of the original targetlist). These chnages
violated some having queries executed against views so I changed
it back again. I did not have time to examine the differences between the
two versions but now it works :-)
If you want to find out, try the file queries/view_having.sql on
both versions and compare the results . Two queries won't produce a
correct result with your version.
regards
Stefan
1999-01-18 01:10:17 +01:00
|
|
|
}
|
|
|
|
$$ = (Node *)makeA_Expr(OR,NULL,$1,$4);
|
|
|
|
}
|
1999-02-23 08:42:41 +01:00
|
|
|
| select_clause INTERSECT select_clause
|
Hi!
INTERSECT and EXCEPT is available for postgresql-v6.4!
The patch against v6.4 is included at the end of the current text
(in uuencoded form!)
I also included the text of my Master's Thesis. (a postscript
version). I hope that you find something of it useful and would be
happy if parts of it find their way into the PostgreSQL documentation
project (If so, tell me, then I send the sources of the document!)
The contents of the document are:
-) The first chapter might be of less interest as it gives only an
overview on SQL.
-) The second chapter gives a description on much of PostgreSQL's
features (like user defined types etc. and how to use these features)
-) The third chapter starts with an overview of PostgreSQL's internal
structure with focus on the stages a query has to pass (i.e. parser,
planner/optimizer, executor). Then a detailed description of the
implementation of the Having clause and the Intersect/Except logic is
given.
Originally I worked on v6.3.2 but never found time enough to prepare
and post a patch. Now I applied the changes to v6.4 to get Intersect
and Except working with the new version. Chapter 3 of my documentation
deals with the changes against v6.3.2, so keep that in mind when
comparing the parts of the code printed there with the patched sources
of v6.4.
Here are some remarks on the patch. There are some things that have
still to be done but at the moment I don't have time to do them
myself. (I'm doing my military service at the moment) Sorry for that
:-(
-) I used a rewrite technique for the implementation of the Except/Intersect
logic which rewrites the query to a semantically equivalent query before
it is handed to the rewrite system (for views, rules etc.), planner,
executor etc.
-) In v6.3.2 the types of the attributes of two select statements
connected by the UNION keyword had to match 100%. In v6.4 the types
only need to be familiar (i.e. int and float can be mixed). Since this
feature did not exist when I worked on Intersect/Except it
does not work correctly for Except/Intersect queries WHEN USED IN
COMBINATION WITH UNIONS! (i.e. sometimes the wrong type is used for the
resulting table. This is because until now the types of the attributes of
the first select statement have been used for the resulting table.
When Intersects and/or Excepts are used in combination with Unions it
might happen, that the first select statement of the original query
appears at another position in the query which will be executed. The reason
for this is the technique used for the implementation of
Except/Intersect which does a query rewrite!)
NOTE: It is NOT broken for pure UNION queries and pure INTERSECT/EXCEPT
queries!!!
-) I had to add the field intersect_clause to some data structures
but did not find time to implement printfuncs for the new field.
This does NOT break the debug modes but when an Except/Intersect
is used the query debug output will be the already rewritten query.
-) Massive changes to the grammar rules for SELECT and INSERT statements
have been necessary (see comments in gram.y and documentation for
deatails) in order to be able to use mixed queries like
(SELECT ... UNION (SELECT ... EXCEPT SELECT)) INTERSECT SELECT...;
-) When using UNION/EXCEPT/INTERSECT you will get:
NOTICE: equal: "Don't know if nodes of type xxx are equal".
I did not have time to add comparsion support for all the needed nodes,
but the default behaviour of the function equal met my requirements.
I did not dare to supress this message!
That's the reason why the regression test for union will fail: These
messages are also included in the union.out file!
-) Somebody of you changed the union_planner() function for v6.4
(I copied the targetlist to new_tlist and that was removed and
replaced by a cleanup of the original targetlist). These chnages
violated some having queries executed against views so I changed
it back again. I did not have time to examine the differences between the
two versions but now it works :-)
If you want to find out, try the file queries/view_having.sql on
both versions and compare the results . Two queries won't produce a
correct result with your version.
regards
Stefan
1999-01-18 01:10:17 +01:00
|
|
|
{
|
|
|
|
$$ = (Node *)makeA_Expr(AND,NULL,$1,$3);
|
|
|
|
}
|
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1999-07-17 00:29:42 +02:00
|
|
|
SubSelect: SELECT opt_unique target_list
|
1997-10-25 07:56:41 +02:00
|
|
|
result from_clause where_clause
|
|
|
|
group_clause having_clause
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
1998-01-09 21:06:08 +01:00
|
|
|
SelectStmt *n = makeNode(SelectStmt);
|
1997-09-08 05:20:18 +02:00
|
|
|
n->unique = $2;
|
Hi!
INTERSECT and EXCEPT is available for postgresql-v6.4!
The patch against v6.4 is included at the end of the current text
(in uuencoded form!)
I also included the text of my Master's Thesis. (a postscript
version). I hope that you find something of it useful and would be
happy if parts of it find their way into the PostgreSQL documentation
project (If so, tell me, then I send the sources of the document!)
The contents of the document are:
-) The first chapter might be of less interest as it gives only an
overview on SQL.
-) The second chapter gives a description on much of PostgreSQL's
features (like user defined types etc. and how to use these features)
-) The third chapter starts with an overview of PostgreSQL's internal
structure with focus on the stages a query has to pass (i.e. parser,
planner/optimizer, executor). Then a detailed description of the
implementation of the Having clause and the Intersect/Except logic is
given.
Originally I worked on v6.3.2 but never found time enough to prepare
and post a patch. Now I applied the changes to v6.4 to get Intersect
and Except working with the new version. Chapter 3 of my documentation
deals with the changes against v6.3.2, so keep that in mind when
comparing the parts of the code printed there with the patched sources
of v6.4.
Here are some remarks on the patch. There are some things that have
still to be done but at the moment I don't have time to do them
myself. (I'm doing my military service at the moment) Sorry for that
:-(
-) I used a rewrite technique for the implementation of the Except/Intersect
logic which rewrites the query to a semantically equivalent query before
it is handed to the rewrite system (for views, rules etc.), planner,
executor etc.
-) In v6.3.2 the types of the attributes of two select statements
connected by the UNION keyword had to match 100%. In v6.4 the types
only need to be familiar (i.e. int and float can be mixed). Since this
feature did not exist when I worked on Intersect/Except it
does not work correctly for Except/Intersect queries WHEN USED IN
COMBINATION WITH UNIONS! (i.e. sometimes the wrong type is used for the
resulting table. This is because until now the types of the attributes of
the first select statement have been used for the resulting table.
When Intersects and/or Excepts are used in combination with Unions it
might happen, that the first select statement of the original query
appears at another position in the query which will be executed. The reason
for this is the technique used for the implementation of
Except/Intersect which does a query rewrite!)
NOTE: It is NOT broken for pure UNION queries and pure INTERSECT/EXCEPT
queries!!!
-) I had to add the field intersect_clause to some data structures
but did not find time to implement printfuncs for the new field.
This does NOT break the debug modes but when an Except/Intersect
is used the query debug output will be the already rewritten query.
-) Massive changes to the grammar rules for SELECT and INSERT statements
have been necessary (see comments in gram.y and documentation for
deatails) in order to be able to use mixed queries like
(SELECT ... UNION (SELECT ... EXCEPT SELECT)) INTERSECT SELECT...;
-) When using UNION/EXCEPT/INTERSECT you will get:
NOTICE: equal: "Don't know if nodes of type xxx are equal".
I did not have time to add comparsion support for all the needed nodes,
but the default behaviour of the function equal met my requirements.
I did not dare to supress this message!
That's the reason why the regression test for union will fail: These
messages are also included in the union.out file!
-) Somebody of you changed the union_planner() function for v6.4
(I copied the targetlist to new_tlist and that was removed and
replaced by a cleanup of the original targetlist). These chnages
violated some having queries executed against views so I changed
it back again. I did not have time to examine the differences between the
two versions but now it works :-)
If you want to find out, try the file queries/view_having.sql on
both versions and compare the results . Two queries won't produce a
correct result with your version.
regards
Stefan
1999-01-18 01:10:17 +01:00
|
|
|
n->unionall = FALSE;
|
1997-09-08 05:20:18 +02:00
|
|
|
n->targetList = $3;
|
Hi!
INTERSECT and EXCEPT is available for postgresql-v6.4!
The patch against v6.4 is included at the end of the current text
(in uuencoded form!)
I also included the text of my Master's Thesis. (a postscript
version). I hope that you find something of it useful and would be
happy if parts of it find their way into the PostgreSQL documentation
project (If so, tell me, then I send the sources of the document!)
The contents of the document are:
-) The first chapter might be of less interest as it gives only an
overview on SQL.
-) The second chapter gives a description on much of PostgreSQL's
features (like user defined types etc. and how to use these features)
-) The third chapter starts with an overview of PostgreSQL's internal
structure with focus on the stages a query has to pass (i.e. parser,
planner/optimizer, executor). Then a detailed description of the
implementation of the Having clause and the Intersect/Except logic is
given.
Originally I worked on v6.3.2 but never found time enough to prepare
and post a patch. Now I applied the changes to v6.4 to get Intersect
and Except working with the new version. Chapter 3 of my documentation
deals with the changes against v6.3.2, so keep that in mind when
comparing the parts of the code printed there with the patched sources
of v6.4.
Here are some remarks on the patch. There are some things that have
still to be done but at the moment I don't have time to do them
myself. (I'm doing my military service at the moment) Sorry for that
:-(
-) I used a rewrite technique for the implementation of the Except/Intersect
logic which rewrites the query to a semantically equivalent query before
it is handed to the rewrite system (for views, rules etc.), planner,
executor etc.
-) In v6.3.2 the types of the attributes of two select statements
connected by the UNION keyword had to match 100%. In v6.4 the types
only need to be familiar (i.e. int and float can be mixed). Since this
feature did not exist when I worked on Intersect/Except it
does not work correctly for Except/Intersect queries WHEN USED IN
COMBINATION WITH UNIONS! (i.e. sometimes the wrong type is used for the
resulting table. This is because until now the types of the attributes of
the first select statement have been used for the resulting table.
When Intersects and/or Excepts are used in combination with Unions it
might happen, that the first select statement of the original query
appears at another position in the query which will be executed. The reason
for this is the technique used for the implementation of
Except/Intersect which does a query rewrite!)
NOTE: It is NOT broken for pure UNION queries and pure INTERSECT/EXCEPT
queries!!!
-) I had to add the field intersect_clause to some data structures
but did not find time to implement printfuncs for the new field.
This does NOT break the debug modes but when an Except/Intersect
is used the query debug output will be the already rewritten query.
-) Massive changes to the grammar rules for SELECT and INSERT statements
have been necessary (see comments in gram.y and documentation for
deatails) in order to be able to use mixed queries like
(SELECT ... UNION (SELECT ... EXCEPT SELECT)) INTERSECT SELECT...;
-) When using UNION/EXCEPT/INTERSECT you will get:
NOTICE: equal: "Don't know if nodes of type xxx are equal".
I did not have time to add comparsion support for all the needed nodes,
but the default behaviour of the function equal met my requirements.
I did not dare to supress this message!
That's the reason why the regression test for union will fail: These
messages are also included in the union.out file!
-) Somebody of you changed the union_planner() function for v6.4
(I copied the targetlist to new_tlist and that was removed and
replaced by a cleanup of the original targetlist). These chnages
violated some having queries executed against views so I changed
it back again. I did not have time to examine the differences between the
two versions but now it works :-)
If you want to find out, try the file queries/view_having.sql on
both versions and compare the results . Two queries won't produce a
correct result with your version.
regards
Stefan
1999-01-18 01:10:17 +01:00
|
|
|
/* This is new: Subselects support the INTO clause
|
|
|
|
* which allows queries that are not part of the
|
|
|
|
* SQL92 standard and should not be formulated!
|
|
|
|
* We need it for INTERSECT and EXCEPT and I did not
|
|
|
|
* want to create a new rule 'SubSelect1' including the
|
|
|
|
* feature. If it makes troubles we will have to add
|
|
|
|
* a new rule and change this to prevent INTOs in
|
1999-07-20 02:18:01 +02:00
|
|
|
* Subselects again.
|
|
|
|
*/
|
1999-02-06 21:28:11 +01:00
|
|
|
n->istemp = (bool) ((Value *) lfirst($4))->val.ival;
|
|
|
|
n->into = (char *) lnext($4);
|
Hi!
INTERSECT and EXCEPT is available for postgresql-v6.4!
The patch against v6.4 is included at the end of the current text
(in uuencoded form!)
I also included the text of my Master's Thesis. (a postscript
version). I hope that you find something of it useful and would be
happy if parts of it find their way into the PostgreSQL documentation
project (If so, tell me, then I send the sources of the document!)
The contents of the document are:
-) The first chapter might be of less interest as it gives only an
overview on SQL.
-) The second chapter gives a description on much of PostgreSQL's
features (like user defined types etc. and how to use these features)
-) The third chapter starts with an overview of PostgreSQL's internal
structure with focus on the stages a query has to pass (i.e. parser,
planner/optimizer, executor). Then a detailed description of the
implementation of the Having clause and the Intersect/Except logic is
given.
Originally I worked on v6.3.2 but never found time enough to prepare
and post a patch. Now I applied the changes to v6.4 to get Intersect
and Except working with the new version. Chapter 3 of my documentation
deals with the changes against v6.3.2, so keep that in mind when
comparing the parts of the code printed there with the patched sources
of v6.4.
Here are some remarks on the patch. There are some things that have
still to be done but at the moment I don't have time to do them
myself. (I'm doing my military service at the moment) Sorry for that
:-(
-) I used a rewrite technique for the implementation of the Except/Intersect
logic which rewrites the query to a semantically equivalent query before
it is handed to the rewrite system (for views, rules etc.), planner,
executor etc.
-) In v6.3.2 the types of the attributes of two select statements
connected by the UNION keyword had to match 100%. In v6.4 the types
only need to be familiar (i.e. int and float can be mixed). Since this
feature did not exist when I worked on Intersect/Except it
does not work correctly for Except/Intersect queries WHEN USED IN
COMBINATION WITH UNIONS! (i.e. sometimes the wrong type is used for the
resulting table. This is because until now the types of the attributes of
the first select statement have been used for the resulting table.
When Intersects and/or Excepts are used in combination with Unions it
might happen, that the first select statement of the original query
appears at another position in the query which will be executed. The reason
for this is the technique used for the implementation of
Except/Intersect which does a query rewrite!)
NOTE: It is NOT broken for pure UNION queries and pure INTERSECT/EXCEPT
queries!!!
-) I had to add the field intersect_clause to some data structures
but did not find time to implement printfuncs for the new field.
This does NOT break the debug modes but when an Except/Intersect
is used the query debug output will be the already rewritten query.
-) Massive changes to the grammar rules for SELECT and INSERT statements
have been necessary (see comments in gram.y and documentation for
deatails) in order to be able to use mixed queries like
(SELECT ... UNION (SELECT ... EXCEPT SELECT)) INTERSECT SELECT...;
-) When using UNION/EXCEPT/INTERSECT you will get:
NOTICE: equal: "Don't know if nodes of type xxx are equal".
I did not have time to add comparsion support for all the needed nodes,
but the default behaviour of the function equal met my requirements.
I did not dare to supress this message!
That's the reason why the regression test for union will fail: These
messages are also included in the union.out file!
-) Somebody of you changed the union_planner() function for v6.4
(I copied the targetlist to new_tlist and that was removed and
replaced by a cleanup of the original targetlist). These chnages
violated some having queries executed against views so I changed
it back again. I did not have time to examine the differences between the
two versions but now it works :-)
If you want to find out, try the file queries/view_having.sql on
both versions and compare the results . Two queries won't produce a
correct result with your version.
regards
Stefan
1999-01-18 01:10:17 +01:00
|
|
|
|
1997-09-08 05:20:18 +02:00
|
|
|
n->fromClause = $5;
|
|
|
|
n->whereClause = $6;
|
|
|
|
n->groupClause = $7;
|
|
|
|
n->havingClause = $8;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
;
|
1997-09-01 08:00:35 +02:00
|
|
|
|
1999-02-02 04:45:56 +01:00
|
|
|
/* easy way to return two values. Can someone improve this? bjm */
|
|
|
|
result: INTO OptTemp opt_table relation_name { $$ = lcons(makeInteger($2), (List *)$4); }
|
|
|
|
| /*EMPTY*/ { $$ = lcons(makeInteger(false), NIL); }
|
1998-03-18 17:50:25 +01:00
|
|
|
;
|
|
|
|
|
|
|
|
opt_table: TABLE { $$ = TRUE; }
|
|
|
|
| /*EMPTY*/ { $$ = FALSE; }
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1999-11-15 03:00:15 +01:00
|
|
|
opt_all: ALL { $$ = TRUE; }
|
1997-11-17 17:37:24 +01:00
|
|
|
| /*EMPTY*/ { $$ = FALSE; }
|
|
|
|
;
|
|
|
|
|
1997-10-25 07:56:41 +02:00
|
|
|
opt_unique: DISTINCT { $$ = "*"; }
|
|
|
|
| DISTINCT ON ColId { $$ = $3; }
|
1997-11-17 17:37:24 +01:00
|
|
|
| ALL { $$ = NULL; }
|
|
|
|
| /*EMPTY*/ { $$ = NULL; }
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-08 05:20:18 +02:00
|
|
|
sort_clause: ORDER BY sortby_list { $$ = $3; }
|
1997-11-07 08:02:10 +01:00
|
|
|
| /*EMPTY*/ { $$ = NIL; }
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-10-25 07:56:41 +02:00
|
|
|
sortby_list: sortby { $$ = lcons($1, NIL); }
|
|
|
|
| sortby_list ',' sortby { $$ = lappend($1, $3); }
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1998-08-05 06:49:19 +02:00
|
|
|
sortby: a_expr OptUseOp
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
$$ = makeNode(SortGroupBy);
|
1998-08-05 06:49:19 +02:00
|
|
|
$$->node = $1;
|
1997-09-08 05:20:18 +02:00
|
|
|
$$->useOp = $2;
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
1999-11-20 22:39:36 +01:00
|
|
|
OptUseOp: USING all_Op { $$ = $2; }
|
1997-10-25 07:56:41 +02:00
|
|
|
| ASC { $$ = "<"; }
|
|
|
|
| DESC { $$ = ">"; }
|
|
|
|
| /*EMPTY*/ { $$ = "<"; /*default*/ }
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1999-02-08 15:14:32 +01:00
|
|
|
|
|
|
|
opt_select_limit: LIMIT select_limit_value ',' select_offset_value
|
|
|
|
{ $$ = lappend(lappend(NIL, $4), $2); }
|
|
|
|
| LIMIT select_limit_value OFFSET select_offset_value
|
|
|
|
{ $$ = lappend(lappend(NIL, $4), $2); }
|
|
|
|
| LIMIT select_limit_value
|
|
|
|
{ $$ = lappend(lappend(NIL, NULL), $2); }
|
|
|
|
| OFFSET select_offset_value LIMIT select_limit_value
|
|
|
|
{ $$ = lappend(lappend(NIL, $2), $4); }
|
|
|
|
| OFFSET select_offset_value
|
|
|
|
{ $$ = lappend(lappend(NIL, $2), NULL); }
|
|
|
|
| /* EMPTY */
|
|
|
|
{ $$ = lappend(lappend(NIL, NULL), NULL); }
|
|
|
|
;
|
|
|
|
|
|
|
|
select_limit_value: Iconst
|
|
|
|
{
|
|
|
|
Const *n = makeNode(Const);
|
|
|
|
|
|
|
|
if ($1 < 1)
|
|
|
|
elog(ERROR, "selection limit must be ALL or a positive integer value > 0");
|
|
|
|
|
|
|
|
n->consttype = INT4OID;
|
|
|
|
n->constlen = sizeof(int4);
|
|
|
|
n->constvalue = (Datum)$1;
|
|
|
|
n->constisnull = FALSE;
|
|
|
|
n->constbyval = TRUE;
|
|
|
|
n->constisset = FALSE;
|
|
|
|
n->constiscast = FALSE;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
| ALL
|
|
|
|
{
|
|
|
|
Const *n = makeNode(Const);
|
|
|
|
|
|
|
|
n->consttype = INT4OID;
|
|
|
|
n->constlen = sizeof(int4);
|
|
|
|
n->constvalue = (Datum)0;
|
|
|
|
n->constisnull = FALSE;
|
|
|
|
n->constbyval = TRUE;
|
|
|
|
n->constisset = FALSE;
|
|
|
|
n->constiscast = FALSE;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
| PARAM
|
|
|
|
{
|
|
|
|
Param *n = makeNode(Param);
|
|
|
|
|
|
|
|
n->paramkind = PARAM_NUM;
|
|
|
|
n->paramid = $1;
|
|
|
|
n->paramtype = INT4OID;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
|
|
|
select_offset_value: Iconst
|
|
|
|
{
|
|
|
|
Const *n = makeNode(Const);
|
|
|
|
|
|
|
|
n->consttype = INT4OID;
|
|
|
|
n->constlen = sizeof(int4);
|
|
|
|
n->constvalue = (Datum)$1;
|
|
|
|
n->constisnull = FALSE;
|
|
|
|
n->constbyval = TRUE;
|
|
|
|
n->constisset = FALSE;
|
|
|
|
n->constiscast = FALSE;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
| PARAM
|
|
|
|
{
|
|
|
|
Param *n = makeNode(Param);
|
|
|
|
|
|
|
|
n->paramkind = PARAM_NUM;
|
|
|
|
n->paramid = $1;
|
|
|
|
n->paramtype = INT4OID;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
/*
|
1997-09-08 05:20:18 +02:00
|
|
|
* jimmy bell-style recursive queries aren't supported in the
|
|
|
|
* current system.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1997-09-08 05:20:18 +02:00
|
|
|
* ...however, recursive addattr and rename supported. make special
|
|
|
|
* cases for these.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
1997-10-25 07:56:41 +02:00
|
|
|
opt_inh_star: '*' { $$ = TRUE; }
|
|
|
|
| /*EMPTY*/ { $$ = FALSE; }
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-10-25 07:56:41 +02:00
|
|
|
relation_name_list: name_list;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-10-25 07:56:41 +02:00
|
|
|
name_list: name
|
1997-09-18 05:46:18 +02:00
|
|
|
{ $$ = lcons(makeString($1),NIL); }
|
1997-09-08 05:20:18 +02:00
|
|
|
| name_list ',' name
|
1997-09-18 05:46:18 +02:00
|
|
|
{ $$ = lappend($1,makeString($3)); }
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1999-02-23 08:42:41 +01:00
|
|
|
group_clause: GROUP BY expr_list { $$ = $3; }
|
1997-09-08 05:20:18 +02:00
|
|
|
| /*EMPTY*/ { $$ = NIL; }
|
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1998-01-20 06:05:08 +01:00
|
|
|
having_clause: HAVING a_expr
|
|
|
|
{
|
1998-05-10 01:22:15 +02:00
|
|
|
$$ = $2;
|
1998-01-20 06:05:08 +01:00
|
|
|
}
|
1997-09-08 05:20:18 +02:00
|
|
|
| /*EMPTY*/ { $$ = NULL; }
|
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1999-02-23 08:42:41 +01:00
|
|
|
for_update_clause: FOR UPDATE update_list { $$ = $3; }
|
1999-05-20 14:12:55 +02:00
|
|
|
| FOR READ ONLY { $$ = NULL; }
|
1999-02-23 08:42:41 +01:00
|
|
|
| /* EMPTY */ { $$ = NULL; }
|
|
|
|
;
|
|
|
|
|
|
|
|
update_list: OF va_list { $$ = $2; }
|
|
|
|
| /* EMPTY */ { $$ = lcons(NULL, NULL); }
|
1999-01-05 16:46:25 +01:00
|
|
|
;
|
1997-10-25 07:56:41 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*****************************************************************************
|
1997-09-01 08:00:35 +02:00
|
|
|
*
|
1997-09-08 05:20:18 +02:00
|
|
|
* clauses common to all Optimizable Stmts:
|
|
|
|
* from_clause -
|
|
|
|
* where_clause -
|
1997-09-01 08:00:35 +02:00
|
|
|
*
|
1996-07-09 08:22:35 +02:00
|
|
|
*****************************************************************************/
|
|
|
|
|
1999-02-23 08:42:41 +01:00
|
|
|
from_clause: FROM from_expr { $$ = $2; }
|
1997-09-08 05:20:18 +02:00
|
|
|
| /*EMPTY*/ { $$ = NIL; }
|
|
|
|
;
|
|
|
|
|
1999-02-23 08:42:41 +01:00
|
|
|
from_expr: '(' join_clause_with_union ')'
|
|
|
|
{ $$ = $2; }
|
|
|
|
| join_clause
|
|
|
|
{ $$ = $1; }
|
|
|
|
| table_list
|
|
|
|
{ $$ = $1; }
|
|
|
|
;
|
|
|
|
|
|
|
|
table_list: table_list ',' table_expr
|
1997-09-08 05:20:18 +02:00
|
|
|
{ $$ = lappend($1, $3); }
|
1999-02-23 08:42:41 +01:00
|
|
|
| table_expr
|
1997-09-08 05:20:18 +02:00
|
|
|
{ $$ = lcons($1, NIL); }
|
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1999-02-23 08:42:41 +01:00
|
|
|
table_expr: relation_expr AS ColLabel
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
$$ = makeNode(RangeVar);
|
|
|
|
$$->relExpr = $1;
|
|
|
|
$$->name = $3;
|
|
|
|
}
|
1997-10-25 07:56:41 +02:00
|
|
|
| relation_expr ColId
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
$$ = makeNode(RangeVar);
|
|
|
|
$$->relExpr = $1;
|
|
|
|
$$->name = $2;
|
|
|
|
}
|
|
|
|
| relation_expr
|
|
|
|
{
|
|
|
|
$$ = makeNode(RangeVar);
|
|
|
|
$$->relExpr = $1;
|
|
|
|
$$->name = NULL;
|
|
|
|
}
|
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1999-02-23 08:42:41 +01:00
|
|
|
/* A UNION JOIN is the same as a FULL OUTER JOIN which *omits*
|
|
|
|
* all result rows which would have matched on an INNER JOIN.
|
|
|
|
* Let's reject this for now. - thomas 1999-01-08
|
|
|
|
*/
|
|
|
|
join_clause_with_union: join_clause
|
|
|
|
{ $$ = $1; }
|
|
|
|
| table_expr UNION JOIN table_expr
|
|
|
|
{ elog(ERROR,"UNION JOIN not yet implemented"); }
|
|
|
|
;
|
|
|
|
|
|
|
|
join_clause: table_expr join_list
|
|
|
|
{
|
|
|
|
Node *n = lfirst($2);
|
|
|
|
|
|
|
|
/* JoinExpr came back? then it is a join of some sort...
|
|
|
|
*/
|
|
|
|
if (IsA(n, JoinExpr))
|
|
|
|
{
|
|
|
|
JoinExpr *j = (JoinExpr *)n;
|
|
|
|
j->larg = $1;
|
|
|
|
$$ = $2;
|
|
|
|
}
|
|
|
|
/* otherwise, it was a cross join,
|
|
|
|
* which we just represent as an inner join...
|
|
|
|
*/
|
|
|
|
else
|
|
|
|
$$ = lcons($1, $2);
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
|
|
|
join_list: join_list join_expr
|
|
|
|
{
|
|
|
|
$$ = lappend($1, $2);
|
|
|
|
}
|
|
|
|
| join_expr
|
|
|
|
{
|
|
|
|
$$ = lcons($1, NIL);
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
|
|
|
/* This is everything but the left side of a join.
|
|
|
|
* Note that a CROSS JOIN is the same as an unqualified
|
|
|
|
* inner join, so just pass back the right-side table.
|
|
|
|
* A NATURAL JOIN implicitly matches column names between
|
|
|
|
* tables, so we'll collect those during the later transformation.
|
|
|
|
*/
|
|
|
|
join_expr: join_type JOIN table_expr join_qual
|
|
|
|
{
|
|
|
|
JoinExpr *n = makeNode(JoinExpr);
|
|
|
|
n->jointype = $1;
|
|
|
|
n->rarg = (Node *)$3;
|
|
|
|
n->quals = $4;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
| NATURAL join_type JOIN table_expr
|
|
|
|
{
|
|
|
|
JoinExpr *n = makeNode(JoinExpr);
|
|
|
|
n->jointype = $2;
|
|
|
|
n->rarg = (Node *)$4;
|
|
|
|
n->quals = NULL; /* figure out which columns later... */
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
| CROSS JOIN table_expr
|
|
|
|
{ $$ = (Node *)$3; }
|
|
|
|
;
|
|
|
|
|
|
|
|
/* OUTER is just noise... */
|
|
|
|
join_type: FULL join_outer
|
|
|
|
{
|
|
|
|
$$ = FULL;
|
|
|
|
elog(NOTICE,"FULL OUTER JOIN not yet implemented");
|
|
|
|
}
|
1997-09-08 05:20:18 +02:00
|
|
|
| LEFT join_outer
|
1999-02-23 08:42:41 +01:00
|
|
|
{
|
|
|
|
$$ = LEFT;
|
|
|
|
elog(NOTICE,"LEFT OUTER JOIN not yet implemented");
|
|
|
|
}
|
1997-09-08 05:20:18 +02:00
|
|
|
| RIGHT join_outer
|
1999-02-23 08:42:41 +01:00
|
|
|
{
|
|
|
|
$$ = RIGHT;
|
|
|
|
elog(NOTICE,"RIGHT OUTER JOIN not yet implemented");
|
|
|
|
}
|
1997-10-25 07:56:41 +02:00
|
|
|
| OUTER_P
|
1999-02-23 08:42:41 +01:00
|
|
|
{
|
|
|
|
$$ = LEFT;
|
|
|
|
elog(NOTICE,"OUTER JOIN not yet implemented");
|
|
|
|
}
|
1997-10-25 07:56:41 +02:00
|
|
|
| INNER_P
|
1999-02-23 08:42:41 +01:00
|
|
|
{
|
|
|
|
$$ = INNER_P;
|
|
|
|
}
|
1997-09-13 05:15:46 +02:00
|
|
|
| /*EMPTY*/
|
1999-02-23 08:42:41 +01:00
|
|
|
{
|
|
|
|
$$ = INNER_P;
|
|
|
|
}
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
|
|
|
|
1997-10-25 07:56:41 +02:00
|
|
|
join_outer: OUTER_P { $$ = NULL; }
|
|
|
|
| /*EMPTY*/ { $$ = NULL; /* no qualifiers */ }
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
|
|
|
|
1999-02-23 08:42:41 +01:00
|
|
|
/* JOIN qualification clauses
|
|
|
|
* Possibilities are:
|
|
|
|
* USING ( column list ) allows only unqualified column names,
|
|
|
|
* which must match between tables.
|
|
|
|
* ON expr allows more general qualifications.
|
|
|
|
* - thomas 1999-01-07
|
|
|
|
*/
|
|
|
|
|
|
|
|
join_qual: USING '(' using_list ')' { $$ = $3; }
|
|
|
|
| ON a_expr { $$ = lcons($2, NIL); }
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
|
|
|
|
1999-02-23 08:42:41 +01:00
|
|
|
using_list: using_list ',' using_expr { $$ = lappend($1, $3); }
|
|
|
|
| using_expr { $$ = lcons($1, NIL); }
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
1997-09-01 08:00:35 +02:00
|
|
|
|
1999-02-23 08:42:41 +01:00
|
|
|
using_expr: ColId
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
1999-02-23 08:42:41 +01:00
|
|
|
/* could be a column name or a relation_name */
|
|
|
|
Ident *n = makeNode(Ident);
|
|
|
|
n->name = $1;
|
|
|
|
n->indirection = NULL;
|
|
|
|
$$ = (Node *)n;
|
1997-09-08 05:20:18 +02:00
|
|
|
}
|
|
|
|
;
|
|
|
|
|
1997-10-25 07:56:41 +02:00
|
|
|
where_clause: WHERE a_expr { $$ = $2; }
|
|
|
|
| /*EMPTY*/ { $$ = NULL; /* no qualifiers */ }
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
|
|
|
|
|
|
|
relation_expr: relation_name
|
|
|
|
{
|
|
|
|
/* normal relations */
|
|
|
|
$$ = makeNode(RelExpr);
|
|
|
|
$$->relname = $1;
|
|
|
|
$$->inh = FALSE;
|
|
|
|
}
|
|
|
|
| relation_name '*' %prec '='
|
|
|
|
{
|
1997-12-23 20:47:32 +01:00
|
|
|
/* inheritance query */
|
1997-09-08 05:20:18 +02:00
|
|
|
$$ = makeNode(RelExpr);
|
|
|
|
$$->relname = $1;
|
|
|
|
$$->inh = TRUE;
|
|
|
|
}
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1999-07-17 00:29:42 +02:00
|
|
|
opt_array_bounds: '[' ']' opt_array_bounds
|
1997-09-08 05:20:18 +02:00
|
|
|
{ $$ = lcons(makeInteger(-1), $3); }
|
1999-07-17 00:29:42 +02:00
|
|
|
| '[' Iconst ']' opt_array_bounds
|
1997-09-08 05:20:18 +02:00
|
|
|
{ $$ = lcons(makeInteger($2), $4); }
|
|
|
|
| /*EMPTY*/
|
|
|
|
{ $$ = NIL; }
|
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-20 18:11:44 +02:00
|
|
|
|
1997-10-25 07:56:41 +02:00
|
|
|
/*****************************************************************************
|
|
|
|
*
|
|
|
|
* Type syntax
|
|
|
|
* SQL92 introduces a large amount of type-specific syntax.
|
|
|
|
* Define individual clauses to handle these cases, and use
|
|
|
|
* the generic case to handle regular type-extensible Postgres syntax.
|
|
|
|
* - thomas 1997-10-10
|
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
|
1999-07-17 00:29:42 +02:00
|
|
|
Typename: SimpleTypename opt_array_bounds
|
1997-10-25 07:56:41 +02:00
|
|
|
{
|
|
|
|
$$ = $1;
|
|
|
|
$$->arrayBounds = $2;
|
1997-09-08 05:20:18 +02:00
|
|
|
|
|
|
|
/* Is this the name of a complex type? If so, implement
|
|
|
|
* it as a set.
|
|
|
|
*/
|
1997-10-25 07:56:41 +02:00
|
|
|
if (!strcmp(saved_relname, $$->name))
|
1997-09-08 05:20:18 +02:00
|
|
|
/* This attr is the same type as the relation
|
|
|
|
* being defined. The classic example: create
|
|
|
|
* emp(name=text,mgr=emp)
|
|
|
|
*/
|
|
|
|
$$->setof = TRUE;
|
1997-11-25 23:07:18 +01:00
|
|
|
else if (typeTypeRelid(typenameType($$->name)) != InvalidOid)
|
1997-09-08 05:20:18 +02:00
|
|
|
/* (Eventually add in here that the set can only
|
|
|
|
* contain one element.)
|
|
|
|
*/
|
|
|
|
$$->setof = TRUE;
|
|
|
|
else
|
|
|
|
$$->setof = FALSE;
|
|
|
|
}
|
1999-07-17 00:29:42 +02:00
|
|
|
| SETOF SimpleTypename
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
1997-10-25 07:56:41 +02:00
|
|
|
$$ = $2;
|
1997-09-08 05:20:18 +02:00
|
|
|
$$->setof = TRUE;
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
1999-07-17 00:29:42 +02:00
|
|
|
SimpleTypename: Generic
|
1997-10-25 07:56:41 +02:00
|
|
|
| Numeric
|
1999-05-03 21:10:48 +02:00
|
|
|
| Character
|
1999-07-17 00:29:42 +02:00
|
|
|
| Datetime
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
1997-09-01 08:00:35 +02:00
|
|
|
|
1997-10-25 07:56:41 +02:00
|
|
|
Generic: generic
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
1997-10-25 07:56:41 +02:00
|
|
|
$$ = makeNode(TypeName);
|
|
|
|
$$->name = xlateSqlType($1);
|
1998-02-10 05:02:59 +01:00
|
|
|
$$->typmod = -1;
|
1997-10-25 07:56:41 +02:00
|
|
|
}
|
|
|
|
;
|
|
|
|
|
1998-02-11 05:09:54 +01:00
|
|
|
generic: IDENT { $$ = $1; }
|
1999-07-17 00:29:42 +02:00
|
|
|
| TYPE_P { $$ = "type"; }
|
1997-10-25 07:56:41 +02:00
|
|
|
;
|
|
|
|
|
|
|
|
/* SQL92 numeric data types
|
|
|
|
* Check FLOAT() precision limits assuming IEEE floating types.
|
1998-12-30 20:56:35 +01:00
|
|
|
* Provide real DECIMAL() and NUMERIC() implementations now - Jan 1998-12-30
|
1997-10-25 07:56:41 +02:00
|
|
|
* - thomas 1997-09-18
|
|
|
|
*/
|
|
|
|
Numeric: FLOAT opt_float
|
|
|
|
{
|
|
|
|
$$ = makeNode(TypeName);
|
|
|
|
$$->name = xlateSqlType($2);
|
1998-02-10 05:02:59 +01:00
|
|
|
$$->typmod = -1;
|
1997-09-08 05:20:18 +02:00
|
|
|
}
|
1998-02-11 05:09:54 +01:00
|
|
|
| DOUBLE PRECISION
|
|
|
|
{
|
|
|
|
$$ = makeNode(TypeName);
|
2000-01-20 03:24:50 +01:00
|
|
|
$$->name = xlateSqlType("float8");
|
|
|
|
$$->typmod = -1;
|
1998-02-11 05:09:54 +01:00
|
|
|
}
|
1997-10-25 07:56:41 +02:00
|
|
|
| DECIMAL opt_decimal
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
1997-09-20 18:11:44 +02:00
|
|
|
$$ = makeNode(TypeName);
|
2000-01-20 03:24:50 +01:00
|
|
|
$$->name = xlateSqlType("decimal");
|
1999-04-27 15:33:43 +02:00
|
|
|
$$->typmod = $2;
|
1997-10-25 07:56:41 +02:00
|
|
|
}
|
|
|
|
| NUMERIC opt_numeric
|
|
|
|
{
|
|
|
|
$$ = makeNode(TypeName);
|
1998-12-30 20:56:35 +01:00
|
|
|
$$->name = xlateSqlType("numeric");
|
|
|
|
$$->typmod = $2;
|
1997-10-25 07:56:41 +02:00
|
|
|
}
|
|
|
|
;
|
1997-09-08 05:20:18 +02:00
|
|
|
|
1998-02-11 05:09:54 +01:00
|
|
|
numeric: FLOAT
|
|
|
|
{ $$ = xlateSqlType("float8"); }
|
|
|
|
| DOUBLE PRECISION
|
|
|
|
{ $$ = xlateSqlType("float8"); }
|
|
|
|
| DECIMAL
|
2000-01-20 03:24:50 +01:00
|
|
|
{ $$ = xlateSqlType("decimal"); }
|
1998-02-11 05:09:54 +01:00
|
|
|
| NUMERIC
|
|
|
|
{ $$ = xlateSqlType("numeric"); }
|
|
|
|
;
|
|
|
|
|
1997-10-25 07:56:41 +02:00
|
|
|
opt_float: '(' Iconst ')'
|
|
|
|
{
|
|
|
|
if ($2 < 1)
|
1998-01-09 21:06:08 +01:00
|
|
|
elog(ERROR,"precision for FLOAT must be at least 1");
|
1997-10-25 07:56:41 +02:00
|
|
|
else if ($2 < 7)
|
|
|
|
$$ = xlateSqlType("float4");
|
|
|
|
else if ($2 < 16)
|
|
|
|
$$ = xlateSqlType("float8");
|
|
|
|
else
|
1998-01-09 21:06:08 +01:00
|
|
|
elog(ERROR,"precision for FLOAT must be less than 16");
|
1997-10-25 07:56:41 +02:00
|
|
|
}
|
|
|
|
| /*EMPTY*/
|
|
|
|
{
|
|
|
|
$$ = xlateSqlType("float8");
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
|
|
|
opt_numeric: '(' Iconst ',' Iconst ')'
|
|
|
|
{
|
1998-12-30 20:56:35 +01:00
|
|
|
if ($2 < 1 || $2 > NUMERIC_MAX_PRECISION)
|
1999-10-30 01:44:42 +02:00
|
|
|
elog(ERROR,"NUMERIC precision %d must be between 1 and %d",
|
1998-12-30 20:56:35 +01:00
|
|
|
$2, NUMERIC_MAX_PRECISION);
|
|
|
|
if ($4 < 0 || $4 > $2)
|
|
|
|
elog(ERROR,"NUMERIC scale %d must be between 0 and precision %d",
|
|
|
|
$4,$2);
|
|
|
|
|
|
|
|
$$ = (($2 << 16) | $4) + VARHDRSZ;
|
1997-10-25 07:56:41 +02:00
|
|
|
}
|
|
|
|
| '(' Iconst ')'
|
|
|
|
{
|
1998-12-30 20:56:35 +01:00
|
|
|
if ($2 < 1 || $2 > NUMERIC_MAX_PRECISION)
|
1999-10-30 01:44:42 +02:00
|
|
|
elog(ERROR,"NUMERIC precision %d must be between 1 and %d",
|
1998-12-30 20:56:35 +01:00
|
|
|
$2, NUMERIC_MAX_PRECISION);
|
|
|
|
|
|
|
|
$$ = ($2 << 16) + VARHDRSZ;
|
1997-10-25 07:56:41 +02:00
|
|
|
}
|
|
|
|
| /*EMPTY*/
|
|
|
|
{
|
2000-01-20 03:24:50 +01:00
|
|
|
/* Insert "-1" meaning "default"; may be replaced later */
|
|
|
|
$$ = -1;
|
1997-10-25 07:56:41 +02:00
|
|
|
}
|
|
|
|
;
|
|
|
|
|
|
|
|
opt_decimal: '(' Iconst ',' Iconst ')'
|
|
|
|
{
|
1998-12-30 20:56:35 +01:00
|
|
|
if ($2 < 1 || $2 > NUMERIC_MAX_PRECISION)
|
1999-10-30 01:44:42 +02:00
|
|
|
elog(ERROR,"DECIMAL precision %d must be between 1 and %d",
|
1998-12-30 20:56:35 +01:00
|
|
|
$2, NUMERIC_MAX_PRECISION);
|
|
|
|
if ($4 < 0 || $4 > $2)
|
|
|
|
elog(ERROR,"DECIMAL scale %d must be between 0 and precision %d",
|
|
|
|
$4,$2);
|
|
|
|
|
|
|
|
$$ = (($2 << 16) | $4) + VARHDRSZ;
|
1997-10-25 07:56:41 +02:00
|
|
|
}
|
|
|
|
| '(' Iconst ')'
|
|
|
|
{
|
1998-12-30 20:56:35 +01:00
|
|
|
if ($2 < 1 || $2 > NUMERIC_MAX_PRECISION)
|
1999-10-30 01:44:42 +02:00
|
|
|
elog(ERROR,"DECIMAL precision %d must be between 1 and %d",
|
1998-12-30 20:56:35 +01:00
|
|
|
$2, NUMERIC_MAX_PRECISION);
|
|
|
|
|
|
|
|
$$ = ($2 << 16) + VARHDRSZ;
|
1997-10-25 07:56:41 +02:00
|
|
|
}
|
|
|
|
| /*EMPTY*/
|
|
|
|
{
|
2000-01-20 03:24:50 +01:00
|
|
|
/* Insert "-1" meaning "default"; may be replaced later */
|
|
|
|
$$ = -1;
|
1997-10-25 07:56:41 +02:00
|
|
|
}
|
|
|
|
;
|
|
|
|
|
1998-12-30 20:56:35 +01:00
|
|
|
|
2000-01-20 03:24:50 +01:00
|
|
|
/*
|
|
|
|
* SQL92 character data types
|
1997-10-25 07:56:41 +02:00
|
|
|
* The following implements CHAR() and VARCHAR().
|
|
|
|
*/
|
|
|
|
Character: character '(' Iconst ')'
|
|
|
|
{
|
|
|
|
$$ = makeNode(TypeName);
|
2000-01-20 03:24:50 +01:00
|
|
|
$$->name = xlateSqlType($1);
|
1997-10-25 07:56:41 +02:00
|
|
|
if ($3 < 1)
|
2000-01-20 03:24:50 +01:00
|
|
|
elog(ERROR,"length for type '%s' must be at least 1",$1);
|
1999-07-04 06:56:02 +02:00
|
|
|
else if ($3 > MaxAttrSize)
|
2000-01-15 03:59:43 +01:00
|
|
|
elog(ERROR,"length for type '%s' cannot exceed %ld",$1,
|
1999-07-04 06:56:02 +02:00
|
|
|
MaxAttrSize);
|
1997-10-25 07:56:41 +02:00
|
|
|
|
2000-01-20 03:24:50 +01:00
|
|
|
/* we actually implement these like a varlen, so
|
1997-10-25 07:56:41 +02:00
|
|
|
* the first 4 bytes is the length. (the difference
|
2000-01-20 03:24:50 +01:00
|
|
|
* between these and "text" is that we blank-pad and
|
|
|
|
* truncate where necessary)
|
1997-10-25 07:56:41 +02:00
|
|
|
*/
|
1998-01-17 00:21:07 +01:00
|
|
|
$$->typmod = VARHDRSZ + $3;
|
1997-09-08 05:20:18 +02:00
|
|
|
}
|
1997-10-25 07:56:41 +02:00
|
|
|
| character
|
1997-09-24 19:53:53 +02:00
|
|
|
{
|
|
|
|
$$ = makeNode(TypeName);
|
2000-01-20 03:24:50 +01:00
|
|
|
$$->name = xlateSqlType($1);
|
|
|
|
/* default length, if needed, will be inserted later */
|
|
|
|
$$->typmod = -1;
|
1997-10-25 07:56:41 +02:00
|
|
|
}
|
|
|
|
;
|
1997-09-24 19:53:53 +02:00
|
|
|
|
1997-10-25 07:56:41 +02:00
|
|
|
character: CHARACTER opt_varying opt_charset opt_collate
|
|
|
|
{
|
|
|
|
char *type, *c;
|
|
|
|
if (($3 == NULL) || (strcasecmp($3, "sql_text") == 0)) {
|
|
|
|
if ($2) type = xlateSqlType("varchar");
|
|
|
|
else type = xlateSqlType("char");
|
1997-09-24 19:53:53 +02:00
|
|
|
} else {
|
1997-10-25 07:56:41 +02:00
|
|
|
if ($2) {
|
|
|
|
c = palloc(strlen("var") + strlen($3) + 1);
|
|
|
|
strcpy(c, "var");
|
|
|
|
strcat(c, $3);
|
|
|
|
type = xlateSqlType(c);
|
|
|
|
} else {
|
|
|
|
type = xlateSqlType($3);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
if ($4 != NULL)
|
1998-05-10 01:22:15 +02:00
|
|
|
elog(NOTICE,"COLLATE %s not yet implemented; clause ignored",$4);
|
1997-10-25 07:56:41 +02:00
|
|
|
$$ = type;
|
|
|
|
}
|
|
|
|
| CHAR opt_varying { $$ = xlateSqlType($2? "varchar": "char"); }
|
|
|
|
| VARCHAR { $$ = xlateSqlType("varchar"); }
|
|
|
|
| NATIONAL CHARACTER opt_varying { $$ = xlateSqlType($3? "varchar": "char"); }
|
|
|
|
| NCHAR opt_varying { $$ = xlateSqlType($2? "varchar": "char"); }
|
|
|
|
;
|
|
|
|
|
|
|
|
opt_varying: VARYING { $$ = TRUE; }
|
|
|
|
| /*EMPTY*/ { $$ = FALSE; }
|
|
|
|
;
|
|
|
|
|
|
|
|
opt_charset: CHARACTER SET ColId { $$ = $3; }
|
|
|
|
| /*EMPTY*/ { $$ = NULL; }
|
|
|
|
;
|
|
|
|
|
|
|
|
opt_collate: COLLATE ColId { $$ = $2; }
|
|
|
|
| /*EMPTY*/ { $$ = NULL; }
|
|
|
|
;
|
|
|
|
|
|
|
|
Datetime: datetime
|
|
|
|
{
|
|
|
|
$$ = makeNode(TypeName);
|
|
|
|
$$->name = xlateSqlType($1);
|
1998-02-10 05:02:59 +01:00
|
|
|
$$->typmod = -1;
|
1997-10-25 07:56:41 +02:00
|
|
|
}
|
|
|
|
| TIMESTAMP opt_timezone
|
|
|
|
{
|
|
|
|
$$ = makeNode(TypeName);
|
|
|
|
$$->name = xlateSqlType("timestamp");
|
|
|
|
$$->timezone = $2;
|
1998-02-10 05:02:59 +01:00
|
|
|
$$->typmod = -1;
|
1997-10-25 07:56:41 +02:00
|
|
|
}
|
|
|
|
| TIME
|
|
|
|
{
|
|
|
|
$$ = makeNode(TypeName);
|
|
|
|
$$->name = xlateSqlType("time");
|
1998-02-10 05:02:59 +01:00
|
|
|
$$->typmod = -1;
|
1997-10-25 07:56:41 +02:00
|
|
|
}
|
|
|
|
| INTERVAL opt_interval
|
|
|
|
{
|
|
|
|
$$ = makeNode(TypeName);
|
|
|
|
$$->name = xlateSqlType("interval");
|
1998-02-10 05:02:59 +01:00
|
|
|
$$->typmod = -1;
|
1997-09-24 19:53:53 +02:00
|
|
|
}
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-10-25 07:56:41 +02:00
|
|
|
datetime: YEAR_P { $$ = "year"; }
|
|
|
|
| MONTH_P { $$ = "month"; }
|
|
|
|
| DAY_P { $$ = "day"; }
|
|
|
|
| HOUR_P { $$ = "hour"; }
|
|
|
|
| MINUTE_P { $$ = "minute"; }
|
|
|
|
| SECOND_P { $$ = "second"; }
|
|
|
|
;
|
|
|
|
|
|
|
|
opt_timezone: WITH TIME ZONE { $$ = TRUE; }
|
|
|
|
| /*EMPTY*/ { $$ = FALSE; }
|
|
|
|
;
|
|
|
|
|
|
|
|
opt_interval: datetime { $$ = lcons($1, NIL); }
|
|
|
|
| YEAR_P TO MONTH_P { $$ = NIL; }
|
|
|
|
| DAY_P TO HOUR_P { $$ = NIL; }
|
|
|
|
| DAY_P TO MINUTE_P { $$ = NIL; }
|
|
|
|
| DAY_P TO SECOND_P { $$ = NIL; }
|
|
|
|
| HOUR_P TO MINUTE_P { $$ = NIL; }
|
|
|
|
| HOUR_P TO SECOND_P { $$ = NIL; }
|
1998-05-10 01:22:15 +02:00
|
|
|
| MINUTE_P TO SECOND_P { $$ = NIL; }
|
1997-12-16 16:50:54 +01:00
|
|
|
| /*EMPTY*/ { $$ = NIL; }
|
1997-10-25 07:56:41 +02:00
|
|
|
;
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
*
|
1999-11-20 22:39:36 +01:00
|
|
|
* expression grammar
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
|
1997-11-07 08:02:10 +01:00
|
|
|
a_expr_or_null: a_expr
|
1997-12-16 16:50:54 +01:00
|
|
|
{ $$ = $1; }
|
1997-12-05 00:07:23 +01:00
|
|
|
| NULL_P
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
A_Const *n = makeNode(A_Const);
|
|
|
|
n->val.type = T_Null;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
1997-12-23 20:47:32 +01:00
|
|
|
;
|
|
|
|
|
|
|
|
/* Expressions using row descriptors
|
|
|
|
* Define row_descriptor to allow yacc to break the reduce/reduce conflict
|
|
|
|
* with singleton expressions.
|
|
|
|
*/
|
|
|
|
row_expr: '(' row_descriptor ')' IN '(' SubSelect ')'
|
|
|
|
{
|
1998-01-17 05:53:46 +01:00
|
|
|
SubLink *n = makeNode(SubLink);
|
|
|
|
n->lefthand = $2;
|
1999-11-15 03:00:15 +01:00
|
|
|
n->oper = lcons("=", NIL);
|
1998-01-19 06:06:41 +01:00
|
|
|
n->useor = false;
|
|
|
|
n->subLinkType = ANY_SUBLINK;
|
1998-01-17 05:53:46 +01:00
|
|
|
n->subselect = $6;
|
|
|
|
$$ = (Node *)n;
|
1997-12-23 20:47:32 +01:00
|
|
|
}
|
|
|
|
| '(' row_descriptor ')' NOT IN '(' SubSelect ')'
|
|
|
|
{
|
1998-01-17 05:53:46 +01:00
|
|
|
SubLink *n = makeNode(SubLink);
|
|
|
|
n->lefthand = $2;
|
1999-11-15 03:00:15 +01:00
|
|
|
n->oper = lcons("<>", NIL);
|
1998-01-19 06:06:41 +01:00
|
|
|
n->useor = true;
|
|
|
|
n->subLinkType = ALL_SUBLINK;
|
|
|
|
n->subselect = $7;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
1999-11-20 22:39:36 +01:00
|
|
|
| '(' row_descriptor ')' all_Op sub_type '(' SubSelect ')'
|
1998-02-13 09:10:33 +01:00
|
|
|
{
|
|
|
|
SubLink *n = makeNode(SubLink);
|
|
|
|
n->lefthand = $2;
|
|
|
|
n->oper = lcons($4, NIL);
|
|
|
|
if (strcmp($4,"<>") == 0)
|
|
|
|
n->useor = true;
|
|
|
|
else
|
|
|
|
n->useor = false;
|
1998-05-10 01:22:15 +02:00
|
|
|
n->subLinkType = $5;
|
1998-02-03 20:27:30 +01:00
|
|
|
n->subselect = $7;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
1999-11-20 22:39:36 +01:00
|
|
|
| '(' row_descriptor ')' all_Op '(' SubSelect ')'
|
1998-02-03 20:27:30 +01:00
|
|
|
{
|
|
|
|
SubLink *n = makeNode(SubLink);
|
|
|
|
n->lefthand = $2;
|
1998-05-10 01:22:15 +02:00
|
|
|
n->oper = lcons($4, NIL);
|
1998-02-18 04:26:54 +01:00
|
|
|
if (strcmp($4,"<>") == 0)
|
|
|
|
n->useor = true;
|
|
|
|
else
|
|
|
|
n->useor = false;
|
1999-11-15 03:00:15 +01:00
|
|
|
n->subLinkType = MULTIEXPR_SUBLINK;
|
1998-05-10 01:22:15 +02:00
|
|
|
n->subselect = $6;
|
1998-02-03 20:27:30 +01:00
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
1999-11-20 22:39:36 +01:00
|
|
|
| '(' row_descriptor ')' all_Op '(' row_descriptor ')'
|
1997-12-23 20:47:32 +01:00
|
|
|
{
|
1998-01-17 06:01:34 +01:00
|
|
|
$$ = makeRowExpr($4, $2, $6);
|
1997-12-23 20:47:32 +01:00
|
|
|
}
|
|
|
|
;
|
|
|
|
|
|
|
|
row_descriptor: row_list ',' a_expr
|
|
|
|
{
|
|
|
|
$$ = lappend($1, $3);
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
|
|
|
row_list: row_list ',' a_expr
|
|
|
|
{
|
|
|
|
$$ = lappend($1, $3);
|
|
|
|
}
|
|
|
|
| a_expr
|
|
|
|
{
|
|
|
|
$$ = lcons($1, NIL);
|
|
|
|
}
|
|
|
|
;
|
1997-09-01 08:00:35 +02:00
|
|
|
|
1998-05-10 01:22:15 +02:00
|
|
|
sub_type: ANY { $$ = ANY_SUBLINK; }
|
|
|
|
| ALL { $$ = ALL_SUBLINK; }
|
|
|
|
;
|
|
|
|
|
1999-11-20 22:39:36 +01:00
|
|
|
all_Op: Op | MathOp;
|
|
|
|
|
|
|
|
MathOp: '+' { $$ = "+"; }
|
|
|
|
| '-' { $$ = "-"; }
|
|
|
|
| '*' { $$ = "*"; }
|
|
|
|
| '/' { $$ = "/"; }
|
|
|
|
| '%' { $$ = "%"; }
|
|
|
|
| '^' { $$ = "^"; }
|
|
|
|
| '|' { $$ = "|"; }
|
|
|
|
| '<' { $$ = "<"; }
|
|
|
|
| '>' { $$ = ">"; }
|
|
|
|
| '=' { $$ = "="; }
|
|
|
|
;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* General expressions
|
1998-02-04 07:11:48 +01:00
|
|
|
* This is the heart of the expression syntax.
|
1999-11-20 22:39:36 +01:00
|
|
|
*
|
|
|
|
* We have two expression types: a_expr is the unrestricted kind, and
|
|
|
|
* b_expr is a subset that must be used in some places to avoid shift/reduce
|
|
|
|
* conflicts. For example, we can't do BETWEEN as "BETWEEN a_expr AND a_expr"
|
|
|
|
* because that use of AND conflicts with AND as a boolean operator. So,
|
|
|
|
* b_expr is used in BETWEEN and we remove boolean keywords from b_expr.
|
|
|
|
*
|
|
|
|
* Note that '(' a_expr ')' is a b_expr, so an unrestricted expression can
|
|
|
|
* always be used by surrounding it with parens.
|
|
|
|
*
|
|
|
|
* com_expr is all the productions that are common to a_expr and b_expr;
|
|
|
|
* it's factored out just to eliminate redundant coding.
|
1998-02-04 07:11:48 +01:00
|
|
|
*/
|
1999-11-20 22:39:36 +01:00
|
|
|
a_expr: com_expr
|
1997-12-23 20:47:32 +01:00
|
|
|
{ $$ = $1; }
|
1999-11-20 22:39:36 +01:00
|
|
|
| a_expr TYPECAST Typename
|
2000-01-17 01:14:49 +01:00
|
|
|
{ $$ = makeTypeCast($1, $3); }
|
1999-12-10 04:01:05 +01:00
|
|
|
/*
|
|
|
|
* Can't collapse this into prior rule by using a_expr_or_null;
|
|
|
|
* that creates reduce/reduce conflicts. Grumble.
|
|
|
|
*/
|
|
|
|
| NULL_P TYPECAST Typename
|
|
|
|
{
|
|
|
|
A_Const *n = makeNode(A_Const);
|
|
|
|
n->val.type = T_Null;
|
|
|
|
n->typename = $3;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
1999-11-20 22:39:36 +01:00
|
|
|
/*
|
|
|
|
* These operators must be called out explicitly in order to make use
|
|
|
|
* of yacc/bison's automatic operator-precedence handling. All other
|
|
|
|
* operator names are handled by the generic productions using "Op",
|
|
|
|
* below; and all those operators will have the same precedence.
|
|
|
|
*
|
|
|
|
* If you add more explicitly-known operators, be sure to add them
|
|
|
|
* also to b_expr and to the MathOp list above.
|
|
|
|
*/
|
1997-09-08 05:20:18 +02:00
|
|
|
| '-' a_expr %prec UMINUS
|
1999-03-18 22:39:56 +01:00
|
|
|
{ $$ = doNegate($2); }
|
1999-03-21 03:30:22 +01:00
|
|
|
| '%' a_expr
|
1999-03-21 03:26:56 +01:00
|
|
|
{ $$ = makeA_Expr(OP, "%", NULL, $2); }
|
1999-07-08 02:00:43 +02:00
|
|
|
| '^' a_expr
|
|
|
|
{ $$ = makeA_Expr(OP, "^", NULL, $2); }
|
1999-09-28 16:31:19 +02:00
|
|
|
| '|' a_expr
|
|
|
|
{ $$ = makeA_Expr(OP, "|", NULL, $2); }
|
1999-09-28 16:49:36 +02:00
|
|
|
| ':' a_expr
|
|
|
|
{ $$ = makeA_Expr(OP, ":", NULL, $2); }
|
|
|
|
| ';' a_expr
|
|
|
|
{ $$ = makeA_Expr(OP, ";", NULL, $2); }
|
1999-03-21 03:30:22 +01:00
|
|
|
| a_expr '%'
|
1999-03-21 03:26:56 +01:00
|
|
|
{ $$ = makeA_Expr(OP, "%", $1, NULL); }
|
1999-07-08 02:00:43 +02:00
|
|
|
| a_expr '^'
|
|
|
|
{ $$ = makeA_Expr(OP, "^", $1, NULL); }
|
1999-09-28 16:31:19 +02:00
|
|
|
| a_expr '|'
|
|
|
|
{ $$ = makeA_Expr(OP, "|", $1, NULL); }
|
1997-09-08 05:20:18 +02:00
|
|
|
| a_expr '+' a_expr
|
|
|
|
{ $$ = makeA_Expr(OP, "+", $1, $3); }
|
|
|
|
| a_expr '-' a_expr
|
|
|
|
{ $$ = makeA_Expr(OP, "-", $1, $3); }
|
1999-09-28 16:31:19 +02:00
|
|
|
| a_expr '*' a_expr
|
|
|
|
{ $$ = makeA_Expr(OP, "*", $1, $3); }
|
1997-09-08 05:20:18 +02:00
|
|
|
| a_expr '/' a_expr
|
|
|
|
{ $$ = makeA_Expr(OP, "/", $1, $3); }
|
1999-03-17 21:17:13 +01:00
|
|
|
| a_expr '%' a_expr
|
|
|
|
{ $$ = makeA_Expr(OP, "%", $1, $3); }
|
1999-07-08 02:00:43 +02:00
|
|
|
| a_expr '^' a_expr
|
|
|
|
{ $$ = makeA_Expr(OP, "^", $1, $3); }
|
1999-09-28 16:31:19 +02:00
|
|
|
| a_expr '|' a_expr
|
|
|
|
{ $$ = makeA_Expr(OP, "|", $1, $3); }
|
1997-09-08 05:20:18 +02:00
|
|
|
| a_expr '<' a_expr
|
|
|
|
{ $$ = makeA_Expr(OP, "<", $1, $3); }
|
|
|
|
| a_expr '>' a_expr
|
|
|
|
{ $$ = makeA_Expr(OP, ">", $1, $3); }
|
1999-03-18 22:39:56 +01:00
|
|
|
|
1999-03-14 06:15:08 +01:00
|
|
|
| a_expr '=' NULL_P
|
|
|
|
{ $$ = makeA_Expr(ISNULL, NULL, $1, NULL); }
|
1999-05-11 05:28:43 +02:00
|
|
|
/* We allow this for standards-broken SQL products, like MS stuff */
|
|
|
|
| NULL_P '=' a_expr
|
1999-03-18 22:39:56 +01:00
|
|
|
{ $$ = makeA_Expr(ISNULL, NULL, $3, NULL); }
|
|
|
|
|
1997-09-08 05:20:18 +02:00
|
|
|
| a_expr '=' a_expr
|
|
|
|
{ $$ = makeA_Expr(OP, "=", $1, $3); }
|
1999-11-20 22:39:36 +01:00
|
|
|
|
1997-09-08 05:20:18 +02:00
|
|
|
| a_expr Op a_expr
|
1999-11-20 22:39:36 +01:00
|
|
|
{ $$ = makeA_Expr(OP, $2, $1, $3); }
|
1997-09-08 05:20:18 +02:00
|
|
|
| Op a_expr
|
|
|
|
{ $$ = makeA_Expr(OP, $1, NULL, $2); }
|
|
|
|
| a_expr Op
|
|
|
|
{ $$ = makeA_Expr(OP, $2, $1, NULL); }
|
1997-09-24 19:53:53 +02:00
|
|
|
|
1999-11-20 22:39:36 +01:00
|
|
|
| a_expr AND a_expr
|
|
|
|
{ $$ = makeA_Expr(AND, NULL, $1, $3); }
|
|
|
|
| a_expr OR a_expr
|
|
|
|
{ $$ = makeA_Expr(OR, NULL, $1, $3); }
|
|
|
|
| NOT a_expr
|
|
|
|
{ $$ = makeA_Expr(NOT, NULL, NULL, $2); }
|
1997-09-24 19:53:53 +02:00
|
|
|
|
1999-11-20 22:39:36 +01:00
|
|
|
| a_expr LIKE a_expr
|
|
|
|
{ $$ = makeA_Expr(OP, "~~", $1, $3); }
|
|
|
|
| a_expr NOT LIKE a_expr
|
|
|
|
{ $$ = makeA_Expr(OP, "!~~", $1, $4); }
|
1997-09-24 19:53:53 +02:00
|
|
|
|
1997-09-08 05:20:18 +02:00
|
|
|
| a_expr ISNULL
|
|
|
|
{ $$ = makeA_Expr(ISNULL, NULL, $1, NULL); }
|
1997-10-25 07:56:41 +02:00
|
|
|
| a_expr IS NULL_P
|
1997-09-08 05:20:18 +02:00
|
|
|
{ $$ = makeA_Expr(ISNULL, NULL, $1, NULL); }
|
|
|
|
| a_expr NOTNULL
|
|
|
|
{ $$ = makeA_Expr(NOTNULL, NULL, $1, NULL); }
|
1997-10-25 07:56:41 +02:00
|
|
|
| a_expr IS NOT NULL_P
|
1997-09-08 05:20:18 +02:00
|
|
|
{ $$ = makeA_Expr(NOTNULL, NULL, $1, NULL); }
|
1997-12-23 20:47:32 +01:00
|
|
|
/* IS TRUE, IS FALSE, etc used to be function calls
|
|
|
|
* but let's make them expressions to allow the optimizer
|
|
|
|
* a chance to eliminate them if a_expr is a constant string.
|
|
|
|
* - thomas 1997-12-22
|
|
|
|
*/
|
1997-10-25 07:56:41 +02:00
|
|
|
| a_expr IS TRUE_P
|
|
|
|
{
|
1997-12-23 20:47:32 +01:00
|
|
|
A_Const *n = makeNode(A_Const);
|
|
|
|
n->val.type = T_String;
|
|
|
|
n->val.val.str = "t";
|
|
|
|
n->typename = makeNode(TypeName);
|
|
|
|
n->typename->name = xlateSqlType("bool");
|
1998-02-10 05:02:59 +01:00
|
|
|
n->typename->typmod = -1;
|
1997-12-23 20:47:32 +01:00
|
|
|
$$ = makeA_Expr(OP, "=", $1,(Node *)n);
|
1997-10-25 07:56:41 +02:00
|
|
|
}
|
1997-12-23 20:47:32 +01:00
|
|
|
| a_expr IS NOT FALSE_P
|
1997-10-25 07:56:41 +02:00
|
|
|
{
|
1997-12-23 20:47:32 +01:00
|
|
|
A_Const *n = makeNode(A_Const);
|
|
|
|
n->val.type = T_String;
|
|
|
|
n->val.val.str = "t";
|
|
|
|
n->typename = makeNode(TypeName);
|
|
|
|
n->typename->name = xlateSqlType("bool");
|
1998-02-10 05:02:59 +01:00
|
|
|
n->typename->typmod = -1;
|
1997-12-23 20:47:32 +01:00
|
|
|
$$ = makeA_Expr(OP, "=", $1,(Node *)n);
|
1997-10-25 07:56:41 +02:00
|
|
|
}
|
1997-12-23 20:47:32 +01:00
|
|
|
| a_expr IS FALSE_P
|
1997-10-25 07:56:41 +02:00
|
|
|
{
|
1997-12-23 20:47:32 +01:00
|
|
|
A_Const *n = makeNode(A_Const);
|
|
|
|
n->val.type = T_String;
|
|
|
|
n->val.val.str = "f";
|
|
|
|
n->typename = makeNode(TypeName);
|
|
|
|
n->typename->name = xlateSqlType("bool");
|
1998-02-10 05:02:59 +01:00
|
|
|
n->typename->typmod = -1;
|
1997-12-23 20:47:32 +01:00
|
|
|
$$ = makeA_Expr(OP, "=", $1,(Node *)n);
|
1997-10-25 07:56:41 +02:00
|
|
|
}
|
1997-12-23 20:47:32 +01:00
|
|
|
| a_expr IS NOT TRUE_P
|
1997-10-25 07:56:41 +02:00
|
|
|
{
|
1997-12-23 20:47:32 +01:00
|
|
|
A_Const *n = makeNode(A_Const);
|
|
|
|
n->val.type = T_String;
|
|
|
|
n->val.val.str = "f";
|
|
|
|
n->typename = makeNode(TypeName);
|
|
|
|
n->typename->name = xlateSqlType("bool");
|
1998-02-10 05:02:59 +01:00
|
|
|
n->typename->typmod = -1;
|
1997-12-23 20:47:32 +01:00
|
|
|
$$ = makeA_Expr(OP, "=", $1,(Node *)n);
|
1997-10-25 07:56:41 +02:00
|
|
|
}
|
1998-02-04 07:11:48 +01:00
|
|
|
| a_expr BETWEEN b_expr AND b_expr
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
$$ = makeA_Expr(AND, NULL,
|
|
|
|
makeA_Expr(OP, ">=", $1, $3),
|
|
|
|
makeA_Expr(OP, "<=", $1, $5));
|
|
|
|
}
|
1998-02-04 07:11:48 +01:00
|
|
|
| a_expr NOT BETWEEN b_expr AND b_expr
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
$$ = makeA_Expr(OR, NULL,
|
|
|
|
makeA_Expr(OP, "<", $1, $4),
|
|
|
|
makeA_Expr(OP, ">", $1, $6));
|
|
|
|
}
|
1999-07-28 19:39:38 +02:00
|
|
|
| a_expr IN '(' in_expr ')'
|
1998-01-17 05:53:46 +01:00
|
|
|
{
|
1999-07-28 19:39:38 +02:00
|
|
|
/* in_expr returns a SubLink or a list of a_exprs */
|
|
|
|
if (IsA($4, SubLink))
|
1998-01-17 05:53:46 +01:00
|
|
|
{
|
1999-07-28 19:39:38 +02:00
|
|
|
SubLink *n = (SubLink *)$4;
|
1998-01-19 06:06:41 +01:00
|
|
|
n->lefthand = lcons($1, NIL);
|
1999-11-15 03:00:15 +01:00
|
|
|
n->oper = lcons("=", NIL);
|
1998-01-19 06:06:41 +01:00
|
|
|
n->useor = false;
|
|
|
|
n->subLinkType = ANY_SUBLINK;
|
|
|
|
$$ = (Node *)n;
|
1998-01-17 05:53:46 +01:00
|
|
|
}
|
1999-07-28 19:39:38 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
Node *n = NULL;
|
|
|
|
List *l;
|
|
|
|
foreach(l, (List *) $4)
|
|
|
|
{
|
|
|
|
Node *cmp = makeA_Expr(OP, "=", $1, lfirst(l));
|
|
|
|
if (n == NULL)
|
|
|
|
n = cmp;
|
|
|
|
else
|
|
|
|
n = makeA_Expr(OR, NULL, n, cmp);
|
|
|
|
}
|
|
|
|
$$ = n;
|
|
|
|
}
|
1998-01-17 05:53:46 +01:00
|
|
|
}
|
1999-07-28 19:39:38 +02:00
|
|
|
| a_expr NOT IN '(' in_expr ')'
|
1998-01-17 05:53:46 +01:00
|
|
|
{
|
1999-07-28 19:39:38 +02:00
|
|
|
/* in_expr returns a SubLink or a list of a_exprs */
|
|
|
|
if (IsA($5, SubLink))
|
1998-01-17 05:53:46 +01:00
|
|
|
{
|
1999-07-28 19:39:38 +02:00
|
|
|
SubLink *n = (SubLink *)$5;
|
|
|
|
n->lefthand = lcons($1, NIL);
|
1999-11-15 03:00:15 +01:00
|
|
|
n->oper = lcons("<>", NIL);
|
1999-07-28 19:39:38 +02:00
|
|
|
n->useor = false;
|
|
|
|
n->subLinkType = ALL_SUBLINK;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Node *n = NULL;
|
|
|
|
List *l;
|
|
|
|
foreach(l, (List *) $5)
|
|
|
|
{
|
|
|
|
Node *cmp = makeA_Expr(OP, "<>", $1, lfirst(l));
|
|
|
|
if (n == NULL)
|
|
|
|
n = cmp;
|
|
|
|
else
|
|
|
|
n = makeA_Expr(AND, NULL, n, cmp);
|
|
|
|
}
|
|
|
|
$$ = n;
|
1998-01-17 05:53:46 +01:00
|
|
|
}
|
|
|
|
}
|
1999-11-20 22:39:36 +01:00
|
|
|
| a_expr all_Op sub_type '(' SubSelect ')'
|
1998-02-03 20:27:30 +01:00
|
|
|
{
|
|
|
|
SubLink *n = makeNode(SubLink);
|
1999-11-15 03:00:15 +01:00
|
|
|
n->lefthand = lcons($1, NIL);
|
|
|
|
n->oper = lcons($2, NIL);
|
|
|
|
n->useor = false; /* doesn't matter since only one col */
|
|
|
|
n->subLinkType = $3;
|
1998-02-13 09:10:33 +01:00
|
|
|
n->subselect = $5;
|
1998-02-03 20:27:30 +01:00
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
1999-11-20 22:39:36 +01:00
|
|
|
| row_expr
|
|
|
|
{ $$ = $1; }
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1999-11-20 22:39:36 +01:00
|
|
|
/*
|
|
|
|
* Restricted expressions
|
|
|
|
*
|
|
|
|
* b_expr is a subset of the complete expression syntax defined by a_expr.
|
|
|
|
*
|
|
|
|
* Presently, AND, NOT, IS, IN, and NULL are the a_expr keywords that would
|
|
|
|
* cause trouble in the places where b_expr is used. For simplicity, we
|
|
|
|
* just eliminate all the boolean-keyword-operator productions from b_expr.
|
1998-02-04 07:11:48 +01:00
|
|
|
*/
|
1999-11-20 22:39:36 +01:00
|
|
|
b_expr: com_expr
|
1998-02-04 07:11:48 +01:00
|
|
|
{ $$ = $1; }
|
1999-11-20 22:39:36 +01:00
|
|
|
| b_expr TYPECAST Typename
|
2000-01-17 01:14:49 +01:00
|
|
|
{ $$ = makeTypeCast($1, $3); }
|
1999-12-10 04:01:05 +01:00
|
|
|
| NULL_P TYPECAST Typename
|
|
|
|
{
|
|
|
|
A_Const *n = makeNode(A_Const);
|
|
|
|
n->val.type = T_Null;
|
|
|
|
n->typename = $3;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
1998-02-04 07:11:48 +01:00
|
|
|
| '-' b_expr %prec UMINUS
|
1999-03-18 22:39:56 +01:00
|
|
|
{ $$ = doNegate($2); }
|
1999-03-22 06:07:32 +01:00
|
|
|
| '%' b_expr
|
|
|
|
{ $$ = makeA_Expr(OP, "%", NULL, $2); }
|
1999-07-08 02:00:43 +02:00
|
|
|
| '^' b_expr
|
|
|
|
{ $$ = makeA_Expr(OP, "^", NULL, $2); }
|
1999-09-28 16:31:19 +02:00
|
|
|
| '|' b_expr
|
|
|
|
{ $$ = makeA_Expr(OP, "|", NULL, $2); }
|
1999-09-28 16:49:36 +02:00
|
|
|
| ':' b_expr
|
|
|
|
{ $$ = makeA_Expr(OP, ":", NULL, $2); }
|
|
|
|
| ';' b_expr
|
|
|
|
{ $$ = makeA_Expr(OP, ";", NULL, $2); }
|
1999-03-22 06:07:32 +01:00
|
|
|
| b_expr '%'
|
|
|
|
{ $$ = makeA_Expr(OP, "%", $1, NULL); }
|
1999-07-08 02:00:43 +02:00
|
|
|
| b_expr '^'
|
|
|
|
{ $$ = makeA_Expr(OP, "^", $1, NULL); }
|
1999-09-28 16:31:19 +02:00
|
|
|
| b_expr '|'
|
|
|
|
{ $$ = makeA_Expr(OP, "|", $1, NULL); }
|
1998-02-04 07:11:48 +01:00
|
|
|
| b_expr '+' b_expr
|
|
|
|
{ $$ = makeA_Expr(OP, "+", $1, $3); }
|
|
|
|
| b_expr '-' b_expr
|
|
|
|
{ $$ = makeA_Expr(OP, "-", $1, $3); }
|
1999-09-28 16:31:19 +02:00
|
|
|
| b_expr '*' b_expr
|
|
|
|
{ $$ = makeA_Expr(OP, "*", $1, $3); }
|
1998-02-04 07:11:48 +01:00
|
|
|
| b_expr '/' b_expr
|
|
|
|
{ $$ = makeA_Expr(OP, "/", $1, $3); }
|
1999-03-17 21:17:13 +01:00
|
|
|
| b_expr '%' b_expr
|
|
|
|
{ $$ = makeA_Expr(OP, "%", $1, $3); }
|
1999-07-17 00:29:42 +02:00
|
|
|
| b_expr '^' b_expr
|
|
|
|
{ $$ = makeA_Expr(OP, "^", $1, $3); }
|
1999-09-28 16:31:19 +02:00
|
|
|
| b_expr '|' b_expr
|
|
|
|
{ $$ = makeA_Expr(OP, "|", $1, $3); }
|
1999-11-20 22:39:36 +01:00
|
|
|
| b_expr '<' b_expr
|
|
|
|
{ $$ = makeA_Expr(OP, "<", $1, $3); }
|
|
|
|
| b_expr '>' b_expr
|
|
|
|
{ $$ = makeA_Expr(OP, ">", $1, $3); }
|
|
|
|
| b_expr '=' b_expr
|
|
|
|
{ $$ = makeA_Expr(OP, "=", $1, $3); }
|
|
|
|
|
|
|
|
| b_expr Op b_expr
|
|
|
|
{ $$ = makeA_Expr(OP, $2, $1, $3); }
|
|
|
|
| Op b_expr
|
|
|
|
{ $$ = makeA_Expr(OP, $1, NULL, $2); }
|
|
|
|
| b_expr Op
|
|
|
|
{ $$ = makeA_Expr(OP, $2, $1, NULL); }
|
|
|
|
;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Productions that can be used in both a_expr and b_expr.
|
|
|
|
*
|
|
|
|
* Note: productions that refer recursively to a_expr or b_expr mostly
|
|
|
|
* cannot appear here. However, it's OK to refer to a_exprs that occur
|
|
|
|
* inside parentheses, such as function arguments; that cannot introduce
|
|
|
|
* ambiguity to the b_expr syntax.
|
|
|
|
*/
|
|
|
|
com_expr: attr
|
|
|
|
{ $$ = (Node *) $1; }
|
|
|
|
| ColId opt_indirection
|
1998-02-04 07:11:48 +01:00
|
|
|
{
|
1999-11-20 22:39:36 +01:00
|
|
|
/* could be a column name or a relation_name */
|
|
|
|
Ident *n = makeNode(Ident);
|
|
|
|
n->name = $1;
|
|
|
|
n->indirection = $2;
|
|
|
|
$$ = (Node *)n;
|
1998-02-04 07:11:48 +01:00
|
|
|
}
|
1999-11-20 22:39:36 +01:00
|
|
|
| AexprConst
|
|
|
|
{ $$ = $1; }
|
|
|
|
| '(' a_expr_or_null ')'
|
|
|
|
{ $$ = $2; }
|
1999-12-10 04:01:05 +01:00
|
|
|
| CAST '(' a_expr_or_null AS Typename ')'
|
2000-01-17 01:14:49 +01:00
|
|
|
{ $$ = makeTypeCast($3, $5); }
|
1999-11-20 22:39:36 +01:00
|
|
|
| case_expr
|
|
|
|
{ $$ = $1; }
|
1998-02-11 05:09:54 +01:00
|
|
|
| func_name '(' ')'
|
1998-02-04 07:11:48 +01:00
|
|
|
{
|
|
|
|
FuncCall *n = makeNode(FuncCall);
|
|
|
|
n->funcname = $1;
|
|
|
|
n->args = NIL;
|
1999-12-10 08:37:35 +01:00
|
|
|
n->agg_star = false;
|
|
|
|
n->agg_distinct = false;
|
1998-02-04 07:11:48 +01:00
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
1998-02-11 05:09:54 +01:00
|
|
|
| func_name '(' expr_list ')'
|
1998-02-04 07:11:48 +01:00
|
|
|
{
|
|
|
|
FuncCall *n = makeNode(FuncCall);
|
|
|
|
n->funcname = $1;
|
|
|
|
n->args = $3;
|
1999-12-10 08:37:35 +01:00
|
|
|
n->agg_star = false;
|
|
|
|
n->agg_distinct = false;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
| func_name '(' DISTINCT expr_list ')'
|
|
|
|
{
|
|
|
|
FuncCall *n = makeNode(FuncCall);
|
|
|
|
n->funcname = $1;
|
|
|
|
n->args = $4;
|
|
|
|
n->agg_star = false;
|
|
|
|
n->agg_distinct = true;
|
1998-02-04 07:11:48 +01:00
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
1999-11-20 22:39:36 +01:00
|
|
|
| func_name '(' '*' ')'
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* For now, we transform AGGREGATE(*) into AGGREGATE(1).
|
|
|
|
*
|
|
|
|
* This does the right thing for COUNT(*) (in fact,
|
|
|
|
* any certainly-non-null expression would do for COUNT),
|
|
|
|
* and there are no other aggregates in SQL92 that accept
|
|
|
|
* '*' as parameter.
|
|
|
|
*
|
1999-12-10 08:37:35 +01:00
|
|
|
* The FuncCall node is also marked agg_star = true,
|
|
|
|
* so that later processing can detect what the argument
|
|
|
|
* really was.
|
1999-11-20 22:39:36 +01:00
|
|
|
*/
|
|
|
|
FuncCall *n = makeNode(FuncCall);
|
|
|
|
A_Const *star = makeNode(A_Const);
|
|
|
|
|
|
|
|
star->val.type = T_Integer;
|
|
|
|
star->val.val.ival = 1;
|
|
|
|
n->funcname = $1;
|
|
|
|
n->args = lcons(star, NIL);
|
1999-12-10 08:37:35 +01:00
|
|
|
n->agg_star = true;
|
|
|
|
n->agg_distinct = false;
|
1999-11-20 22:39:36 +01:00
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
1998-02-04 07:11:48 +01:00
|
|
|
| CURRENT_DATE
|
|
|
|
{
|
1999-11-20 22:39:36 +01:00
|
|
|
/*
|
|
|
|
* Translate as "date('now'::text)".
|
|
|
|
*
|
|
|
|
* We cannot use "'now'::date" because coerce_type() will
|
|
|
|
* immediately reduce that to a constant representing
|
|
|
|
* today's date. We need to delay the conversion until
|
|
|
|
* runtime, else the wrong things will happen when
|
|
|
|
* CURRENT_DATE is used in a column default value or rule.
|
|
|
|
*
|
|
|
|
* This could be simplified if we had a way to generate
|
|
|
|
* an expression tree representing runtime application
|
|
|
|
* of type-input conversion functions...
|
|
|
|
*/
|
|
|
|
A_Const *s = makeNode(A_Const);
|
1998-02-04 07:11:48 +01:00
|
|
|
TypeName *t = makeNode(TypeName);
|
1999-11-20 22:39:36 +01:00
|
|
|
FuncCall *n = makeNode(FuncCall);
|
1998-02-04 07:11:48 +01:00
|
|
|
|
1999-11-20 22:39:36 +01:00
|
|
|
s->val.type = T_String;
|
|
|
|
s->val.val.str = "now";
|
|
|
|
s->typename = t;
|
1998-02-04 07:11:48 +01:00
|
|
|
|
1999-11-20 22:39:36 +01:00
|
|
|
t->name = xlateSqlType("text");
|
1998-02-04 07:11:48 +01:00
|
|
|
t->setof = FALSE;
|
1998-02-10 05:02:59 +01:00
|
|
|
t->typmod = -1;
|
1998-02-04 07:11:48 +01:00
|
|
|
|
1999-11-20 22:39:36 +01:00
|
|
|
n->funcname = xlateSqlType("date");
|
|
|
|
n->args = lcons(s, NIL);
|
1999-12-10 08:37:35 +01:00
|
|
|
n->agg_star = false;
|
|
|
|
n->agg_distinct = false;
|
1999-11-20 22:39:36 +01:00
|
|
|
|
1998-02-04 07:11:48 +01:00
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
| CURRENT_TIME
|
|
|
|
{
|
1999-11-20 22:39:36 +01:00
|
|
|
/*
|
|
|
|
* Translate as "time('now'::text)".
|
|
|
|
* See comments for CURRENT_DATE.
|
|
|
|
*/
|
|
|
|
A_Const *s = makeNode(A_Const);
|
1998-02-04 07:11:48 +01:00
|
|
|
TypeName *t = makeNode(TypeName);
|
1999-11-20 22:39:36 +01:00
|
|
|
FuncCall *n = makeNode(FuncCall);
|
1998-02-04 07:11:48 +01:00
|
|
|
|
1999-11-20 22:39:36 +01:00
|
|
|
s->val.type = T_String;
|
|
|
|
s->val.val.str = "now";
|
|
|
|
s->typename = t;
|
1998-02-04 07:11:48 +01:00
|
|
|
|
1999-11-20 22:39:36 +01:00
|
|
|
t->name = xlateSqlType("text");
|
1998-02-04 07:11:48 +01:00
|
|
|
t->setof = FALSE;
|
1998-02-10 05:02:59 +01:00
|
|
|
t->typmod = -1;
|
1998-02-04 07:11:48 +01:00
|
|
|
|
1999-11-20 22:39:36 +01:00
|
|
|
n->funcname = xlateSqlType("time");
|
|
|
|
n->args = lcons(s, NIL);
|
1999-12-10 08:37:35 +01:00
|
|
|
n->agg_star = false;
|
|
|
|
n->agg_distinct = false;
|
1999-11-20 22:39:36 +01:00
|
|
|
|
1998-02-04 07:11:48 +01:00
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
| CURRENT_TIME '(' Iconst ')'
|
|
|
|
{
|
1999-11-20 22:39:36 +01:00
|
|
|
/*
|
|
|
|
* Translate as "time('now'::text)".
|
|
|
|
* See comments for CURRENT_DATE.
|
|
|
|
*/
|
1998-02-04 07:11:48 +01:00
|
|
|
A_Const *s = makeNode(A_Const);
|
|
|
|
TypeName *t = makeNode(TypeName);
|
1999-11-20 22:39:36 +01:00
|
|
|
FuncCall *n = makeNode(FuncCall);
|
1998-02-04 07:11:48 +01:00
|
|
|
|
|
|
|
s->val.type = T_String;
|
|
|
|
s->val.val.str = "now";
|
|
|
|
s->typename = t;
|
|
|
|
|
1999-11-20 22:39:36 +01:00
|
|
|
t->name = xlateSqlType("text");
|
1998-02-04 07:11:48 +01:00
|
|
|
t->setof = FALSE;
|
1998-02-10 05:02:59 +01:00
|
|
|
t->typmod = -1;
|
1998-02-04 07:11:48 +01:00
|
|
|
|
1999-11-20 22:39:36 +01:00
|
|
|
n->funcname = xlateSqlType("time");
|
|
|
|
n->args = lcons(s, NIL);
|
1999-12-10 08:37:35 +01:00
|
|
|
n->agg_star = false;
|
|
|
|
n->agg_distinct = false;
|
1999-11-20 22:39:36 +01:00
|
|
|
|
1998-02-04 07:11:48 +01:00
|
|
|
if ($3 != 0)
|
|
|
|
elog(NOTICE,"CURRENT_TIME(%d) precision not implemented; zero used instead",$3);
|
|
|
|
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
| CURRENT_TIMESTAMP
|
|
|
|
{
|
1999-11-20 22:39:36 +01:00
|
|
|
/*
|
|
|
|
* Translate as "timestamp('now'::text)".
|
|
|
|
* See comments for CURRENT_DATE.
|
|
|
|
*/
|
|
|
|
A_Const *s = makeNode(A_Const);
|
1998-02-04 07:11:48 +01:00
|
|
|
TypeName *t = makeNode(TypeName);
|
1999-11-20 22:39:36 +01:00
|
|
|
FuncCall *n = makeNode(FuncCall);
|
1998-02-04 07:11:48 +01:00
|
|
|
|
1999-11-20 22:39:36 +01:00
|
|
|
s->val.type = T_String;
|
|
|
|
s->val.val.str = "now";
|
|
|
|
s->typename = t;
|
1998-02-04 07:11:48 +01:00
|
|
|
|
1999-11-20 22:39:36 +01:00
|
|
|
t->name = xlateSqlType("text");
|
1998-02-04 07:11:48 +01:00
|
|
|
t->setof = FALSE;
|
1998-02-10 05:02:59 +01:00
|
|
|
t->typmod = -1;
|
1998-02-04 07:11:48 +01:00
|
|
|
|
1999-11-20 22:39:36 +01:00
|
|
|
n->funcname = xlateSqlType("timestamp");
|
|
|
|
n->args = lcons(s, NIL);
|
1999-12-10 08:37:35 +01:00
|
|
|
n->agg_star = false;
|
|
|
|
n->agg_distinct = false;
|
1999-11-20 22:39:36 +01:00
|
|
|
|
1998-02-04 07:11:48 +01:00
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
| CURRENT_TIMESTAMP '(' Iconst ')'
|
|
|
|
{
|
1999-11-20 22:39:36 +01:00
|
|
|
/*
|
|
|
|
* Translate as "timestamp('now'::text)".
|
|
|
|
* See comments for CURRENT_DATE.
|
|
|
|
*/
|
1998-02-04 07:11:48 +01:00
|
|
|
A_Const *s = makeNode(A_Const);
|
|
|
|
TypeName *t = makeNode(TypeName);
|
1999-11-20 22:39:36 +01:00
|
|
|
FuncCall *n = makeNode(FuncCall);
|
1998-02-04 07:11:48 +01:00
|
|
|
|
|
|
|
s->val.type = T_String;
|
|
|
|
s->val.val.str = "now";
|
|
|
|
s->typename = t;
|
|
|
|
|
1999-11-20 22:39:36 +01:00
|
|
|
t->name = xlateSqlType("text");
|
1998-02-04 07:11:48 +01:00
|
|
|
t->setof = FALSE;
|
1998-02-10 05:02:59 +01:00
|
|
|
t->typmod = -1;
|
1998-02-04 07:11:48 +01:00
|
|
|
|
1999-11-20 22:39:36 +01:00
|
|
|
n->funcname = xlateSqlType("timestamp");
|
|
|
|
n->args = lcons(s, NIL);
|
1999-12-10 08:37:35 +01:00
|
|
|
n->agg_star = false;
|
|
|
|
n->agg_distinct = false;
|
1999-11-20 22:39:36 +01:00
|
|
|
|
1998-02-04 07:11:48 +01:00
|
|
|
if ($3 != 0)
|
|
|
|
elog(NOTICE,"CURRENT_TIMESTAMP(%d) precision not implemented; zero used instead",$3);
|
|
|
|
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
| CURRENT_USER
|
|
|
|
{
|
|
|
|
FuncCall *n = makeNode(FuncCall);
|
|
|
|
n->funcname = "getpgusername";
|
|
|
|
n->args = NIL;
|
1999-12-10 08:37:35 +01:00
|
|
|
n->agg_star = false;
|
|
|
|
n->agg_distinct = false;
|
1998-02-04 07:11:48 +01:00
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
1998-05-10 01:22:15 +02:00
|
|
|
| USER
|
|
|
|
{
|
|
|
|
FuncCall *n = makeNode(FuncCall);
|
|
|
|
n->funcname = "getpgusername";
|
|
|
|
n->args = NIL;
|
1999-12-10 08:37:35 +01:00
|
|
|
n->agg_star = false;
|
|
|
|
n->agg_distinct = false;
|
1998-05-10 01:22:15 +02:00
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
1999-11-20 22:39:36 +01:00
|
|
|
| EXTRACT '(' extract_list ')'
|
|
|
|
{
|
|
|
|
FuncCall *n = makeNode(FuncCall);
|
|
|
|
n->funcname = "date_part";
|
|
|
|
n->args = $3;
|
1999-12-10 08:37:35 +01:00
|
|
|
n->agg_star = false;
|
|
|
|
n->agg_distinct = false;
|
1999-11-20 22:39:36 +01:00
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
1998-02-04 07:11:48 +01:00
|
|
|
| POSITION '(' position_list ')'
|
|
|
|
{
|
|
|
|
FuncCall *n = makeNode(FuncCall);
|
|
|
|
n->funcname = "strpos";
|
|
|
|
n->args = $3;
|
1999-12-10 08:37:35 +01:00
|
|
|
n->agg_star = false;
|
|
|
|
n->agg_distinct = false;
|
1998-02-04 07:11:48 +01:00
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
| SUBSTRING '(' substr_list ')'
|
|
|
|
{
|
|
|
|
FuncCall *n = makeNode(FuncCall);
|
|
|
|
n->funcname = "substr";
|
|
|
|
n->args = $3;
|
1999-12-10 08:37:35 +01:00
|
|
|
n->agg_star = false;
|
|
|
|
n->agg_distinct = false;
|
1998-02-04 07:11:48 +01:00
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
/* various trim expressions are defined in SQL92 - thomas 1997-07-19 */
|
|
|
|
| TRIM '(' BOTH trim_list ')'
|
|
|
|
{
|
|
|
|
FuncCall *n = makeNode(FuncCall);
|
|
|
|
n->funcname = "btrim";
|
|
|
|
n->args = $4;
|
1999-12-10 08:37:35 +01:00
|
|
|
n->agg_star = false;
|
|
|
|
n->agg_distinct = false;
|
1998-02-04 07:11:48 +01:00
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
| TRIM '(' LEADING trim_list ')'
|
|
|
|
{
|
|
|
|
FuncCall *n = makeNode(FuncCall);
|
|
|
|
n->funcname = "ltrim";
|
|
|
|
n->args = $4;
|
1999-12-10 08:37:35 +01:00
|
|
|
n->agg_star = false;
|
|
|
|
n->agg_distinct = false;
|
1998-02-04 07:11:48 +01:00
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
| TRIM '(' TRAILING trim_list ')'
|
|
|
|
{
|
|
|
|
FuncCall *n = makeNode(FuncCall);
|
|
|
|
n->funcname = "rtrim";
|
|
|
|
n->args = $4;
|
1999-12-10 08:37:35 +01:00
|
|
|
n->agg_star = false;
|
|
|
|
n->agg_distinct = false;
|
1998-02-04 07:11:48 +01:00
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
| TRIM '(' trim_list ')'
|
|
|
|
{
|
|
|
|
FuncCall *n = makeNode(FuncCall);
|
|
|
|
n->funcname = "btrim";
|
|
|
|
n->args = $3;
|
1999-12-10 08:37:35 +01:00
|
|
|
n->agg_star = false;
|
|
|
|
n->agg_distinct = false;
|
1998-02-04 07:11:48 +01:00
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
1999-11-15 03:00:15 +01:00
|
|
|
| '(' SubSelect ')'
|
|
|
|
{
|
|
|
|
SubLink *n = makeNode(SubLink);
|
|
|
|
n->lefthand = NIL;
|
|
|
|
n->oper = NIL;
|
|
|
|
n->useor = false;
|
|
|
|
n->subLinkType = EXPR_SUBLINK;
|
|
|
|
n->subselect = $2;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
1999-11-20 22:39:36 +01:00
|
|
|
| EXISTS '(' SubSelect ')'
|
|
|
|
{
|
|
|
|
SubLink *n = makeNode(SubLink);
|
|
|
|
n->lefthand = NIL;
|
|
|
|
n->oper = NIL;
|
|
|
|
n->useor = false;
|
|
|
|
n->subLinkType = EXISTS_SUBLINK;
|
|
|
|
n->subselect = $3;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
1998-02-04 07:11:48 +01:00
|
|
|
;
|
|
|
|
|
1999-11-20 22:39:36 +01:00
|
|
|
/*
|
|
|
|
* Supporting nonterminals for expressions.
|
|
|
|
*/
|
|
|
|
|
1997-09-01 08:00:35 +02:00
|
|
|
opt_indirection: '[' a_expr ']' opt_indirection
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
A_Indices *ai = makeNode(A_Indices);
|
|
|
|
ai->lidx = NULL;
|
|
|
|
ai->uidx = $2;
|
|
|
|
$$ = lcons(ai, $4);
|
|
|
|
}
|
|
|
|
| '[' a_expr ':' a_expr ']' opt_indirection
|
|
|
|
{
|
|
|
|
A_Indices *ai = makeNode(A_Indices);
|
|
|
|
ai->lidx = $2;
|
|
|
|
ai->uidx = $4;
|
|
|
|
$$ = lcons(ai, $6);
|
|
|
|
}
|
1998-12-04 16:34:49 +01:00
|
|
|
| /*EMPTY*/
|
1997-09-08 05:20:18 +02:00
|
|
|
{ $$ = NIL; }
|
|
|
|
;
|
1997-09-01 08:00:35 +02:00
|
|
|
|
1997-11-07 08:02:10 +01:00
|
|
|
expr_list: a_expr_or_null
|
1997-09-08 05:20:18 +02:00
|
|
|
{ $$ = lcons($1, NIL); }
|
1997-11-07 08:02:10 +01:00
|
|
|
| expr_list ',' a_expr_or_null
|
1997-09-08 05:20:18 +02:00
|
|
|
{ $$ = lappend($1, $3); }
|
1997-11-07 08:02:10 +01:00
|
|
|
| expr_list USING a_expr
|
1997-09-08 05:20:18 +02:00
|
|
|
{ $$ = lappend($1, $3); }
|
|
|
|
;
|
1997-09-01 08:00:35 +02:00
|
|
|
|
1998-04-08 08:39:01 +02:00
|
|
|
extract_list: extract_arg FROM a_expr
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
A_Const *n = makeNode(A_Const);
|
|
|
|
n->val.type = T_String;
|
|
|
|
n->val.val.str = $1;
|
|
|
|
$$ = lappend(lcons((Node *)n,NIL), $3);
|
|
|
|
}
|
1998-12-04 16:34:49 +01:00
|
|
|
| /*EMPTY*/
|
1997-09-08 05:20:18 +02:00
|
|
|
{ $$ = NIL; }
|
|
|
|
;
|
1997-09-01 08:00:35 +02:00
|
|
|
|
1998-05-10 01:22:15 +02:00
|
|
|
extract_arg: datetime { $$ = $1; }
|
|
|
|
| TIMEZONE_HOUR { $$ = "tz_hour"; }
|
|
|
|
| TIMEZONE_MINUTE { $$ = "tz_minute"; }
|
1998-04-08 08:39:01 +02:00
|
|
|
;
|
|
|
|
|
1999-07-17 00:29:42 +02:00
|
|
|
/* position_list uses b_expr not a_expr to avoid conflict with general IN */
|
|
|
|
|
|
|
|
position_list: b_expr IN b_expr
|
1997-09-13 05:15:46 +02:00
|
|
|
{ $$ = makeList($3, $1, -1); }
|
1998-12-04 16:34:49 +01:00
|
|
|
| /*EMPTY*/
|
1997-09-08 05:20:18 +02:00
|
|
|
{ $$ = NIL; }
|
|
|
|
;
|
1997-09-01 08:00:35 +02:00
|
|
|
|
1997-11-07 08:02:10 +01:00
|
|
|
substr_list: expr_list substr_from substr_for
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
1997-09-26 17:09:11 +02:00
|
|
|
$$ = nconc(nconc($1,$2),$3);
|
1997-09-08 05:20:18 +02:00
|
|
|
}
|
1998-12-04 16:34:49 +01:00
|
|
|
| /*EMPTY*/
|
1997-09-08 05:20:18 +02:00
|
|
|
{ $$ = NIL; }
|
|
|
|
;
|
1997-09-01 08:00:35 +02:00
|
|
|
|
1997-11-07 08:02:10 +01:00
|
|
|
substr_from: FROM expr_list
|
1997-09-08 05:20:18 +02:00
|
|
|
{ $$ = $2; }
|
1998-12-04 16:34:49 +01:00
|
|
|
| /*EMPTY*/
|
1997-09-26 17:09:11 +02:00
|
|
|
{
|
|
|
|
A_Const *n = makeNode(A_Const);
|
|
|
|
n->val.type = T_Integer;
|
|
|
|
n->val.val.ival = 1;
|
|
|
|
$$ = lcons((Node *)n,NIL);
|
|
|
|
}
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
1997-09-01 08:00:35 +02:00
|
|
|
|
1997-11-07 08:02:10 +01:00
|
|
|
substr_for: FOR expr_list
|
1997-09-08 05:20:18 +02:00
|
|
|
{ $$ = $2; }
|
1998-12-04 16:34:49 +01:00
|
|
|
| /*EMPTY*/
|
1997-09-08 05:20:18 +02:00
|
|
|
{ $$ = NIL; }
|
|
|
|
;
|
1997-09-01 08:00:35 +02:00
|
|
|
|
1997-11-07 08:02:10 +01:00
|
|
|
trim_list: a_expr FROM expr_list
|
1997-09-08 05:20:18 +02:00
|
|
|
{ $$ = lappend($3, $1); }
|
1997-11-07 08:02:10 +01:00
|
|
|
| FROM expr_list
|
1997-09-08 05:20:18 +02:00
|
|
|
{ $$ = $2; }
|
1997-11-07 08:02:10 +01:00
|
|
|
| expr_list
|
1997-09-08 05:20:18 +02:00
|
|
|
{ $$ = $1; }
|
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-10-25 07:56:41 +02:00
|
|
|
in_expr: SubSelect
|
|
|
|
{
|
1998-01-17 05:53:46 +01:00
|
|
|
SubLink *n = makeNode(SubLink);
|
|
|
|
n->subselect = $1;
|
|
|
|
$$ = (Node *)n;
|
1997-10-25 07:56:41 +02:00
|
|
|
}
|
|
|
|
| in_expr_nodes
|
1999-07-28 19:39:38 +02:00
|
|
|
{ $$ = (Node *)$1; }
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
1996-11-30 04:38:09 +01:00
|
|
|
|
1999-07-28 19:39:38 +02:00
|
|
|
in_expr_nodes: a_expr
|
|
|
|
{ $$ = lcons($1, NIL); }
|
|
|
|
| in_expr_nodes ',' a_expr
|
|
|
|
{ $$ = lappend($1, $3); }
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
1996-11-30 04:38:09 +01:00
|
|
|
|
1998-12-04 16:34:49 +01:00
|
|
|
/* Case clause
|
|
|
|
* Define SQL92-style case clause.
|
|
|
|
* Allow all four forms described in the standard:
|
|
|
|
* - Full specification
|
|
|
|
* CASE WHEN a = b THEN c ... ELSE d END
|
|
|
|
* - Implicit argument
|
|
|
|
* CASE a WHEN b THEN c ... ELSE d END
|
|
|
|
* - Conditional NULL
|
|
|
|
* NULLIF(x,y)
|
|
|
|
* same as CASE WHEN x = y THEN NULL ELSE x END
|
|
|
|
* - Conditional substitution from list, use first non-null argument
|
|
|
|
* COALESCE(a,b,...)
|
|
|
|
* same as CASE WHEN a IS NOT NULL THEN a WHEN b IS NOT NULL THEN b ... END
|
|
|
|
* - thomas 1998-11-09
|
|
|
|
*/
|
|
|
|
case_expr: CASE case_arg when_clause_list case_default END_TRANS
|
|
|
|
{
|
|
|
|
CaseExpr *c = makeNode(CaseExpr);
|
|
|
|
c->arg = $2;
|
|
|
|
c->args = $3;
|
|
|
|
c->defresult = $4;
|
|
|
|
$$ = (Node *)c;
|
|
|
|
}
|
|
|
|
| NULLIF '(' a_expr ',' a_expr ')'
|
|
|
|
{
|
|
|
|
CaseExpr *c = makeNode(CaseExpr);
|
|
|
|
CaseWhen *w = makeNode(CaseWhen);
|
1999-02-23 08:42:41 +01:00
|
|
|
/*
|
|
|
|
A_Const *n = makeNode(A_Const);
|
|
|
|
n->val.type = T_Null;
|
|
|
|
w->result = (Node *)n;
|
|
|
|
*/
|
|
|
|
w->expr = makeA_Expr(OP, "=", $3, $5);
|
1998-12-04 16:34:49 +01:00
|
|
|
c->args = lcons(w, NIL);
|
|
|
|
c->defresult = $3;
|
|
|
|
$$ = (Node *)c;
|
|
|
|
}
|
|
|
|
| COALESCE '(' expr_list ')'
|
|
|
|
{
|
|
|
|
CaseExpr *c = makeNode(CaseExpr);
|
|
|
|
CaseWhen *w;
|
|
|
|
List *l;
|
|
|
|
foreach (l,$3)
|
|
|
|
{
|
|
|
|
w = makeNode(CaseWhen);
|
|
|
|
w->expr = makeA_Expr(NOTNULL, NULL, lfirst(l), NULL);
|
|
|
|
w->result = lfirst(l);
|
|
|
|
c->args = lappend(c->args, w);
|
|
|
|
}
|
|
|
|
$$ = (Node *)c;
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
|
|
|
when_clause_list: when_clause_list when_clause
|
|
|
|
{ $$ = lappend($1, $2); }
|
|
|
|
| when_clause
|
|
|
|
{ $$ = lcons($1, NIL); }
|
|
|
|
;
|
|
|
|
|
|
|
|
when_clause: WHEN a_expr THEN a_expr_or_null
|
|
|
|
{
|
|
|
|
CaseWhen *w = makeNode(CaseWhen);
|
|
|
|
w->expr = $2;
|
|
|
|
w->result = $4;
|
|
|
|
$$ = (Node *)w;
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
|
|
|
case_default: ELSE a_expr_or_null { $$ = $2; }
|
|
|
|
| /*EMPTY*/ { $$ = NULL; }
|
|
|
|
;
|
|
|
|
|
1999-07-17 00:29:42 +02:00
|
|
|
case_arg: a_expr
|
|
|
|
{ $$ = $1; }
|
1998-12-04 16:34:49 +01:00
|
|
|
| /*EMPTY*/
|
|
|
|
{ $$ = NULL; }
|
|
|
|
;
|
|
|
|
|
1999-07-17 00:29:42 +02:00
|
|
|
attr: relation_name '.' attrs opt_indirection
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
$$ = makeNode(Attr);
|
|
|
|
$$->relname = $1;
|
|
|
|
$$->paramNo = NULL;
|
|
|
|
$$->attrs = $3;
|
1999-07-17 00:29:42 +02:00
|
|
|
$$->indirection = $4;
|
1997-09-08 05:20:18 +02:00
|
|
|
}
|
1999-07-17 00:29:42 +02:00
|
|
|
| ParamNo '.' attrs opt_indirection
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
$$ = makeNode(Attr);
|
|
|
|
$$->relname = NULL;
|
|
|
|
$$->paramNo = $1;
|
|
|
|
$$->attrs = $3;
|
1999-07-17 00:29:42 +02:00
|
|
|
$$->indirection = $4;
|
1997-09-08 05:20:18 +02:00
|
|
|
}
|
|
|
|
;
|
|
|
|
|
|
|
|
attrs: attr_name
|
|
|
|
{ $$ = lcons(makeString($1), NIL); }
|
|
|
|
| attrs '.' attr_name
|
|
|
|
{ $$ = lappend($1, makeString($3)); }
|
|
|
|
| attrs '.' '*'
|
|
|
|
{ $$ = lappend($1, makeString("*")); }
|
|
|
|
;
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
*
|
1997-09-08 05:20:18 +02:00
|
|
|
* target lists
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
|
1999-07-17 00:29:42 +02:00
|
|
|
/* Target lists as found in SELECT ... and INSERT VALUES ( ... ) */
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1999-07-17 00:29:42 +02:00
|
|
|
target_list: target_list ',' target_el
|
1997-09-08 05:20:18 +02:00
|
|
|
{ $$ = lappend($1, $3); }
|
1999-07-17 00:29:42 +02:00
|
|
|
| target_el
|
1997-09-08 05:20:18 +02:00
|
|
|
{ $$ = lcons($1, NIL); }
|
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
/* AS is not optional because shift/red conflict with unary ops */
|
1999-07-17 00:29:42 +02:00
|
|
|
target_el: a_expr_or_null AS ColLabel
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
$$ = makeNode(ResTarget);
|
|
|
|
$$->name = $3;
|
|
|
|
$$->indirection = NULL;
|
|
|
|
$$->val = (Node *)$1;
|
|
|
|
}
|
|
|
|
| a_expr_or_null
|
|
|
|
{
|
|
|
|
$$ = makeNode(ResTarget);
|
|
|
|
$$->name = NULL;
|
|
|
|
$$->indirection = NULL;
|
|
|
|
$$->val = (Node *)$1;
|
|
|
|
}
|
|
|
|
| relation_name '.' '*'
|
|
|
|
{
|
|
|
|
Attr *att = makeNode(Attr);
|
|
|
|
att->relname = $1;
|
|
|
|
att->paramNo = NULL;
|
|
|
|
att->attrs = lcons(makeString("*"), NIL);
|
|
|
|
att->indirection = NIL;
|
|
|
|
$$ = makeNode(ResTarget);
|
|
|
|
$$->name = NULL;
|
|
|
|
$$->indirection = NULL;
|
|
|
|
$$->val = (Node *)att;
|
|
|
|
}
|
|
|
|
| '*'
|
|
|
|
{
|
|
|
|
Attr *att = makeNode(Attr);
|
|
|
|
att->relname = "*";
|
|
|
|
att->paramNo = NULL;
|
|
|
|
att->attrs = NULL;
|
|
|
|
att->indirection = NIL;
|
|
|
|
$$ = makeNode(ResTarget);
|
|
|
|
$$->name = NULL;
|
|
|
|
$$->indirection = NULL;
|
|
|
|
$$->val = (Node *)att;
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
1999-07-17 00:29:42 +02:00
|
|
|
/* Target list as found in UPDATE table SET ... */
|
|
|
|
|
|
|
|
update_target_list: update_target_list ',' update_target_el
|
|
|
|
{ $$ = lappend($1,$3); }
|
|
|
|
| update_target_el
|
|
|
|
{ $$ = lcons($1, NIL); }
|
|
|
|
;
|
|
|
|
|
|
|
|
update_target_el: ColId opt_indirection '=' a_expr_or_null
|
|
|
|
{
|
|
|
|
$$ = makeNode(ResTarget);
|
|
|
|
$$->name = $1;
|
|
|
|
$$->indirection = $2;
|
|
|
|
$$->val = (Node *)$4;
|
|
|
|
}
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
|
|
|
|
1999-07-17 00:29:42 +02:00
|
|
|
/*****************************************************************************
|
|
|
|
*
|
|
|
|
* Names and constants
|
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
|
1997-09-08 05:20:18 +02:00
|
|
|
relation_name: SpecialRuleRelation
|
|
|
|
{
|
|
|
|
$$ = $1;
|
1997-10-25 03:10:58 +02:00
|
|
|
StrNCpy(saved_relname, $1, NAMEDATALEN);
|
1997-09-08 05:20:18 +02:00
|
|
|
}
|
|
|
|
| ColId
|
|
|
|
{
|
1997-11-15 21:58:05 +01:00
|
|
|
/* disallow refs to variable system tables */
|
1997-09-08 05:20:18 +02:00
|
|
|
if (strcmp(LogRelationName, $1) == 0
|
1997-11-15 21:58:05 +01:00
|
|
|
|| strcmp(VariableRelationName, $1) == 0)
|
1998-01-05 17:40:20 +01:00
|
|
|
elog(ERROR,"%s cannot be accessed by users",$1);
|
1997-09-08 05:20:18 +02:00
|
|
|
else
|
|
|
|
$$ = $1;
|
1997-10-25 03:10:58 +02:00
|
|
|
StrNCpy(saved_relname, $1, NAMEDATALEN);
|
1997-09-08 05:20:18 +02:00
|
|
|
}
|
|
|
|
;
|
|
|
|
|
1997-10-25 07:56:41 +02:00
|
|
|
database_name: ColId { $$ = $1; };
|
1998-02-11 05:09:54 +01:00
|
|
|
access_method: IDENT { $$ = $1; };
|
1997-09-08 05:20:18 +02:00
|
|
|
attr_name: ColId { $$ = $1; };
|
1998-02-11 05:09:54 +01:00
|
|
|
class: IDENT { $$ = $1; };
|
1997-10-25 07:56:41 +02:00
|
|
|
index_name: ColId { $$ = $1; };
|
1997-09-24 19:53:53 +02:00
|
|
|
|
1997-10-25 07:56:41 +02:00
|
|
|
/* Functions
|
|
|
|
* Include date/time keywords as SQL92 extension.
|
|
|
|
* Include TYPE as a SQL92 unreserved keyword. - thomas 1997-10-05
|
|
|
|
*/
|
|
|
|
name: ColId { $$ = $1; };
|
1998-02-11 05:09:54 +01:00
|
|
|
func_name: ColId { $$ = xlateSqlFunc($1); };
|
1997-09-08 05:20:18 +02:00
|
|
|
|
|
|
|
file_name: Sconst { $$ = $1; };
|
1999-03-07 04:34:11 +01:00
|
|
|
/* NOT USED recipe_name: IDENT { $$ = $1; };*/
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-10-25 07:56:41 +02:00
|
|
|
/* Constants
|
|
|
|
* Include TRUE/FALSE for SQL3 support. - thomas 1997-10-24
|
|
|
|
*/
|
1996-07-09 08:22:35 +02:00
|
|
|
AexprConst: Iconst
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
A_Const *n = makeNode(A_Const);
|
|
|
|
n->val.type = T_Integer;
|
|
|
|
n->val.val.ival = $1;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
| FCONST
|
|
|
|
{
|
|
|
|
A_Const *n = makeNode(A_Const);
|
|
|
|
n->val.type = T_Float;
|
|
|
|
n->val.val.dval = $1;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
| Sconst
|
|
|
|
{
|
|
|
|
A_Const *n = makeNode(A_Const);
|
|
|
|
n->val.type = T_String;
|
|
|
|
n->val.val.str = $1;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
1999-07-17 00:29:42 +02:00
|
|
|
/* this rule formerly used Typename, but that causes reduce conflicts
|
|
|
|
* with subscripted column names ...
|
|
|
|
*/
|
|
|
|
| SimpleTypename Sconst
|
1997-11-17 17:37:24 +01:00
|
|
|
{
|
|
|
|
A_Const *n = makeNode(A_Const);
|
|
|
|
n->typename = $1;
|
|
|
|
n->val.type = T_String;
|
|
|
|
n->val.val.str = $2;
|
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
1997-09-08 05:20:18 +02:00
|
|
|
| ParamNo
|
|
|
|
{ $$ = (Node *)$1; }
|
1997-10-25 07:56:41 +02:00
|
|
|
| TRUE_P
|
|
|
|
{
|
|
|
|
A_Const *n = makeNode(A_Const);
|
|
|
|
n->val.type = T_String;
|
|
|
|
n->val.val.str = "t";
|
1997-12-23 20:47:32 +01:00
|
|
|
n->typename = makeNode(TypeName);
|
|
|
|
n->typename->name = xlateSqlType("bool");
|
1998-02-10 05:02:59 +01:00
|
|
|
n->typename->typmod = -1;
|
1997-10-25 07:56:41 +02:00
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
|
|
|
| FALSE_P
|
|
|
|
{
|
|
|
|
A_Const *n = makeNode(A_Const);
|
|
|
|
n->val.type = T_String;
|
|
|
|
n->val.val.str = "f";
|
1997-12-23 20:47:32 +01:00
|
|
|
n->typename = makeNode(TypeName);
|
|
|
|
n->typename->name = xlateSqlType("bool");
|
1998-02-10 05:02:59 +01:00
|
|
|
n->typename->typmod = -1;
|
1997-10-25 07:56:41 +02:00
|
|
|
$$ = (Node *)n;
|
|
|
|
}
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1998-10-02 18:23:07 +02:00
|
|
|
ParamNo: PARAM opt_indirection
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
$$ = makeNode(ParamNo);
|
|
|
|
$$->number = $1;
|
1998-10-02 18:23:07 +02:00
|
|
|
$$->indirection = $2;
|
1997-09-08 05:20:18 +02:00
|
|
|
}
|
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-08 05:20:18 +02:00
|
|
|
Iconst: ICONST { $$ = $1; };
|
|
|
|
Sconst: SCONST { $$ = $1; };
|
1998-02-11 05:09:54 +01:00
|
|
|
UserId: IDENT { $$ = $1; };
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-10-25 07:56:41 +02:00
|
|
|
/* Column and type identifier
|
|
|
|
* Does not include explicit datetime types
|
|
|
|
* since these must be decoupled in Typename syntax.
|
|
|
|
* Use ColId for most identifiers. - thomas 1997-10-21
|
|
|
|
*/
|
1998-02-11 05:09:54 +01:00
|
|
|
TypeId: ColId
|
|
|
|
{ $$ = xlateSqlType($1); }
|
|
|
|
| numeric
|
|
|
|
{ $$ = xlateSqlType($1); }
|
|
|
|
| character
|
|
|
|
{ $$ = xlateSqlType($1); }
|
|
|
|
;
|
1997-10-25 07:56:41 +02:00
|
|
|
/* Column identifier
|
|
|
|
* Include date/time keywords as SQL92 extension.
|
|
|
|
* Include TYPE as a SQL92 unreserved keyword. - thomas 1997-10-05
|
1997-11-07 08:02:10 +01:00
|
|
|
* Add other keywords. Note that as the syntax expands,
|
|
|
|
* some of these keywords will have to be removed from this
|
|
|
|
* list due to shift/reduce conflicts in yacc. If so, move
|
|
|
|
* down to the ColLabel entity. - thomas 1997-11-06
|
1997-10-09 07:00:54 +02:00
|
|
|
*/
|
1998-02-11 05:09:54 +01:00
|
|
|
ColId: IDENT { $$ = $1; }
|
1997-10-25 07:56:41 +02:00
|
|
|
| datetime { $$ = $1; }
|
1998-09-13 06:19:33 +02:00
|
|
|
| ABSOLUTE { $$ = "absolute"; }
|
1999-05-12 09:22:52 +02:00
|
|
|
| ACCESS { $$ = "access"; }
|
1997-11-07 08:02:10 +01:00
|
|
|
| ACTION { $$ = "action"; }
|
1998-09-30 07:47:57 +02:00
|
|
|
| AFTER { $$ = "after"; }
|
|
|
|
| AGGREGATE { $$ = "aggregate"; }
|
|
|
|
| BACKWARD { $$ = "backward"; }
|
|
|
|
| BEFORE { $$ = "before"; }
|
1998-03-18 17:50:25 +01:00
|
|
|
| CACHE { $$ = "cache"; }
|
This patch implements ORACLE's COMMENT SQL command.
>From the ORACLE 7 SQL Language Reference Manual:
-----------------------------------------------------
COMMENT
Purpose:
To add a comment about a table, view, snapshot, or
column into the data dictionary.
Prerequisites:
The table, view, or snapshot must be in your own
schema
or you must have COMMENT ANY TABLE system privilege.
Syntax:
COMMENT ON [ TABLE table ] |
[ COLUMN table.column] IS 'text'
You can effectively drop a comment from the database
by setting it to the empty string ''.
-----------------------------------------------------
Example:
COMMENT ON TABLE workorders IS
'Maintains base records for workorder information';
COMMENT ON COLUMN workorders.hours IS
'Number of hours the engineer worked on the task';
to drop a comment:
COMMENT ON COLUMN workorders.hours IS '';
The current patch will simply perform the insert into
pg_description, as per the TODO. And, of course, when
the table is dropped, any comments relating to it
or any of its attributes are also dropped. I haven't
looked at the ODBC source yet, but I do know from
an ODBC client standpoint that the standard does
support the notion of table and column comments.
Hopefully the ODBC driver is already fetching these
values from pg_description, but if not, it should be
trivial.
Hope this makes the grade,
Mike Mascari
(mascarim@yahoo.com)
1999-10-15 03:49:49 +02:00
|
|
|
| COMMENT { $$ = "comment"; }
|
1999-05-12 09:22:52 +02:00
|
|
|
| COMMITTED { $$ = "committed"; }
|
1999-09-29 18:06:40 +02:00
|
|
|
| CONSTRAINTS { $$ = "constraints"; }
|
1998-09-30 07:47:57 +02:00
|
|
|
| CREATEDB { $$ = "createdb"; }
|
|
|
|
| CREATEUSER { $$ = "createuser"; }
|
1998-03-18 17:50:25 +01:00
|
|
|
| CYCLE { $$ = "cycle"; }
|
1997-11-07 08:02:10 +01:00
|
|
|
| DATABASE { $$ = "database"; }
|
1999-09-29 18:06:40 +02:00
|
|
|
| DEFERRABLE { $$ = "deferrable"; }
|
|
|
|
| DEFERRED { $$ = "deferred"; }
|
1997-11-07 08:02:10 +01:00
|
|
|
| DELIMITERS { $$ = "delimiters"; }
|
1998-02-11 05:09:54 +01:00
|
|
|
| DOUBLE { $$ = "double"; }
|
|
|
|
| EACH { $$ = "each"; }
|
1998-07-24 05:32:46 +02:00
|
|
|
| ENCODING { $$ = "encoding"; }
|
1999-05-12 09:22:52 +02:00
|
|
|
| EXCLUSIVE { $$ = "exclusive"; }
|
1998-09-30 07:47:57 +02:00
|
|
|
| FORWARD { $$ = "forward"; }
|
1997-11-07 08:02:10 +01:00
|
|
|
| FUNCTION { $$ = "function"; }
|
1998-09-30 07:47:57 +02:00
|
|
|
| HANDLER { $$ = "handler"; }
|
1999-09-29 18:06:40 +02:00
|
|
|
| IMMEDIATE { $$ = "immediate"; }
|
1998-03-18 17:50:25 +01:00
|
|
|
| INCREMENT { $$ = "increment"; }
|
1997-11-07 08:02:10 +01:00
|
|
|
| INDEX { $$ = "index"; }
|
1998-09-30 07:47:57 +02:00
|
|
|
| INHERITS { $$ = "inherits"; }
|
1999-09-29 18:06:40 +02:00
|
|
|
| INITIALLY { $$ = "initially"; }
|
1998-09-13 06:19:33 +02:00
|
|
|
| INSENSITIVE { $$ = "insensitive"; }
|
1998-09-30 07:47:57 +02:00
|
|
|
| INSTEAD { $$ = "instead"; }
|
|
|
|
| ISNULL { $$ = "isnull"; }
|
1999-09-14 08:06:31 +02:00
|
|
|
| ISOLATION { $$ = "isolation"; }
|
1997-11-07 08:02:10 +01:00
|
|
|
| KEY { $$ = "key"; }
|
|
|
|
| LANGUAGE { $$ = "language"; }
|
1998-09-30 07:47:57 +02:00
|
|
|
| LANCOMPILER { $$ = "lancompiler"; }
|
1999-09-14 08:06:31 +02:00
|
|
|
| LEVEL { $$ = "level"; }
|
1997-11-07 08:02:10 +01:00
|
|
|
| LOCATION { $$ = "location"; }
|
|
|
|
| MATCH { $$ = "match"; }
|
1998-03-18 17:50:25 +01:00
|
|
|
| MAXVALUE { $$ = "maxvalue"; }
|
|
|
|
| MINVALUE { $$ = "minvalue"; }
|
1999-05-12 09:22:52 +02:00
|
|
|
| MODE { $$ = "mode"; }
|
1998-09-13 06:19:33 +02:00
|
|
|
| NEXT { $$ = "next"; }
|
1998-09-30 07:47:57 +02:00
|
|
|
| NOCREATEDB { $$ = "nocreatedb"; }
|
|
|
|
| NOCREATEUSER { $$ = "nocreateuser"; }
|
|
|
|
| NOTHING { $$ = "nothing"; }
|
|
|
|
| NOTNULL { $$ = "notnull"; }
|
1998-09-13 06:19:33 +02:00
|
|
|
| OF { $$ = "of"; }
|
1998-09-30 07:47:57 +02:00
|
|
|
| OIDS { $$ = "oids"; }
|
1998-09-13 06:19:33 +02:00
|
|
|
| ONLY { $$ = "only"; }
|
1997-11-07 08:02:10 +01:00
|
|
|
| OPERATOR { $$ = "operator"; }
|
|
|
|
| OPTION { $$ = "option"; }
|
1998-03-18 17:50:25 +01:00
|
|
|
| PASSWORD { $$ = "password"; }
|
1999-09-29 18:06:40 +02:00
|
|
|
| PENDANT { $$ = "pendant"; }
|
1998-09-13 06:19:33 +02:00
|
|
|
| PRIOR { $$ = "prior"; }
|
1997-11-07 08:02:10 +01:00
|
|
|
| PRIVILEGES { $$ = "privileges"; }
|
1998-09-30 07:47:57 +02:00
|
|
|
| PROCEDURAL { $$ = "procedural"; }
|
1998-09-13 06:19:33 +02:00
|
|
|
| READ { $$ = "read"; }
|
|
|
|
| RELATIVE { $$ = "relative"; }
|
1998-09-30 07:47:57 +02:00
|
|
|
| RENAME { $$ = "rename"; }
|
1999-09-29 18:06:40 +02:00
|
|
|
| RESTRICT { $$ = "restrict"; }
|
1998-09-30 07:47:57 +02:00
|
|
|
| RETURNS { $$ = "returns"; }
|
1998-02-11 05:09:54 +01:00
|
|
|
| ROW { $$ = "row"; }
|
1998-09-30 07:47:57 +02:00
|
|
|
| RULE { $$ = "rule"; }
|
1998-09-13 06:19:33 +02:00
|
|
|
| SCROLL { $$ = "scroll"; }
|
1998-09-30 07:47:57 +02:00
|
|
|
| SEQUENCE { $$ = "sequence"; }
|
1998-08-25 17:04:24 +02:00
|
|
|
| SERIAL { $$ = "serial"; }
|
1999-05-12 09:22:52 +02:00
|
|
|
| SERIALIZABLE { $$ = "serializable"; }
|
|
|
|
| SHARE { $$ = "share"; }
|
1998-04-08 08:39:01 +02:00
|
|
|
| START { $$ = "start"; }
|
1998-02-11 05:09:54 +01:00
|
|
|
| STATEMENT { $$ = "statement"; }
|
1998-09-30 07:47:57 +02:00
|
|
|
| STDIN { $$ = "stdin"; }
|
|
|
|
| STDOUT { $$ = "stdout"; }
|
1999-12-10 04:01:05 +01:00
|
|
|
| SYSID { $$ = "sysid"; }
|
1997-10-09 07:00:54 +02:00
|
|
|
| TIME { $$ = "time"; }
|
1998-10-14 17:57:25 +02:00
|
|
|
| TIMESTAMP { $$ = "timestamp"; }
|
1998-05-10 01:22:15 +02:00
|
|
|
| TIMEZONE_HOUR { $$ = "timezone_hour"; }
|
|
|
|
| TIMEZONE_MINUTE { $$ = "timezone_minute"; }
|
1997-11-07 08:02:10 +01:00
|
|
|
| TRIGGER { $$ = "trigger"; }
|
This patch implements ORACLE's COMMENT SQL command.
>From the ORACLE 7 SQL Language Reference Manual:
-----------------------------------------------------
COMMENT
Purpose:
To add a comment about a table, view, snapshot, or
column into the data dictionary.
Prerequisites:
The table, view, or snapshot must be in your own
schema
or you must have COMMENT ANY TABLE system privilege.
Syntax:
COMMENT ON [ TABLE table ] |
[ COLUMN table.column] IS 'text'
You can effectively drop a comment from the database
by setting it to the empty string ''.
-----------------------------------------------------
Example:
COMMENT ON TABLE workorders IS
'Maintains base records for workorder information';
COMMENT ON COLUMN workorders.hours IS
'Number of hours the engineer worked on the task';
to drop a comment:
COMMENT ON COLUMN workorders.hours IS '';
The current patch will simply perform the insert into
pg_description, as per the TODO. And, of course, when
the table is dropped, any comments relating to it
or any of its attributes are also dropped. I haven't
looked at the ODBC source yet, but I do know from
an ODBC client standpoint that the standard does
support the notion of table and column comments.
Hopefully the ODBC driver is already fetching these
values from pg_description, but if not, it should be
trivial.
Hope this makes the grade,
Mike Mascari
(mascarim@yahoo.com)
1999-10-15 03:49:49 +02:00
|
|
|
| TRUNCATE { $$ = "truncate"; }
|
1998-09-30 07:47:57 +02:00
|
|
|
| TRUSTED { $$ = "trusted"; }
|
1997-10-25 07:56:41 +02:00
|
|
|
| TYPE_P { $$ = "type"; }
|
1998-02-18 08:25:57 +01:00
|
|
|
| VALID { $$ = "valid"; }
|
1997-11-07 08:02:10 +01:00
|
|
|
| VERSION { $$ = "version"; }
|
|
|
|
| ZONE { $$ = "zone"; }
|
1997-10-25 07:56:41 +02:00
|
|
|
;
|
|
|
|
|
|
|
|
/* Column label
|
|
|
|
* Allowed labels in "AS" clauses.
|
|
|
|
* Include TRUE/FALSE SQL3 reserved words for Postgres backward
|
|
|
|
* compatibility. Cannot allow this for column names since the
|
|
|
|
* syntax would not distinguish between the constant value and
|
|
|
|
* a column name. - thomas 1997-10-24
|
1997-11-07 08:02:10 +01:00
|
|
|
* Add other keywords to this list. Note that they appear here
|
|
|
|
* rather than in ColId if there was a shift/reduce conflict
|
|
|
|
* when used as a full identifier. - thomas 1997-11-06
|
1997-10-25 07:56:41 +02:00
|
|
|
*/
|
|
|
|
ColLabel: ColId { $$ = $1; }
|
1998-09-30 07:47:57 +02:00
|
|
|
| ABORT_TRANS { $$ = "abort"; }
|
|
|
|
| ANALYZE { $$ = "analyze"; }
|
|
|
|
| BINARY { $$ = "binary"; }
|
1998-12-04 16:34:49 +01:00
|
|
|
| CASE { $$ = "case"; }
|
1997-11-07 08:02:10 +01:00
|
|
|
| CLUSTER { $$ = "cluster"; }
|
1998-12-04 16:34:49 +01:00
|
|
|
| COALESCE { $$ = "coalesce"; }
|
1997-11-07 08:02:10 +01:00
|
|
|
| CONSTRAINT { $$ = "constraint"; }
|
1998-09-30 07:47:57 +02:00
|
|
|
| COPY { $$ = "copy"; }
|
|
|
|
| CURRENT { $$ = "current"; }
|
2000-01-17 01:14:49 +01:00
|
|
|
| DECIMAL { $$ = "decimal"; }
|
1998-09-30 07:47:57 +02:00
|
|
|
| DO { $$ = "do"; }
|
1998-12-04 16:34:49 +01:00
|
|
|
| ELSE { $$ = "else"; }
|
|
|
|
| END_TRANS { $$ = "end"; }
|
1998-09-30 07:47:57 +02:00
|
|
|
| EXPLAIN { $$ = "explain"; }
|
|
|
|
| EXTEND { $$ = "extend"; }
|
|
|
|
| FALSE_P { $$ = "false"; }
|
2000-01-20 03:24:50 +01:00
|
|
|
| FLOAT { $$ = "float"; }
|
1997-11-07 08:02:10 +01:00
|
|
|
| FOREIGN { $$ = "foreign"; }
|
1999-05-12 09:22:52 +02:00
|
|
|
| GLOBAL { $$ = "global"; }
|
1997-11-07 08:02:10 +01:00
|
|
|
| GROUP { $$ = "group"; }
|
1998-09-30 07:47:57 +02:00
|
|
|
| LISTEN { $$ = "listen"; }
|
1997-11-07 08:02:10 +01:00
|
|
|
| LOAD { $$ = "load"; }
|
1999-05-12 09:22:52 +02:00
|
|
|
| LOCAL { $$ = "local"; }
|
1998-09-30 07:47:57 +02:00
|
|
|
| LOCK_P { $$ = "lock"; }
|
|
|
|
| MOVE { $$ = "move"; }
|
|
|
|
| NEW { $$ = "new"; }
|
|
|
|
| NONE { $$ = "none"; }
|
1998-12-04 16:34:49 +01:00
|
|
|
| NULLIF { $$ = "nullif"; }
|
2000-01-17 01:14:49 +01:00
|
|
|
| NUMERIC { $$ = "numeric"; }
|
1997-11-07 08:02:10 +01:00
|
|
|
| ORDER { $$ = "order"; }
|
|
|
|
| POSITION { $$ = "position"; }
|
|
|
|
| PRECISION { $$ = "precision"; }
|
1998-09-30 07:47:57 +02:00
|
|
|
| RESET { $$ = "reset"; }
|
|
|
|
| SETOF { $$ = "setof"; }
|
|
|
|
| SHOW { $$ = "show"; }
|
1997-11-07 08:02:10 +01:00
|
|
|
| TABLE { $$ = "table"; }
|
1998-12-04 16:34:49 +01:00
|
|
|
| THEN { $$ = "then"; }
|
1997-11-07 08:02:10 +01:00
|
|
|
| TRANSACTION { $$ = "transaction"; }
|
1997-10-25 07:56:41 +02:00
|
|
|
| TRUE_P { $$ = "true"; }
|
1998-09-30 07:47:57 +02:00
|
|
|
| VACUUM { $$ = "vacuum"; }
|
|
|
|
| VERBOSE { $$ = "verbose"; }
|
1998-12-04 16:34:49 +01:00
|
|
|
| WHEN { $$ = "when"; }
|
1997-09-08 05:20:18 +02:00
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
SpecialRuleRelation: CURRENT
|
1997-09-08 05:20:18 +02:00
|
|
|
{
|
|
|
|
if (QueryIsRule)
|
|
|
|
$$ = "*CURRENT*";
|
|
|
|
else
|
1998-01-09 21:06:08 +01:00
|
|
|
elog(ERROR,"CURRENT used in non-rule query");
|
1997-09-08 05:20:18 +02:00
|
|
|
}
|
|
|
|
| NEW
|
|
|
|
{
|
|
|
|
if (QueryIsRule)
|
|
|
|
$$ = "*NEW*";
|
|
|
|
else
|
1998-01-09 21:06:08 +01:00
|
|
|
elog(ERROR,"NEW used in non-rule query");
|
1997-09-08 05:20:18 +02:00
|
|
|
}
|
|
|
|
;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
%%
|
|
|
|
|
1997-12-23 20:47:32 +01:00
|
|
|
static Node *
|
|
|
|
makeA_Expr(int oper, char *opname, Node *lexpr, Node *rexpr)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 05:20:18 +02:00
|
|
|
A_Expr *a = makeNode(A_Expr);
|
|
|
|
a->oper = oper;
|
|
|
|
a->opname = opname;
|
|
|
|
a->lexpr = lexpr;
|
|
|
|
a->rexpr = rexpr;
|
|
|
|
return (Node *)a;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2000-01-17 01:14:49 +01:00
|
|
|
static Node *
|
|
|
|
makeTypeCast(Node *arg, TypeName *typename)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* If arg is an A_Const or ParamNo, just stick the typename into the
|
|
|
|
* field reserved for it --- unless there's something there already!
|
|
|
|
* (We don't want to collapse x::type1::type2 into just x::type2.)
|
|
|
|
* Otherwise, generate a TypeCast node.
|
|
|
|
*/
|
|
|
|
if (IsA(arg, A_Const) &&
|
|
|
|
((A_Const *) arg)->typename == NULL)
|
|
|
|
{
|
|
|
|
((A_Const *) arg)->typename = typename;
|
|
|
|
return arg;
|
|
|
|
}
|
|
|
|
else if (IsA(arg, ParamNo) &&
|
|
|
|
((ParamNo *) arg)->typename == NULL)
|
|
|
|
{
|
|
|
|
((ParamNo *) arg)->typename = typename;
|
|
|
|
return arg;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
TypeCast *n = makeNode(TypeCast);
|
|
|
|
n->arg = arg;
|
|
|
|
n->typename = typename;
|
|
|
|
return (Node *) n;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-01-17 06:01:34 +01:00
|
|
|
/* makeRowExpr()
|
|
|
|
* Generate separate operator nodes for a single row descriptor expression.
|
1999-02-23 08:42:41 +01:00
|
|
|
* Perhaps this should go deeper in the parser someday...
|
|
|
|
* - thomas 1997-12-22
|
1998-01-17 06:01:34 +01:00
|
|
|
*/
|
|
|
|
static Node *
|
|
|
|
makeRowExpr(char *opr, List *largs, List *rargs)
|
|
|
|
{
|
|
|
|
Node *expr = NULL;
|
|
|
|
Node *larg, *rarg;
|
|
|
|
|
|
|
|
if (length(largs) != length(rargs))
|
|
|
|
elog(ERROR,"Unequal number of entries in row expression");
|
|
|
|
|
|
|
|
if (lnext(largs) != NIL)
|
|
|
|
expr = makeRowExpr(opr,lnext(largs),lnext(rargs));
|
|
|
|
|
|
|
|
larg = lfirst(largs);
|
|
|
|
rarg = lfirst(rargs);
|
|
|
|
|
|
|
|
if ((strcmp(opr, "=") == 0)
|
|
|
|
|| (strcmp(opr, "<") == 0)
|
|
|
|
|| (strcmp(opr, "<=") == 0)
|
|
|
|
|| (strcmp(opr, ">") == 0)
|
|
|
|
|| (strcmp(opr, ">=") == 0))
|
|
|
|
{
|
|
|
|
if (expr == NULL)
|
|
|
|
expr = makeA_Expr(OP, opr, larg, rarg);
|
|
|
|
else
|
|
|
|
expr = makeA_Expr(AND, NULL, expr, makeA_Expr(OP, opr, larg, rarg));
|
|
|
|
}
|
|
|
|
else if (strcmp(opr, "<>") == 0)
|
|
|
|
{
|
|
|
|
if (expr == NULL)
|
|
|
|
expr = makeA_Expr(OP, opr, larg, rarg);
|
|
|
|
else
|
|
|
|
expr = makeA_Expr(OR, NULL, expr, makeA_Expr(OP, opr, larg, rarg));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
elog(ERROR,"Operator '%s' not implemented for row expressions",opr);
|
|
|
|
}
|
|
|
|
|
|
|
|
return expr;
|
|
|
|
}
|
|
|
|
|
1998-10-08 20:30:52 +02:00
|
|
|
static void
|
1997-12-23 20:47:32 +01:00
|
|
|
mapTargetColumns(List *src, List *dst)
|
|
|
|
{
|
|
|
|
ColumnDef *s;
|
|
|
|
ResTarget *d;
|
|
|
|
|
|
|
|
if (length(src) != length(dst))
|
1998-01-09 21:06:08 +01:00
|
|
|
elog(ERROR,"CREATE TABLE/AS SELECT has mismatched column count");
|
1997-12-23 20:47:32 +01:00
|
|
|
|
|
|
|
while ((src != NIL) && (dst != NIL))
|
|
|
|
{
|
|
|
|
s = (ColumnDef *)lfirst(src);
|
|
|
|
d = (ResTarget *)lfirst(dst);
|
|
|
|
|
|
|
|
d->name = s->colname;
|
|
|
|
|
|
|
|
src = lnext(src);
|
|
|
|
dst = lnext(dst);
|
|
|
|
}
|
|
|
|
} /* mapTargetColumns() */
|
1997-11-10 16:22:36 +01:00
|
|
|
|
1997-10-31 01:50:39 +01:00
|
|
|
|
1998-02-11 05:09:54 +01:00
|
|
|
/* xlateSqlFunc()
|
1997-09-13 05:15:46 +02:00
|
|
|
* Convert alternate type names to internal Postgres types.
|
1997-09-20 18:11:44 +02:00
|
|
|
* Do not convert "float", since that is handled elsewhere
|
|
|
|
* for FLOAT(p) syntax.
|
1997-09-13 05:15:46 +02:00
|
|
|
*/
|
1996-07-09 08:22:35 +02:00
|
|
|
static char *
|
1998-02-11 05:09:54 +01:00
|
|
|
xlateSqlFunc(char *name)
|
|
|
|
{
|
|
|
|
if (!strcasecmp(name,"character_length")
|
|
|
|
|| !strcasecmp(name,"char_length"))
|
|
|
|
return "length";
|
|
|
|
else
|
|
|
|
return name;
|
|
|
|
} /* xlateSqlFunc() */
|
|
|
|
|
|
|
|
/* xlateSqlType()
|
|
|
|
* Convert alternate type names to internal Postgres types.
|
|
|
|
*/
|
|
|
|
static char *
|
1996-07-09 08:22:35 +02:00
|
|
|
xlateSqlType(char *name)
|
|
|
|
{
|
1997-11-07 08:02:10 +01:00
|
|
|
if (!strcasecmp(name,"int")
|
|
|
|
|| !strcasecmp(name,"integer"))
|
1997-10-25 07:56:41 +02:00
|
|
|
return "int4";
|
1997-09-08 05:20:18 +02:00
|
|
|
else if (!strcasecmp(name, "smallint"))
|
|
|
|
return "int2";
|
1998-02-11 05:09:54 +01:00
|
|
|
else if (!strcasecmp(name, "real")
|
|
|
|
|| !strcasecmp(name, "float"))
|
1997-09-08 05:20:18 +02:00
|
|
|
return "float8";
|
2000-01-20 03:24:50 +01:00
|
|
|
else if (!strcasecmp(name, "decimal"))
|
|
|
|
return "numeric";
|
|
|
|
else if (!strcasecmp(name, "char"))
|
|
|
|
return "bpchar";
|
1997-09-08 05:20:18 +02:00
|
|
|
else if (!strcasecmp(name, "interval"))
|
|
|
|
return "timespan";
|
1997-10-25 07:56:41 +02:00
|
|
|
else if (!strcasecmp(name, "boolean"))
|
|
|
|
return "bool";
|
1997-09-08 05:20:18 +02:00
|
|
|
else
|
|
|
|
return name;
|
1998-02-11 05:09:54 +01:00
|
|
|
} /* xlateSqlType() */
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-11-10 16:22:36 +01:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
void parser_init(Oid *typev, int nargs)
|
|
|
|
{
|
1997-09-13 05:15:46 +02:00
|
|
|
QueryIsRule = FALSE;
|
1997-09-08 05:20:18 +02:00
|
|
|
saved_relname[0]= '\0';
|
1997-09-01 08:00:35 +02:00
|
|
|
|
1997-09-08 05:20:18 +02:00
|
|
|
param_type_init(typev, nargs);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
1997-09-13 05:15:46 +02:00
|
|
|
|
1997-11-10 16:22:36 +01:00
|
|
|
|
1997-11-25 23:07:18 +01:00
|
|
|
/*
|
|
|
|
* param_type_init()
|
|
|
|
*
|
|
|
|
* keep enough information around fill out the type of param nodes
|
|
|
|
* used in postquel functions
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
param_type_init(Oid *typev, int nargs)
|
|
|
|
{
|
|
|
|
pfunc_num_args = nargs;
|
|
|
|
param_type_info = typev;
|
|
|
|
}
|
|
|
|
|
|
|
|
Oid param_type(int t)
|
|
|
|
{
|
|
|
|
if ((t > pfunc_num_args) || (t == 0))
|
|
|
|
return InvalidOid;
|
|
|
|
return param_type_info[t - 1];
|
|
|
|
}
|
1999-03-18 22:39:56 +01:00
|
|
|
|
|
|
|
/*
|
1999-03-18 23:03:59 +01:00
|
|
|
* The optimizer doesn't like '-' 4 for index use. It only checks for
|
|
|
|
* Var '=' Const. It wants an integer of -4, so we try to merge the
|
|
|
|
* minus into the constant.
|
1999-10-07 06:23:24 +02:00
|
|
|
*
|
|
|
|
* This code is no longer essential as of 10/1999, since the optimizer
|
|
|
|
* now has a constant-subexpression simplifier. However, we can save
|
|
|
|
* a few cycles throughout the parse and rewrite stages if we collapse
|
|
|
|
* the minus into the constant sooner rather than later...
|
1999-03-18 22:39:56 +01:00
|
|
|
*/
|
|
|
|
static Node *doNegate(Node *n)
|
|
|
|
{
|
|
|
|
if (IsA(n, A_Const))
|
|
|
|
{
|
|
|
|
A_Const *con = (A_Const *)n;
|
|
|
|
|
|
|
|
if (con->val.type == T_Integer)
|
|
|
|
{
|
|
|
|
con->val.val.ival = -con->val.val.ival;
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
if (con->val.type == T_Float)
|
|
|
|
{
|
|
|
|
con->val.val.dval = -con->val.val.dval;
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return makeA_Expr(OP, "-", NULL, n);
|
|
|
|
}
|