📄 sequence.c
字号:
do_setval(relid, next, iscalled); PG_RETURN_INT64(next);}/* * If we haven't touched the sequence already in this transaction, * we need to acquire AccessShareLock. We arrange for the lock to * be owned by the top transaction, so that we don't need to do it * more than once per xact. */static voidacquire_share_lock(Relation seqrel, SeqTable seq){ TransactionId thisxid = GetTopTransactionId(); if (seq->xid != thisxid) { ResourceOwner currentOwner; currentOwner = CurrentResourceOwner; PG_TRY(); { CurrentResourceOwner = TopTransactionResourceOwner; LockRelation(seqrel, AccessShareLock); } PG_CATCH(); { /* Ensure CurrentResourceOwner is restored on error */ CurrentResourceOwner = currentOwner; PG_RE_THROW(); } PG_END_TRY(); CurrentResourceOwner = currentOwner; /* Flag that we have a lock in the current xact. */ seq->xid = thisxid; }}/* * Given a relation OID, open and lock the sequence. p_elm and p_rel are * output parameters. */static voidinit_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel){ Relation seqrel; volatile SeqTable elm; /* * Open the sequence relation. */ seqrel = relation_open(relid, NoLock); if (seqrel->rd_rel->relkind != RELKIND_SEQUENCE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is not a sequence", RelationGetRelationName(seqrel)))); /* Look to see if we already have a seqtable entry for relation */ for (elm = seqtab; elm != NULL; elm = elm->next) { if (elm->relid == relid) break; } /* * Allocate new seqtable entry if we didn't find one. * * NOTE: seqtable entries remain in the list for the life of a backend. If * the sequence itself is deleted then the entry becomes wasted memory, * but it's small enough that this should not matter. */ if (elm == NULL) { /* * Time to make a new seqtable entry. These entries live as long as * the backend does, so we use plain malloc for them. */ elm = (SeqTable) malloc(sizeof(SeqTableData)); if (elm == NULL) ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"))); elm->relid = relid; elm->xid = InvalidTransactionId; /* increment is set to 0 until we do read_info (see currval) */ elm->last = elm->cached = elm->increment = 0; elm->next = seqtab; seqtab = elm; } acquire_share_lock(seqrel, elm); *p_elm = elm; *p_rel = seqrel;}/* Given an opened relation, lock the page buffer and find the tuple */static Form_pg_sequenceread_info(SeqTable elm, Relation rel, Buffer *buf){ PageHeader page; ItemId lp; HeapTupleData tuple; sequence_magic *sm; Form_pg_sequence seq; *buf = ReadBuffer(rel, 0); LockBuffer(*buf, BUFFER_LOCK_EXCLUSIVE); page = (PageHeader) BufferGetPage(*buf); sm = (sequence_magic *) PageGetSpecialPointer(page); if (sm->magic != SEQ_MAGIC) elog(ERROR, "bad magic number in sequence \"%s\": %08X", RelationGetRelationName(rel), sm->magic); lp = PageGetItemId(page, FirstOffsetNumber); Assert(ItemIdIsUsed(lp)); tuple.t_data = (HeapTupleHeader) PageGetItem((Page) page, lp); seq = (Form_pg_sequence) GETSTRUCT(&tuple); elm->increment = seq->increment_by; return seq;}/* * init_params: process the options list of CREATE or ALTER SEQUENCE, * and store the values into appropriate fields of *new. * * If isInit is true, fill any unspecified options with default values; * otherwise, do not change existing options that aren't explicitly overridden. */static voidinit_params(List *options, Form_pg_sequence new, bool isInit){ DefElem *last_value = NULL; DefElem *increment_by = NULL; DefElem *max_value = NULL; DefElem *min_value = NULL; DefElem *cache_value = NULL; DefElem *is_cycled = NULL; ListCell *option; foreach(option, options) { DefElem *defel = (DefElem *) lfirst(option); if (strcmp(defel->defname, "increment") == 0) { if (increment_by) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options"))); increment_by = defel; } /* * start is for a new sequence restart is for alter */ else if (strcmp(defel->defname, "start") == 0 || strcmp(defel->defname, "restart") == 0) { if (last_value) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options"))); last_value = defel; } else if (strcmp(defel->defname, "maxvalue") == 0) { if (max_value) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options"))); max_value = defel; } else if (strcmp(defel->defname, "minvalue") == 0) { if (min_value) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options"))); min_value = defel; } else if (strcmp(defel->defname, "cache") == 0) { if (cache_value) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options"))); cache_value = defel; } else if (strcmp(defel->defname, "cycle") == 0) { if (is_cycled) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options"))); is_cycled = defel; } else elog(ERROR, "option \"%s\" not recognized", defel->defname); } /* INCREMENT BY */ if (increment_by != NULL) { new->increment_by = defGetInt64(increment_by); if (new->increment_by == 0) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("INCREMENT must not be zero"))); } else if (isInit) new->increment_by = 1; /* CYCLE */ if (is_cycled != NULL) { new->is_cycled = intVal(is_cycled->arg); Assert(new->is_cycled == false || new->is_cycled == true); } else if (isInit) new->is_cycled = false; /* MAXVALUE (null arg means NO MAXVALUE) */ if (max_value != NULL && max_value->arg) new->max_value = defGetInt64(max_value); else if (isInit || max_value != NULL) { if (new->increment_by > 0) new->max_value = SEQ_MAXVALUE; /* ascending seq */ else new->max_value = -1; /* descending seq */ } /* MINVALUE (null arg means NO MINVALUE) */ if (min_value != NULL && min_value->arg) new->min_value = defGetInt64(min_value); else if (isInit || min_value != NULL) { if (new->increment_by > 0) new->min_value = 1; /* ascending seq */ else new->min_value = SEQ_MINVALUE; /* descending seq */ } /* crosscheck min/max */ if (new->min_value >= new->max_value) { char bufm[100], bufx[100]; snprintf(bufm, sizeof(bufm), INT64_FORMAT, new->min_value); snprintf(bufx, sizeof(bufx), INT64_FORMAT, new->max_value); ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("MINVALUE (%s) must be less than MAXVALUE (%s)", bufm, bufx))); } /* START WITH */ if (last_value != NULL) { new->last_value = defGetInt64(last_value); new->is_called = false; new->log_cnt = 1; } else if (isInit) { if (new->increment_by > 0) new->last_value = new->min_value; /* ascending seq */ else new->last_value = new->max_value; /* descending seq */ new->is_called = false; new->log_cnt = 1; } /* crosscheck */ if (new->last_value < new->min_value) { char bufs[100], bufm[100]; snprintf(bufs, sizeof(bufs), INT64_FORMAT, new->last_value); snprintf(bufm, sizeof(bufm), INT64_FORMAT, new->min_value); ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("START value (%s) can't be less than MINVALUE (%s)", bufs, bufm))); } if (new->last_value > new->max_value) { char bufs[100], bufm[100]; snprintf(bufs, sizeof(bufs), INT64_FORMAT, new->last_value); snprintf(bufm, sizeof(bufm), INT64_FORMAT, new->max_value); ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("START value (%s) can't be greater than MAXVALUE (%s)", bufs, bufm))); } /* CACHE */ if (cache_value != NULL) { new->cache_value = defGetInt64(cache_value); if (new->cache_value <= 0) { char buf[100]; snprintf(buf, sizeof(buf), INT64_FORMAT, new->cache_value); ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("CACHE (%s) must be greater than zero", buf))); } } else if (isInit) new->cache_value = 1;}voidseq_redo(XLogRecPtr lsn, XLogRecord *record){ uint8 info = record->xl_info & ~XLR_INFO_MASK; Relation reln; Buffer buffer; Page page; char *item; Size itemsz; xl_seq_rec *xlrec = (xl_seq_rec *) XLogRecGetData(record); sequence_magic *sm; if (info != XLOG_SEQ_LOG) elog(PANIC, "seq_redo: unknown op code %u", info); reln = XLogOpenRelation(xlrec->node); if (!RelationIsValid(reln)) return; buffer = XLogReadBuffer(true, reln, 0); if (!BufferIsValid(buffer)) elog(PANIC, "seq_redo: can't read block 0 of rel %u/%u/%u", xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode); page = (Page) BufferGetPage(buffer); /* Always reinit the page and reinstall the magic number */ /* See comments in DefineSequence */ PageInit((Page) page, BufferGetPageSize(buffer), sizeof(sequence_magic)); sm = (sequence_magic *) PageGetSpecialPointer(page); sm->magic = SEQ_MAGIC; item = (char *) xlrec + sizeof(xl_seq_rec); itemsz = record->xl_len - sizeof(xl_seq_rec); itemsz = MAXALIGN(itemsz); if (PageAddItem(page, (Item) item, itemsz, FirstOffsetNumber, LP_USED) == InvalidOffsetNumber) elog(PANIC, "seq_redo: failed to add item to page"); PageSetLSN(page, lsn); PageSetTLI(page, ThisTimeLineID); LockBuffer(buffer, BUFFER_LOCK_UNLOCK); WriteBuffer(buffer);}voidseq_desc(char *buf, uint8 xl_info, char *rec){ uint8 info = xl_info & ~XLR_INFO_MASK; xl_seq_rec *xlrec = (xl_seq_rec *) rec; if (info == XLOG_SEQ_LOG) strcat(buf, "log: "); else { strcat(buf, "UNKNOWN"); return; } sprintf(buf + strlen(buf), "rel %u/%u/%u", xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -