diff options
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/commands/sequence.c | 106 | ||||
-rw-r--r-- | src/backend/parser/parse_func.c | 58 |
2 files changed, 91 insertions, 73 deletions
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c index 0667297d763..f95d6fbb6c1 100644 --- a/src/backend/commands/sequence.c +++ b/src/backend/commands/sequence.c @@ -6,6 +6,8 @@ *------------------------------------------------------------------------- */ +#include <ctype.h> + #include "postgres.h" #include "access/heapam.h" @@ -54,6 +56,7 @@ typedef SeqTableData *SeqTable; static SeqTable seqtab = NULL; +static char *get_seq_name(text *seqin); static SeqTable init_sequence(char *caller, char *name); static Form_pg_sequence read_info(char *caller, SeqTable elm, Buffer *buf); static void init_params(CreateSeqStmt *seq, Form_pg_sequence new); @@ -181,29 +184,37 @@ DefineSequence(CreateSeqStmt *seq) } -int4 -nextval(struct varlena * seqin) +Datum +nextval(PG_FUNCTION_ARGS) { - char *seqname = textout(seqin); + text *seqin = PG_GETARG_TEXT_P(0); + char *seqname = get_seq_name(seqin); SeqTable elm; Buffer buf; Form_pg_sequence seq; - int4 incby, + int32 incby, maxv, minv, cache; - int4 result, + int32 result, next, 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 */ elm = init_sequence("nextval", seqname); + pfree(seqname); if (elm->last != elm->cached) /* some numbers were cached */ { elm->last += elm->increment; - return elm->last; + PG_RETURN_INT32(elm->last); } seq = read_info("nextval", elm, &buf); /* lock page' buffer and @@ -225,8 +236,9 @@ nextval(struct varlena * seqin) * Check MAXVALUE for ascending sequences and MINVALUE for * descending sequences */ - if (incby > 0) /* ascending sequence */ + if (incby > 0) { + /* ascending sequence */ if ((maxv >= 0 && next > maxv - incby) || (maxv < 0 && next + incby > maxv)) { @@ -241,8 +253,8 @@ nextval(struct varlena * seqin) next += incby; } else -/* descending sequence */ { + /* descending sequence */ if ((minv < 0 && next < minv - incby) || (minv >= 0 && next + incby < minv)) { @@ -274,35 +286,43 @@ nextval(struct varlena * seqin) if (WriteBuffer(buf) == STATUS_ERROR) elog(ERROR, "%s.nextval: WriteBuffer failed", elm->name); - return result; - + PG_RETURN_INT32(result); } - -int4 -currval(struct varlena * seqin) +Datum +currval(PG_FUNCTION_ARGS) { - char *seqname = textout(seqin); + text *seqin = PG_GETARG_TEXT_P(0); + char *seqname = get_seq_name(seqin); 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 */ elm = init_sequence("currval", seqname); - pfree(seqname); 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; - return result; + pfree(seqname); + PG_RETURN_INT32(result); } -int4 -setval(struct varlena * seqin, int4 next) +Datum +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; Buffer buf; Form_pg_sequence seq; @@ -341,9 +361,49 @@ setval(struct varlena * seqin, int4 next) LockBuffer(buf, BUFFER_LOCK_UNLOCK); 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 diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c index 878c5530054..541211af64d 100644 --- a/src/backend/parser/parse_func.c +++ b/src/backend/parser/parse_func.c @@ -8,7 +8,7 @@ * * * 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, } /* - * 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 || - funcid == F_CURRVAL || - funcid == F_SETVAL) - { - 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"); - } + 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->typeOid = rettype; |