You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

reloptions.c 42KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637
  1. /*-------------------------------------------------------------------------
  2. *
  3. * reloptions.c
  4. * Core support for relation options (pg_class.reloptions)
  5. *
  6. * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
  7. * Portions Copyright (c) 1994, Regents of the University of California
  8. *
  9. *
  10. * IDENTIFICATION
  11. * src/backend/access/common/reloptions.c
  12. *
  13. *-------------------------------------------------------------------------
  14. */
  15. #include "postgres.h"
  16. #include <float.h>
  17. #include "access/gist_private.h"
  18. #include "access/hash.h"
  19. #include "access/htup_details.h"
  20. #include "access/nbtree.h"
  21. #include "access/reloptions.h"
  22. #include "access/spgist.h"
  23. #include "access/tuptoaster.h"
  24. #include "catalog/pg_type.h"
  25. #include "commands/defrem.h"
  26. #include "commands/tablespace.h"
  27. #include "commands/view.h"
  28. #include "nodes/makefuncs.h"
  29. #include "postmaster/postmaster.h"
  30. #include "utils/array.h"
  31. #include "utils/attoptcache.h"
  32. #include "utils/builtins.h"
  33. #include "utils/guc.h"
  34. #include "utils/memutils.h"
  35. #include "utils/rel.h"
  36. /*
  37. * Contents of pg_class.reloptions
  38. *
  39. * To add an option:
  40. *
  41. * (i) decide on a type (integer, real, bool, string), name, default value,
  42. * upper and lower bounds (if applicable); for strings, consider a validation
  43. * routine.
  44. * (ii) add a record below (or use add_<type>_reloption).
  45. * (iii) add it to the appropriate options struct (perhaps StdRdOptions)
  46. * (iv) add it to the appropriate handling routine (perhaps
  47. * default_reloptions)
  48. * (v) make sure the lock level is set correctly for that operation
  49. * (vi) don't forget to document the option
  50. *
  51. * Note that we don't handle "oids" in relOpts because it is handled by
  52. * interpretOidsOption().
  53. *
  54. * The default choice for any new option should be AccessExclusiveLock.
  55. * In some cases the lock level can be reduced from there, but the lock
  56. * level chosen should always conflict with itself to ensure that multiple
  57. * changes aren't lost when we attempt concurrent changes.
  58. * The choice of lock level depends completely upon how that parameter
  59. * is used within the server, not upon how and when you'd like to change it.
  60. * Safety first. Existing choices are documented here, and elsewhere in
  61. * backend code where the parameters are used.
  62. *
  63. * In general, anything that affects the results obtained from a SELECT must be
  64. * protected by AccessExclusiveLock.
  65. *
  66. * Autovacuum related parameters can be set at ShareUpdateExclusiveLock
  67. * since they are only used by the AV procs and don't change anything
  68. * currently executing.
  69. *
  70. * Fillfactor can be set because it applies only to subsequent changes made to
  71. * data blocks, as documented in heapio.c
  72. *
  73. * n_distinct options can be set at ShareUpdateExclusiveLock because they
  74. * are only used during ANALYZE, which uses a ShareUpdateExclusiveLock,
  75. * so the ANALYZE will not be affected by in-flight changes. Changing those
  76. * values has no affect until the next ANALYZE, so no need for stronger lock.
  77. *
  78. * Planner-related parameters can be set with ShareUpdateExclusiveLock because
  79. * they only affect planning and not the correctness of the execution. Plans
  80. * cannot be changed in mid-flight, so changes here could not easily result in
  81. * new improved plans in any case. So we allow existing queries to continue
  82. * and existing plans to survive, a small price to pay for allowing better
  83. * plans to be introduced concurrently without interfering with users.
  84. *
  85. * Setting parallel_workers is safe, since it acts the same as
  86. * max_parallel_workers_per_gather which is a USERSET parameter that doesn't
  87. * affect existing plans or queries.
  88. */
  89. static relopt_bool boolRelOpts[] =
  90. {
  91. {
  92. {
  93. "autosummarize",
  94. "Enables automatic summarization on this BRIN index",
  95. RELOPT_KIND_BRIN,
  96. AccessExclusiveLock
  97. },
  98. false
  99. },
  100. {
  101. {
  102. "autovacuum_enabled",
  103. "Enables autovacuum in this relation",
  104. RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
  105. ShareUpdateExclusiveLock
  106. },
  107. true
  108. },
  109. {
  110. {
  111. "user_catalog_table",
  112. "Declare a table as an additional catalog table, e.g. for the purpose of logical replication",
  113. RELOPT_KIND_HEAP,
  114. AccessExclusiveLock
  115. },
  116. false
  117. },
  118. {
  119. {
  120. "fastupdate",
  121. "Enables \"fast update\" feature for this GIN index",
  122. RELOPT_KIND_GIN,
  123. AccessExclusiveLock
  124. },
  125. true
  126. },
  127. {
  128. {
  129. "recheck_on_update",
  130. "Recheck functional index expression for changed value after update",
  131. RELOPT_KIND_INDEX,
  132. ShareUpdateExclusiveLock /* since only applies to later UPDATEs */
  133. },
  134. true
  135. },
  136. {
  137. {
  138. "security_barrier",
  139. "View acts as a row security barrier",
  140. RELOPT_KIND_VIEW,
  141. AccessExclusiveLock
  142. },
  143. false
  144. },
  145. /* list terminator */
  146. {{NULL}}
  147. };
  148. static relopt_int intRelOpts[] =
  149. {
  150. {
  151. {
  152. "fillfactor",
  153. "Packs table pages only to this percentage",
  154. RELOPT_KIND_HEAP,
  155. ShareUpdateExclusiveLock /* since it applies only to later
  156. * inserts */
  157. },
  158. HEAP_DEFAULT_FILLFACTOR, HEAP_MIN_FILLFACTOR, 100
  159. },
  160. {
  161. {
  162. "fillfactor",
  163. "Packs btree index pages only to this percentage",
  164. RELOPT_KIND_BTREE,
  165. ShareUpdateExclusiveLock /* since it applies only to later
  166. * inserts */
  167. },
  168. BTREE_DEFAULT_FILLFACTOR, BTREE_MIN_FILLFACTOR, 100
  169. },
  170. {
  171. {
  172. "fillfactor",
  173. "Packs hash index pages only to this percentage",
  174. RELOPT_KIND_HASH,
  175. ShareUpdateExclusiveLock /* since it applies only to later
  176. * inserts */
  177. },
  178. HASH_DEFAULT_FILLFACTOR, HASH_MIN_FILLFACTOR, 100
  179. },
  180. {
  181. {
  182. "fillfactor",
  183. "Packs gist index pages only to this percentage",
  184. RELOPT_KIND_GIST,
  185. ShareUpdateExclusiveLock /* since it applies only to later
  186. * inserts */
  187. },
  188. GIST_DEFAULT_FILLFACTOR, GIST_MIN_FILLFACTOR, 100
  189. },
  190. {
  191. {
  192. "fillfactor",
  193. "Packs spgist index pages only to this percentage",
  194. RELOPT_KIND_SPGIST,
  195. ShareUpdateExclusiveLock /* since it applies only to later
  196. * inserts */
  197. },
  198. SPGIST_DEFAULT_FILLFACTOR, SPGIST_MIN_FILLFACTOR, 100
  199. },
  200. {
  201. {
  202. "autovacuum_vacuum_threshold",
  203. "Minimum number of tuple updates or deletes prior to vacuum",
  204. RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
  205. ShareUpdateExclusiveLock
  206. },
  207. -1, 0, INT_MAX
  208. },
  209. {
  210. {
  211. "autovacuum_analyze_threshold",
  212. "Minimum number of tuple inserts, updates or deletes prior to analyze",
  213. RELOPT_KIND_HEAP,
  214. ShareUpdateExclusiveLock
  215. },
  216. -1, 0, INT_MAX
  217. },
  218. {
  219. {
  220. "autovacuum_vacuum_cost_delay",
  221. "Vacuum cost delay in milliseconds, for autovacuum",
  222. RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
  223. ShareUpdateExclusiveLock
  224. },
  225. -1, 0, 100
  226. },
  227. {
  228. {
  229. "autovacuum_vacuum_cost_limit",
  230. "Vacuum cost amount available before napping, for autovacuum",
  231. RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
  232. ShareUpdateExclusiveLock
  233. },
  234. -1, 1, 10000
  235. },
  236. {
  237. {
  238. "autovacuum_freeze_min_age",
  239. "Minimum age at which VACUUM should freeze a table row, for autovacuum",
  240. RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
  241. ShareUpdateExclusiveLock
  242. },
  243. -1, 0, 1000000000
  244. },
  245. {
  246. {
  247. "autovacuum_multixact_freeze_min_age",
  248. "Minimum multixact age at which VACUUM should freeze a row multixact's, for autovacuum",
  249. RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
  250. ShareUpdateExclusiveLock
  251. },
  252. -1, 0, 1000000000
  253. },
  254. {
  255. {
  256. "autovacuum_freeze_max_age",
  257. "Age at which to autovacuum a table to prevent transaction ID wraparound",
  258. RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
  259. ShareUpdateExclusiveLock
  260. },
  261. -1, 100000, 2000000000
  262. },
  263. {
  264. {
  265. "autovacuum_multixact_freeze_max_age",
  266. "Multixact age at which to autovacuum a table to prevent multixact wraparound",
  267. RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
  268. ShareUpdateExclusiveLock
  269. },
  270. -1, 10000, 2000000000
  271. },
  272. {
  273. {
  274. "autovacuum_freeze_table_age",
  275. "Age at which VACUUM should perform a full table sweep to freeze row versions",
  276. RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
  277. ShareUpdateExclusiveLock
  278. }, -1, 0, 2000000000
  279. },
  280. {
  281. {
  282. "autovacuum_multixact_freeze_table_age",
  283. "Age of multixact at which VACUUM should perform a full table sweep to freeze row versions",
  284. RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
  285. ShareUpdateExclusiveLock
  286. }, -1, 0, 2000000000
  287. },
  288. {
  289. {
  290. "log_autovacuum_min_duration",
  291. "Sets the minimum execution time above which autovacuum actions will be logged",
  292. RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
  293. ShareUpdateExclusiveLock
  294. },
  295. -1, -1, INT_MAX
  296. },
  297. {
  298. {
  299. "toast_tuple_target",
  300. "Sets the target tuple length at which external columns will be toasted",
  301. RELOPT_KIND_HEAP,
  302. ShareUpdateExclusiveLock
  303. },
  304. TOAST_TUPLE_TARGET, 128, TOAST_TUPLE_TARGET_MAIN
  305. },
  306. {
  307. {
  308. "pages_per_range",
  309. "Number of pages that each page range covers in a BRIN index",
  310. RELOPT_KIND_BRIN,
  311. AccessExclusiveLock
  312. }, 128, 1, 131072
  313. },
  314. {
  315. {
  316. "gin_pending_list_limit",
  317. "Maximum size of the pending list for this GIN index, in kilobytes.",
  318. RELOPT_KIND_GIN,
  319. AccessExclusiveLock
  320. },
  321. -1, 64, MAX_KILOBYTES
  322. },
  323. {
  324. {
  325. "effective_io_concurrency",
  326. "Number of simultaneous requests that can be handled efficiently by the disk subsystem.",
  327. RELOPT_KIND_TABLESPACE,
  328. ShareUpdateExclusiveLock
  329. },
  330. #ifdef USE_PREFETCH
  331. -1, 0, MAX_IO_CONCURRENCY
  332. #else
  333. 0, 0, 0
  334. #endif
  335. },
  336. {
  337. {
  338. "parallel_workers",
  339. "Number of parallel processes that can be used per executor node for this relation.",
  340. RELOPT_KIND_HEAP,
  341. ShareUpdateExclusiveLock
  342. },
  343. -1, 0, 1024
  344. },
  345. /* list terminator */
  346. {{NULL}}
  347. };
  348. static relopt_real realRelOpts[] =
  349. {
  350. {
  351. {
  352. "autovacuum_vacuum_scale_factor",
  353. "Number of tuple updates or deletes prior to vacuum as a fraction of reltuples",
  354. RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
  355. ShareUpdateExclusiveLock
  356. },
  357. -1, 0.0, 100.0
  358. },
  359. {
  360. {
  361. "autovacuum_analyze_scale_factor",
  362. "Number of tuple inserts, updates or deletes prior to analyze as a fraction of reltuples",
  363. RELOPT_KIND_HEAP,
  364. ShareUpdateExclusiveLock
  365. },
  366. -1, 0.0, 100.0
  367. },
  368. {
  369. {
  370. "seq_page_cost",
  371. "Sets the planner's estimate of the cost of a sequentially fetched disk page.",
  372. RELOPT_KIND_TABLESPACE,
  373. ShareUpdateExclusiveLock
  374. },
  375. -1, 0.0, DBL_MAX
  376. },
  377. {
  378. {
  379. "random_page_cost",
  380. "Sets the planner's estimate of the cost of a nonsequentially fetched disk page.",
  381. RELOPT_KIND_TABLESPACE,
  382. ShareUpdateExclusiveLock
  383. },
  384. -1, 0.0, DBL_MAX
  385. },
  386. {
  387. {
  388. "n_distinct",
  389. "Sets the planner's estimate of the number of distinct values appearing in a column (excluding child relations).",
  390. RELOPT_KIND_ATTRIBUTE,
  391. ShareUpdateExclusiveLock
  392. },
  393. 0, -1.0, DBL_MAX
  394. },
  395. {
  396. {
  397. "n_distinct_inherited",
  398. "Sets the planner's estimate of the number of distinct values appearing in a column (including child relations).",
  399. RELOPT_KIND_ATTRIBUTE,
  400. ShareUpdateExclusiveLock
  401. },
  402. 0, -1.0, DBL_MAX
  403. },
  404. {
  405. {
  406. "vacuum_cleanup_index_scale_factor",
  407. "Number of tuple inserts prior to index cleanup as a fraction of reltuples.",
  408. RELOPT_KIND_BTREE,
  409. ShareUpdateExclusiveLock
  410. },
  411. -1, 0.0, 1e10
  412. },
  413. /* list terminator */
  414. {{NULL}}
  415. };
  416. static relopt_string stringRelOpts[] =
  417. {
  418. {
  419. {
  420. "buffering",
  421. "Enables buffering build for this GiST index",
  422. RELOPT_KIND_GIST,
  423. AccessExclusiveLock
  424. },
  425. 4,
  426. false,
  427. gistValidateBufferingOption,
  428. "auto"
  429. },
  430. {
  431. {
  432. "check_option",
  433. "View has WITH CHECK OPTION defined (local or cascaded).",
  434. RELOPT_KIND_VIEW,
  435. AccessExclusiveLock
  436. },
  437. 0,
  438. true,
  439. validateWithCheckOption,
  440. NULL
  441. },
  442. /* list terminator */
  443. {{NULL}}
  444. };
  445. static relopt_gen **relOpts = NULL;
  446. static bits32 last_assigned_kind = RELOPT_KIND_LAST_DEFAULT;
  447. static int num_custom_options = 0;
  448. static relopt_gen **custom_options = NULL;
  449. static bool need_initialization = true;
  450. static void initialize_reloptions(void);
  451. static void parse_one_reloption(relopt_value *option, char *text_str,
  452. int text_len, bool validate);
  453. /*
  454. * initialize_reloptions
  455. * initialization routine, must be called before parsing
  456. *
  457. * Initialize the relOpts array and fill each variable's type and name length.
  458. */
  459. static void
  460. initialize_reloptions(void)
  461. {
  462. int i;
  463. int j;
  464. j = 0;
  465. for (i = 0; boolRelOpts[i].gen.name; i++)
  466. {
  467. Assert(DoLockModesConflict(boolRelOpts[i].gen.lockmode,
  468. boolRelOpts[i].gen.lockmode));
  469. j++;
  470. }
  471. for (i = 0; intRelOpts[i].gen.name; i++)
  472. {
  473. Assert(DoLockModesConflict(intRelOpts[i].gen.lockmode,
  474. intRelOpts[i].gen.lockmode));
  475. j++;
  476. }
  477. for (i = 0; realRelOpts[i].gen.name; i++)
  478. {
  479. Assert(DoLockModesConflict(realRelOpts[i].gen.lockmode,
  480. realRelOpts[i].gen.lockmode));
  481. j++;
  482. }
  483. for (i = 0; stringRelOpts[i].gen.name; i++)
  484. {
  485. Assert(DoLockModesConflict(stringRelOpts[i].gen.lockmode,
  486. stringRelOpts[i].gen.lockmode));
  487. j++;
  488. }
  489. j += num_custom_options;
  490. if (relOpts)
  491. pfree(relOpts);
  492. relOpts = MemoryContextAlloc(TopMemoryContext,
  493. (j + 1) * sizeof(relopt_gen *));
  494. j = 0;
  495. for (i = 0; boolRelOpts[i].gen.name; i++)
  496. {
  497. relOpts[j] = &boolRelOpts[i].gen;
  498. relOpts[j]->type = RELOPT_TYPE_BOOL;
  499. relOpts[j]->namelen = strlen(relOpts[j]->name);
  500. j++;
  501. }
  502. for (i = 0; intRelOpts[i].gen.name; i++)
  503. {
  504. relOpts[j] = &intRelOpts[i].gen;
  505. relOpts[j]->type = RELOPT_TYPE_INT;
  506. relOpts[j]->namelen = strlen(relOpts[j]->name);
  507. j++;
  508. }
  509. for (i = 0; realRelOpts[i].gen.name; i++)
  510. {
  511. relOpts[j] = &realRelOpts[i].gen;
  512. relOpts[j]->type = RELOPT_TYPE_REAL;
  513. relOpts[j]->namelen = strlen(relOpts[j]->name);
  514. j++;
  515. }
  516. for (i = 0; stringRelOpts[i].gen.name; i++)
  517. {
  518. relOpts[j] = &stringRelOpts[i].gen;
  519. relOpts[j]->type = RELOPT_TYPE_STRING;
  520. relOpts[j]->namelen = strlen(relOpts[j]->name);
  521. j++;
  522. }
  523. for (i = 0; i < num_custom_options; i++)
  524. {
  525. relOpts[j] = custom_options[i];
  526. j++;
  527. }
  528. /* add a list terminator */
  529. relOpts[j] = NULL;
  530. /* flag the work is complete */
  531. need_initialization = false;
  532. }
  533. /*
  534. * add_reloption_kind
  535. * Create a new relopt_kind value, to be used in custom reloptions by
  536. * user-defined AMs.
  537. */
  538. relopt_kind
  539. add_reloption_kind(void)
  540. {
  541. /* don't hand out the last bit so that the enum's behavior is portable */
  542. if (last_assigned_kind >= RELOPT_KIND_MAX)
  543. ereport(ERROR,
  544. (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
  545. errmsg("user-defined relation parameter types limit exceeded")));
  546. last_assigned_kind <<= 1;
  547. return (relopt_kind) last_assigned_kind;
  548. }
  549. /*
  550. * add_reloption
  551. * Add an already-created custom reloption to the list, and recompute the
  552. * main parser table.
  553. */
  554. static void
  555. add_reloption(relopt_gen *newoption)
  556. {
  557. static int max_custom_options = 0;
  558. if (num_custom_options >= max_custom_options)
  559. {
  560. MemoryContext oldcxt;
  561. oldcxt = MemoryContextSwitchTo(TopMemoryContext);
  562. if (max_custom_options == 0)
  563. {
  564. max_custom_options = 8;
  565. custom_options = palloc(max_custom_options * sizeof(relopt_gen *));
  566. }
  567. else
  568. {
  569. max_custom_options *= 2;
  570. custom_options = repalloc(custom_options,
  571. max_custom_options * sizeof(relopt_gen *));
  572. }
  573. MemoryContextSwitchTo(oldcxt);
  574. }
  575. custom_options[num_custom_options++] = newoption;
  576. need_initialization = true;
  577. }
  578. /*
  579. * allocate_reloption
  580. * Allocate a new reloption and initialize the type-agnostic fields
  581. * (for types other than string)
  582. */
  583. static relopt_gen *
  584. allocate_reloption(bits32 kinds, int type, const char *name, const char *desc)
  585. {
  586. MemoryContext oldcxt;
  587. size_t size;
  588. relopt_gen *newoption;
  589. oldcxt = MemoryContextSwitchTo(TopMemoryContext);
  590. switch (type)
  591. {
  592. case RELOPT_TYPE_BOOL:
  593. size = sizeof(relopt_bool);
  594. break;
  595. case RELOPT_TYPE_INT:
  596. size = sizeof(relopt_int);
  597. break;
  598. case RELOPT_TYPE_REAL:
  599. size = sizeof(relopt_real);
  600. break;
  601. case RELOPT_TYPE_STRING:
  602. size = sizeof(relopt_string);
  603. break;
  604. default:
  605. elog(ERROR, "unsupported reloption type %d", type);
  606. return NULL; /* keep compiler quiet */
  607. }
  608. newoption = palloc(size);
  609. newoption->name = pstrdup(name);
  610. if (desc)
  611. newoption->desc = pstrdup(desc);
  612. else
  613. newoption->desc = NULL;
  614. newoption->kinds = kinds;
  615. newoption->namelen = strlen(name);
  616. newoption->type = type;
  617. MemoryContextSwitchTo(oldcxt);
  618. return newoption;
  619. }
  620. /*
  621. * add_bool_reloption
  622. * Add a new boolean reloption
  623. */
  624. void
  625. add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val)
  626. {
  627. relopt_bool *newoption;
  628. newoption = (relopt_bool *) allocate_reloption(kinds, RELOPT_TYPE_BOOL,
  629. name, desc);
  630. newoption->default_val = default_val;
  631. add_reloption((relopt_gen *) newoption);
  632. }
  633. /*
  634. * add_int_reloption
  635. * Add a new integer reloption
  636. */
  637. void
  638. add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val,
  639. int min_val, int max_val)
  640. {
  641. relopt_int *newoption;
  642. newoption = (relopt_int *) allocate_reloption(kinds, RELOPT_TYPE_INT,
  643. name, desc);
  644. newoption->default_val = default_val;
  645. newoption->min = min_val;
  646. newoption->max = max_val;
  647. add_reloption((relopt_gen *) newoption);
  648. }
  649. /*
  650. * add_real_reloption
  651. * Add a new float reloption
  652. */
  653. void
  654. add_real_reloption(bits32 kinds, const char *name, const char *desc, double default_val,
  655. double min_val, double max_val)
  656. {
  657. relopt_real *newoption;
  658. newoption = (relopt_real *) allocate_reloption(kinds, RELOPT_TYPE_REAL,
  659. name, desc);
  660. newoption->default_val = default_val;
  661. newoption->min = min_val;
  662. newoption->max = max_val;
  663. add_reloption((relopt_gen *) newoption);
  664. }
  665. /*
  666. * add_string_reloption
  667. * Add a new string reloption
  668. *
  669. * "validator" is an optional function pointer that can be used to test the
  670. * validity of the values. It must elog(ERROR) when the argument string is
  671. * not acceptable for the variable. Note that the default value must pass
  672. * the validation.
  673. */
  674. void
  675. add_string_reloption(bits32 kinds, const char *name, const char *desc, const char *default_val,
  676. validate_string_relopt validator)
  677. {
  678. relopt_string *newoption;
  679. /* make sure the validator/default combination is sane */
  680. if (validator)
  681. (validator) (default_val);
  682. newoption = (relopt_string *) allocate_reloption(kinds, RELOPT_TYPE_STRING,
  683. name, desc);
  684. newoption->validate_cb = validator;
  685. if (default_val)
  686. {
  687. newoption->default_val = MemoryContextStrdup(TopMemoryContext,
  688. default_val);
  689. newoption->default_len = strlen(default_val);
  690. newoption->default_isnull = false;
  691. }
  692. else
  693. {
  694. newoption->default_val = "";
  695. newoption->default_len = 0;
  696. newoption->default_isnull = true;
  697. }
  698. add_reloption((relopt_gen *) newoption);
  699. }
  700. /*
  701. * Transform a relation options list (list of DefElem) into the text array
  702. * format that is kept in pg_class.reloptions, including only those options
  703. * that are in the passed namespace. The output values do not include the
  704. * namespace.
  705. *
  706. * This is used for three cases: CREATE TABLE/INDEX, ALTER TABLE SET, and
  707. * ALTER TABLE RESET. In the ALTER cases, oldOptions is the existing
  708. * reloptions value (possibly NULL), and we replace or remove entries
  709. * as needed.
  710. *
  711. * If acceptOidsOff is true, then we allow oids = false, but throw error when
  712. * on. This is solely needed for backwards compatibility.
  713. *
  714. * Note that this is not responsible for determining whether the options
  715. * are valid, but it does check that namespaces for all the options given are
  716. * listed in validnsps. The NULL namespace is always valid and need not be
  717. * explicitly listed. Passing a NULL pointer means that only the NULL
  718. * namespace is valid.
  719. *
  720. * Both oldOptions and the result are text arrays (or NULL for "default"),
  721. * but we declare them as Datums to avoid including array.h in reloptions.h.
  722. */
  723. Datum
  724. transformRelOptions(Datum oldOptions, List *defList, const char *namspace,
  725. char *validnsps[], bool acceptOidsOff, bool isReset)
  726. {
  727. Datum result;
  728. ArrayBuildState *astate;
  729. ListCell *cell;
  730. /* no change if empty list */
  731. if (defList == NIL)
  732. return oldOptions;
  733. /* We build new array using accumArrayResult */
  734. astate = NULL;
  735. /* Copy any oldOptions that aren't to be replaced */
  736. if (PointerIsValid(DatumGetPointer(oldOptions)))
  737. {
  738. ArrayType *array = DatumGetArrayTypeP(oldOptions);
  739. Datum *oldoptions;
  740. int noldoptions;
  741. int i;
  742. deconstruct_array(array, TEXTOID, -1, false, 'i',
  743. &oldoptions, NULL, &noldoptions);
  744. for (i = 0; i < noldoptions; i++)
  745. {
  746. char *text_str = VARDATA(oldoptions[i]);
  747. int text_len = VARSIZE(oldoptions[i]) - VARHDRSZ;
  748. /* Search for a match in defList */
  749. foreach(cell, defList)
  750. {
  751. DefElem *def = (DefElem *) lfirst(cell);
  752. int kw_len;
  753. /* ignore if not in the same namespace */
  754. if (namspace == NULL)
  755. {
  756. if (def->defnamespace != NULL)
  757. continue;
  758. }
  759. else if (def->defnamespace == NULL)
  760. continue;
  761. else if (strcmp(def->defnamespace, namspace) != 0)
  762. continue;
  763. kw_len = strlen(def->defname);
  764. if (text_len > kw_len && text_str[kw_len] == '=' &&
  765. strncmp(text_str, def->defname, kw_len) == 0)
  766. break;
  767. }
  768. if (!cell)
  769. {
  770. /* No match, so keep old option */
  771. astate = accumArrayResult(astate, oldoptions[i],
  772. false, TEXTOID,
  773. CurrentMemoryContext);
  774. }
  775. }
  776. }
  777. /*
  778. * If CREATE/SET, add new options to array; if RESET, just check that the
  779. * user didn't say RESET (option=val). (Must do this because the grammar
  780. * doesn't enforce it.)
  781. */
  782. foreach(cell, defList)
  783. {
  784. DefElem *def = (DefElem *) lfirst(cell);
  785. if (isReset)
  786. {
  787. if (def->arg != NULL)
  788. ereport(ERROR,
  789. (errcode(ERRCODE_SYNTAX_ERROR),
  790. errmsg("RESET must not include values for parameters")));
  791. }
  792. else
  793. {
  794. text *t;
  795. const char *value;
  796. Size len;
  797. /*
  798. * Error out if the namespace is not valid. A NULL namespace is
  799. * always valid.
  800. */
  801. if (def->defnamespace != NULL)
  802. {
  803. bool valid = false;
  804. int i;
  805. if (validnsps)
  806. {
  807. for (i = 0; validnsps[i]; i++)
  808. {
  809. if (strcmp(def->defnamespace, validnsps[i]) == 0)
  810. {
  811. valid = true;
  812. break;
  813. }
  814. }
  815. }
  816. if (!valid)
  817. ereport(ERROR,
  818. (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
  819. errmsg("unrecognized parameter namespace \"%s\"",
  820. def->defnamespace)));
  821. }
  822. /* ignore if not in the same namespace */
  823. if (namspace == NULL)
  824. {
  825. if (def->defnamespace != NULL)
  826. continue;
  827. }
  828. else if (def->defnamespace == NULL)
  829. continue;
  830. else if (strcmp(def->defnamespace, namspace) != 0)
  831. continue;
  832. /*
  833. * Flatten the DefElem into a text string like "name=arg". If we
  834. * have just "name", assume "name=true" is meant. Note: the
  835. * namespace is not output.
  836. */
  837. if (def->arg != NULL)
  838. value = defGetString(def);
  839. else
  840. value = "true";
  841. /*
  842. * This is not a great place for this test, but there's no other
  843. * convenient place to filter the option out. As WITH (oids =
  844. * false) will be removed someday, this seems like an acceptable
  845. * amount of ugly.
  846. */
  847. if (acceptOidsOff && def->defnamespace == NULL &&
  848. strcmp(def->defname, "oids") == 0)
  849. {
  850. if (defGetBoolean(def))
  851. ereport(ERROR,
  852. (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
  853. errmsg("tables declared WITH OIDS are not supported")));
  854. /* skip over option, reloptions machinery doesn't know it */
  855. continue;
  856. }
  857. len = VARHDRSZ + strlen(def->defname) + 1 + strlen(value);
  858. /* +1 leaves room for sprintf's trailing null */
  859. t = (text *) palloc(len + 1);
  860. SET_VARSIZE(t, len);
  861. sprintf(VARDATA(t), "%s=%s", def->defname, value);
  862. astate = accumArrayResult(astate, PointerGetDatum(t),
  863. false, TEXTOID,
  864. CurrentMemoryContext);
  865. }
  866. }
  867. if (astate)
  868. result = makeArrayResult(astate, CurrentMemoryContext);
  869. else
  870. result = (Datum) 0;
  871. return result;
  872. }
  873. /*
  874. * Convert the text-array format of reloptions into a List of DefElem.
  875. * This is the inverse of transformRelOptions().
  876. */
  877. List *
  878. untransformRelOptions(Datum options)
  879. {
  880. List *result = NIL;
  881. ArrayType *array;
  882. Datum *optiondatums;
  883. int noptions;
  884. int i;
  885. /* Nothing to do if no options */
  886. if (!PointerIsValid(DatumGetPointer(options)))
  887. return result;
  888. array = DatumGetArrayTypeP(options);
  889. deconstruct_array(array, TEXTOID, -1, false, 'i',
  890. &optiondatums, NULL, &noptions);
  891. for (i = 0; i < noptions; i++)
  892. {
  893. char *s;
  894. char *p;
  895. Node *val = NULL;
  896. s = TextDatumGetCString(optiondatums[i]);
  897. p = strchr(s, '=');
  898. if (p)
  899. {
  900. *p++ = '\0';
  901. val = (Node *) makeString(pstrdup(p));
  902. }
  903. result = lappend(result, makeDefElem(pstrdup(s), val, -1));
  904. }
  905. return result;
  906. }
  907. /*
  908. * Extract and parse reloptions from a pg_class tuple.
  909. *
  910. * This is a low-level routine, expected to be used by relcache code and
  911. * callers that do not have a table's relcache entry (e.g. autovacuum). For
  912. * other uses, consider grabbing the rd_options pointer from the relcache entry
  913. * instead.
  914. *
  915. * tupdesc is pg_class' tuple descriptor. amoptions is a pointer to the index
  916. * AM's options parser function in the case of a tuple corresponding to an
  917. * index, or NULL otherwise.
  918. */
  919. bytea *
  920. extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
  921. amoptions_function amoptions)
  922. {
  923. bytea *options;
  924. bool isnull;
  925. Datum datum;
  926. Form_pg_class classForm;
  927. datum = fastgetattr(tuple,
  928. Anum_pg_class_reloptions,
  929. tupdesc,
  930. &isnull);
  931. if (isnull)
  932. return NULL;
  933. classForm = (Form_pg_class) GETSTRUCT(tuple);
  934. /* Parse into appropriate format; don't error out here */
  935. switch (classForm->relkind)
  936. {
  937. case RELKIND_RELATION:
  938. case RELKIND_TOASTVALUE:
  939. case RELKIND_MATVIEW:
  940. case RELKIND_PARTITIONED_TABLE:
  941. options = heap_reloptions(classForm->relkind, datum, false);
  942. break;
  943. case RELKIND_VIEW:
  944. options = view_reloptions(datum, false);
  945. break;
  946. case RELKIND_INDEX:
  947. case RELKIND_PARTITIONED_INDEX:
  948. options = index_reloptions(amoptions, datum, false);
  949. break;
  950. case RELKIND_FOREIGN_TABLE:
  951. options = NULL;
  952. break;
  953. default:
  954. Assert(false); /* can't get here */
  955. options = NULL; /* keep compiler quiet */
  956. break;
  957. }
  958. return options;
  959. }
  960. /*
  961. * Interpret reloptions that are given in text-array format.
  962. *
  963. * options is a reloption text array as constructed by transformRelOptions.
  964. * kind specifies the family of options to be processed.
  965. *
  966. * The return value is a relopt_value * array on which the options actually
  967. * set in the options array are marked with isset=true. The length of this
  968. * array is returned in *numrelopts. Options not set are also present in the
  969. * array; this is so that the caller can easily locate the default values.
  970. *
  971. * If there are no options of the given kind, numrelopts is set to 0 and NULL
  972. * is returned (unless options are illegally supplied despite none being
  973. * defined, in which case an error occurs).
  974. *
  975. * Note: values of type int, bool and real are allocated as part of the
  976. * returned array. Values of type string are allocated separately and must
  977. * be freed by the caller.
  978. */
  979. relopt_value *
  980. parseRelOptions(Datum options, bool validate, relopt_kind kind,
  981. int *numrelopts)
  982. {
  983. relopt_value *reloptions = NULL;
  984. int numoptions = 0;
  985. int i;
  986. int j;
  987. if (need_initialization)
  988. initialize_reloptions();
  989. /* Build a list of expected options, based on kind */
  990. for (i = 0; relOpts[i]; i++)
  991. if (relOpts[i]->kinds & kind)
  992. numoptions++;
  993. if (numoptions > 0)
  994. {
  995. reloptions = palloc(numoptions * sizeof(relopt_value));
  996. for (i = 0, j = 0; relOpts[i]; i++)
  997. {
  998. if (relOpts[i]->kinds & kind)
  999. {
  1000. reloptions[j].gen = relOpts[i];
  1001. reloptions[j].isset = false;
  1002. j++;
  1003. }
  1004. }
  1005. }
  1006. /* Done if no options */
  1007. if (PointerIsValid(DatumGetPointer(options)))
  1008. {
  1009. ArrayType *array = DatumGetArrayTypeP(options);
  1010. Datum *optiondatums;
  1011. int noptions;
  1012. deconstruct_array(array, TEXTOID, -1, false, 'i',
  1013. &optiondatums, NULL, &noptions);
  1014. for (i = 0; i < noptions; i++)
  1015. {
  1016. char *text_str = VARDATA(optiondatums[i]);
  1017. int text_len = VARSIZE(optiondatums[i]) - VARHDRSZ;
  1018. int j;
  1019. /* Search for a match in reloptions */
  1020. for (j = 0; j < numoptions; j++)
  1021. {
  1022. int kw_len = reloptions[j].gen->namelen;
  1023. if (text_len > kw_len && text_str[kw_len] == '=' &&
  1024. strncmp(text_str, reloptions[j].gen->name, kw_len) == 0)
  1025. {
  1026. parse_one_reloption(&reloptions[j], text_str, text_len,
  1027. validate);
  1028. break;
  1029. }
  1030. }
  1031. if (j >= numoptions && validate)
  1032. {
  1033. char *s;
  1034. char *p;
  1035. s = TextDatumGetCString(optiondatums[i]);
  1036. p = strchr(s, '=');
  1037. if (p)
  1038. *p = '\0';
  1039. ereport(ERROR,
  1040. (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
  1041. errmsg("unrecognized parameter \"%s\"", s)));
  1042. }
  1043. }
  1044. /* It's worth avoiding memory leaks in this function */
  1045. pfree(optiondatums);
  1046. if (((void *) array) != DatumGetPointer(options))
  1047. pfree(array);
  1048. }
  1049. *numrelopts = numoptions;
  1050. return reloptions;
  1051. }
  1052. /*
  1053. * Subroutine for parseRelOptions, to parse and validate a single option's
  1054. * value
  1055. */
  1056. static void
  1057. parse_one_reloption(relopt_value *option, char *text_str, int text_len,
  1058. bool validate)
  1059. {
  1060. char *value;
  1061. int value_len;
  1062. bool parsed;
  1063. bool nofree = false;
  1064. if (option->isset && validate)
  1065. ereport(ERROR,
  1066. (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
  1067. errmsg("parameter \"%s\" specified more than once",
  1068. option->gen->name)));
  1069. value_len = text_len - option->gen->namelen - 1;
  1070. value = (char *) palloc(value_len + 1);
  1071. memcpy(value, text_str + option->gen->namelen + 1, value_len);
  1072. value[value_len] = '\0';
  1073. switch (option->gen->type)
  1074. {
  1075. case RELOPT_TYPE_BOOL:
  1076. {
  1077. parsed = parse_bool(value, &option->values.bool_val);
  1078. if (validate && !parsed)
  1079. ereport(ERROR,
  1080. (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
  1081. errmsg("invalid value for boolean option \"%s\": %s",
  1082. option->gen->name, value)));
  1083. }
  1084. break;
  1085. case RELOPT_TYPE_INT:
  1086. {
  1087. relopt_int *optint = (relopt_int *) option->gen;
  1088. parsed = parse_int(value, &option->values.int_val, 0, NULL);
  1089. if (validate && !parsed)
  1090. ereport(ERROR,
  1091. (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
  1092. errmsg("invalid value for integer option \"%s\": %s",
  1093. option->gen->name, value)));
  1094. if (validate && (option->values.int_val < optint->min ||
  1095. option->values.int_val > optint->max))
  1096. ereport(ERROR,
  1097. (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
  1098. errmsg("value %s out of bounds for option \"%s\"",
  1099. value, option->gen->name),
  1100. errdetail("Valid values are between \"%d\" and \"%d\".",
  1101. optint->min, optint->max)));
  1102. }
  1103. break;
  1104. case RELOPT_TYPE_REAL:
  1105. {
  1106. relopt_real *optreal = (relopt_real *) option->gen;
  1107. parsed = parse_real(value, &option->values.real_val);
  1108. if (validate && !parsed)
  1109. ereport(ERROR,
  1110. (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
  1111. errmsg("invalid value for floating point option \"%s\": %s",
  1112. option->gen->name, value)));
  1113. if (validate && (option->values.real_val < optreal->min ||
  1114. option->values.real_val > optreal->max))
  1115. ereport(ERROR,
  1116. (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
  1117. errmsg("value %s out of bounds for option \"%s\"",
  1118. value, option->gen->name),
  1119. errdetail("Valid values are between \"%f\" and \"%f\".",
  1120. optreal->min, optreal->max)));
  1121. }
  1122. break;
  1123. case RELOPT_TYPE_STRING:
  1124. {
  1125. relopt_string *optstring = (relopt_string *) option->gen;
  1126. option->values.string_val = value;
  1127. nofree = true;
  1128. if (validate && optstring->validate_cb)
  1129. (optstring->validate_cb) (value);
  1130. parsed = true;
  1131. }
  1132. break;
  1133. default:
  1134. elog(ERROR, "unsupported reloption type %d", option->gen->type);
  1135. parsed = true; /* quiet compiler */
  1136. break;
  1137. }
  1138. if (parsed)
  1139. option->isset = true;
  1140. if (!nofree)
  1141. pfree(value);
  1142. }
  1143. /*
  1144. * Given the result from parseRelOptions, allocate a struct that's of the
  1145. * specified base size plus any extra space that's needed for string variables.
  1146. *
  1147. * "base" should be sizeof(struct) of the reloptions struct (StdRdOptions or
  1148. * equivalent).
  1149. */
  1150. void *
  1151. allocateReloptStruct(Size base, relopt_value *options, int numoptions)
  1152. {
  1153. Size size = base;
  1154. int i;
  1155. for (i = 0; i < numoptions; i++)
  1156. if (options[i].gen->type == RELOPT_TYPE_STRING)
  1157. size += GET_STRING_RELOPTION_LEN(options[i]) + 1;
  1158. return palloc0(size);
  1159. }
  1160. /*
  1161. * Given the result of parseRelOptions and a parsing table, fill in the
  1162. * struct (previously allocated with allocateReloptStruct) with the parsed
  1163. * values.
  1164. *
  1165. * rdopts is the pointer to the allocated struct to be filled.
  1166. * basesize is the sizeof(struct) that was passed to allocateReloptStruct.
  1167. * options, of length numoptions, is parseRelOptions' output.
  1168. * elems, of length numelems, is the table describing the allowed options.
  1169. * When validate is true, it is expected that all options appear in elems.
  1170. */
  1171. void
  1172. fillRelOptions(void *rdopts, Size basesize,
  1173. relopt_value *options, int numoptions,
  1174. bool validate,
  1175. const relopt_parse_elt *elems, int numelems)
  1176. {
  1177. int i;
  1178. int offset = basesize;
  1179. for (i = 0; i < numoptions; i++)
  1180. {
  1181. int j;
  1182. bool found = false;
  1183. for (j = 0; j < numelems; j++)
  1184. {
  1185. if (strcmp(options[i].gen->name, elems[j].optname) == 0)
  1186. {
  1187. relopt_string *optstring;
  1188. char *itempos = ((char *) rdopts) + elems[j].offset;
  1189. char *string_val;
  1190. switch (options[i].gen->type)
  1191. {
  1192. case RELOPT_TYPE_BOOL:
  1193. *(bool *) itempos = options[i].isset ?
  1194. options[i].values.bool_val :
  1195. ((relopt_bool *) options[i].gen)->default_val;
  1196. break;
  1197. case RELOPT_TYPE_INT:
  1198. *(int *) itempos = options[i].isset ?
  1199. options[i].values.int_val :
  1200. ((relopt_int *) options[i].gen)->default_val;
  1201. break;
  1202. case RELOPT_TYPE_REAL:
  1203. *(double *) itempos = options[i].isset ?
  1204. options[i].values.real_val :
  1205. ((relopt_real *) options[i].gen)->default_val;
  1206. break;
  1207. case RELOPT_TYPE_STRING:
  1208. optstring = (relopt_string *) options[i].gen;
  1209. if (options[i].isset)
  1210. string_val = options[i].values.string_val;
  1211. else if (!optstring->default_isnull)
  1212. string_val = optstring->default_val;
  1213. else
  1214. string_val = NULL;
  1215. if (string_val == NULL)
  1216. *(int *) itempos = 0;
  1217. else
  1218. {
  1219. strcpy((char *) rdopts + offset, string_val);
  1220. *(int *) itempos = offset;
  1221. offset += strlen(string_val) + 1;
  1222. }
  1223. break;
  1224. default:
  1225. elog(ERROR, "unsupported reloption type %d",
  1226. options[i].gen->type);
  1227. break;
  1228. }
  1229. found = true;
  1230. break;
  1231. }
  1232. }
  1233. if (validate && !found && options[i].gen->kinds != RELOPT_KIND_INDEX)
  1234. elog(ERROR, "reloption \"%s\" not found in parse table",
  1235. options[i].gen->name);
  1236. }
  1237. SET_VARSIZE(rdopts, offset);
  1238. }
  1239. /*
  1240. * Option parser for anything that uses StdRdOptions.
  1241. */
  1242. bytea *
  1243. default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
  1244. {
  1245. relopt_value *options;
  1246. StdRdOptions *rdopts;
  1247. int numoptions;
  1248. static const relopt_parse_elt tab[] = {
  1249. {"fillfactor", RELOPT_TYPE_INT, offsetof(StdRdOptions, fillfactor)},
  1250. {"autovacuum_enabled", RELOPT_TYPE_BOOL,
  1251. offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, enabled)},
  1252. {"autovacuum_vacuum_threshold", RELOPT_TYPE_INT,
  1253. offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_threshold)},
  1254. {"autovacuum_analyze_threshold", RELOPT_TYPE_INT,
  1255. offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, analyze_threshold)},
  1256. {"autovacuum_vacuum_cost_delay", RELOPT_TYPE_INT,
  1257. offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_cost_delay)},
  1258. {"autovacuum_vacuum_cost_limit", RELOPT_TYPE_INT,
  1259. offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_cost_limit)},
  1260. {"autovacuum_freeze_min_age", RELOPT_TYPE_INT,
  1261. offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, freeze_min_age)},
  1262. {"autovacuum_freeze_max_age", RELOPT_TYPE_INT,
  1263. offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, freeze_max_age)},
  1264. {"autovacuum_freeze_table_age", RELOPT_TYPE_INT,
  1265. offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, freeze_table_age)},
  1266. {"autovacuum_multixact_freeze_min_age", RELOPT_TYPE_INT,
  1267. offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, multixact_freeze_min_age)},
  1268. {"autovacuum_multixact_freeze_max_age", RELOPT_TYPE_INT,
  1269. offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, multixact_freeze_max_age)},
  1270. {"autovacuum_multixact_freeze_table_age", RELOPT_TYPE_INT,
  1271. offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, multixact_freeze_table_age)},
  1272. {"log_autovacuum_min_duration", RELOPT_TYPE_INT,
  1273. offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, log_min_duration)},
  1274. {"toast_tuple_target", RELOPT_TYPE_INT,
  1275. offsetof(StdRdOptions, toast_tuple_target)},
  1276. {"autovacuum_vacuum_scale_factor", RELOPT_TYPE_REAL,
  1277. offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_scale_factor)},
  1278. {"autovacuum_analyze_scale_factor", RELOPT_TYPE_REAL,
  1279. offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, analyze_scale_factor)},
  1280. {"user_catalog_table", RELOPT_TYPE_BOOL,
  1281. offsetof(StdRdOptions, user_catalog_table)},
  1282. {"parallel_workers", RELOPT_TYPE_INT,
  1283. offsetof(StdRdOptions, parallel_workers)},
  1284. {"vacuum_cleanup_index_scale_factor", RELOPT_TYPE_REAL,
  1285. offsetof(StdRdOptions, vacuum_cleanup_index_scale_factor)}
  1286. };
  1287. options = parseRelOptions(reloptions, validate, kind, &numoptions);
  1288. /* if none set, we're done */
  1289. if (numoptions == 0)
  1290. return NULL;
  1291. rdopts = allocateReloptStruct(sizeof(StdRdOptions), options, numoptions);
  1292. fillRelOptions((void *) rdopts, sizeof(StdRdOptions), options, numoptions,
  1293. validate, tab, lengthof(tab));
  1294. pfree(options);
  1295. return (bytea *) rdopts;
  1296. }
  1297. /*
  1298. * Option parser for views
  1299. */
  1300. bytea *
  1301. view_reloptions(Datum reloptions, bool validate)
  1302. {
  1303. relopt_value *options;
  1304. ViewOptions *vopts;
  1305. int numoptions;
  1306. static const relopt_parse_elt tab[] = {
  1307. {"security_barrier", RELOPT_TYPE_BOOL,
  1308. offsetof(ViewOptions, security_barrier)},
  1309. {"check_option", RELOPT_TYPE_STRING,
  1310. offsetof(ViewOptions, check_option_offset)}
  1311. };
  1312. options = parseRelOptions(reloptions, validate, RELOPT_KIND_VIEW, &numoptions);
  1313. /* if none set, we're done */
  1314. if (numoptions == 0)
  1315. return NULL;
  1316. vopts = allocateReloptStruct(sizeof(ViewOptions), options, numoptions);
  1317. fillRelOptions((void *) vopts, sizeof(ViewOptions), options, numoptions,
  1318. validate, tab, lengthof(tab));
  1319. pfree(options);
  1320. return (bytea *) vopts;
  1321. }
  1322. /*
  1323. * Parse options for heaps, views and toast tables.
  1324. */
  1325. bytea *
  1326. heap_reloptions(char relkind, Datum reloptions, bool validate)
  1327. {
  1328. StdRdOptions *rdopts;
  1329. switch (relkind)
  1330. {
  1331. case RELKIND_TOASTVALUE:
  1332. rdopts = (StdRdOptions *)
  1333. default_reloptions(reloptions, validate, RELOPT_KIND_TOAST);
  1334. if (rdopts != NULL)
  1335. {
  1336. /* adjust default-only parameters for TOAST relations */
  1337. rdopts->fillfactor = 100;
  1338. rdopts->autovacuum.analyze_threshold = -1;
  1339. rdopts->autovacuum.analyze_scale_factor = -1;
  1340. }
  1341. return (bytea *) rdopts;
  1342. case RELKIND_RELATION:
  1343. case RELKIND_MATVIEW:
  1344. return default_reloptions(reloptions, validate, RELOPT_KIND_HEAP);
  1345. case RELKIND_PARTITIONED_TABLE:
  1346. return default_reloptions(reloptions, validate,
  1347. RELOPT_KIND_PARTITIONED);
  1348. default:
  1349. /* other relkinds are not supported */
  1350. return NULL;
  1351. }
  1352. }
  1353. /*
  1354. * Parse options for indexes.
  1355. *
  1356. * amoptions index AM's option parser function
  1357. * reloptions options as text[] datum
  1358. * validate error flag
  1359. */
  1360. bytea *
  1361. index_reloptions(amoptions_function amoptions, Datum reloptions, bool validate)
  1362. {
  1363. Assert(amoptions != NULL);
  1364. /* Assume function is strict */
  1365. if (!PointerIsValid(DatumGetPointer(reloptions)))
  1366. return NULL;
  1367. return amoptions(reloptions, validate);
  1368. }
  1369. /*
  1370. * Parse generic options for all indexes.
  1371. *
  1372. * reloptions options as text[] datum
  1373. * validate error flag
  1374. */
  1375. bytea *
  1376. index_generic_reloptions(Datum reloptions, bool validate)
  1377. {
  1378. int numoptions;
  1379. GenericIndexOpts *idxopts;
  1380. relopt_value *options;
  1381. static const relopt_parse_elt tab[] = {
  1382. {"recheck_on_update", RELOPT_TYPE_BOOL, offsetof(GenericIndexOpts, recheck_on_update)}
  1383. };
  1384. options = parseRelOptions(reloptions, validate,
  1385. RELOPT_KIND_INDEX,
  1386. &numoptions);
  1387. /* if none set, we're done */
  1388. if (numoptions == 0)
  1389. return NULL;
  1390. idxopts = allocateReloptStruct(sizeof(GenericIndexOpts), options, numoptions);
  1391. fillRelOptions((void *) idxopts, sizeof(GenericIndexOpts), options, numoptions,
  1392. validate, tab, lengthof(tab));
  1393. pfree(options);
  1394. return (bytea *) idxopts;
  1395. }
  1396. /*
  1397. * Option parser for attribute reloptions
  1398. */
  1399. bytea *
  1400. attribute_reloptions(Datum reloptions, bool validate)
  1401. {
  1402. relopt_value *options;
  1403. AttributeOpts *aopts;
  1404. int numoptions;
  1405. static const relopt_parse_elt tab[] = {
  1406. {"n_distinct", RELOPT_TYPE_REAL, offsetof(AttributeOpts, n_distinct)},
  1407. {"n_distinct_inherited", RELOPT_TYPE_REAL, offsetof(AttributeOpts, n_distinct_inherited)}
  1408. };
  1409. options = parseRelOptions(reloptions, validate, RELOPT_KIND_ATTRIBUTE,
  1410. &numoptions);
  1411. /* if none set, we're done */
  1412. if (numoptions == 0)
  1413. return NULL;
  1414. aopts = allocateReloptStruct(sizeof(AttributeOpts), options, numoptions);
  1415. fillRelOptions((void *) aopts, sizeof(AttributeOpts), options, numoptions,
  1416. validate, tab, lengthof(tab));
  1417. pfree(options);
  1418. return (bytea *) aopts;
  1419. }
  1420. /*
  1421. * Option parser for tablespace reloptions
  1422. */
  1423. bytea *
  1424. tablespace_reloptions(Datum reloptions, bool validate)
  1425. {
  1426. relopt_value *options;
  1427. TableSpaceOpts *tsopts;
  1428. int numoptions;
  1429. static const relopt_parse_elt tab[] = {
  1430. {"random_page_cost", RELOPT_TYPE_REAL, offsetof(TableSpaceOpts, random_page_cost)},
  1431. {"seq_page_cost", RELOPT_TYPE_REAL, offsetof(TableSpaceOpts, seq_page_cost)},
  1432. {"effective_io_concurrency", RELOPT_TYPE_INT, offsetof(TableSpaceOpts, effective_io_concurrency)}
  1433. };
  1434. options = parseRelOptions(reloptions, validate, RELOPT_KIND_TABLESPACE,
  1435. &numoptions);
  1436. /* if none set, we're done */
  1437. if (numoptions == 0)
  1438. return NULL;
  1439. tsopts = allocateReloptStruct(sizeof(TableSpaceOpts), options, numoptions);
  1440. fillRelOptions((void *) tsopts, sizeof(TableSpaceOpts), options, numoptions,
  1441. validate, tab, lengthof(tab));
  1442. pfree(options);
  1443. return (bytea *) tsopts;
  1444. }
  1445. /*
  1446. * Determine the required LOCKMODE from an option list.
  1447. *
  1448. * Called from AlterTableGetLockLevel(), see that function
  1449. * for a longer explanation of how this works.
  1450. */
  1451. LOCKMODE
  1452. AlterTableGetRelOptionsLockLevel(List *defList)
  1453. {
  1454. LOCKMODE lockmode = NoLock;
  1455. ListCell *cell;
  1456. if (defList == NIL)
  1457. return AccessExclusiveLock;
  1458. if (need_initialization)
  1459. initialize_reloptions();
  1460. foreach(cell, defList)
  1461. {
  1462. DefElem *def = (DefElem *) lfirst(cell);
  1463. int i;
  1464. for (i = 0; relOpts[i]; i++)
  1465. {
  1466. if (strncmp(relOpts[i]->name,
  1467. def->defname,
  1468. relOpts[i]->namelen + 1) == 0)
  1469. {
  1470. if (lockmode < relOpts[i]->lockmode)
  1471. lockmode = relOpts[i]->lockmode;
  1472. }
  1473. }
  1474. }
  1475. return lockmode;
  1476. }