sequence.c
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:13k
源码类别:

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * sequence.c
  4.  *   PostgreSQL sequences support code.
  5.  *
  6.  *-------------------------------------------------------------------------
  7.  */
  8. #include "postgres.h"
  9. #include "access/heapam.h"
  10. #include "commands/creatinh.h"
  11. #include "commands/sequence.h"
  12. #include "miscadmin.h"
  13. #include "utils/acl.h"
  14. #include "utils/builtins.h"
  15. #define SEQ_MAGIC   0x1717
  16. #define SEQ_MAXVALUE ((int4)0x7FFFFFFF)
  17. #define SEQ_MINVALUE -(SEQ_MAXVALUE)
  18. typedef struct FormData_pg_sequence
  19. {
  20. NameData sequence_name;
  21. int4 last_value;
  22. int4 increment_by;
  23. int4 max_value;
  24. int4 min_value;
  25. int4 cache_value;
  26. char is_cycled;
  27. char is_called;
  28. } FormData_pg_sequence;
  29. typedef FormData_pg_sequence *Form_pg_sequence;
  30. typedef struct sequence_magic
  31. {
  32. uint32 magic;
  33. } sequence_magic;
  34. typedef struct SeqTableData
  35. {
  36. char    *name;
  37. Oid relid;
  38. Relation rel;
  39. int4 cached;
  40. int4 last;
  41. int4 increment;
  42. struct SeqTableData *next;
  43. } SeqTableData;
  44. typedef SeqTableData *SeqTable;
  45. static SeqTable seqtab = NULL;
  46. static SeqTable init_sequence(char *caller, char *name);
  47. static Form_pg_sequence read_info(char *caller, SeqTable elm, Buffer *buf);
  48. static void init_params(CreateSeqStmt *seq, Form_pg_sequence new);
  49. static int get_param(DefElem *def);
  50. /*
  51.  * DefineSequence
  52.  * Creates a new sequence relation
  53.  */
  54. void
  55. DefineSequence(CreateSeqStmt *seq)
  56. {
  57. FormData_pg_sequence new;
  58. CreateStmt *stmt = makeNode(CreateStmt);
  59. ColumnDef  *coldef;
  60. TypeName   *typnam;
  61. Relation rel;
  62. Buffer buf;
  63. PageHeader page;
  64. sequence_magic *sm;
  65. HeapTuple tuple;
  66. TupleDesc tupDesc;
  67. Datum value[SEQ_COL_LASTCOL];
  68. char null[SEQ_COL_LASTCOL];
  69. int i;
  70. NameData name;
  71. /* Check and set values */
  72. init_params(seq, &new);
  73. /*
  74.  * Create relation (and fill *null & *value)
  75.  */
  76. stmt->tableElts = NIL;
  77. for (i = SEQ_COL_FIRSTCOL; i <= SEQ_COL_LASTCOL; i++)
  78. {
  79. typnam = makeNode(TypeName);
  80. typnam->setof = FALSE;
  81. typnam->arrayBounds = NULL;
  82. typnam->typmod = -1;
  83. coldef = makeNode(ColumnDef);
  84. coldef->typename = typnam;
  85. coldef->defval = NULL;
  86. coldef->is_not_null = false;
  87. null[i - 1] = ' ';
  88. switch (i)
  89. {
  90. case SEQ_COL_NAME:
  91. typnam->name = "name";
  92. coldef->colname = "sequence_name";
  93. namestrcpy(&name, seq->seqname);
  94. value[i - 1] = NameGetDatum(&name);
  95. break;
  96. case SEQ_COL_LASTVAL:
  97. typnam->name = "int4";
  98. coldef->colname = "last_value";
  99. value[i - 1] = Int32GetDatum(new.last_value);
  100. break;
  101. case SEQ_COL_INCBY:
  102. typnam->name = "int4";
  103. coldef->colname = "increment_by";
  104. value[i - 1] = Int32GetDatum(new.increment_by);
  105. break;
  106. case SEQ_COL_MAXVALUE:
  107. typnam->name = "int4";
  108. coldef->colname = "max_value";
  109. value[i - 1] = Int32GetDatum(new.max_value);
  110. break;
  111. case SEQ_COL_MINVALUE:
  112. typnam->name = "int4";
  113. coldef->colname = "min_value";
  114. value[i - 1] = Int32GetDatum(new.min_value);
  115. break;
  116. case SEQ_COL_CACHE:
  117. typnam->name = "int4";
  118. coldef->colname = "cache_value";
  119. value[i - 1] = Int32GetDatum(new.cache_value);
  120. break;
  121. case SEQ_COL_CYCLE:
  122. typnam->name = "char";
  123. coldef->colname = "is_cycled";
  124. value[i - 1] = CharGetDatum(new.is_cycled);
  125. break;
  126. case SEQ_COL_CALLED:
  127. typnam->name = "char";
  128. coldef->colname = "is_called";
  129. value[i - 1] = CharGetDatum('f');
  130. break;
  131. }
  132. stmt->tableElts = lappend(stmt->tableElts, coldef);
  133. }
  134. stmt->relname = seq->seqname;
  135. stmt->inhRelnames = NIL;
  136. stmt->constraints = NIL;
  137. DefineRelation(stmt, RELKIND_SEQUENCE);
  138. rel = heap_openr(seq->seqname);
  139. Assert(RelationIsValid(rel));
  140. LockRelation(rel, AccessExclusiveLock);
  141. tupDesc = RelationGetDescr(rel);
  142. Assert(RelationGetNumberOfBlocks(rel) == 0);
  143. buf = ReadBuffer(rel, P_NEW);
  144. if (!BufferIsValid(buf))
  145. elog(ERROR, "DefineSequence: ReadBuffer failed");
  146. page = (PageHeader) BufferGetPage(buf);
  147. PageInit((Page) page, BufferGetPageSize(buf), sizeof(sequence_magic));
  148. sm = (sequence_magic *) PageGetSpecialPointer(page);
  149. sm->magic = SEQ_MAGIC;
  150. /* Now - form & insert sequence tuple */
  151. tuple = heap_formtuple(tupDesc, value, null);
  152. heap_insert(rel, tuple);
  153. if (WriteBuffer(buf) == STATUS_ERROR)
  154. elog(ERROR, "DefineSequence: WriteBuffer failed");
  155. UnlockRelation(rel, AccessExclusiveLock);
  156. heap_close(rel);
  157. return;
  158. }
  159. int4
  160. nextval(struct varlena * seqin)
  161. {
  162. char    *seqname = textout(seqin);
  163. SeqTable elm;
  164. Buffer buf;
  165. Form_pg_sequence seq;
  166. int4 incby,
  167. maxv,
  168. minv,
  169. cache;
  170. int4 result,
  171. next,
  172. rescnt = 0;
  173. /* open and AccessShareLock sequence */
  174. elm = init_sequence("nextval", seqname);
  175. pfree(seqname);
  176. if (elm->last != elm->cached) /* some numbers were cached */
  177. {
  178. elm->last += elm->increment;
  179. return elm->last;
  180. }
  181. seq = read_info("nextval", elm, &buf); /* lock page' buffer and
  182.  * read tuple */
  183. next = result = seq->last_value;
  184. incby = seq->increment_by;
  185. maxv = seq->max_value;
  186. minv = seq->min_value;
  187. cache = seq->cache_value;
  188. if (seq->is_called != 't')
  189. rescnt++; /* last_value if not called */
  190. while (rescnt < cache) /* try to fetch cache numbers */
  191. {
  192. /*
  193.  * Check MAXVALUE for ascending sequences and MINVALUE for
  194.  * descending sequences
  195.  */
  196. if (incby > 0) /* ascending sequence */
  197. {
  198. if ((maxv >= 0 && next > maxv - incby) ||
  199. (maxv < 0 && next + incby > maxv))
  200. {
  201. if (rescnt > 0)
  202. break; /* stop caching */
  203. if (seq->is_cycled != 't')
  204. elog(ERROR, "%s.nextval: got MAXVALUE (%d)",
  205.  elm->name, maxv);
  206. next = minv;
  207. }
  208. else
  209. next += incby;
  210. }
  211. else
  212. /* descending sequence */
  213. {
  214. if ((minv < 0 && next < minv - incby) ||
  215. (minv >= 0 && next + incby < minv))
  216. {
  217. if (rescnt > 0)
  218. break; /* stop caching */
  219. if (seq->is_cycled != 't')
  220. elog(ERROR, "%s.nextval: got MINVALUE (%d)",
  221.  elm->name, minv);
  222. next = maxv;
  223. }
  224. else
  225. next += incby;
  226. }
  227. rescnt++; /* got result */
  228. if (rescnt == 1) /* if it's first one - */
  229. result = next; /* it's what to return */
  230. }
  231. /* save info in local cache */
  232. elm->last = result; /* last returned number */
  233. elm->cached = next; /* last cached number */
  234. /* save info in sequence relation */
  235. seq->last_value = next; /* last fetched number */
  236. seq->is_called = 't';
  237. LockBuffer(buf, BUFFER_LOCK_UNLOCK);
  238. if (WriteBuffer(buf) == STATUS_ERROR)
  239. elog(ERROR, "%s.nextval: WriteBuffer failed", elm->name);
  240. return result;
  241. }
  242. int4
  243. currval(struct varlena * seqin)
  244. {
  245. char    *seqname = textout(seqin);
  246. SeqTable elm;
  247. int4 result;
  248. /* open and AccessShareLock sequence */
  249. elm = init_sequence("currval", seqname);
  250. pfree(seqname);
  251. if (elm->increment == 0) /* nextval/read_info were not called */
  252. elog(ERROR, "%s.currval is not yet defined in this session", elm->name);
  253. result = elm->last;
  254. return result;
  255. }
  256. int4
  257. setval(struct varlena * seqin, int4 next)
  258. {
  259. char    *seqname = textout(seqin);
  260. SeqTable elm;
  261. Buffer buf;
  262. Form_pg_sequence seq;
  263. #ifndef NO_SECURITY
  264. if (pg_aclcheck(seqname, getpgusername(), ACL_WR) != ACLCHECK_OK)
  265. elog(ERROR, "%s.setval: you don't have permissions to set sequence %s",
  266.  seqname, seqname);
  267. #endif
  268. /* open and AccessShareLock sequence */
  269. elm = init_sequence("setval", seqname);
  270. seq = read_info("setval", elm, &buf); /* lock page' buffer and
  271.  * read tuple */
  272. if (seq->cache_value != 1)
  273. {
  274. elog(ERROR, "%s.setval: can't set value of sequence %s, cache != 1",
  275.  seqname, seqname);
  276. }
  277. if ((next < seq->min_value) || (next > seq->max_value))
  278. {
  279. elog(ERROR, "%s.setval: value %d is of of bounds (%d,%d)",
  280.  seqname, next, seq->min_value, seq->max_value);
  281. }
  282. /* save info in local cache */
  283. elm->last = next; /* last returned number */
  284. elm->cached = next; /* last cached number */
  285. /* save info in sequence relation */
  286. seq->last_value = next; /* last fetched number */
  287. seq->is_called = 't';
  288. LockBuffer(buf, BUFFER_LOCK_UNLOCK);
  289. if (WriteBuffer(buf) == STATUS_ERROR)
  290. elog(ERROR, "%s.settval: WriteBuffer failed", seqname);
  291. return next;
  292. }
  293. static Form_pg_sequence
  294. read_info(char *caller, SeqTable elm, Buffer *buf)
  295. {
  296. PageHeader page;
  297. ItemId lp;
  298. HeapTupleData tuple;
  299. sequence_magic *sm;
  300. Form_pg_sequence seq;
  301. if (RelationGetNumberOfBlocks(elm->rel) != 1)
  302. elog(ERROR, "%s.%s: invalid number of blocks in sequence",
  303.  elm->name, caller);
  304. *buf = ReadBuffer(elm->rel, 0);
  305. if (!BufferIsValid(*buf))
  306. elog(ERROR, "%s.%s: ReadBuffer failed", elm->name, caller);
  307. LockBuffer(*buf, BUFFER_LOCK_EXCLUSIVE);
  308. page = (PageHeader) BufferGetPage(*buf);
  309. sm = (sequence_magic *) PageGetSpecialPointer(page);
  310. if (sm->magic != SEQ_MAGIC)
  311. elog(ERROR, "%s.%s: bad magic (%08X)", elm->name, caller, sm->magic);
  312. lp = PageGetItemId(page, FirstOffsetNumber);
  313. Assert(ItemIdIsUsed(lp));
  314. tuple.t_data = (HeapTupleHeader) PageGetItem((Page) page, lp);
  315. seq = (Form_pg_sequence) GETSTRUCT(&tuple);
  316. elm->increment = seq->increment_by;
  317. return seq;
  318. }
  319. static SeqTable
  320. init_sequence(char *caller, char *name)
  321. {
  322. SeqTable elm,
  323. priv = (SeqTable) NULL;
  324. SeqTable temp;
  325. for (elm = seqtab; elm != (SeqTable) NULL;)
  326. {
  327. if (strcmp(elm->name, name) == 0)
  328. break;
  329. priv = elm;
  330. elm = elm->next;
  331. }
  332. if (elm == (SeqTable) NULL) /* not found */
  333. {
  334. temp = (SeqTable) malloc(sizeof(SeqTableData));
  335. temp->name = malloc(strlen(name) + 1);
  336. strcpy(temp->name, name);
  337. temp->rel = (Relation) NULL;
  338. temp->cached = temp->last = temp->increment = 0;
  339. temp->next = (SeqTable) NULL;
  340. }
  341. else
  342. /* found */
  343. {
  344. if (elm->rel != (Relation) NULL) /* already opened */
  345. return elm;
  346. temp = elm;
  347. }
  348. temp->rel = heap_openr(name);
  349. if (!RelationIsValid(temp->rel))
  350. elog(ERROR, "%s.%s: sequence does not exist", name, caller);
  351. LockRelation(temp->rel, AccessShareLock);
  352. if (temp->rel->rd_rel->relkind != RELKIND_SEQUENCE)
  353. elog(ERROR, "%s.%s: %s is not sequence !", name, caller, name);
  354. if (elm != (SeqTable) NULL) /* we opened sequence from our */
  355. { /* SeqTable - check relid ! */
  356. if (RelationGetRelid(elm->rel) != elm->relid)
  357. {
  358. elog(NOTICE, "%s.%s: sequence was re-created",
  359.  name, caller, name);
  360. elm->cached = elm->last = elm->increment = 0;
  361. elm->relid = RelationGetRelid(elm->rel);
  362. }
  363. }
  364. else
  365. {
  366. elm = temp;
  367. elm->relid = RelationGetRelid(elm->rel);
  368. if (seqtab == (SeqTable) NULL)
  369. seqtab = elm;
  370. else
  371. priv->next = elm;
  372. }
  373. return elm;
  374. }
  375. /*
  376.  * CloseSequences
  377.  * is calling by xact mgr at commit/abort.
  378.  */
  379. void
  380. CloseSequences(void)
  381. {
  382. SeqTable elm;
  383. Relation rel;
  384. for (elm = seqtab; elm != (SeqTable) NULL;)
  385. {
  386. if (elm->rel != (Relation) NULL) /* opened in current xact */
  387. {
  388. rel = elm->rel;
  389. elm->rel = (Relation) NULL;
  390. UnlockRelation(rel, AccessShareLock);
  391. heap_close(rel);
  392. }
  393. elm = elm->next;
  394. }
  395. return;
  396. }
  397. static void
  398. init_params(CreateSeqStmt *seq, Form_pg_sequence new)
  399. {
  400. DefElem    *last_value = NULL;
  401. DefElem    *increment_by = NULL;
  402. DefElem    *max_value = NULL;
  403. DefElem    *min_value = NULL;
  404. DefElem    *cache_value = NULL;
  405. List    *option;
  406. new->is_cycled = 'f';
  407. foreach(option, seq->options)
  408. {
  409. DefElem    *defel = (DefElem *) lfirst(option);
  410. if (!strcasecmp(defel->defname, "increment"))
  411. increment_by = defel;
  412. else if (!strcasecmp(defel->defname, "start"))
  413. last_value = defel;
  414. else if (!strcasecmp(defel->defname, "maxvalue"))
  415. max_value = defel;
  416. else if (!strcasecmp(defel->defname, "minvalue"))
  417. min_value = defel;
  418. else if (!strcasecmp(defel->defname, "cache"))
  419. cache_value = defel;
  420. else if (!strcasecmp(defel->defname, "cycle"))
  421. {
  422. if (defel->arg != (Node *) NULL)
  423. elog(ERROR, "DefineSequence: CYCLE ??");
  424. new->is_cycled = 't';
  425. }
  426. else
  427. elog(ERROR, "DefineSequence: option "%s" not recognized",
  428.  defel->defname);
  429. }
  430. if (increment_by == (DefElem *) NULL) /* INCREMENT BY */
  431. new->increment_by = 1;
  432. else if ((new->increment_by = get_param(increment_by)) == 0)
  433. elog(ERROR, "DefineSequence: can't INCREMENT by 0");
  434. if (max_value == (DefElem *) NULL) /* MAXVALUE */
  435. {
  436. if (new->increment_by > 0)
  437. new->max_value = SEQ_MAXVALUE; /* ascending seq */
  438. else
  439. new->max_value = -1;/* descending seq */
  440. }
  441. else
  442. new->max_value = get_param(max_value);
  443. if (min_value == (DefElem *) NULL) /* MINVALUE */
  444. {
  445. if (new->increment_by > 0)
  446. new->min_value = 1; /* ascending seq */
  447. else
  448. new->min_value = SEQ_MINVALUE; /* descending seq */
  449. }
  450. else
  451. new->min_value = get_param(min_value);
  452. if (new->min_value >= new->max_value)
  453. elog(ERROR, "DefineSequence: MINVALUE (%d) can't be >= MAXVALUE (%d)",
  454.  new->min_value, new->max_value);
  455. if (last_value == (DefElem *) NULL) /* START WITH */
  456. {
  457. if (new->increment_by > 0)
  458. new->last_value = new->min_value; /* ascending seq */
  459. else
  460. new->last_value = new->max_value; /* descending seq */
  461. }
  462. else
  463. new->last_value = get_param(last_value);
  464. if (new->last_value < new->min_value)
  465. elog(ERROR, "DefineSequence: START value (%d) can't be < MINVALUE (%d)",
  466.  new->last_value, new->min_value);
  467. if (new->last_value > new->max_value)
  468. elog(ERROR, "DefineSequence: START value (%d) can't be > MAXVALUE (%d)",
  469.  new->last_value, new->max_value);
  470. if (cache_value == (DefElem *) NULL) /* CACHE */
  471. new->cache_value = 1;
  472. else if ((new->cache_value = get_param(cache_value)) <= 0)
  473. elog(ERROR, "DefineSequence: CACHE (%d) can't be <= 0",
  474.  new->cache_value);
  475. }
  476. static int
  477. get_param(DefElem *def)
  478. {
  479. if (def->arg == (Node *) NULL)
  480. elog(ERROR, "DefineSequence: "%s" value unspecified", def->defname);
  481. if (nodeTag(def->arg) == T_Integer)
  482. return intVal(def->arg);
  483. elog(ERROR, "DefineSequence: "%s" is to be integer", def->defname);
  484. return -1;
  485. }