It would appear the spec was approved of before we got foo.nextval, so
here it is again.

NEXT VALUE FOR and CURRENT VALUE FOR where CURRENT is an unreserved
keyword and VALUE is not reserved in any way (ident with comparison to
"value").

This allows the default of a table to depend on a sequence, CASCADE drop
of the sequence removes removes references to it.

CURRENT VALUE FOR is an extension of the spec.


This gives us almost everything required for the Sequence feature (T176)
(as per the draft).

We're missing the datatype specification on the sequence.

CREATE SEQUENCE t AS numeric(130);


Rod Taylor <rbt ( at ) rbt ( dot ) 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
Index: src/backend/catalog/dependency.c
===================================================================
RCS file: /home/rbt/work/postgresql/cvs/pgsql-server/src/backend/catalog/dependency.c,v
retrieving revision 1.34
diff -c -r1.34 dependency.c
*** src/backend/catalog/dependency.c	29 Nov 2003 19:51:42 -0000	1.34
--- src/backend/catalog/dependency.c	30 Nov 2003 15:54:36 -0000
***************
*** 1123,1128 ****
--- 1123,1137 ----
  		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.109
diff -c -r1.109 sequence.c
*** src/backend/commands/sequence.c	6 Apr 2004 16:39:30 -0000	1.109
--- src/backend/commands/sequence.c	19 Apr 2004 20:20:33 -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(RangeVar *relation,
! 			  SeqTable *p_elm, Relation *p_rel);
  static Form_pg_sequence read_info(SeqTable elm, Relation rel, Buffer *buf);
  static void init_params(List *options, Form_pg_sequence new, bool isInit);
  static void do_setval(RangeVar *sequence, int64 next, bool iscalled);
--- 68,75 ----
  static SeqTable seqtab = NULL;	/* Head of list of SeqTable items */
  
  
! static void init_sequence(Oid relId,
! 						  SeqTable *p_elm, Relation *p_rel);
  static Form_pg_sequence read_info(SeqTable elm, Relation rel, Buffer *buf);
  static void init_params(List *options, Form_pg_sequence new, bool isInit);
  static void do_setval(RangeVar *sequence, int64 next, bool iscalled);
***************
*** 304,310 ****
  	FormData_pg_sequence new;
  
  	/* open and AccessShareLock sequence */
! 	init_sequence(stmt->sequence, &elm, &seqrel);
  
  	/* allow ALTER to sequence owner only */
  	if (!pg_class_ownercheck(elm->relid, GetUserId()))
--- 305,311 ----
  	FormData_pg_sequence new;
  
  	/* open and AccessShareLock sequence */
! 	init_sequence(RangeVarGetRelid(stmt->sequence, false), &elm, &seqrel);
  
  	/* allow ALTER to sequence owner only */
  	if (!pg_class_ownercheck(elm->relid, GetUserId()))
***************
*** 371,376 ****
--- 372,390 ----
  {
  	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;
***************
*** 388,404 ****
  				rescnt = 0;
  	bool		logit = false;
  
- 	sequence = makeRangeVarFromNameList(textToQualifiedNameList(seqin,
- 															 "nextval"));
- 
  	/* open and AccessShareLock sequence */
! 	init_sequence(sequence, &elm, &seqrel);
  
  	if (pg_class_aclcheck(elm->relid, GetUserId(), ACL_UPDATE) != ACLCHECK_OK)
  		ereport(ERROR,
  				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
  				 errmsg("permission denied for sequence %s",
! 						sequence->relname)));
  
  	if (elm->last != elm->cached)		/* some numbers were cached */
  	{
--- 402,415 ----
  				rescnt = 0;
  	bool		logit = false;
  
  	/* open and AccessShareLock sequence */
! 	init_sequence(seqId, &elm, &seqrel);
  
  	if (pg_class_aclcheck(elm->relid, GetUserId(), ACL_UPDATE) != ACLCHECK_OK)
  		ereport(ERROR,
  				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
  				 errmsg("permission denied for sequence %s",
! 						get_rel_name(seqId))));
  
  	if (elm->last != elm->cached)		/* some numbers were cached */
  	{
***************
*** 475,481 ****
  					ereport(ERROR,
  					  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
  					   errmsg("nextval: reached maximum value of sequence \"%s\" (%s)",
! 							  sequence->relname, buf)));
  				}
  				next = minv;
  			}
--- 486,492 ----
  					ereport(ERROR,
  					  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
  					   errmsg("nextval: reached maximum value of sequence \"%s\" (%s)",
! 							  get_rel_name(seqId), buf)));
  				}
  				next = minv;
  			}
***************
*** 498,504 ****
  					ereport(ERROR,
  					  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
  					   errmsg("nextval: reached minimum value of sequence \"%s\" (%s)",
! 							  sequence->relname, buf)));
  				}
  				next = maxv;
  			}
--- 509,515 ----
  					ereport(ERROR,
  					  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
  					   errmsg("nextval: reached minimum value of sequence \"%s\" (%s)",
! 							  get_rel_name(seqId), buf)));
  				}
  				next = maxv;
  			}
***************
*** 568,608 ****
  
  	relation_close(seqrel, NoLock);
  
! 	PG_RETURN_INT64(result);
  }
  
  Datum
  currval(PG_FUNCTION_ARGS)
  {
  	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(sequence, &elm, &seqrel);
  
  	if (pg_class_aclcheck(elm->relid, GetUserId(), ACL_SELECT) != ACLCHECK_OK)
  		ereport(ERROR,
  				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
  				 errmsg("permission denied for sequence %s",
! 						sequence->relname)));
  
  	if (elm->increment == 0)	/* nextval/read_info were not called */
  		ereport(ERROR,
  				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
  				 errmsg("currval of sequence \"%s\" is not yet defined in this session",
! 						sequence->relname)));
  
  	result = elm->last;
  
  	relation_close(seqrel, NoLock);
  
! 	PG_RETURN_INT64(result);
  }
  
  /*
--- 579,630 ----
  
  	relation_close(seqrel, NoLock);
  
! 	return(result);
  }
  
+ 
  Datum
  currval(PG_FUNCTION_ARGS)
  {
  	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(seqId, &elm, &seqrel);
  
  	if (pg_class_aclcheck(elm->relid, GetUserId(), ACL_SELECT) != ACLCHECK_OK)
  		ereport(ERROR,
  				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
  				 errmsg("permission denied for sequence %s",
! 						get_rel_name(seqId))));
  
  	if (elm->increment == 0)	/* nextval/read_info were not called */
  		ereport(ERROR,
  				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
  				 errmsg("currval of sequence \"%s\" is not yet defined in this session",
! 						get_rel_name(seqId))));
  
  	result = elm->last;
  
  	relation_close(seqrel, NoLock);
  
! 	return result;
  }
  
  /*
***************
*** 627,633 ****
  	Form_pg_sequence seq;
  
  	/* open and AccessShareLock sequence */
! 	init_sequence(sequence, &elm, &seqrel);
  
  	if (pg_class_aclcheck(elm->relid, GetUserId(), ACL_UPDATE) != ACLCHECK_OK)
  		ereport(ERROR,
--- 649,655 ----
  	Form_pg_sequence seq;
  
  	/* open and AccessShareLock sequence */
! 	init_sequence(RangeVarGetRelid(sequence, false), &elm, &seqrel);
  
  	if (pg_class_aclcheck(elm->relid, GetUserId(), ACL_UPDATE) != ACLCHECK_OK)
  		ereport(ERROR,
***************
*** 750,758 ****
   * output parameters.
   */
  static void
! init_sequence(RangeVar *relation, SeqTable *p_elm, Relation *p_rel)
  {
- 	Oid			relid = RangeVarGetRelid(relation, false);
  	TransactionId thisxid = GetCurrentTransactionId();
  	SeqTable	elm;
  	Relation	seqrel;
--- 772,779 ----
   * output parameters.
   */
  static void
! init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel)
  {
  	TransactionId thisxid = GetCurrentTransactionId();
  	SeqTable	elm;
  	Relation	seqrel;
***************
*** 777,783 ****
  		ereport(ERROR,
  				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
  				 errmsg("\"%s\" is not a sequence",
! 						relation->relname)));
  
  	/*
  	 * Allocate new seqtable entry if we didn't find one.
--- 798,804 ----
  		ereport(ERROR,
  				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
  				 errmsg("\"%s\" is not a sequence",
! 						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.158
diff -c -r1.158 execQual.c
*** src/backend/executor/execQual.c	1 Apr 2004 21:28:44 -0000	1.158
--- src/backend/executor/execQual.c	20 Apr 2004 13:13:57 -0000
***************
*** 38,43 ****
--- 38,44 ----
  
  #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"
***************
*** 2420,2425 ****
--- 2421,2453 ----
  	return econtext->domainValue_datum;
  }
  
+ /*
+  * ExecEvalSequenceOp
+  *
+  * Return the next value of the sequence
+  */
+ static Datum
+ ExecEvalSequenceOp(ExprState *exprstate,
+ 				   ExprContext *econtext,
+ 				   bool *isNull, ExprDoneCond *isDone)
+ {
+ 	SequenceOp *sop = (SequenceOp *) exprstate->expr;
+ 	int64	result;
+ 
+ 	/* There is always a value or an error */
+ 	*isNull = false;
+ 	if (isDone)
+ 		*isDone = ExprSingleResult;
+ 
+ 	/* Call out for the work */
+ 	if (sop->next)
+ 		result = do_nextval(sop->seqId);
+ 	else
+ 		result = do_currval(sop->seqId);
+ 
+ 	return Int64GetDatum(result);
+ }
+ 
  /* ----------------------------------------------------------------
   *		ExecEvalFieldSelect
   *
***************
*** 2501,2507 ****
  	return ExecEvalExpr(exprstate->arg, econtext, isNull, isDone);
  }
  
- 
  /*
   * ExecEvalExprSwitchContext
   *
--- 2529,2534 ----
***************
*** 2587,2592 ****
--- 2614,2623 ----
  		case T_CaseTestExpr:
  			state = (ExprState *) makeNode(ExprState);
  			state->evalfunc = ExecEvalCaseTestExpr;
+ 			break;
+ 		case T_SequenceOp:
+ 			state = (ExprState *) makeNode(ExprState);
+ 			state->evalfunc = ExecEvalSequenceOp;
  			break;
  		case T_Aggref:
  			{
Index: src/backend/nodes/copyfuncs.c
===================================================================
RCS file: /home/rbt/work/postgresql/cvs/pgsql-server/src/backend/nodes/copyfuncs.c,v
retrieving revision 1.279
diff -c -r1.279 copyfuncs.c
*** src/backend/nodes/copyfuncs.c	17 Mar 2004 20:48:42 -0000	1.279
--- src/backend/nodes/copyfuncs.c	20 Apr 2004 22:51:34 -0000
***************
*** 2479,2484 ****
--- 2479,2495 ----
  	return newnode;
  }
  
+ static SequenceOp *
+ _copySequenceOp(SequenceOp *from)
+ {
+ 	SequenceOp *newnode = makeNode(SequenceOp);
+ 
+ 	COPY_SCALAR_FIELD(seqId);
+ 	COPY_SCALAR_FIELD(next);
+ 	COPY_NODE_FIELD(sequence);
+ 
+ 	return newnode;
+ }
  
  /* ****************************************************************
   *					pg_list.h copy functions
***************
*** 3034,3039 ****
--- 3045,3053 ----
  			break;
  		case T_FuncWithArgs:
  			retval = _copyFuncWithArgs(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.218
diff -c -r1.218 equalfuncs.c
*** src/backend/nodes/equalfuncs.c	17 Mar 2004 20:48:42 -0000	1.218
--- src/backend/nodes/equalfuncs.c	19 Apr 2004 20:20:43 -0000
***************
*** 1616,1621 ****
--- 1616,1629 ----
  	return true;
  }
  
+ static bool
+ _equalSequenceOp(SequenceOp *a, SequenceOp *b)
+ {
+ 	COMPARE_NODE_FIELD(sequence);
+ 
+ 	return true;
+ }
+ 
  
  /*
   * Stuff from pg_list.h
***************
*** 2108,2113 ****
--- 2116,2124 ----
  			break;
  		case T_FuncWithArgs:
  			retval = _equalFuncWithArgs(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.233
diff -c -r1.233 outfuncs.c
*** src/backend/nodes/outfuncs.c	17 Mar 2004 20:48:42 -0000	1.233
--- src/backend/nodes/outfuncs.c	20 Apr 2004 12:29:43 -0000
***************
*** 1550,1555 ****
--- 1550,1563 ----
  	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 -
***************
*** 1858,1863 ****
--- 1866,1874 ----
  				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.166
diff -c -r1.166 readfuncs.c
*** src/backend/nodes/readfuncs.c	17 Mar 2004 20:48:42 -0000	1.166
--- src/backend/nodes/readfuncs.c	20 Apr 2004 12:30:08 -0000
***************
*** 959,964 ****
--- 959,974 ----
  	READ_DONE();
  }
  
+ static SequenceOp *
+ _readSequenceOp(void)
+ {
+ 	READ_LOCALS(SequenceOp);
+ 
+ 	READ_BOOL_FIELD(next);
+ 	READ_OID_FIELD(seqId);
+ 
+ 	READ_DONE();
+ }
  
  /*
   * parseNodeString
***************
*** 1064,1069 ****
--- 1074,1081 ----
  		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.169
diff -c -r1.169 clauses.c
*** src/backend/optimizer/util/clauses.c	2 Apr 2004 23:14:08 -0000	1.169
--- src/backend/optimizer/util/clauses.c	19 Apr 2004 20:26:28 -0000
***************
*** 2360,2365 ****
--- 2360,2366 ----
  		case T_CaseTestExpr:
  		case T_SetToDefault:
  		case T_RangeTblRef:
+ 		case T_SequenceOp:
  			/* primitive node types with no subnodes */
  			break;
  		case T_Aggref:
***************
*** 3021,3026 ****
--- 3022,3035 ----
  				return (Node *) newnode;
  			}
  			break;
+ 		case T_SequenceOp:
+ 			{
+ 				SequenceOp *sop = (SequenceOp *) node;
+ 				SequenceOp *newnode;
+ 
+ 				FLATCOPY(newnode, sop, SequenceOp);
+ 				return (Node *) newnode;
+ 			}
  		default:
  			elog(ERROR, "unrecognized node type: %d",
  				 (int) 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.298
diff -c -r1.298 analyze.c
*** src/backend/parser/analyze.c	2 Apr 2004 21:05:32 -0000	1.298
--- src/backend/parser/analyze.c	19 Apr 2004 20:20:49 -0000
***************
*** 971,979 ****
  	{
  		char	   *sname;
  		char	   *snamespace;
! 		char	   *qstring;
! 		A_Const    *snamenode;
! 		FuncCall   *funccallnode;
  		CreateSeqStmt *seqstmt;
  
  		/*
--- 971,977 ----
  	{
  		char	   *sname;
  		char	   *snamespace;
! 		SequenceOp  *sop;
  		CreateSeqStmt *seqstmt;
  
  		/*
***************
*** 1010,1032 ****
  		 * 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);
--- 1008,1023 ----
  		 * 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.451
diff -c -r2.451 gram.y
*** src/backend/parser/gram.y	19 Apr 2004 17:22:30 -0000	2.451
--- src/backend/parser/gram.y	20 Apr 2004 14:46:22 -0000
***************
*** 343,349 ****
  	CHARACTER CHARACTERISTICS CHECK CHECKPOINT CLASS CLOSE
  	CLUSTER COALESCE COLLATE COLUMN COMMENT COMMIT
  	COMMITTED CONSTRAINT CONSTRAINTS CONVERSION_P CONVERT COPY CREATE CREATEDB
! 	CREATEUSER CROSS CSV CURRENT_DATE CURRENT_TIME
  	CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE
  
  	DATABASE DAY_P DEALLOCATE DEC DECIMAL_P DECLARE DEFAULT DEFAULTS
--- 343,349 ----
  	CHARACTER CHARACTERISTICS CHECK CHECKPOINT CLASS CLOSE
  	CLUSTER COALESCE COLLATE COLUMN COMMENT COMMIT
  	COMMITTED CONSTRAINT CONSTRAINTS CONVERSION_P CONVERT COPY CREATE CREATEDB
! 	CREATEUSER CROSS CSV CURRENT CURRENT_DATE CURRENT_TIME
  	CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE
  
  	DATABASE DAY_P DEALLOCATE DEC DECIMAL_P DECLARE DEFAULT DEFAULTS
***************
*** 6798,6803 ****
--- 6798,6838 ----
  				}
  			| 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;
+ 				}
+ 
  		;
  
  /*
***************
*** 7443,7448 ****
--- 7478,7484 ----
  			| CREATEDB
  			| CREATEUSER
  			| CSV
+ 			| CURRENT
  			| CURSOR
  			| CYCLE
  			| DATABASE
Index: src/backend/parser/keywords.c
===================================================================
RCS file: /home/rbt/work/postgresql/cvs/pgsql-server/src/backend/parser/keywords.c,v
retrieving revision 1.148
diff -c -r1.148 keywords.c
*** src/backend/parser/keywords.c	19 Apr 2004 17:22:31 -0000	1.148
--- src/backend/parser/keywords.c	19 Apr 2004 20:38:39 -0000
***************
*** 91,96 ****
--- 91,97 ----
  	{"createuser", CREATEUSER},
  	{"cross", CROSS},
  	{"csv", CSV},
+ 	{"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.169
diff -c -r1.169 parse_expr.c
*** src/backend/parser/parse_expr.c	18 Apr 2004 18:12:58 -0000	1.169
--- src/backend/parser/parse_expr.c	19 Apr 2004 20:43:27 -0000
***************
*** 15,20 ****
--- 15,21 ----
  
  #include "postgres.h"
  
+ #include "catalog/namespace.h"
  #include "catalog/pg_operator.h"
  #include "catalog/pg_proc.h"
  #include "commands/dbcommands.h"
***************
*** 875,880 ****
--- 876,890 ----
  				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
***************
*** 1360,1365 ****
--- 1370,1378 ----
  			break;
  		case T_SetToDefault:
  			type = ((SetToDefault *) expr)->typeId;
+ 			break;
+ 		case T_SequenceOp:
+ 			type = INT8OID;
  			break;
  		default:
  			elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr));
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.163
diff -c -r1.163 ruleutils.c
*** src/backend/utils/adt/ruleutils.c	17 Mar 2004 20:48:42 -0000	1.163
--- src/backend/utils/adt/ruleutils.c	19 Apr 2004 20:21:21 -0000
***************
*** 2616,2622 ****
  				default:
  					return false;
  			}
- 
  		default:
  			break;
  	}
--- 2616,2621 ----
***************
*** 3222,3227 ****
--- 3221,3240 ----
  		case T_SetToDefault:
  			appendStringInfo(buf, "DEFAULT");
  			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, "unrecognized node type: %d", (int) nodeTag(node));
Index: src/include/commands/sequence.h
===================================================================
RCS file: /home/rbt/work/postgresql/cvs/pgsql-server/src/include/commands/sequence.h,v
retrieving revision 1.28
diff -c -r1.28 sequence.h
*** src/include/commands/sequence.h	29 Nov 2003 22:40:59 -0000	1.28
--- src/include/commands/sequence.h	1 Dec 2003 01:59:01 -0000
***************
*** 81,87 ****
--- 81,89 ----
  } 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/execnodes.h
===================================================================
RCS file: /home/rbt/work/postgresql/cvs/pgsql-server/src/include/nodes/execnodes.h,v
retrieving revision 1.115
diff -c -r1.115 execnodes.h
*** src/include/nodes/execnodes.h	1 Apr 2004 21:28:46 -0000	1.115
--- src/include/nodes/execnodes.h	20 Apr 2004 12:24:59 -0000
***************
*** 632,638 ****
  	ExprState	xprstate;
  	ExprState  *arg;			/* input expression */
  	/* Cached list of constraints that need to be checked */
! 	List	   *constraints;	/* list of DomainConstraintState nodes */
  } CoerceToDomainState;
  
  /*
--- 632,638 ----
  	ExprState	xprstate;
  	ExprState  *arg;			/* input expression */
  	/* Cached list of constraints that need to be checked */
!  	List	   *constraints;	/* list of DomainConstraintState nodes */
  } CoerceToDomainState;
  
  /*
Index: src/include/nodes/nodes.h
===================================================================
RCS file: /home/rbt/work/postgresql/cvs/pgsql-server/src/include/nodes/nodes.h,v
retrieving revision 1.152
diff -c -r1.152 nodes.h
*** src/include/nodes/nodes.h	1 Apr 2004 21:28:46 -0000	1.152
--- src/include/nodes/nodes.h	19 Apr 2004 20:22:03 -0000
***************
*** 121,126 ****
--- 121,127 ----
  	T_BooleanTest,
  	T_CoerceToDomain,
  	T_CoerceToDomainValue,
+ 	T_SequenceOp,
  	T_SetToDefault,
  	T_TargetEntry,
  	T_RangeTblRef,
Index: src/include/nodes/primnodes.h
===================================================================
RCS file: /home/rbt/work/postgresql/cvs/pgsql-server/src/include/nodes/primnodes.h,v
retrieving revision 1.97
diff -c -r1.97 primnodes.h
*** src/include/nodes/primnodes.h	1 Apr 2004 21:28:46 -0000	1.97
--- src/include/nodes/primnodes.h	19 Apr 2004 20:22:04 -0000
***************
*** 760,765 ****
--- 760,775 ----
  	Expr	   *expr;			/* expression to evaluate */
  } TargetEntry;
  
+ /*
+  * Sequence Operation
+  */
+ typedef struct SequenceOp
+ {
+ 	NodeTag		type;
+ 	bool		next;		/* CURRENT VALUE if false, NEXT VALUE if true */
+ 	RangeVar   *sequence;
+ 	Oid			seqId;
+ } SequenceOp;
  
  /* ----------------------------------------------------------------
   *					node types for join trees
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.5
diff -c -r1.5 sequence.out
*** src/test/regress/expected/sequence.out	21 Nov 2003 22:32:49 -0000	1.5
--- src/test/regress/expected/sequence.out	1 Dec 2003 18:51:47 -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,74 ****
--- 75,92 ----
   nextval 
  ---------
         5
+ (1 row)
+ 
+ SELECT CURRENT VALUE FOR sequence_test2;
+  ?column? 
+ ----------
+         5
+ (1 row)
+ 
+ SELECT NEXT VALUE FOR sequence_test2;
+  ?column? 
+ ----------
+         9
  (1 row)
  
  -- Test comments
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.2
diff -c -r1.2 sequence.sql
*** src/test/regress/sql/sequence.sql	21 Nov 2003 22:32:49 -0000	1.2
--- src/test/regress/sql/sequence.sql	23 Nov 2003 17:29:02 -0000
***************
*** 34,41 ****
  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');
  
  -- Test comments
  COMMENT ON SEQUENCE asdf IS 'won''t work';
--- 34,44 ----
  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;
  
  -- Test comments
  COMMENT ON SEQUENCE asdf IS 'won''t work';
---------------------------(end of broadcast)---------------------------
TIP 9: the planner will ignore your desire to choose an index scan if your
      joining column's datatypes do not match

Reply via email to