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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy