Commit 3477957b authored by Tom Lane's avatar Tom Lane

Update sequence-related functions to new fmgr style. Remove downcasing,

quote-stripping, and acl-checking tasks for these functions from the
parser, and do them at function execution time instead.  This fixes
the failure of pg_dump to produce correct output for nextval(Foo)
used in a rule, and also eliminates the restriction that the argument
of these functions must be a parse-time constant.
parent e9acba1a
#include "executor/spi.h" /* this is what you need to work with SPI */ #include "executor/spi.h" /* this is what you need to work with SPI */
#include "commands/trigger.h" /* -"- and triggers */ #include "commands/trigger.h" /* -"- and triggers */
#include "commands/sequence.h" /* for nextval() */
extern Datum autoinc(PG_FUNCTION_ARGS); extern Datum autoinc(PG_FUNCTION_ARGS);
extern int4 nextval(struct varlena * seqin);
Datum Datum
autoinc(PG_FUNCTION_ARGS) autoinc(PG_FUNCTION_ARGS)
...@@ -53,7 +53,7 @@ autoinc(PG_FUNCTION_ARGS) ...@@ -53,7 +53,7 @@ autoinc(PG_FUNCTION_ARGS)
for (i = 0; i < nargs;) for (i = 0; i < nargs;)
{ {
struct varlena *seqname; text *seqname;
int attnum = SPI_fnumber(tupdesc, args[i]); int attnum = SPI_fnumber(tupdesc, args[i]);
int32 val; int32 val;
...@@ -74,9 +74,11 @@ autoinc(PG_FUNCTION_ARGS) ...@@ -74,9 +74,11 @@ autoinc(PG_FUNCTION_ARGS)
i++; i++;
chattrs[chnattrs] = attnum; chattrs[chnattrs] = attnum;
seqname = textin(args[i]); seqname = textin(args[i]);
newvals[chnattrs] = Int32GetDatum(nextval(seqname)); newvals[chnattrs] = DirectFunctionCall1(nextval,
PointerGetDatum(seqname));
if (DatumGetInt32(newvals[chnattrs]) == 0) if (DatumGetInt32(newvals[chnattrs]) == 0)
newvals[chnattrs] = Int32GetDatum(nextval(seqname)); newvals[chnattrs] = DirectFunctionCall1(nextval,
PointerGetDatum(seqname));
pfree(seqname); pfree(seqname);
chnattrs++; chnattrs++;
i++; i++;
......
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
#include <ctype.h>
#include "postgres.h" #include "postgres.h"
#include "access/heapam.h" #include "access/heapam.h"
...@@ -54,6 +56,7 @@ typedef SeqTableData *SeqTable; ...@@ -54,6 +56,7 @@ typedef SeqTableData *SeqTable;
static SeqTable seqtab = NULL; static SeqTable seqtab = NULL;
static char *get_seq_name(text *seqin);
static SeqTable init_sequence(char *caller, char *name); static SeqTable init_sequence(char *caller, char *name);
static Form_pg_sequence read_info(char *caller, SeqTable elm, Buffer *buf); static Form_pg_sequence read_info(char *caller, SeqTable elm, Buffer *buf);
static void init_params(CreateSeqStmt *seq, Form_pg_sequence new); static void init_params(CreateSeqStmt *seq, Form_pg_sequence new);
...@@ -181,29 +184,37 @@ DefineSequence(CreateSeqStmt *seq) ...@@ -181,29 +184,37 @@ DefineSequence(CreateSeqStmt *seq)
} }
int4 Datum
nextval(struct varlena * seqin) nextval(PG_FUNCTION_ARGS)
{ {
char *seqname = textout(seqin); text *seqin = PG_GETARG_TEXT_P(0);
char *seqname = get_seq_name(seqin);
SeqTable elm; SeqTable elm;
Buffer buf; Buffer buf;
Form_pg_sequence seq; Form_pg_sequence seq;
int4 incby, int32 incby,
maxv, maxv,
minv, minv,
cache; cache;
int4 result, int32 result,
next, next,
rescnt = 0; rescnt = 0;
#ifndef NO_SECURITY
if (pg_aclcheck(seqname, getpgusername(), ACL_WR) != ACLCHECK_OK)
elog(ERROR, "%s.nextval: you don't have permissions to set sequence %s",
seqname, seqname);
#endif
/* open and AccessShareLock sequence */ /* open and AccessShareLock sequence */
elm = init_sequence("nextval", seqname); elm = init_sequence("nextval", seqname);
pfree(seqname); pfree(seqname);
if (elm->last != elm->cached) /* some numbers were cached */ if (elm->last != elm->cached) /* some numbers were cached */
{ {
elm->last += elm->increment; elm->last += elm->increment;
return elm->last; PG_RETURN_INT32(elm->last);
} }
seq = read_info("nextval", elm, &buf); /* lock page' buffer and seq = read_info("nextval", elm, &buf); /* lock page' buffer and
...@@ -225,8 +236,9 @@ nextval(struct varlena * seqin) ...@@ -225,8 +236,9 @@ nextval(struct varlena * seqin)
* Check MAXVALUE for ascending sequences and MINVALUE for * Check MAXVALUE for ascending sequences and MINVALUE for
* descending sequences * descending sequences
*/ */
if (incby > 0) /* ascending sequence */ if (incby > 0)
{ {
/* ascending sequence */
if ((maxv >= 0 && next > maxv - incby) || if ((maxv >= 0 && next > maxv - incby) ||
(maxv < 0 && next + incby > maxv)) (maxv < 0 && next + incby > maxv))
{ {
...@@ -241,8 +253,8 @@ nextval(struct varlena * seqin) ...@@ -241,8 +253,8 @@ nextval(struct varlena * seqin)
next += incby; next += incby;
} }
else else
/* descending sequence */
{ {
/* descending sequence */
if ((minv < 0 && next < minv - incby) || if ((minv < 0 && next < minv - incby) ||
(minv >= 0 && next + incby < minv)) (minv >= 0 && next + incby < minv))
{ {
...@@ -274,35 +286,43 @@ nextval(struct varlena * seqin) ...@@ -274,35 +286,43 @@ nextval(struct varlena * seqin)
if (WriteBuffer(buf) == STATUS_ERROR) if (WriteBuffer(buf) == STATUS_ERROR)
elog(ERROR, "%s.nextval: WriteBuffer failed", elm->name); elog(ERROR, "%s.nextval: WriteBuffer failed", elm->name);
return result; PG_RETURN_INT32(result);
} }
Datum
int4 currval(PG_FUNCTION_ARGS)
currval(struct varlena * seqin)
{ {
char *seqname = textout(seqin); text *seqin = PG_GETARG_TEXT_P(0);
char *seqname = get_seq_name(seqin);
SeqTable elm; SeqTable elm;
int4 result; int32 result;
#ifndef NO_SECURITY
if (pg_aclcheck(seqname, getpgusername(), ACL_RD) != ACLCHECK_OK)
elog(ERROR, "%s.currval: you don't have permissions to read sequence %s",
seqname, seqname);
#endif
/* open and AccessShareLock sequence */ /* open and AccessShareLock sequence */
elm = init_sequence("currval", seqname); elm = init_sequence("currval", seqname);
pfree(seqname);
if (elm->increment == 0) /* nextval/read_info were not called */ if (elm->increment == 0) /* nextval/read_info were not called */
elog(ERROR, "%s.currval is not yet defined in this session", elm->name); elog(ERROR, "%s.currval is not yet defined in this session",
seqname);
result = elm->last; result = elm->last;
return result; pfree(seqname);
PG_RETURN_INT32(result);
} }
int4 Datum
setval(struct varlena * seqin, int4 next) setval(PG_FUNCTION_ARGS)
{ {
char *seqname = textout(seqin); text *seqin = PG_GETARG_TEXT_P(0);
int32 next = PG_GETARG_INT32(1);
char *seqname = get_seq_name(seqin);
SeqTable elm; SeqTable elm;
Buffer buf; Buffer buf;
Form_pg_sequence seq; Form_pg_sequence seq;
...@@ -341,9 +361,49 @@ setval(struct varlena * seqin, int4 next) ...@@ -341,9 +361,49 @@ setval(struct varlena * seqin, int4 next)
LockBuffer(buf, BUFFER_LOCK_UNLOCK); LockBuffer(buf, BUFFER_LOCK_UNLOCK);
if (WriteBuffer(buf) == STATUS_ERROR) if (WriteBuffer(buf) == STATUS_ERROR)
elog(ERROR, "%s.settval: WriteBuffer failed", seqname); elog(ERROR, "%s.setval: WriteBuffer failed", seqname);
pfree(seqname);
return next; PG_RETURN_INT32(next);
}
/*
* Given a 'text' parameter to a sequence function, extract the actual
* sequence name. We downcase the name if it's not double-quoted.
*
* This is a kluge, really --- should be able to write nextval(seqrel).
*/
static char *
get_seq_name(text *seqin)
{
char *rawname = textout(seqin);
int rawlen = strlen(rawname);
char *seqname;
if (rawlen >= 2 &&
rawname[0] == '\"' && rawname[rawlen - 1] == '\"')
{
/* strip off quotes, keep case */
rawname[rawlen - 1] = '\0';
seqname = pstrdup(rawname + 1);
pfree(rawname);
}
else
{
seqname = rawname;
/*
* It's important that this match the identifier downcasing code
* used by backend/parser/scan.l.
*/
for (; *rawname; rawname++)
{
if (isascii((unsigned char) *rawname) &&
isupper(*rawname))
*rawname = tolower(*rawname);
}
}
return seqname;
} }
static Form_pg_sequence static Form_pg_sequence
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.82 2000/06/03 04:41:32 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.83 2000/06/11 20:08:00 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -709,56 +709,14 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs, ...@@ -709,56 +709,14 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
} }
/* /*
* Sequence handling. * Special checks to disallow sequence functions with side-effects
* in WHERE clauses. This is pretty much of a hack; why disallow these
* when we have no way to check for side-effects of user-defined fns?
*/ */
if (funcid == F_NEXTVAL || if (funcid == F_NEXTVAL && pstate->p_in_where_clause)
funcid == F_CURRVAL || elog(ERROR, "Sequence function nextval is not allowed in WHERE clauses");
funcid == F_SETVAL) if (funcid == F_SETVAL && pstate->p_in_where_clause)
{ elog(ERROR, "Sequence function setval is not allowed in WHERE clauses");
Const *seq;
char *seqrel;
text *seqname;
int32 aclcheck_result = -1;
Assert(nargs == ((funcid == F_SETVAL) ? 2 : 1));
seq = (Const *) lfirst(fargs);
if (!IsA((Node *) seq, Const))
elog(ERROR, "Only constant sequence names are acceptable for function '%s'", funcname);
seqrel = textout((text *) DatumGetPointer(seq->constvalue));
/* Do we have nextval('"Aa"')? */
if (strlen(seqrel) >= 2 &&
seqrel[0] == '\"' && seqrel[strlen(seqrel) - 1] == '\"')
{
/* strip off quotes, keep case */
seqrel = pstrdup(seqrel + 1);
seqrel[strlen(seqrel) - 1] = '\0';
pfree(DatumGetPointer(seq->constvalue));
seq->constvalue = (Datum) textin(seqrel);
}
else
{
pfree(seqrel);
seqname = lower((text *) DatumGetPointer(seq->constvalue));
pfree(DatumGetPointer(seq->constvalue));
seq->constvalue = PointerGetDatum(seqname);
seqrel = textout(seqname);
}
if ((aclcheck_result = pg_aclcheck(seqrel, GetPgUserName(),
(((funcid == F_NEXTVAL) || (funcid == F_SETVAL)) ?
ACL_WR : ACL_RD)))
!= ACLCHECK_OK)
elog(ERROR, "%s.%s: %s",
seqrel, funcname, aclcheck_error_strings[aclcheck_result]);
pfree(seqrel);
if (funcid == F_NEXTVAL && pstate->p_in_where_clause)
elog(ERROR, "Sequence function nextval is not allowed in WHERE clauses");
if (funcid == F_SETVAL && pstate->p_in_where_clause)
elog(ERROR, "Sequence function setval is not allowed in WHERE clauses");
}
expr = makeNode(Expr); expr = makeNode(Expr);
expr->typeOid = rettype; expr->typeOid = rettype;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: pg_proc.h,v 1.137 2000/06/09 01:11:10 tgl Exp $ * $Id: pg_proc.h,v 1.138 2000/06/11 20:07:51 tgl Exp $
* *
* NOTES * NOTES
* The script catalog/genbki.sh reads this file and generates .bki * The script catalog/genbki.sh reads this file and generates .bki
...@@ -2003,12 +2003,12 @@ DESCR("convert int8 to int8 (no-op)"); ...@@ -2003,12 +2003,12 @@ DESCR("convert int8 to int8 (no-op)");
/* SEQUENCEs nextval & currval functions */ /* SEQUENCEs nextval & currval functions */
DATA(insert OID = 1574 ( nextval PGUID 11 f t f t 1 f 23 "25" 100 0 0 100 nextval - )); DATA(insert OID = 1574 ( nextval PGUID 12 f t f t 1 f 23 "25" 100 0 0 100 nextval - ));
DESCR("sequence next value"); DESCR("sequence next value");
DATA(insert OID = 1575 ( currval PGUID 11 f t f t 1 f 23 "25" 100 0 0 100 currval - )); DATA(insert OID = 1575 ( currval PGUID 12 f t f t 1 f 23 "25" 100 0 0 100 currval - ));
DESCR("sequence current value"); DESCR("sequence current value");
DATA(insert OID = 1576 ( setval PGUID 11 f t f t 2 f 23 "25 23" 100 0 0 100 setval - )); DATA(insert OID = 1576 ( setval PGUID 12 f t f t 2 f 23 "25 23" 100 0 0 100 setval - ));
DESCR("sequence set value"); DESCR("set sequence value");
DATA(insert OID = 1579 ( varbit_in PGUID 11 f t t t 1 f 1562 "0" 100 0 0 100 varbit_in - )); DATA(insert OID = 1579 ( varbit_in PGUID 11 f t t t 1 f 1562 "0" 100 0 0 100 varbit_in - ));
DESCR("(internal)"); DESCR("(internal)");
......
...@@ -9,10 +9,11 @@ ...@@ -9,10 +9,11 @@
#ifndef SEQUENCE_H #ifndef SEQUENCE_H
#define SEQUENCE_H #define SEQUENCE_H
#include "fmgr.h"
#include "nodes/parsenodes.h" #include "nodes/parsenodes.h"
/* /*
* Columns of a sequnece relation * Columns of a sequence relation
*/ */
#define SEQ_COL_NAME 1 #define SEQ_COL_NAME 1
...@@ -27,10 +28,11 @@ ...@@ -27,10 +28,11 @@
#define SEQ_COL_FIRSTCOL SEQ_COL_NAME #define SEQ_COL_FIRSTCOL SEQ_COL_NAME
#define SEQ_COL_LASTCOL SEQ_COL_CALLED #define SEQ_COL_LASTCOL SEQ_COL_CALLED
extern Datum nextval(PG_FUNCTION_ARGS);
extern Datum currval(PG_FUNCTION_ARGS);
extern Datum setval(PG_FUNCTION_ARGS);
extern void DefineSequence(CreateSeqStmt *stmt); extern void DefineSequence(CreateSeqStmt *stmt);
extern int4 nextval(struct varlena * seqname);
extern int4 currval(struct varlena * seqname);
extern int4 setval(struct varlena * seqname, int4 next);
extern void CloseSequences(void); extern void CloseSequences(void);
#endif /* SEQUENCE_H */ #endif /* SEQUENCE_H */
/* /*
* $Header: /cvsroot/pgsql/src/test/regress/regress.c,v 1.38 2000/06/05 07:29:22 tgl Exp $ * $Header: /cvsroot/pgsql/src/test/regress/regress.c,v 1.39 2000/06/11 20:07:44 tgl Exp $
*/ */
#include <float.h> /* faked on sunos */ #include <float.h> /* faked on sunos */
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "utils/geo_decls.h" /* includes <math.h> */ #include "utils/geo_decls.h" /* includes <math.h> */
#include "executor/executor.h" /* For GetAttributeByName */ #include "executor/executor.h" /* For GetAttributeByName */
#include "commands/sequence.h" /* for nextval() */
#define P_MAXDIG 12 #define P_MAXDIG 12
#define LDELIM '(' #define LDELIM '('
...@@ -420,8 +421,6 @@ funny_dup17(PG_FUNCTION_ARGS) ...@@ -420,8 +421,6 @@ funny_dup17(PG_FUNCTION_ARGS)
extern Datum ttdummy(PG_FUNCTION_ARGS); extern Datum ttdummy(PG_FUNCTION_ARGS);
int32 set_ttdummy(int32 on); int32 set_ttdummy(int32 on);
extern int4 nextval(struct varlena * seqin);
#define TTDUMMY_INFINITY 999999 #define TTDUMMY_INFINITY 999999
static void *splan = NULL; static void *splan = NULL;
...@@ -528,9 +527,10 @@ ttdummy(PG_FUNCTION_ARGS) ...@@ -528,9 +527,10 @@ ttdummy(PG_FUNCTION_ARGS)
} }
{ {
struct varlena *seqname = textin("ttdummy_seq"); text *seqname = textin("ttdummy_seq");
newoff = nextval(seqname); newoff = DirectFunctionCall1(nextval,
PointerGetDatum(seqname));
pfree(seqname); pfree(seqname);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment