Skip to content

Commit 3477957

Browse files
committed
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.
1 parent e9acba1 commit 3477957

File tree

6 files changed

+113
-91
lines changed

6 files changed

+113
-91
lines changed

contrib/spi/autoinc.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11

22
#include "executor/spi.h" /* this is what you need to work with SPI */
33
#include "commands/trigger.h" /* -"- and triggers */
4+
#include "commands/sequence.h" /* for nextval() */
45

56
extern Datum autoinc(PG_FUNCTION_ARGS);
6-
extern int4 nextval(struct varlena * seqin);
77

88
Datum
99
autoinc(PG_FUNCTION_ARGS)
@@ -53,7 +53,7 @@ autoinc(PG_FUNCTION_ARGS)
5353

5454
for (i = 0; i < nargs;)
5555
{
56-
struct varlena *seqname;
56+
text *seqname;
5757
int attnum = SPI_fnumber(tupdesc, args[i]);
5858
int32 val;
5959

@@ -74,9 +74,11 @@ autoinc(PG_FUNCTION_ARGS)
7474
i++;
7575
chattrs[chnattrs] = attnum;
7676
seqname = textin(args[i]);
77-
newvals[chnattrs] = Int32GetDatum(nextval(seqname));
77+
newvals[chnattrs] = DirectFunctionCall1(nextval,
78+
PointerGetDatum(seqname));
7879
if (DatumGetInt32(newvals[chnattrs]) == 0)
79-
newvals[chnattrs] = Int32GetDatum(nextval(seqname));
80+
newvals[chnattrs] = DirectFunctionCall1(nextval,
81+
PointerGetDatum(seqname));
8082
pfree(seqname);
8183
chnattrs++;
8284
i++;

src/backend/commands/sequence.c

Lines changed: 83 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
*-------------------------------------------------------------------------
77
*/
88

9+
#include <ctype.h>
10+
911
#include "postgres.h"
1012

1113
#include "access/heapam.h"
@@ -54,6 +56,7 @@ typedef SeqTableData *SeqTable;
5456

5557
static SeqTable seqtab = NULL;
5658

59+
static char *get_seq_name(text *seqin);
5760
static SeqTable init_sequence(char *caller, char *name);
5861
static Form_pg_sequence read_info(char *caller, SeqTable elm, Buffer *buf);
5962
static void init_params(CreateSeqStmt *seq, Form_pg_sequence new);
@@ -181,29 +184,37 @@ DefineSequence(CreateSeqStmt *seq)
181184
}
182185

183186

