6
6
*-------------------------------------------------------------------------
7
7
*/
8
8
9
+ #include <ctype.h>
10
+
9
11
#include "postgres.h"
10
12
11
13
#include "access/heapam.h"
@@ -54,6 +56,7 @@ typedef SeqTableData *SeqTable;
54
56
55
57
static SeqTable seqtab = NULL ;
56
58
59
+ static char * get_seq_name (text * seqin );
57
60
static SeqTable init_sequence (char * caller , char * name );
58
61
static Form_pg_sequence read_info (char * caller , SeqTable elm , Buffer * buf );
59
62
static void init_params (CreateSeqStmt * seq , Form_pg_sequence new );
@@ -181,29 +184,37 @@ DefineSequence(CreateSeqStmt *seq)
181
184
}
182
185
183
186
184
- int4
185
- nextval (struct varlena * seqin )
187
+ Datum
188
+ nextval (PG_FUNCTION_ARGS )
186
189
{
187
- char * seqname = textout (seqin );
190
+ text * seqin = PG_GETARG_TEXT_P (0 );
191
+ char * seqname = get_seq_name (seqin );
188
192
SeqTable elm ;
189
193
Buffer buf ;
190
194
Form_pg_sequence seq ;
191
- int4 incby ,
195
+ int32 incby ,
192
196
maxv ,
193
197
minv ,
194
198
cache ;
195
- int4 result ,
199
+ int32 result ,
196
200
next ,
197
201
rescnt = 0 ;
198
202
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
+
199
209
/* open and AccessShareLock sequence */
200
210
elm = init_sequence ("nextval" , seqname );
211
+
201
212
pfree (seqname );
202
213
203
214
if (elm -> last != elm -> cached ) /* some numbers were cached */
204
215
{
205
216
elm -> last += elm -> increment ;
206
- return elm -> last ;
217
+ PG_RETURN_INT32 ( elm -> last ) ;
207
218
}
208
219
209
220
seq = read_info ("nextval" , elm , & buf ); /* lock page' buffer and
@@ -225,8 +236,9 @@ nextval(struct varlena * seqin)
225
236
* Check MAXVALUE for ascending sequences and MINVALUE for
226
237
* descending sequences
227
238
*/
228
- if (incby > 0 ) /* ascending sequence */
239
+ if (incby > 0 )
229
240
{
241
+ /* ascending sequence */
230
242
if ((maxv >= 0 && next > maxv - incby ) ||
231
243
(maxv < 0 && next + incby > maxv ))
232
244
{
@@ -241,8 +253,8 @@ nextval(struct varlena * seqin)
241
253
next += incby ;
242
254
}
243
255
else
244
- /* descending sequence */
245
256
{
257
+ /* descending sequence */
246
258
if ((minv < 0 && next < minv - incby ) ||
247
259
(minv >= 0 && next + incby < minv ))
248
260
{
@@ -274,35 +286,43 @@ nextval(struct varlena * seqin)
274
286
if (WriteBuffer (buf ) == STATUS_ERROR )
275
287
elog (ERROR , "%s.nextval: WriteBuffer failed" , elm -> name );
276
288
277
- return result ;
278
-
289
+ PG_RETURN_INT32 (result );
279
290
}
280
291
281
-
282
- int4
283
- currval (struct varlena * seqin )
292
+ Datum
293
+ currval (PG_FUNCTION_ARGS )
284
294
{
285
- char * seqname = textout (seqin );
295
+ text * seqin = PG_GETARG_TEXT_P (0 );
296
+ char * seqname = get_seq_name (seqin );
286
297
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
288
305
289
306
/* open and AccessShareLock sequence */
290
307
elm = init_sequence ("currval" , seqname );
291
- pfree (seqname );
292
308
293
309
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 );
295
312
296
313
result = elm -> last ;
297
314
298
- return result ;
315
+ pfree ( seqname ) ;
299
316
317
+ PG_RETURN_INT32 (result );
300
318
}
301
319
302
- int4
303
- setval (struct varlena * seqin , int4 next )
320
+ Datum
321
+ setval (PG_FUNCTION_ARGS )
304
322
{
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 );
306
326
SeqTable elm ;
307
327
Buffer buf ;
308
328
Form_pg_sequence seq ;
@@ -341,9 +361,49 @@ setval(struct varlena * seqin, int4 next)
341
361
LockBuffer (buf , BUFFER_LOCK_UNLOCK );
342
362
343
363
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 );
345
367
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 ;
347
407
}
348
408
349
409
static Form_pg_sequence
0 commit comments