Sequence usage patch
Enables syntax: NEXT VALUE FOR <seqname> and CURRENT VALUE FOR <seqname>
The 200N spec is based on DB2, not MSSQL, so it is very likely NEXT
VALUE FOR will be the official syntax.
DB2 uses PREVIOUS VALUE FOR <seqname> as their currval() (nothing in
spec about this). I don't see PREVIOUS as a reserved word, but CURRENT
certainly is -- WHERE CURRENT OF for cursors, and several other places.
The attached patch makes CURRENT a reserved word. VALUE is treated as
an IDENT to preserve the ability to use it as a column.
SequenceOp is the node (primnode) used in the executor, and required
splitting up nextval / currval into public and internal interfaces. The
internal interface operates on the sequence OID, and the public
interface on the sequence name as usual.
Dependencies are recorded for the SequenceOp node so now we cannot drop
a sequence used in a default expression.
I've not figured out the best place to record the dependency to prevent
the default expression from being changed for SERIAL columns yet, but
that should be a separate patch. The concept of a serial will need to
be brought in deeper than parser/analyze.c for this to happen.
No documentation changes attached. I want to know whether this would be
applied before I make those.
Tom,
Should I have created another parser node strictly for the gram.y stuff,
then had it copy the info to the primnode within parse_expr.c? As it
is, SequenceOp is left with a hanging RangeVar that is unused past that
point.
--
Rod Taylor <rbt@rbt.ca>
PGP Key: http://www.rbt.ca/rbtpub.asc
Attachments:
nextvaluefor.patchtext/x-patch; charset=ISO-8859-1; name=nextvaluefor.patchDownload
Index: src/backend/catalog/dependency.c
===================================================================
RCS file: /home/rbt/work/postgresql/cvs/pgsql-server/src/backend/catalog/dependency.c,v
retrieving revision 1.23
diff -c -r1.23 dependency.c
*** src/backend/catalog/dependency.c 6 Mar 2003 22:54:49 -0000 1.23
--- src/backend/catalog/dependency.c 27 May 2003 03:20:57 -0000
***************
*** 1004,1009 ****
--- 1004,1018 ----
context->rtables = lnext(context->rtables);
return result;
}
+ if (IsA(node, SequenceOp))
+ {
+ SequenceOp *sop = (SequenceOp *) node;
+
+ add_object_address(OCLASS_CLASS, sop->seqId, 0,
+ &context->addrs);
+
+ return false;
+ }
return expression_tree_walker(node, find_expr_references_walker,
(void *) context);
}
Index: src/backend/commands/sequence.c
===================================================================
RCS file: /home/rbt/work/postgresql/cvs/pgsql-server/src/backend/commands/sequence.c,v
retrieving revision 1.95
diff -c -r1.95 sequence.c
*** src/backend/commands/sequence.c 21 Mar 2003 03:55:21 -0000 1.95
--- src/backend/commands/sequence.c 27 May 2003 03:29:17 -0000
***************
*** 23,28 ****
--- 23,29 ----
#include "miscadmin.h"
#include "utils/acl.h"
#include "utils/builtins.h"
+ #include "utils/lsyscache.h"
/*
* We don't want to log each fetching of a value from a sequence,
***************
*** 67,74 ****
static SeqTable seqtab = NULL; /* Head of list of SeqTable items */
! static void init_sequence(const char *caller, RangeVar *relation,
! SeqTable *p_elm, Relation *p_rel);
static Form_pg_sequence read_info(const char *caller, SeqTable elm,
Relation rel, Buffer *buf);
static void init_params(char *caller, List *options, Form_pg_sequence new);
--- 68,75 ----
static SeqTable seqtab = NULL; /* Head of list of SeqTable items */
! static void init_sequence(const char *caller, Oid relid,
! SeqTable *p_elm, Relation *p_rel);
static Form_pg_sequence read_info(const char *caller, SeqTable elm,
Relation rel, Buffer *buf);
static void init_params(char *caller, List *options, Form_pg_sequence new);
***************
*** 313,319 ****
FormData_pg_sequence new;
/* open and AccessShareLock sequence */
! init_sequence("setval", stmt->sequence, &elm, &seqrel);
/* Allow DROP to sequence owner only*/
if (!pg_class_ownercheck(elm->relid, GetUserId()))
--- 314,321 ----
FormData_pg_sequence new;
/* open and AccessShareLock sequence */
! init_sequence("setval", RangeVarGetRelid(stmt->sequence, false),
! &elm, &seqrel);
/* Allow DROP to sequence owner only*/
if (!pg_class_ownercheck(elm->relid, GetUserId()))
***************
*** 387,392 ****
--- 389,407 ----
{
text *seqin = PG_GETARG_TEXT_P(0);
RangeVar *sequence;
+ int64 result;
+
+ sequence = makeRangeVarFromNameList(textToQualifiedNameList(seqin,
+ "nextval"));
+
+ result = do_nextval(RangeVarGetRelid(sequence, false));
+
+ PG_RETURN_INT64(result);
+ }
+
+ int64
+ do_nextval(Oid seqId)
+ {
SeqTable elm;
Relation seqrel;
Buffer buf;
***************
*** 404,418 ****
rescnt = 0;
bool logit = false;
- sequence = makeRangeVarFromNameList(textToQualifiedNameList(seqin,
- "nextval"));
-
/* open and AccessShareLock sequence */
! init_sequence("nextval", sequence, &elm, &seqrel);
if (pg_class_aclcheck(elm->relid, GetUserId(), ACL_UPDATE) != ACLCHECK_OK)
! elog(ERROR, "%s.nextval: you don't have permissions to set sequence %s",
! sequence->relname, sequence->relname);
if (elm->last != elm->cached) /* some numbers were cached */
{
--- 419,431 ----
rescnt = 0;
bool logit = false;
/* open and AccessShareLock sequence */
! init_sequence("nextval", seqId, &elm, &seqrel);
if (pg_class_aclcheck(elm->relid, GetUserId(), ACL_UPDATE) != ACLCHECK_OK)
! elog(ERROR, "you don't have permissions to set sequence %s.%s",
! get_namespace_name(get_rel_namespace(seqId)),
! get_rel_name(seqId));
if (elm->last != elm->cached) /* some numbers were cached */
{
***************
*** 486,493 ****
char buf[100];
snprintf(buf, sizeof(buf), INT64_FORMAT, maxv);
! elog(ERROR, "%s.nextval: reached MAXVALUE (%s)",
! sequence->relname, buf);
}
next = minv;
}
--- 499,507 ----
char buf[100];
snprintf(buf, sizeof(buf), INT64_FORMAT, maxv);
! elog(ERROR, "sequence %s.%s reached MAXVALUE (%s)",
! get_namespace_name(get_rel_namespace(seqId)),
! get_rel_name(seqId), buf);
}
next = minv;
}
***************
*** 507,514 ****
char buf[100];
snprintf(buf, sizeof(buf), INT64_FORMAT, minv);
! elog(ERROR, "%s.nextval: reached MINVALUE (%s)",
! sequence->relname, buf);
}
next = maxv;
}
--- 521,529 ----
char buf[100];
snprintf(buf, sizeof(buf), INT64_FORMAT, minv);
! elog(ERROR, "sequence %s.%s reached MINVALUE (%s)",
! get_namespace_name(get_rel_namespace(seqId)),
! get_rel_name(seqId), buf);
}
next = maxv;
}
***************
*** 578,584 ****
relation_close(seqrel, NoLock);
! PG_RETURN_INT64(result);
}
Datum
--- 593,599 ----
relation_close(seqrel, NoLock);
! return(result);
}
Datum
***************
*** 586,614 ****
{
text *seqin = PG_GETARG_TEXT_P(0);
RangeVar *sequence;
- SeqTable elm;
- Relation seqrel;
int64 result;
sequence = makeRangeVarFromNameList(textToQualifiedNameList(seqin,
"currval"));
/* open and AccessShareLock sequence */
! init_sequence("currval", sequence, &elm, &seqrel);
if (pg_class_aclcheck(elm->relid, GetUserId(), ACL_SELECT) != ACLCHECK_OK)
! elog(ERROR, "%s.currval: you don't have permissions to read sequence %s",
! sequence->relname, sequence->relname);
if (elm->increment == 0) /* nextval/read_info were not called */
! elog(ERROR, "%s.currval is not yet defined in this session",
! sequence->relname);
result = elm->last;
relation_close(seqrel, NoLock);
! PG_RETURN_INT64(result);
}
/*
--- 601,642 ----
{
text *seqin = PG_GETARG_TEXT_P(0);
RangeVar *sequence;
int64 result;
sequence = makeRangeVarFromNameList(textToQualifiedNameList(seqin,
"currval"));
+ result = do_currval(RangeVarGetRelid(sequence, false));
+
+ PG_RETURN_INT64(result);
+ }
+
+ int64
+ do_currval(Oid seqId)
+ {
+ SeqTable elm;
+ Relation seqrel;
+ int64 result;
+
/* open and AccessShareLock sequence */
! init_sequence("currval", seqId,
! &elm, &seqrel);
if (pg_class_aclcheck(elm->relid, GetUserId(), ACL_SELECT) != ACLCHECK_OK)
! elog(ERROR, "you don't have permissions to read sequence %s.%s",
! get_namespace_name(get_rel_namespace(seqId)),
! get_rel_name(seqId));
if (elm->increment == 0) /* nextval/read_info were not called */
! elog(ERROR, "current value not set on %s.%s for this session",
! get_namespace_name(get_rel_namespace(seqId)),
! get_rel_name(seqId));
result = elm->last;
relation_close(seqrel, NoLock);
! return result;
}
/*
***************
*** 633,639 ****
Form_pg_sequence seq;
/* open and AccessShareLock sequence */
! init_sequence("setval", sequence, &elm, &seqrel);
if (pg_class_aclcheck(elm->relid, GetUserId(), ACL_UPDATE) != ACLCHECK_OK)
elog(ERROR, "%s.setval: you don't have permissions to set sequence %s",
--- 661,668 ----
Form_pg_sequence seq;
/* open and AccessShareLock sequence */
! init_sequence("setval", RangeVarGetRelid(sequence, false),
! &elm, &seqrel);
if (pg_class_aclcheck(elm->relid, GetUserId(), ACL_UPDATE) != ACLCHECK_OK)
elog(ERROR, "%s.setval: you don't have permissions to set sequence %s",
***************
*** 752,761 ****
* output parameters.
*/
static void
! init_sequence(const char *caller, RangeVar *relation,
! SeqTable *p_elm, Relation *p_rel)
{
- Oid relid = RangeVarGetRelid(relation, false);
TransactionId thisxid = GetCurrentTransactionId();
SeqTable elm;
Relation seqrel;
--- 781,788 ----
* output parameters.
*/
static void
! init_sequence(const char *caller, Oid relid, SeqTable *p_elm, Relation *p_rel)
{
TransactionId thisxid = GetCurrentTransactionId();
SeqTable elm;
Relation seqrel;
***************
*** 777,784 ****
seqrel = relation_open(relid, NoLock);
if (seqrel->rd_rel->relkind != RELKIND_SEQUENCE)
! elog(ERROR, "%s.%s: %s is not a sequence",
! relation->relname, caller, relation->relname);
/*
* Allocate new seqtable entry if we didn't find one.
--- 804,812 ----
seqrel = relation_open(relid, NoLock);
if (seqrel->rd_rel->relkind != RELKIND_SEQUENCE)
! elog(ERROR, "%s.%s is not a sequence",
! get_namespace_name(get_rel_namespace(relid)),
! get_rel_name(relid));
/*
* Allocate new seqtable entry if we didn't find one.
Index: src/backend/executor/execQual.c
===================================================================
RCS file: /home/rbt/work/postgresql/cvs/pgsql-server/src/backend/executor/execQual.c,v
retrieving revision 1.129
diff -c -r1.129 execQual.c
*** src/backend/executor/execQual.c 2 May 2003 20:54:33 -0000 1.129
--- src/backend/executor/execQual.c 27 May 2003 03:31:51 -0000
***************
*** 36,41 ****
--- 36,42 ----
#include "access/heapam.h"
#include "catalog/pg_type.h"
+ #include "commands/sequence.h"
#include "commands/typecmds.h"
#include "executor/execdebug.h"
#include "executor/functions.h"
***************
*** 1883,1888 ****
--- 1884,1911 ----
return econtext->domainValue_datum;
}
+ /*
+ * ExecEvalSequenceOp
+ *
+ * Return the next value of the sequence
+ */
+ static Datum
+ ExecEvalSequenceOp(SequenceOp *sop,
+ ExprContext *econtext, bool *isNull)
+ {
+ int64 result;
+ Datum datum;
+
+ if (sop->next)
+ result = do_nextval(sop->seqId);
+ else
+ result = do_currval(sop->seqId);
+
+ datum = Int64GetDatum(result);
+
+ return datum;
+ }
+
/* ----------------------------------------------------------------
* ExecEvalFieldSelect
*
***************
*** 2102,2107 ****
--- 2125,2135 ----
econtext,
isNull);
break;
+ case T_SequenceOp:
+ retDatum = ExecEvalSequenceOp((SequenceOp *) expr,
+ econtext,
+ isNull);
+ break;
default:
elog(ERROR, "ExecEvalExpr: unknown expression type %d",
nodeTag(expression));
***************
*** 2177,2182 ****
--- 2205,2211 ----
case T_Const:
case T_Param:
case T_CoerceToDomainValue:
+ case T_SequenceOp:
/* No special setup needed for these node types */
state = (ExprState *) makeNode(ExprState);
break;
Index: src/backend/nodes/copyfuncs.c
===================================================================
RCS file: /home/rbt/work/postgresql/cvs/pgsql-server/src/backend/nodes/copyfuncs.c,v
retrieving revision 1.250
diff -c -r1.250 copyfuncs.c
*** src/backend/nodes/copyfuncs.c 6 May 2003 00:20:32 -0000 1.250
--- src/backend/nodes/copyfuncs.c 25 May 2003 03:00:44 -0000
***************
*** 2380,2385 ****
--- 2380,2395 ----
return newnode;
}
+ static SequenceOp *
+ _copySequenceOp(SequenceOp *from)
+ {
+ SequenceOp *newnode = makeNode(SequenceOp);
+
+ COPY_SCALAR_FIELD(seqId);
+
+ return newnode;
+ }
+
/* ****************************************************************
* pg_list.h copy functions
***************
*** 2922,2927 ****
--- 2932,2940 ----
break;
case T_InsertDefault:
retval = _copyInsertDefault(from);
+ break;
+ case T_SequenceOp:
+ retval = _copySequenceOp(from);
break;
default:
Index: src/backend/nodes/equalfuncs.c
===================================================================
RCS file: /home/rbt/work/postgresql/cvs/pgsql-server/src/backend/nodes/equalfuncs.c,v
retrieving revision 1.193
diff -c -r1.193 equalfuncs.c
*** src/backend/nodes/equalfuncs.c 6 May 2003 00:20:32 -0000 1.193
--- src/backend/nodes/equalfuncs.c 25 May 2003 03:00:51 -0000
***************
*** 1557,1562 ****
--- 1557,1570 ----
return true;
}
+ static bool
+ _equalSequenceOp(SequenceOp *a, SequenceOp *b)
+ {
+ COMPARE_NODE_FIELD(sequence);
+
+ return true;
+ }
+
/*
* Stuff from pg_list.h
***************
*** 2037,2042 ****
--- 2045,2053 ----
break;
case T_InsertDefault:
retval = _equalInsertDefault(a, b);
+ break;
+ case T_SequenceOp:
+ retval = _equalSequenceOp(a, b);
break;
default:
Index: src/backend/nodes/outfuncs.c
===================================================================
RCS file: /home/rbt/work/postgresql/cvs/pgsql-server/src/backend/nodes/outfuncs.c,v
retrieving revision 1.205
diff -c -r1.205 outfuncs.c
*** src/backend/nodes/outfuncs.c 6 May 2003 00:20:32 -0000 1.205
--- src/backend/nodes/outfuncs.c 25 May 2003 03:29:03 -0000
***************
*** 1479,1484 ****
--- 1479,1493 ----
WRITE_BOOL_FIELD(skip_validation);
}
+ static void
+ _outSequenceOp(StringInfo str, SequenceOp *node)
+ {
+ WRITE_NODE_TYPE("SEQUENCEOP");
+
+ WRITE_BOOL_FIELD(next);
+ WRITE_OID_FIELD(seqId);
+ }
+
/*
* _outNode -
***************
*** 1778,1783 ****
--- 1787,1795 ----
break;
case T_FuncCall:
_outFuncCall(str, obj);
+ break;
+ case T_SequenceOp:
+ _outSequenceOp(str, obj);
break;
default:
Index: src/backend/nodes/readfuncs.c
===================================================================
RCS file: /home/rbt/work/postgresql/cvs/pgsql-server/src/backend/nodes/readfuncs.c,v
retrieving revision 1.153
diff -c -r1.153 readfuncs.c
*** src/backend/nodes/readfuncs.c 6 May 2003 00:20:32 -0000 1.153
--- src/backend/nodes/readfuncs.c 27 May 2003 02:50:46 -0000
***************
*** 900,905 ****
--- 900,916 ----
READ_DONE();
}
+ static SequenceOp *
+ _readSequenceOp(void)
+ {
+ READ_LOCALS(SequenceOp);
+
+ READ_BOOL_FIELD(next);
+ READ_OID_FIELD(seqId);
+
+ READ_DONE();
+ }
+
/*
* parseNodeString
***************
*** 998,1003 ****
--- 1009,1016 ----
return_value = _readNotifyStmt();
else if (MATCH("DECLARECURSOR", 13))
return_value = _readDeclareCursorStmt();
+ else if (MATCH("SEQUENCEOP", 10))
+ return_value = _readSequenceOp();
else
{
elog(ERROR, "badly formatted node string \"%.32s\"...", token);
Index: src/backend/optimizer/util/clauses.c
===================================================================
RCS file: /home/rbt/work/postgresql/cvs/pgsql-server/src/backend/optimizer/util/clauses.c,v
retrieving revision 1.136
diff -c -r1.136 clauses.c
*** src/backend/optimizer/util/clauses.c 29 Apr 2003 22:13:09 -0000 1.136
--- src/backend/optimizer/util/clauses.c 25 May 2003 03:29:33 -0000
***************
*** 2094,2099 ****
--- 2094,2100 ----
case T_Param:
case T_CoerceToDomainValue:
case T_RangeTblRef:
+ case T_SequenceOp:
/* primitive node types with no subnodes */
break;
case T_Aggref:
***************
*** 2726,2731 ****
--- 2727,2740 ----
return (Node *) newnode;
}
break;
+ case T_SequenceOp:
+ {
+ SequenceOp *sop = (SequenceOp *) node;
+ SequenceOp *newnode;
+
+ FLATCOPY(newnode, sop, SequenceOp);
+ return (Node *) newnode;
+ }
default:
elog(ERROR, "expression_tree_mutator: Unexpected node type %d",
nodeTag(node));
Index: src/backend/parser/analyze.c
===================================================================
RCS file: /home/rbt/work/postgresql/cvs/pgsql-server/src/backend/parser/analyze.c,v
retrieving revision 1.271
diff -c -r1.271 analyze.c
*** src/backend/parser/analyze.c 6 May 2003 00:20:32 -0000 1.271
--- src/backend/parser/analyze.c 25 May 2003 03:10:16 -0000
***************
*** 952,960 ****
{
char *sname;
char *snamespace;
! char *qstring;
! A_Const *snamenode;
! FuncCall *funccallnode;
CreateSeqStmt *seqstmt;
/*
--- 952,958 ----
{
char *sname;
char *snamespace;
! SequenceOp *sop;
CreateSeqStmt *seqstmt;
/*
***************
*** 989,1011 ****
* conflicting constraints the user wrote (like a different
* DEFAULT).
*
! * Create an expression tree representing the function call
! * nextval('"sequencename"')
*/
! qstring = quote_qualified_identifier(snamespace, sname);
! snamenode = makeNode(A_Const);
! snamenode->val.type = T_String;
! snamenode->val.val.str = qstring;
! funccallnode = makeNode(FuncCall);
! funccallnode->funcname = SystemFuncName("nextval");
! funccallnode->args = makeList1(snamenode);
! funccallnode->agg_star = false;
! funccallnode->agg_distinct = false;
constraint = makeNode(Constraint);
constraint->contype = CONSTR_DEFAULT;
constraint->name = sname;
! constraint->raw_expr = (Node *) funccallnode;
constraint->cooked_expr = NULL;
constraint->keys = NIL;
column->constraints = lappend(column->constraints, constraint);
--- 987,1002 ----
* conflicting constraints the user wrote (like a different
* DEFAULT).
*
! * Create an expression tree representing NEXT VALUE FOR <sequencename>
*/
! sop = makeNode(SequenceOp);
! sop->sequence = makeRangeVar(snamespace, sname);
! sop->next = true;
constraint = makeNode(Constraint);
constraint->contype = CONSTR_DEFAULT;
constraint->name = sname;
! constraint->raw_expr = (Node *) sop;
constraint->cooked_expr = NULL;
constraint->keys = NIL;
column->constraints = lappend(column->constraints, constraint);
Index: src/backend/parser/gram.y
===================================================================
RCS file: /home/rbt/work/postgresql/cvs/pgsql-server/src/backend/parser/gram.y,v
retrieving revision 2.414
diff -c -r2.414 gram.y
*** src/backend/parser/gram.y 15 May 2003 16:35:28 -0000 2.414
--- src/backend/parser/gram.y 25 May 2003 03:06:41 -0000
***************
*** 333,339 ****
CHARACTER CHARACTERISTICS CHECK CHECKPOINT CLASS CLOSE
CLUSTER COALESCE COLLATE COLUMN COMMENT COMMIT
COMMITTED CONSTRAINT CONSTRAINTS CONVERSION_P CONVERT COPY CREATE CREATEDB
! CREATEUSER CROSS CURRENT_DATE CURRENT_TIME
CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE
DATABASE DAY_P DEALLOCATE DEC DECIMAL_P DECLARE DEFAULT
--- 333,339 ----
CHARACTER CHARACTERISTICS CHECK CHECKPOINT CLASS CLOSE
CLUSTER COALESCE COLLATE COLUMN COMMENT COMMIT
COMMITTED CONSTRAINT CONSTRAINTS CONVERSION_P CONVERT COPY CREATE CREATEDB
! CREATEUSER CROSS CURRENT CURRENT_DATE CURRENT_TIME
CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE
DATABASE DAY_P DEALLOCATE DEC DECIMAL_P DECLARE DEFAULT
***************
*** 6585,6590 ****
--- 6585,6625 ----
}
| ARRAY array_expr
{ $$ = $2; }
+ /*
+ * In order to prevent VALUE from becoming a reserved
+ * keyword, we treat it as an IDENT whos value
+ * must be value.
+ *
+ * This prevents breakages of applications using VALUE as
+ * a column name.
+ *
+ * SQL92 and above state that VALUE is a reserved keyword.
+ */
+ | NEXT IDENT FOR qualified_name
+ {
+ SequenceOp *n = makeNode(SequenceOp);
+
+ if (strcmp($2, "value") != 0)
+ elog(ERROR, "parse error at or near \"%s\"", $2);
+
+ n->sequence = $4;
+ n->next = true;
+
+ $$ = (Node *)n;
+ }
+ | CURRENT IDENT FOR qualified_name
+ {
+ SequenceOp *n = makeNode(SequenceOp);
+
+ if (strcmp($2, "value") != 0)
+ elog(ERROR, "parse error at or near \"%s\"", $2);
+
+ n->sequence = $4;
+ n->next = false;
+
+ $$ = (Node *)n;
+ }
+
;
/*
Index: src/backend/parser/keywords.c
===================================================================
RCS file: /home/rbt/work/postgresql/cvs/pgsql-server/src/backend/parser/keywords.c,v
retrieving revision 1.139
diff -c -r1.139 keywords.c
*** src/backend/parser/keywords.c 15 May 2003 16:35:28 -0000 1.139
--- src/backend/parser/keywords.c 25 May 2003 03:06:23 -0000
***************
*** 89,94 ****
--- 89,95 ----
{"createdb", CREATEDB},
{"createuser", CREATEUSER},
{"cross", CROSS},
+ {"current", CURRENT},
{"current_date", CURRENT_DATE},
{"current_time", CURRENT_TIME},
{"current_timestamp", CURRENT_TIMESTAMP},
Index: src/backend/parser/parse_expr.c
===================================================================
RCS file: /home/rbt/work/postgresql/cvs/pgsql-server/src/backend/parser/parse_expr.c,v
retrieving revision 1.148
diff -c -r1.148 parse_expr.c
*** src/backend/parser/parse_expr.c 29 Apr 2003 22:13:10 -0000 1.148
--- src/backend/parser/parse_expr.c 25 May 2003 03:11:23 -0000
***************
*** 15,20 ****
--- 15,21 ----
#include "postgres.h"
+ #include "catalog/namespace.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_proc.h"
#include "miscadmin.h"
***************
*** 861,866 ****
--- 862,876 ----
result = expr;
break;
}
+ case T_SequenceOp:
+ {
+ SequenceOp *sop = (SequenceOp *) expr;
+
+ sop->seqId = RangeVarGetRelid(sop->sequence, false);
+
+ result = expr;
+ break;
+ }
/*********************************************
* Quietly accept node types that may be presented when we are
***************
*** 1267,1272 ****
--- 1277,1285 ----
elog(ERROR, "Relation reference \"%s\" cannot be used in an expression",
((RangeVar *) expr)->relname);
type = InvalidOid; /* keep compiler quiet */
+ break;
+ case T_SequenceOp:
+ type = INT8OID;
break;
default:
elog(ERROR, "exprType: Do not know how to get type for %d node",
Index: src/backend/utils/adt/ruleutils.c
===================================================================
RCS file: /home/rbt/work/postgresql/cvs/pgsql-server/src/backend/utils/adt/ruleutils.c,v
retrieving revision 1.140
diff -c -r1.140 ruleutils.c
*** src/backend/utils/adt/ruleutils.c 20 May 2003 20:35:10 -0000 1.140
--- src/backend/utils/adt/ruleutils.c 27 May 2003 03:03:41 -0000
***************
*** 2543,2548 ****
--- 2543,2561 ----
appendStringInfo(buf, "VALUE");
break;
+ case T_SequenceOp:
+ {
+ SequenceOp *sop = (SequenceOp *) node;
+
+ appendStringInfo(buf, "%s VALUE FOR",
+ sop->next ? "NEXT" : "CURRENT");
+ appendStringInfo(buf, " %s.%s",
+ quote_identifier(
+ get_namespace_name(
+ get_rel_namespace(sop->seqId))),
+ quote_identifier(get_rel_name(sop->seqId)));
+ break;
+ }
default:
elog(ERROR, "get_rule_expr: unknown node type %d", nodeTag(node));
break;
Index: src/include/commands/sequence.h
===================================================================
RCS file: /home/rbt/work/postgresql/cvs/pgsql-server/src/include/commands/sequence.h,v
retrieving revision 1.23
diff -c -r1.23 sequence.h
*** src/include/commands/sequence.h 20 Mar 2003 07:02:11 -0000 1.23
--- src/include/commands/sequence.h 27 May 2003 02:54:19 -0000
***************
*** 79,85 ****
--- 79,87 ----
} xl_seq_rec;
extern Datum nextval(PG_FUNCTION_ARGS);
+ extern int64 do_nextval(Oid seqId);
extern Datum currval(PG_FUNCTION_ARGS);
+ extern int64 do_currval(Oid seqId);
extern Datum setval(PG_FUNCTION_ARGS);
extern Datum setval_and_iscalled(PG_FUNCTION_ARGS);
Index: src/include/nodes/nodes.h
===================================================================
RCS file: /home/rbt/work/postgresql/cvs/pgsql-server/src/include/nodes/nodes.h,v
retrieving revision 1.140
diff -c -r1.140 nodes.h
*** src/include/nodes/nodes.h 8 Apr 2003 23:20:04 -0000 1.140
--- src/include/nodes/nodes.h 25 May 2003 03:09:07 -0000
***************
*** 119,124 ****
--- 119,125 ----
T_BooleanTest,
T_CoerceToDomain,
T_CoerceToDomainValue,
+ T_SequenceOp,
T_TargetEntry,
T_RangeTblRef,
T_JoinExpr,
Index: src/include/nodes/parsenodes.h
===================================================================
RCS file: /home/rbt/work/postgresql/cvs/pgsql-server/src/include/nodes/parsenodes.h,v
retrieving revision 1.237
diff -c -r1.237 parsenodes.h
*** src/include/nodes/parsenodes.h 2 May 2003 20:54:36 -0000 1.237
--- src/include/nodes/parsenodes.h 25 May 2003 02:59:20 -0000
***************
*** 1701,1704 ****
--- 1701,1705 ----
char *name; /* The name of the plan to remove */
} DeallocateStmt;
+
#endif /* PARSENODES_H */
Index: src/include/nodes/primnodes.h
===================================================================
RCS file: /home/rbt/work/postgresql/cvs/pgsql-server/src/include/nodes/primnodes.h,v
retrieving revision 1.82
diff -c -r1.82 primnodes.h
*** src/include/nodes/primnodes.h 6 May 2003 00:20:33 -0000 1.82
--- src/include/nodes/primnodes.h 25 May 2003 03:08:02 -0000
***************
*** 654,659 ****
--- 654,669 ----
int32 typeMod; /* typemod for substituted value */
} CoerceToDomainValue;
+ /*
+ * Sequence Operation
+ */
+ typedef struct SequenceOp
+ {
+ NodeTag type;
+ bool next; /* CURRENT VALUE if false, NEXT VALUE if true */
+ RangeVar *sequence;
+ Oid seqId;
+ } SequenceOp;
/*
* TargetEntry -
Index: src/test/regress/expected/sequence.out
===================================================================
RCS file: /home/rbt/work/postgresql/cvs/pgsql-server/src/test/regress/expected/sequence.out,v
retrieving revision 1.1
diff -c -r1.1 sequence.out
*** src/test/regress/expected/sequence.out 20 Mar 2003 07:02:11 -0000 1.1
--- src/test/regress/expected/sequence.out 27 May 2003 03:08:54 -0000
***************
*** 59,67 ****
16
(1 row)
! SELECT nextval('sequence_test2');
! nextval
! ---------
20
(1 row)
--- 59,73 ----
16
(1 row)
! SELECT NEXT VALUE FOR sequence_test2;
! ?column?
! ----------
! 20
! (1 row)
!
! SELECT CURRENT VALUE FOR sequence_test2;
! ?column?
! ----------
20
(1 row)
***************
*** 69,73 ****
--- 75,91 ----
nextval
---------
5
+ (1 row)
+
+ SELECT CURRENT VALUE FOR sequence_test2;
+ ?column?
+ ----------
+ 5
+ (1 row)
+
+ SELECT NEXT VALUE FOR sequence_test2;
+ ?column?
+ ----------
+ 9
(1 row)
Index: src/test/regress/sql/sequence.sql
===================================================================
RCS file: /home/rbt/work/postgresql/cvs/pgsql-server/src/test/regress/sql/sequence.sql,v
retrieving revision 1.1
diff -c -r1.1 sequence.sql
*** src/test/regress/sql/sequence.sql 20 Mar 2003 07:02:11 -0000 1.1
--- src/test/regress/sql/sequence.sql 25 May 2003 02:54:48 -0000
***************
*** 34,39 ****
ALTER SEQUENCE sequence_test2 RESTART WITH 16
INCREMENT BY 4 MAXVALUE 22 MINVALUE 5 CYCLE;
SELECT nextval('sequence_test2');
SELECT nextval('sequence_test2');
! SELECT nextval('sequence_test2');
--- 34,42 ----
ALTER SEQUENCE sequence_test2 RESTART WITH 16
INCREMENT BY 4 MAXVALUE 22 MINVALUE 5 CYCLE;
SELECT nextval('sequence_test2');
+ SELECT NEXT VALUE FOR sequence_test2;
+ SELECT CURRENT VALUE FOR sequence_test2;
SELECT nextval('sequence_test2');
! SELECT CURRENT VALUE FOR sequence_test2;
! SELECT NEXT VALUE FOR sequence_test2;
Rod Taylor <rbt@rbt.ca> writes:
I don't see PREVIOUS as a reserved word, but CURRENT
certainly is -- WHERE CURRENT OF for cursors, and several other places.
The attached patch makes CURRENT a reserved word.
I do not think it will be necessary to treat CURRENT as a fully-reserved
word in order to support WHERE CURRENT OF, and accordingly I'm not very
happy with reserving it in order to support this ungainly,
not-yet-and-possibly-never-standard syntax. I still think that Oracle's
syntax is nicer, and by any sane estimate it is more of a real-world
standard than an unapproved 2000-something draft.
regards, tom lane
On Tue, 27 May 2003, Tom Lane wrote:
Rod Taylor <rbt@rbt.ca> writes:
I don't see PREVIOUS as a reserved word, but CURRENT
certainly is -- WHERE CURRENT OF for cursors, and several other places.The attached patch makes CURRENT a reserved word.
I do not think it will be necessary to treat CURRENT as a fully-reserved
word in order to support WHERE CURRENT OF, and accordingly I'm not very
happy with reserving it in order to support this ungainly,
not-yet-and-possibly-never-standard syntax. I still think that Oracle's
syntax is nicer, and by any sane estimate it is more of a real-world
standard than an unapproved 2000-something draft.
I have an in development patch to add where current of. CURRENT needs only
be added to the unreserved_keyword list. gram.y compiles fine and usage of
current doesn't cause parse errors:
template1=# create table abc (current text);
CREATE TABLE
template1=# insert into abc values('that');
INSERT 17079 1
template1=# insert into abc values('this');
INSERT 17080 1
template1=# begin;
BEGIN
template1=# declare blah cursor for select * from abc;
DECLARE CURSOR
template1=# fetch blah;
current
---------
that
(1 row)
template1=# update abc set current='that2' where current of blah;
UPDATE 1
template1=# commit;
Gavin
On Tue, 2003-05-27 at 00:21, Tom Lane wrote:
Rod Taylor <rbt@rbt.ca> writes:
I don't see PREVIOUS as a reserved word, but CURRENT
certainly is -- WHERE CURRENT OF for cursors, and several other places.The attached patch makes CURRENT a reserved word.
I do not think it will be necessary to treat CURRENT as a fully-reserved
word in order to support WHERE CURRENT OF, and accordingly I'm not very
Very well.. I'll hold onto the CURRENT portion until the term current
has been reserved (bound to happen eventually if we implement all of
SQL99).
Are you ok with the DB2 and draft-spec syntax of NEXT VALUE FOR (where
value is not a reserved word)? Or should I hold onto that until the
spec has gone through the final draft / release?
--
Rod Taylor <rbt@rbt.ca>
PGP Key: http://www.rbt.ca/rbtpub.asc
Rod Taylor <rbt@rbt.ca> writes:
Are you ok with the DB2 and draft-spec syntax of NEXT VALUE FOR (where
value is not a reserved word)? Or should I hold onto that until the
spec has gone through the final draft / release?
By that time we'll have done the Oracle-style foo.nextval, and it'll
become kind of a moot point ;-)
regards, tom lane
On Tue, 2003-05-27 at 09:57, Tom Lane wrote:
Rod Taylor <rbt@rbt.ca> writes:
Are you ok with the DB2 and draft-spec syntax of NEXT VALUE FOR (where
value is not a reserved word)? Or should I hold onto that until the
spec has gone through the final draft / release?By that time we'll have done the Oracle-style foo.nextval, and it'll
become kind of a moot point ;-)
Well, not moot for anyone trying to go between PostgreSQL and a
non-Oracle (or SapDB) database, but certainly of less concern.
--
Rod Taylor <rbt@rbt.ca>
PGP Key: http://www.rbt.ca/rbtpub.asc
(Moved to -hackers)
Rod Taylor <rbt@rbt.ca> writes:
Are you ok with the DB2 and draft-spec syntax of NEXT VALUE FOR (where
value is not a reserved word)? Or should I hold onto that until the
spec has gone through the final draft / release?By that time we'll have done the Oracle-style foo.nextval, and it'll
become kind of a moot point ;-)
I actually like the NEXT VALUE FOR a lot more. The reason is that the
Oracle syntax is very much an 'object.property' lookup, which we do nowhere
else in PostgreSQL. In fact, it's actually a bit bizarre when you start
going database.schema.sequence.nextval, etc.
The NEXT VALUE FOR syntax would be more in keeping with our current sytacies
methinks...
Chris
"Christopher Kings-Lynne" <chriskl@familyhealth.com.au> writes:
I actually like the NEXT VALUE FOR a lot more. The reason is that the
Oracle syntax is very much an 'object.property' lookup, which we do nowhere
else in PostgreSQL.
I beg to differ. We have supported table.function since day one ---
it's in the original Berkeley code. For example:
regression=# \d int8_tbl
Table "public.int8_tbl"
Column | Type | Modifiers
--------+--------+-----------
q1 | bigint |
q2 | bigint |
regression=# create function mysum(int8_tbl) returns int8 as '
regression'# select $1.q1 + $1.q2' language sql;
CREATE FUNCTION
regression=# select *, mysum(t1), t1.mysum from int8_tbl t1;
q1 | q2 | mysum | mysum
------------------+-------------------+------------------+------------------
123 | 456 | 579 | 579
123 | 4567890123456789 | 4567890123456912 | 4567890123456912
4567890123456789 | 123 | 4567890123456912 | 4567890123456912
4567890123456789 | 4567890123456789 | 9135780246913578 | 9135780246913578
4567890123456789 | -4567890123456789 | 0 | 0
(5 rows)
So syntactically, the Oracle notation is in our direct line of
inheritance from Berkeley. The only reason we can't quite get
foo.nextval to work today is that the system wants to put foo
into the query's FROM list, which we don't want for a sequence
reference.
regards, tom lane
There was a lot of discussion about this patch, and shorter version
posted with just the CURRENT part. However, I think some felt that this
wasn't a standard yet, and therefore weren't ready to implement this.
Is that correct?
---------------------------------------------------------------------------
Rod Taylor wrote:
-- Start of PGP signed section.
Enables syntax: NEXT VALUE FOR <seqname> and CURRENT VALUE FOR <seqname>
The 200N spec is based on DB2, not MSSQL, so it is very likely NEXT
VALUE FOR will be the official syntax.DB2 uses PREVIOUS VALUE FOR <seqname> as their currval() (nothing in
spec about this). I don't see PREVIOUS as a reserved word, but CURRENT
certainly is -- WHERE CURRENT OF for cursors, and several other places.The attached patch makes CURRENT a reserved word. VALUE is treated as
an IDENT to preserve the ability to use it as a column.SequenceOp is the node (primnode) used in the executor, and required
splitting up nextval / currval into public and internal interfaces. The
internal interface operates on the sequence OID, and the public
interface on the sequence name as usual.Dependencies are recorded for the SequenceOp node so now we cannot drop
a sequence used in a default expression.I've not figured out the best place to record the dependency to prevent
the default expression from being changed for SERIAL columns yet, but
that should be a separate patch. The concept of a serial will need to
be brought in deeper than parser/analyze.c for this to happen.No documentation changes attached. I want to know whether this would be
applied before I make those.Tom,
Should I have created another parser node strictly for the gram.y stuff,
then had it copy the info to the primnode within parse_expr.c? As it
is, SequenceOp is left with a hanging RangeVar that is unused past that
point.
--
Rod Taylor <rbt@rbt.ca>PGP Key: http://www.rbt.ca/rbtpub.asc
[ Attachment, skipping... ]
-- End of PGP section, PGP failed!
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
On Fri, 2003-06-06 at 11:17, Bruce Momjian wrote:
There was a lot of discussion about this patch, and shorter version
posted with just the CURRENT part. However, I think some felt that this
wasn't a standard yet, and therefore weren't ready to implement this.
Is that correct?
Thats about what it boils down to.
People seem to prefer Oracle compatibility over DB2 compatibility, so
I'm going to hold it until the next spec is released.
Rod Taylor wrote:
-- Start of PGP signed section.Enables syntax: NEXT VALUE FOR <seqname> and CURRENT VALUE FOR <seqname>
The 200N spec is based on DB2, not MSSQL, so it is very likely NEXT
VALUE FOR will be the official syntax.DB2 uses PREVIOUS VALUE FOR <seqname> as their currval() (nothing in
spec about this). I don't see PREVIOUS as a reserved word, but CURRENT
certainly is -- WHERE CURRENT OF for cursors, and several other places.The attached patch makes CURRENT a reserved word. VALUE is treated as
an IDENT to preserve the ability to use it as a column.SequenceOp is the node (primnode) used in the executor, and required
splitting up nextval / currval into public and internal interfaces. The
internal interface operates on the sequence OID, and the public
interface on the sequence name as usual.Dependencies are recorded for the SequenceOp node so now we cannot drop
a sequence used in a default expression.I've not figured out the best place to record the dependency to prevent
the default expression from being changed for SERIAL columns yet, but
that should be a separate patch. The concept of a serial will need to
be brought in deeper than parser/analyze.c for this to happen.No documentation changes attached. I want to know whether this would be
applied before I make those.Tom,
Should I have created another parser node strictly for the gram.y stuff,
then had it copy the info to the primnode within parse_expr.c? As it
is, SequenceOp is left with a hanging RangeVar that is unused past that
point.
--
Rod Taylor <rbt@rbt.ca>PGP Key: http://www.rbt.ca/rbtpub.asc
[ Attachment, skipping... ]
-- End of PGP section, PGP failed!
--
Rod Taylor <rbt@rbt.ca>
PGP Key: http://www.rbt.ca/rbtpub.asc