184-
int4
185-
nextval(struct varlena * seqin)
187+
Datum
188+
nextval(PG_FUNCTION_ARGS)
186189
{
187-
char *seqname = textout(seqin);
190+
text *seqin = PG_GETARG_TEXT_P(0);
191+
char *seqname = get_seq_name(seqin);
188192
SeqTable elm;
189193
Buffer buf;
190194
Form_pg_sequence seq;
191-
int4 incby,
195+
int32 incby,
192196
maxv,
193197
minv,
194198
cache;
195-
int4 result,
199+
int32 result,
196200
next,
197201
rescnt = 0;
198202

203+
#ifndef NO_SECURITY
204+
if (pg_aclcheck(seqname, getpgusername(), ACL_WR) != ACLCHECK_OK)
205+
elog(ERROR, "%s.nextval: you don't have permissions to set sequence %s",
206+
seqname, seqname);
207+
#endif
208+
199209
/* open and AccessShareLock sequence */
200210
elm = init_sequence("nextval", seqname);
211+
201212
pfree(seqname);
202213

203214
if (elm->last != elm->cached) /* some numbers were cached */
204215
{
205216
elm->last += elm->increment;
206-
return elm->last;
217+
PG_RETURN_INT32(elm->last);
207218
}
208219

209220
seq = read_info("nextval", elm, &buf); /* lock page' buffer and
@@ -225,8 +236,9 @@ nextval(struct varlena * seqin)
225236
* Check MAXVALUE for ascending sequences and MINVALUE for
226237
* descending sequences
227238
*/
228-
if (incby > 0) /* ascending sequence */
239+
if (incby > 0)
229240
{
241+
/* ascending sequence */
230242
if ((maxv >= 0 && next > maxv - incby) ||
231243
(maxv < 0 && next + incby > maxv))
232244
{
@@ -241,8 +253,8 @@ nextval(struct varlena * seqin)
241253
next += incby;
242254
}
243255
else
244-
/* descending sequence */
245256
{
257+
/* descending sequence */
246258
if ((minv < 0 && next < minv - incby) ||
247259
(minv >= 0 && next + incby < minv))
248260
{
@@ -274,35 +286,43 @@ nextval(struct varlena * seqin)
274286
if (WriteBuffer(buf) == STATUS_ERROR)
275287
elog(ERROR, "%s.nextval: WriteBuffer failed", elm->name);
276288

277-
return result;
278-
289+
PG_RETURN_INT32(result);
279290
}
280291

281-
282-
int4
283-
currval(struct varlena * seqin)
292+
Datum
293+
currval(PG_FUNCTION_ARGS)
284294
{
285-
char *seqname = textout(seqin);
295+
text *seqin = PG_GETARG_TEXT_P(0);
296+
char *seqname = get_seq_name(seqin);
286297
SeqTable elm;
287-
int4 result;
298+
int32 result;
299+
300+
#ifndef NO_SECURITY
301+
if (pg_aclcheck(seqname, getpgusername(), ACL_RD) != ACLCHECK_OK)
302+
elog(ERROR, "%s.currval: you don't have permissions to read sequence %s",
303+
seqname, seqname);
304+
#endif
288305

289306
/* open and AccessShareLock sequence */
290307
elm = init_sequence("currval", seqname);
291-
pfree(seqname);
292308

293309
if (elm->increment == 0) /* nextval/read_info were not called */
294-
elog(ERROR, "%s.currval is not yet defined in this session", elm->name);
310+
elog(ERROR, "%s.currval is not yet defined in this session",
311+
seqname);
295312

296313
result = elm->last;
297314

298-
return result;
315+
pfree(seqname);
299316

317+
PG_RETURN_INT32(result);
300318
}
301319

302-
int4
303-
setval(struct varlena * seqin, int4 next)
320+
Datum
321+
setval(PG_FUNCTION_ARGS)
304322
{
305-
char *seqname = textout(seqin);
323+
text *seqin = PG_GETARG_TEXT_P(0);
324+
int32 next = PG_GETARG_INT32(1);
325+
char *seqname = get_seq_name(seqin);
306326
SeqTable elm;
307327
Buffer buf;
308328
Form_pg_sequence seq;
@@ -341,9 +361,49 @@ setval(struct varlena * seqin, int4 next)
341361
LockBuffer(buf, BUFFER_LOCK_UNLOCK);
342362

343363
if (WriteBuffer(buf) == STATUS_ERROR)
344-
elog(ERROR, "%s.settval: WriteBuffer failed", seqname);
364+
elog(ERROR, "%s.setval: WriteBuffer failed", seqname);
365+
366+
pfree(seqname);
345367

346-
return next;
368+
PG_RETURN_INT32(next);
369+
}
370+
371+
/*
372+
* Given a 'text' parameter to a sequence function, extract the actual
373+
* sequence name. We downcase the name if it's not double-quoted.
374+
*
375+
* This is a kluge, really --- should be able to write nextval(seqrel).
376+
*/
377+
static char *
378+
get_seq_name(text *seqin)
379+
{
380+
char *rawname = textout(seqin);
381+
int rawlen = strlen(rawname);
382+
char *seqname;
383+
384+
if (rawlen >= 2 &&
385+
rawname[0] == '\"' && rawname[rawlen - 1] == '\"')
386+
{
387+
/* strip off quotes, keep case */
388+
rawname[rawlen - 1] = '\0';
389+
seqname = pstrdup(rawname + 1);
390+
pfree(rawname);
391+
}
392+
else
393+
{
394+
seqname = rawname;
395+
/*
396+
* It's important that this match the identifier downcasing code
397+
* used by backend/parser/scan.l.
398+
*/
399+
for (; *rawname; rawname++)
400+
{
401+
if (isascii((unsigned char) *rawname) &&
402+
isupper(*rawname))
403+
*rawname = tolower(*rawname);
404+
}
405+
}
406+
return seqname;
347407
}
348408

349409
static Form_pg_sequence

src/backend/parser/parse_func.c

Lines changed: 8 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.82 2000/06/03 04:41:32 momjian Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.83 2000/06/11 20:08:00 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -709,56 +709,14 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
709709
}
710710

711711
/*
712-
* Sequence handling.
712+
* Special checks to disallow sequence functions with side-effects
713+
* in WHERE clauses. This is pretty much of a hack; why disallow these
714+
* when we have no way to check for side-effects of user-defined fns?
713715
*/
714-
if (funcid == F_NEXTVAL ||
715-
funcid == F_CURRVAL ||
716-
funcid == F_SETVAL)
717-
{
718-
Const *seq;
719-
char *seqrel;
720-
text *seqname;
721-
int32 aclcheck_result = -1;
722-
723-
Assert(nargs == ((funcid == F_SETVAL) ? 2 : 1));
724-
seq = (Const *) lfirst(fargs);
725-
if (!IsA((Node *) seq, Const))
726-
elog(ERROR, "Only constant sequence names are acceptable for function '%s'", funcname);
727-
728-
seqrel = textout((text *) DatumGetPointer(seq->constvalue));
729-
/* Do we have nextval('"Aa"')? */
730-
if (strlen(seqrel) >= 2 &&
731-
seqrel[0] == '\"' && seqrel[strlen(seqrel) - 1] == '\"')
732-
{
733-
/* strip off quotes, keep case */
734-
seqrel = pstrdup(seqrel + 1);
735-
seqrel[strlen(seqrel) - 1] = '\0';
736-
pfree(DatumGetPointer(seq->constvalue));
737-
seq->constvalue = (Datum) textin(seqrel);
738-
}
739-
else
740-
{
741-
pfree(seqrel);
742-
seqname = lower((text *) DatumGetPointer(seq->constvalue));
743-
pfree(DatumGetPointer(seq->constvalue));
744-
seq->constvalue = PointerGetDatum(seqname);
745-
seqrel = textout(seqname);
746-
}
747-
748-
if ((aclcheck_result = pg_aclcheck(seqrel, GetPgUserName(),
749-
(((funcid == F_NEXTVAL) || (funcid == F_SETVAL)) ?
750-
ACL_WR : ACL_RD)))
751-
!= ACLCHECK_OK)
752-
elog(ERROR, "%s.%s: %s",
753-
seqrel, funcname, aclcheck_error_strings[aclcheck_result]);
754-
755-
pfree(seqrel);
756-
757-
if (funcid == F_NEXTVAL && pstate->p_in_where_clause)
758-
elog(ERROR, "Sequence function nextval is not allowed in WHERE clauses");
759-
if (funcid == F_SETVAL && pstate->p_in_where_clause)
760-
elog(ERROR, "Sequence function setval is not allowed in WHERE clauses");
761-
}
716+
if (funcid == F_NEXTVAL && pstate->p_in_where_clause)
717+
elog(ERROR, "Sequence function nextval is not allowed in WHERE clauses");
718+
if (funcid == F_SETVAL && pstate->p_in_where_clause)
719+
elog(ERROR, "Sequence function setval is not allowed in WHERE clauses");
762720

763721
expr = makeNode(Expr);
764722
expr->typeOid = rettype;

src/include/catalog/pg_proc.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $Id: pg_proc.h,v 1.137 2000/06/09 01:11:10 tgl Exp $
10+
* $Id: pg_proc.h,v 1.138 2000/06/11 20:07:51 tgl Exp $
1111
*
1212
* NOTES
1313
* The script catalog/genbki.sh reads this file and generates .bki
@@ -2003,12 +2003,12 @@ DESCR("convert int8 to int8 (no-op)");
20032003

20042004

20052005
/* SEQUENCEs nextval & currval functions */
2006-
DATA(insert OID = 1574 ( nextval PGUID 11 f t f t 1 f 23 "25" 100 0 0 100 nextval - ));
2006+
DATA(insert OID = 1574 ( nextval PGUID 12 f t f t 1 f 23 "25" 100 0 0 100 nextval - ));
20072007
DESCR("sequence next value");
2008-
DATA(insert OID = 1575 ( currval PGUID 11 f t f t 1 f 23 "25" 100 0 0 100 currval - ));
2008+
DATA(insert OID = 1575 ( currval PGUID 12 f t f t 1 f 23 "25" 100 0 0 100 currval - ));
20092009
DESCR("sequence current value");
2010-
DATA(insert OID = 1576 ( setval PGUID 11 f t f t 2 f 23 "25 23" 100 0 0 100 setval - ));
2011-
DESCR("sequence set value");
2010+
DATA(insert OID = 1576 ( setval PGUID 12 f t f t 2 f 23 "25 23" 100 0 0 100 setval - ));
2011+
DESCR("set sequence value");
20122012

20132013
DATA(insert OID = 1579 ( varbit_in PGUID 11 f t t t 1 f 1562 "0" 100 0 0 100 varbit_in - ));
20142014
DESCR("(internal)");

src/include/commands/sequence.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@
99
#ifndef SEQUENCE_H
1010
#define SEQUENCE_H
1111

12+
#include "fmgr.h"
1213
#include "nodes/parsenodes.h"
1314

1415
/*
15-
* Columns of a sequnece relation
16+
* Columns of a sequence relation
1617
*/
1718

1819
#define SEQ_COL_NAME 1
@@ -27,10 +28,11 @@
2728
#define SEQ_COL_FIRSTCOL SEQ_COL_NAME
2829
#define SEQ_COL_LASTCOL SEQ_COL_CALLED
2930

31+
extern Datum nextval(PG_FUNCTION_ARGS);
32+
extern Datum currval(PG_FUNCTION_ARGS);
33+
extern Datum setval(PG_FUNCTION_ARGS);
34+
3035
extern void DefineSequence(CreateSeqStmt *stmt);
31-
extern int4 nextval(struct varlena * seqname);
32-
extern int4 currval(struct varlena * seqname);
33-
extern int4 setval(struct varlena * seqname, int4 next);
3436
extern void CloseSequences(void);
3537

3638
#endif /* SEQUENCE_H */

src/test/regress/regress.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* $Header: /cvsroot/pgsql/src/test/regress/regress.c,v 1.38 2000/06/05 07:29:22 tgl Exp $
2+
* $Header: /cvsroot/pgsql/src/test/regress/regress.c,v 1.39 2000/06/11 20:07:44 tgl Exp $
33
*/
44

55
#include <float.h> /* faked on sunos */
@@ -8,6 +8,7 @@
88

99
#include "utils/geo_decls.h" /* includes <math.h> */
1010
#include "executor/executor.h" /* For GetAttributeByName */
11+
#include "commands/sequence.h" /* for nextval() */
1112

1213
#define P_MAXDIG 12
1314
#define LDELIM '('
@@ -420,8 +421,6 @@ funny_dup17(PG_FUNCTION_ARGS)
420421
extern Datum ttdummy(PG_FUNCTION_ARGS);
421422
int32 set_ttdummy(int32 on);
422423

423-
extern int4 nextval(struct varlena * seqin);
424-
425424
#define TTDUMMY_INFINITY 999999
426425

427426
static void *splan = NULL;
@@ -528,9 +527,10 @@ ttdummy(PG_FUNCTION_ARGS)
528527
}
529528

530529
{
531-
struct varlena *seqname = textin("ttdummy_seq");
530+
text *seqname = textin("ttdummy_seq");
532531

533-
newoff = nextval(seqname);
532+
newoff = DirectFunctionCall1(nextval,
533+
PointerGetDatum(seqname));
534534
pfree(seqname);
535535
}
536536

0 commit comments

Comments
 (0)