00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "postgres.h"
00028
00029 #include <sys/file.h>
00030 #include <fcntl.h>
00031 #include <unistd.h>
00032
00033 #include "access/htup_details.h"
00034 #include "access/multixact.h"
00035 #include "access/reloptions.h"
00036 #include "access/sysattr.h"
00037 #include "access/transam.h"
00038 #include "access/xact.h"
00039 #include "catalog/catalog.h"
00040 #include "catalog/heap.h"
00041 #include "catalog/index.h"
00042 #include "catalog/indexing.h"
00043 #include "catalog/namespace.h"
00044 #include "catalog/pg_amproc.h"
00045 #include "catalog/pg_attrdef.h"
00046 #include "catalog/pg_authid.h"
00047 #include "catalog/pg_auth_members.h"
00048 #include "catalog/pg_constraint.h"
00049 #include "catalog/pg_database.h"
00050 #include "catalog/pg_namespace.h"
00051 #include "catalog/pg_opclass.h"
00052 #include "catalog/pg_proc.h"
00053 #include "catalog/pg_rewrite.h"
00054 #include "catalog/pg_tablespace.h"
00055 #include "catalog/pg_trigger.h"
00056 #include "catalog/pg_type.h"
00057 #include "catalog/schemapg.h"
00058 #include "catalog/storage.h"
00059 #include "commands/trigger.h"
00060 #include "common/relpath.h"
00061 #include "miscadmin.h"
00062 #include "optimizer/clauses.h"
00063 #include "optimizer/planmain.h"
00064 #include "optimizer/prep.h"
00065 #include "optimizer/var.h"
00066 #include "rewrite/rewriteDefine.h"
00067 #include "storage/lmgr.h"
00068 #include "storage/smgr.h"
00069 #include "utils/array.h"
00070 #include "utils/builtins.h"
00071 #include "utils/fmgroids.h"
00072 #include "utils/inval.h"
00073 #include "utils/lsyscache.h"
00074 #include "utils/memutils.h"
00075 #include "utils/relmapper.h"
00076 #include "utils/resowner_private.h"
00077 #include "utils/syscache.h"
00078 #include "utils/tqual.h"
00079
00080
00081
00082
00083
00084 #define RELCACHE_INIT_FILENAME "pg_internal.init"
00085
00086 #define RELCACHE_INIT_FILEMAGIC 0x573266
00087
00088
00089
00090
00091 static const FormData_pg_attribute Desc_pg_class[Natts_pg_class] = {Schema_pg_class};
00092 static const FormData_pg_attribute Desc_pg_attribute[Natts_pg_attribute] = {Schema_pg_attribute};
00093 static const FormData_pg_attribute Desc_pg_proc[Natts_pg_proc] = {Schema_pg_proc};
00094 static const FormData_pg_attribute Desc_pg_type[Natts_pg_type] = {Schema_pg_type};
00095 static const FormData_pg_attribute Desc_pg_database[Natts_pg_database] = {Schema_pg_database};
00096 static const FormData_pg_attribute Desc_pg_authid[Natts_pg_authid] = {Schema_pg_authid};
00097 static const FormData_pg_attribute Desc_pg_auth_members[Natts_pg_auth_members] = {Schema_pg_auth_members};
00098 static const FormData_pg_attribute Desc_pg_index[Natts_pg_index] = {Schema_pg_index};
00099
00100
00101
00102
00103
00104
00105
00106 typedef struct relidcacheent
00107 {
00108 Oid reloid;
00109 Relation reldesc;
00110 } RelIdCacheEnt;
00111
00112 static HTAB *RelationIdCache;
00113
00114
00115
00116
00117
00118 bool criticalRelcachesBuilt = false;
00119
00120
00121
00122
00123
00124 bool criticalSharedRelcachesBuilt = false;
00125
00126
00127
00128
00129
00130
00131
00132 static long relcacheInvalsReceived = 0L;
00133
00134
00135
00136
00137
00138
00139
00140 static List *initFileRelationIds = NIL;
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152 #define MAX_EOXACT_LIST 32
00153 static Oid eoxact_list[MAX_EOXACT_LIST];
00154 static int eoxact_list_len = 0;
00155 static bool eoxact_list_overflowed = false;
00156
00157 #define EOXactListAdd(rel) \
00158 do { \
00159 if (eoxact_list_len < MAX_EOXACT_LIST) \
00160 eoxact_list[eoxact_list_len++] = (rel)->rd_id; \
00161 else \
00162 eoxact_list_overflowed = true; \
00163 } while (0)
00164
00165
00166
00167
00168
00169 #define RelationCacheInsert(RELATION) \
00170 do { \
00171 RelIdCacheEnt *idhentry; bool found; \
00172 idhentry = (RelIdCacheEnt*)hash_search(RelationIdCache, \
00173 (void *) &(RELATION->rd_id), \
00174 HASH_ENTER, &found); \
00175 \
00176 idhentry->reldesc = RELATION; \
00177 } while(0)
00178
00179 #define RelationIdCacheLookup(ID, RELATION) \
00180 do { \
00181 RelIdCacheEnt *hentry; \
00182 hentry = (RelIdCacheEnt*)hash_search(RelationIdCache, \
00183 (void *) &(ID), \
00184 HASH_FIND, NULL); \
00185 if (hentry) \
00186 RELATION = hentry->reldesc; \
00187 else \
00188 RELATION = NULL; \
00189 } while(0)
00190
00191 #define RelationCacheDelete(RELATION) \
00192 do { \
00193 RelIdCacheEnt *idhentry; \
00194 idhentry = (RelIdCacheEnt*)hash_search(RelationIdCache, \
00195 (void *) &(RELATION->rd_id), \
00196 HASH_REMOVE, NULL); \
00197 if (idhentry == NULL) \
00198 elog(WARNING, "trying to delete a rd_id reldesc that does not exist"); \
00199 } while(0)
00200
00201
00202
00203
00204
00205
00206
00207
00208 typedef struct opclasscacheent
00209 {
00210 Oid opclassoid;
00211 bool valid;
00212 StrategyNumber numSupport;
00213 Oid opcfamily;
00214 Oid opcintype;
00215 RegProcedure *supportProcs;
00216 } OpClassCacheEnt;
00217
00218 static HTAB *OpClassCache = NULL;
00219
00220
00221
00222
00223 static void RelationDestroyRelation(Relation relation);
00224 static void RelationClearRelation(Relation relation, bool rebuild);
00225
00226 static void RelationReloadIndexInfo(Relation relation);
00227 static void RelationFlushRelation(Relation relation);
00228 static void AtEOXact_cleanup(Relation relation, bool isCommit);
00229 static void AtEOSubXact_cleanup(Relation relation, bool isCommit,
00230 SubTransactionId mySubid, SubTransactionId parentSubid);
00231 static bool load_relcache_init_file(bool shared);
00232 static void write_relcache_init_file(bool shared);
00233 static void write_item(const void *data, Size len, FILE *fp);
00234
00235 static void formrdesc(const char *relationName, Oid relationReltype,
00236 bool isshared, bool hasoids,
00237 int natts, const FormData_pg_attribute *attrs);
00238
00239 static HeapTuple ScanPgRelation(Oid targetRelId, bool indexOK);
00240 static Relation AllocateRelationDesc(Form_pg_class relp);
00241 static void RelationParseRelOptions(Relation relation, HeapTuple tuple);
00242 static void RelationBuildTupleDesc(Relation relation);
00243 static Relation RelationBuildDesc(Oid targetRelId, bool insertIt);
00244 static void RelationInitPhysicalAddr(Relation relation);
00245 static void load_critical_index(Oid indexoid, Oid heapoid);
00246 static TupleDesc GetPgClassDescriptor(void);
00247 static TupleDesc GetPgIndexDescriptor(void);
00248 static void AttrDefaultFetch(Relation relation);
00249 static void CheckConstraintFetch(Relation relation);
00250 static List *insert_ordered_oid(List *list, Oid datum);
00251 static void IndexSupportInitialize(oidvector *indclass,
00252 RegProcedure *indexSupport,
00253 Oid *opFamily,
00254 Oid *opcInType,
00255 StrategyNumber maxSupportNumber,
00256 AttrNumber maxAttributeNumber);
00257 static OpClassCacheEnt *LookupOpclassInfo(Oid operatorClassOid,
00258 StrategyNumber numSupport);
00259 static void RelationCacheInitFileRemoveInDir(const char *tblspcpath);
00260 static void unlink_initfile(const char *initfilename);
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275 static HeapTuple
00276 ScanPgRelation(Oid targetRelId, bool indexOK)
00277 {
00278 HeapTuple pg_class_tuple;
00279 Relation pg_class_desc;
00280 SysScanDesc pg_class_scan;
00281 ScanKeyData key[1];
00282
00283
00284
00285
00286
00287
00288
00289 if (!OidIsValid(MyDatabaseId))
00290 elog(FATAL, "cannot read pg_class without having selected a database");
00291
00292
00293
00294
00295 ScanKeyInit(&key[0],
00296 ObjectIdAttributeNumber,
00297 BTEqualStrategyNumber, F_OIDEQ,
00298 ObjectIdGetDatum(targetRelId));
00299
00300
00301
00302
00303
00304
00305
00306 pg_class_desc = heap_open(RelationRelationId, AccessShareLock);
00307 pg_class_scan = systable_beginscan(pg_class_desc, ClassOidIndexId,
00308 indexOK && criticalRelcachesBuilt,
00309 SnapshotNow,
00310 1, key);
00311
00312 pg_class_tuple = systable_getnext(pg_class_scan);
00313
00314
00315
00316
00317 if (HeapTupleIsValid(pg_class_tuple))
00318 pg_class_tuple = heap_copytuple(pg_class_tuple);
00319
00320
00321 systable_endscan(pg_class_scan);
00322 heap_close(pg_class_desc, AccessShareLock);
00323
00324 return pg_class_tuple;
00325 }
00326
00327
00328
00329
00330
00331
00332
00333 static Relation
00334 AllocateRelationDesc(Form_pg_class relp)
00335 {
00336 Relation relation;
00337 MemoryContext oldcxt;
00338 Form_pg_class relationForm;
00339
00340
00341 oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
00342
00343
00344
00345
00346 relation = (Relation) palloc0(sizeof(RelationData));
00347
00348
00349 relation->rd_smgr = NULL;
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363 relationForm = (Form_pg_class) palloc(CLASS_TUPLE_SIZE);
00364
00365 memcpy(relationForm, relp, CLASS_TUPLE_SIZE);
00366
00367
00368 relation->rd_rel = relationForm;
00369
00370
00371 relation->rd_att = CreateTemplateTupleDesc(relationForm->relnatts,
00372 relationForm->relhasoids);
00373
00374 relation->rd_att->tdrefcount = 1;
00375
00376 MemoryContextSwitchTo(oldcxt);
00377
00378 return relation;
00379 }
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389 static void
00390 RelationParseRelOptions(Relation relation, HeapTuple tuple)
00391 {
00392 bytea *options;
00393
00394 relation->rd_options = NULL;
00395
00396
00397 switch (relation->rd_rel->relkind)
00398 {
00399 case RELKIND_RELATION:
00400 case RELKIND_TOASTVALUE:
00401 case RELKIND_INDEX:
00402 case RELKIND_VIEW:
00403 case RELKIND_MATVIEW:
00404 break;
00405 default:
00406 return;
00407 }
00408
00409
00410
00411
00412
00413
00414 options = extractRelOptions(tuple,
00415 GetPgClassDescriptor(),
00416 relation->rd_rel->relkind == RELKIND_INDEX ?
00417 relation->rd_am->amoptions : InvalidOid);
00418
00419
00420
00421
00422
00423
00424
00425 if (options)
00426 {
00427 relation->rd_options = MemoryContextAlloc(CacheMemoryContext,
00428 VARSIZE(options));
00429 memcpy(relation->rd_options, options, VARSIZE(options));
00430 pfree(options);
00431 }
00432 }
00433
00434
00435
00436
00437
00438
00439
00440 static void
00441 RelationBuildTupleDesc(Relation relation)
00442 {
00443 HeapTuple pg_attribute_tuple;
00444 Relation pg_attribute_desc;
00445 SysScanDesc pg_attribute_scan;
00446 ScanKeyData skey[2];
00447 int need;
00448 TupleConstr *constr;
00449 AttrDefault *attrdef = NULL;
00450 int ndef = 0;
00451
00452
00453 relation->rd_att->tdtypeid = relation->rd_rel->reltype;
00454 relation->rd_att->tdtypmod = -1;
00455 relation->rd_att->tdhasoid = relation->rd_rel->relhasoids;
00456
00457 constr = (TupleConstr *) MemoryContextAlloc(CacheMemoryContext,
00458 sizeof(TupleConstr));
00459 constr->has_not_null = false;
00460
00461
00462
00463
00464
00465
00466 ScanKeyInit(&skey[0],
00467 Anum_pg_attribute_attrelid,
00468 BTEqualStrategyNumber, F_OIDEQ,
00469 ObjectIdGetDatum(RelationGetRelid(relation)));
00470 ScanKeyInit(&skey[1],
00471 Anum_pg_attribute_attnum,
00472 BTGreaterStrategyNumber, F_INT2GT,
00473 Int16GetDatum(0));
00474
00475
00476
00477
00478
00479
00480 pg_attribute_desc = heap_open(AttributeRelationId, AccessShareLock);
00481 pg_attribute_scan = systable_beginscan(pg_attribute_desc,
00482 AttributeRelidNumIndexId,
00483 criticalRelcachesBuilt,
00484 SnapshotNow,
00485 2, skey);
00486
00487
00488
00489
00490 need = relation->rd_rel->relnatts;
00491
00492 while (HeapTupleIsValid(pg_attribute_tuple = systable_getnext(pg_attribute_scan)))
00493 {
00494 Form_pg_attribute attp;
00495
00496 attp = (Form_pg_attribute) GETSTRUCT(pg_attribute_tuple);
00497
00498 if (attp->attnum <= 0 ||
00499 attp->attnum > relation->rd_rel->relnatts)
00500 elog(ERROR, "invalid attribute number %d for %s",
00501 attp->attnum, RelationGetRelationName(relation));
00502
00503 memcpy(relation->rd_att->attrs[attp->attnum - 1],
00504 attp,
00505 ATTRIBUTE_FIXED_PART_SIZE);
00506
00507
00508 if (attp->attnotnull)
00509 constr->has_not_null = true;
00510
00511 if (attp->atthasdef)
00512 {
00513 if (attrdef == NULL)
00514 attrdef = (AttrDefault *)
00515 MemoryContextAllocZero(CacheMemoryContext,
00516 relation->rd_rel->relnatts *
00517 sizeof(AttrDefault));
00518 attrdef[ndef].adnum = attp->attnum;
00519 attrdef[ndef].adbin = NULL;
00520 ndef++;
00521 }
00522 need--;
00523 if (need == 0)
00524 break;
00525 }
00526
00527
00528
00529
00530 systable_endscan(pg_attribute_scan);
00531 heap_close(pg_attribute_desc, AccessShareLock);
00532
00533 if (need != 0)
00534 elog(ERROR, "catalog is missing %d attribute(s) for relid %u",
00535 need, RelationGetRelid(relation));
00536
00537
00538
00539
00540
00541
00542 #ifdef USE_ASSERT_CHECKING
00543 {
00544 int i;
00545
00546 for (i = 0; i < relation->rd_rel->relnatts; i++)
00547 Assert(relation->rd_att->attrs[i]->attcacheoff == -1);
00548 }
00549 #endif
00550
00551
00552
00553
00554
00555
00556 if (relation->rd_rel->relnatts > 0)
00557 relation->rd_att->attrs[0]->attcacheoff = 0;
00558
00559
00560
00561
00562 if (constr->has_not_null || ndef > 0 || relation->rd_rel->relchecks)
00563 {
00564 relation->rd_att->constr = constr;
00565
00566 if (ndef > 0)
00567 {
00568 if (ndef < relation->rd_rel->relnatts)
00569 constr->defval = (AttrDefault *)
00570 repalloc(attrdef, ndef * sizeof(AttrDefault));
00571 else
00572 constr->defval = attrdef;
00573 constr->num_defval = ndef;
00574 AttrDefaultFetch(relation);
00575 }
00576 else
00577 constr->num_defval = 0;
00578
00579 if (relation->rd_rel->relchecks > 0)
00580 {
00581 constr->num_check = relation->rd_rel->relchecks;
00582 constr->check = (ConstrCheck *)
00583 MemoryContextAllocZero(CacheMemoryContext,
00584 constr->num_check * sizeof(ConstrCheck));
00585 CheckConstraintFetch(relation);
00586 }
00587 else
00588 constr->num_check = 0;
00589 }
00590 else
00591 {
00592 pfree(constr);
00593 relation->rd_att->constr = NULL;
00594 }
00595 }
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612 static void
00613 RelationBuildRuleLock(Relation relation)
00614 {
00615 MemoryContext rulescxt;
00616 MemoryContext oldcxt;
00617 HeapTuple rewrite_tuple;
00618 Relation rewrite_desc;
00619 TupleDesc rewrite_tupdesc;
00620 SysScanDesc rewrite_scan;
00621 ScanKeyData key;
00622 RuleLock *rulelock;
00623 int numlocks;
00624 RewriteRule **rules;
00625 int maxlocks;
00626
00627
00628
00629
00630
00631 rulescxt = AllocSetContextCreate(CacheMemoryContext,
00632 RelationGetRelationName(relation),
00633 ALLOCSET_SMALL_MINSIZE,
00634 ALLOCSET_SMALL_INITSIZE,
00635 ALLOCSET_SMALL_MAXSIZE);
00636 relation->rd_rulescxt = rulescxt;
00637
00638
00639
00640
00641
00642 maxlocks = 4;
00643 rules = (RewriteRule **)
00644 MemoryContextAlloc(rulescxt, sizeof(RewriteRule *) * maxlocks);
00645 numlocks = 0;
00646
00647
00648
00649
00650 ScanKeyInit(&key,
00651 Anum_pg_rewrite_ev_class,
00652 BTEqualStrategyNumber, F_OIDEQ,
00653 ObjectIdGetDatum(RelationGetRelid(relation)));
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663 rewrite_desc = heap_open(RewriteRelationId, AccessShareLock);
00664 rewrite_tupdesc = RelationGetDescr(rewrite_desc);
00665 rewrite_scan = systable_beginscan(rewrite_desc,
00666 RewriteRelRulenameIndexId,
00667 true, SnapshotNow,
00668 1, &key);
00669
00670 while (HeapTupleIsValid(rewrite_tuple = systable_getnext(rewrite_scan)))
00671 {
00672 Form_pg_rewrite rewrite_form = (Form_pg_rewrite) GETSTRUCT(rewrite_tuple);
00673 bool isnull;
00674 Datum rule_datum;
00675 char *rule_str;
00676 RewriteRule *rule;
00677
00678 rule = (RewriteRule *) MemoryContextAlloc(rulescxt,
00679 sizeof(RewriteRule));
00680
00681 rule->ruleId = HeapTupleGetOid(rewrite_tuple);
00682
00683 rule->event = rewrite_form->ev_type - '0';
00684 rule->attrno = rewrite_form->ev_attr;
00685 rule->enabled = rewrite_form->ev_enabled;
00686 rule->isInstead = rewrite_form->is_instead;
00687
00688
00689
00690
00691
00692
00693
00694 rule_datum = heap_getattr(rewrite_tuple,
00695 Anum_pg_rewrite_ev_action,
00696 rewrite_tupdesc,
00697 &isnull);
00698 Assert(!isnull);
00699 rule_str = TextDatumGetCString(rule_datum);
00700 oldcxt = MemoryContextSwitchTo(rulescxt);
00701 rule->actions = (List *) stringToNode(rule_str);
00702 MemoryContextSwitchTo(oldcxt);
00703 pfree(rule_str);
00704
00705 rule_datum = heap_getattr(rewrite_tuple,
00706 Anum_pg_rewrite_ev_qual,
00707 rewrite_tupdesc,
00708 &isnull);
00709 Assert(!isnull);
00710 rule_str = TextDatumGetCString(rule_datum);
00711 oldcxt = MemoryContextSwitchTo(rulescxt);
00712 rule->qual = (Node *) stringToNode(rule_str);
00713 MemoryContextSwitchTo(oldcxt);
00714 pfree(rule_str);
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729 setRuleCheckAsUser((Node *) rule->actions, relation->rd_rel->relowner);
00730 setRuleCheckAsUser(rule->qual, relation->rd_rel->relowner);
00731
00732 if (numlocks >= maxlocks)
00733 {
00734 maxlocks *= 2;
00735 rules = (RewriteRule **)
00736 repalloc(rules, sizeof(RewriteRule *) * maxlocks);
00737 }
00738 rules[numlocks++] = rule;
00739 }
00740
00741
00742
00743
00744 systable_endscan(rewrite_scan);
00745 heap_close(rewrite_desc, AccessShareLock);
00746
00747
00748
00749
00750 if (numlocks == 0)
00751 {
00752 relation->rd_rules = NULL;
00753 relation->rd_rulescxt = NULL;
00754 MemoryContextDelete(rulescxt);
00755 return;
00756 }
00757
00758
00759
00760
00761 rulelock = (RuleLock *) MemoryContextAlloc(rulescxt, sizeof(RuleLock));
00762 rulelock->numLocks = numlocks;
00763 rulelock->rules = rules;
00764
00765 relation->rd_rules = rulelock;
00766 }
00767
00768
00769
00770
00771
00772
00773
00774
00775 static bool
00776 equalRuleLocks(RuleLock *rlock1, RuleLock *rlock2)
00777 {
00778 int i;
00779
00780
00781
00782
00783
00784
00785 if (rlock1 != NULL)
00786 {
00787 if (rlock2 == NULL)
00788 return false;
00789 if (rlock1->numLocks != rlock2->numLocks)
00790 return false;
00791 for (i = 0; i < rlock1->numLocks; i++)
00792 {
00793 RewriteRule *rule1 = rlock1->rules[i];
00794 RewriteRule *rule2 = rlock2->rules[i];
00795
00796 if (rule1->ruleId != rule2->ruleId)
00797 return false;
00798 if (rule1->event != rule2->event)
00799 return false;
00800 if (rule1->attrno != rule2->attrno)
00801 return false;
00802 if (rule1->enabled != rule2->enabled)
00803 return false;
00804 if (rule1->isInstead != rule2->isInstead)
00805 return false;
00806 if (!equal(rule1->qual, rule2->qual))
00807 return false;
00808 if (!equal(rule1->actions, rule2->actions))
00809 return false;
00810 }
00811 }
00812 else if (rlock2 != NULL)
00813 return false;
00814 return true;
00815 }
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827
00828
00829
00830 static Relation
00831 RelationBuildDesc(Oid targetRelId, bool insertIt)
00832 {
00833 Relation relation;
00834 Oid relid;
00835 HeapTuple pg_class_tuple;
00836 Form_pg_class relp;
00837
00838
00839
00840
00841 pg_class_tuple = ScanPgRelation(targetRelId, true);
00842
00843
00844
00845
00846 if (!HeapTupleIsValid(pg_class_tuple))
00847 return NULL;
00848
00849
00850
00851
00852 relid = HeapTupleGetOid(pg_class_tuple);
00853 relp = (Form_pg_class) GETSTRUCT(pg_class_tuple);
00854 Assert(relid == targetRelId);
00855
00856
00857
00858
00859
00860 relation = AllocateRelationDesc(relp);
00861
00862
00863
00864
00865 RelationGetRelid(relation) = relid;
00866
00867
00868
00869
00870
00871
00872 relation->rd_refcnt = 0;
00873 relation->rd_isnailed = false;
00874 relation->rd_createSubid = InvalidSubTransactionId;
00875 relation->rd_newRelfilenodeSubid = InvalidSubTransactionId;
00876 switch (relation->rd_rel->relpersistence)
00877 {
00878 case RELPERSISTENCE_UNLOGGED:
00879 case RELPERSISTENCE_PERMANENT:
00880 relation->rd_backend = InvalidBackendId;
00881 relation->rd_islocaltemp = false;
00882 break;
00883 case RELPERSISTENCE_TEMP:
00884 if (isTempOrToastNamespace(relation->rd_rel->relnamespace))
00885 {
00886 relation->rd_backend = MyBackendId;
00887 relation->rd_islocaltemp = true;
00888 }
00889 else
00890 {
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900
00901
00902
00903
00904 relation->rd_backend =
00905 GetTempNamespaceBackendId(relation->rd_rel->relnamespace);
00906 Assert(relation->rd_backend != InvalidBackendId);
00907 relation->rd_islocaltemp = false;
00908 }
00909 break;
00910 default:
00911 elog(ERROR, "invalid relpersistence: %c",
00912 relation->rd_rel->relpersistence);
00913 break;
00914 }
00915
00916
00917
00918
00919 RelationBuildTupleDesc(relation);
00920
00921
00922
00923
00924 if (relation->rd_rel->relhasrules)
00925 RelationBuildRuleLock(relation);
00926 else
00927 {
00928 relation->rd_rules = NULL;
00929 relation->rd_rulescxt = NULL;
00930 }
00931
00932 if (relation->rd_rel->relhastriggers)
00933 RelationBuildTriggers(relation);
00934 else
00935 relation->trigdesc = NULL;
00936
00937
00938
00939
00940 if (OidIsValid(relation->rd_rel->relam))
00941 RelationInitIndexAccessInfo(relation);
00942
00943
00944 RelationParseRelOptions(relation, pg_class_tuple);
00945
00946
00947
00948
00949 RelationInitLockInfo(relation);
00950
00951
00952
00953
00954 RelationInitPhysicalAddr(relation);
00955
00956
00957 relation->rd_smgr = NULL;
00958
00959 if (relation->rd_rel->relkind == RELKIND_MATVIEW &&
00960 heap_is_matview_init_state(relation))
00961 relation->rd_ispopulated = false;
00962 else
00963 relation->rd_ispopulated = true;
00964
00965
00966
00967
00968 heap_freetuple(pg_class_tuple);
00969
00970
00971
00972
00973 if (insertIt)
00974 RelationCacheInsert(relation);
00975
00976
00977 relation->rd_isvalid = true;
00978
00979 return relation;
00980 }
00981
00982
00983
00984
00985
00986
00987
00988
00989 static void
00990 RelationInitPhysicalAddr(Relation relation)
00991 {
00992 if (relation->rd_rel->reltablespace)
00993 relation->rd_node.spcNode = relation->rd_rel->reltablespace;
00994 else
00995 relation->rd_node.spcNode = MyDatabaseTableSpace;
00996 if (relation->rd_node.spcNode == GLOBALTABLESPACE_OID)
00997 relation->rd_node.dbNode = InvalidOid;
00998 else
00999 relation->rd_node.dbNode = MyDatabaseId;
01000 if (relation->rd_rel->relfilenode)
01001 relation->rd_node.relNode = relation->rd_rel->relfilenode;
01002 else
01003 {
01004
01005 relation->rd_node.relNode =
01006 RelationMapOidToFilenode(relation->rd_id,
01007 relation->rd_rel->relisshared);
01008 if (!OidIsValid(relation->rd_node.relNode))
01009 elog(ERROR, "could not find relation mapping for relation \"%s\", OID %u",
01010 RelationGetRelationName(relation), relation->rd_id);
01011 }
01012 }
01013
01014
01015
01016
01017 void
01018 RelationInitIndexAccessInfo(Relation relation)
01019 {
01020 HeapTuple tuple;
01021 Form_pg_am aform;
01022 Datum indcollDatum;
01023 Datum indclassDatum;
01024 Datum indoptionDatum;
01025 bool isnull;
01026 oidvector *indcoll;
01027 oidvector *indclass;
01028 int2vector *indoption;
01029 MemoryContext indexcxt;
01030 MemoryContext oldcontext;
01031 int natts;
01032 uint16 amsupport;
01033
01034
01035
01036
01037
01038
01039 tuple = SearchSysCache1(INDEXRELID,
01040 ObjectIdGetDatum(RelationGetRelid(relation)));
01041 if (!HeapTupleIsValid(tuple))
01042 elog(ERROR, "cache lookup failed for index %u",
01043 RelationGetRelid(relation));
01044 oldcontext = MemoryContextSwitchTo(CacheMemoryContext);
01045 relation->rd_indextuple = heap_copytuple(tuple);
01046 relation->rd_index = (Form_pg_index) GETSTRUCT(relation->rd_indextuple);
01047 MemoryContextSwitchTo(oldcontext);
01048 ReleaseSysCache(tuple);
01049
01050
01051
01052
01053 tuple = SearchSysCache1(AMOID, ObjectIdGetDatum(relation->rd_rel->relam));
01054 if (!HeapTupleIsValid(tuple))
01055 elog(ERROR, "cache lookup failed for access method %u",
01056 relation->rd_rel->relam);
01057 aform = (Form_pg_am) MemoryContextAlloc(CacheMemoryContext, sizeof *aform);
01058 memcpy(aform, GETSTRUCT(tuple), sizeof *aform);
01059 ReleaseSysCache(tuple);
01060 relation->rd_am = aform;
01061
01062 natts = relation->rd_rel->relnatts;
01063 if (natts != relation->rd_index->indnatts)
01064 elog(ERROR, "relnatts disagrees with indnatts for index %u",
01065 RelationGetRelid(relation));
01066 amsupport = aform->amsupport;
01067
01068
01069
01070
01071
01072
01073
01074
01075
01076 indexcxt = AllocSetContextCreate(CacheMemoryContext,
01077 RelationGetRelationName(relation),
01078 ALLOCSET_SMALL_MINSIZE,
01079 ALLOCSET_SMALL_INITSIZE,
01080 ALLOCSET_SMALL_MAXSIZE);
01081 relation->rd_indexcxt = indexcxt;
01082
01083
01084
01085
01086 relation->rd_aminfo = (RelationAmInfo *)
01087 MemoryContextAllocZero(indexcxt, sizeof(RelationAmInfo));
01088
01089 relation->rd_opfamily = (Oid *)
01090 MemoryContextAllocZero(indexcxt, natts * sizeof(Oid));
01091 relation->rd_opcintype = (Oid *)
01092 MemoryContextAllocZero(indexcxt, natts * sizeof(Oid));
01093
01094 if (amsupport > 0)
01095 {
01096 int nsupport = natts * amsupport;
01097
01098 relation->rd_support = (RegProcedure *)
01099 MemoryContextAllocZero(indexcxt, nsupport * sizeof(RegProcedure));
01100 relation->rd_supportinfo = (FmgrInfo *)
01101 MemoryContextAllocZero(indexcxt, nsupport * sizeof(FmgrInfo));
01102 }
01103 else
01104 {
01105 relation->rd_support = NULL;
01106 relation->rd_supportinfo = NULL;
01107 }
01108
01109 relation->rd_indcollation = (Oid *)
01110 MemoryContextAllocZero(indexcxt, natts * sizeof(Oid));
01111
01112 relation->rd_indoption = (int16 *)
01113 MemoryContextAllocZero(indexcxt, natts * sizeof(int16));
01114
01115
01116
01117
01118
01119
01120 indcollDatum = fastgetattr(relation->rd_indextuple,
01121 Anum_pg_index_indcollation,
01122 GetPgIndexDescriptor(),
01123 &isnull);
01124 Assert(!isnull);
01125 indcoll = (oidvector *) DatumGetPointer(indcollDatum);
01126 memcpy(relation->rd_indcollation, indcoll->values, natts * sizeof(Oid));
01127
01128
01129
01130
01131
01132
01133 indclassDatum = fastgetattr(relation->rd_indextuple,
01134 Anum_pg_index_indclass,
01135 GetPgIndexDescriptor(),
01136 &isnull);
01137 Assert(!isnull);
01138 indclass = (oidvector *) DatumGetPointer(indclassDatum);
01139
01140
01141
01142
01143
01144
01145 IndexSupportInitialize(indclass, relation->rd_support,
01146 relation->rd_opfamily, relation->rd_opcintype,
01147 amsupport, natts);
01148
01149
01150
01151
01152 indoptionDatum = fastgetattr(relation->rd_indextuple,
01153 Anum_pg_index_indoption,
01154 GetPgIndexDescriptor(),
01155 &isnull);
01156 Assert(!isnull);
01157 indoption = (int2vector *) DatumGetPointer(indoptionDatum);
01158 memcpy(relation->rd_indoption, indoption->values, natts * sizeof(int16));
01159
01160
01161
01162
01163 relation->rd_indexprs = NIL;
01164 relation->rd_indpred = NIL;
01165 relation->rd_exclops = NULL;
01166 relation->rd_exclprocs = NULL;
01167 relation->rd_exclstrats = NULL;
01168 relation->rd_amcache = NULL;
01169 }
01170
01171
01172
01173
01174
01175
01176
01177
01178
01179
01180
01181
01182
01183
01184 static void
01185 IndexSupportInitialize(oidvector *indclass,
01186 RegProcedure *indexSupport,
01187 Oid *opFamily,
01188 Oid *opcInType,
01189 StrategyNumber maxSupportNumber,
01190 AttrNumber maxAttributeNumber)
01191 {
01192 int attIndex;
01193
01194 for (attIndex = 0; attIndex < maxAttributeNumber; attIndex++)
01195 {
01196 OpClassCacheEnt *opcentry;
01197
01198 if (!OidIsValid(indclass->values[attIndex]))
01199 elog(ERROR, "bogus pg_index tuple");
01200
01201
01202 opcentry = LookupOpclassInfo(indclass->values[attIndex],
01203 maxSupportNumber);
01204
01205
01206 opFamily[attIndex] = opcentry->opcfamily;
01207 opcInType[attIndex] = opcentry->opcintype;
01208 if (maxSupportNumber > 0)
01209 memcpy(&indexSupport[attIndex * maxSupportNumber],
01210 opcentry->supportProcs,
01211 maxSupportNumber * sizeof(RegProcedure));
01212 }
01213 }
01214
01215
01216
01217
01218
01219
01220
01221
01222
01223
01224
01225
01226
01227
01228
01229
01230
01231
01232
01233
01234
01235 static OpClassCacheEnt *
01236 LookupOpclassInfo(Oid operatorClassOid,
01237 StrategyNumber numSupport)
01238 {
01239 OpClassCacheEnt *opcentry;
01240 bool found;
01241 Relation rel;
01242 SysScanDesc scan;
01243 ScanKeyData skey[3];
01244 HeapTuple htup;
01245 bool indexOK;
01246
01247 if (OpClassCache == NULL)
01248 {
01249
01250 HASHCTL ctl;
01251
01252 MemSet(&ctl, 0, sizeof(ctl));
01253 ctl.keysize = sizeof(Oid);
01254 ctl.entrysize = sizeof(OpClassCacheEnt);
01255 ctl.hash = oid_hash;
01256 OpClassCache = hash_create("Operator class cache", 64,
01257 &ctl, HASH_ELEM | HASH_FUNCTION);
01258
01259
01260 if (!CacheMemoryContext)
01261 CreateCacheMemoryContext();
01262 }
01263
01264 opcentry = (OpClassCacheEnt *) hash_search(OpClassCache,
01265 (void *) &operatorClassOid,
01266 HASH_ENTER, &found);
01267
01268 if (!found)
01269 {
01270
01271 opcentry->valid = false;
01272 opcentry->numSupport = numSupport;
01273
01274 if (numSupport > 0)
01275 opcentry->supportProcs = (RegProcedure *)
01276 MemoryContextAllocZero(CacheMemoryContext,
01277 numSupport * sizeof(RegProcedure));
01278 else
01279 opcentry->supportProcs = NULL;
01280 }
01281 else
01282 {
01283 Assert(numSupport == opcentry->numSupport);
01284 }
01285
01286
01287
01288
01289
01290
01291
01292
01293 #if defined(CLOBBER_CACHE_ALWAYS)
01294 opcentry->valid = false;
01295 #endif
01296
01297 if (opcentry->valid)
01298 return opcentry;
01299
01300
01301
01302
01303
01304
01305
01306
01307 indexOK = criticalRelcachesBuilt ||
01308 (operatorClassOid != OID_BTREE_OPS_OID &&
01309 operatorClassOid != INT2_BTREE_OPS_OID);
01310
01311
01312
01313
01314
01315
01316
01317 ScanKeyInit(&skey[0],
01318 ObjectIdAttributeNumber,
01319 BTEqualStrategyNumber, F_OIDEQ,
01320 ObjectIdGetDatum(operatorClassOid));
01321 rel = heap_open(OperatorClassRelationId, AccessShareLock);
01322 scan = systable_beginscan(rel, OpclassOidIndexId, indexOK,
01323 SnapshotNow, 1, skey);
01324
01325 if (HeapTupleIsValid(htup = systable_getnext(scan)))
01326 {
01327 Form_pg_opclass opclassform = (Form_pg_opclass) GETSTRUCT(htup);
01328
01329 opcentry->opcfamily = opclassform->opcfamily;
01330 opcentry->opcintype = opclassform->opcintype;
01331 }
01332 else
01333 elog(ERROR, "could not find tuple for opclass %u", operatorClassOid);
01334
01335 systable_endscan(scan);
01336 heap_close(rel, AccessShareLock);
01337
01338
01339
01340
01341
01342 if (numSupport > 0)
01343 {
01344 ScanKeyInit(&skey[0],
01345 Anum_pg_amproc_amprocfamily,
01346 BTEqualStrategyNumber, F_OIDEQ,
01347 ObjectIdGetDatum(opcentry->opcfamily));
01348 ScanKeyInit(&skey[1],
01349 Anum_pg_amproc_amproclefttype,
01350 BTEqualStrategyNumber, F_OIDEQ,
01351 ObjectIdGetDatum(opcentry->opcintype));
01352 ScanKeyInit(&skey[2],
01353 Anum_pg_amproc_amprocrighttype,
01354 BTEqualStrategyNumber, F_OIDEQ,
01355 ObjectIdGetDatum(opcentry->opcintype));
01356 rel = heap_open(AccessMethodProcedureRelationId, AccessShareLock);
01357 scan = systable_beginscan(rel, AccessMethodProcedureIndexId, indexOK,
01358 SnapshotNow, 3, skey);
01359
01360 while (HeapTupleIsValid(htup = systable_getnext(scan)))
01361 {
01362 Form_pg_amproc amprocform = (Form_pg_amproc) GETSTRUCT(htup);
01363
01364 if (amprocform->amprocnum <= 0 ||
01365 (StrategyNumber) amprocform->amprocnum > numSupport)
01366 elog(ERROR, "invalid amproc number %d for opclass %u",
01367 amprocform->amprocnum, operatorClassOid);
01368
01369 opcentry->supportProcs[amprocform->amprocnum - 1] =
01370 amprocform->amproc;
01371 }
01372
01373 systable_endscan(scan);
01374 heap_close(rel, AccessShareLock);
01375 }
01376
01377 opcentry->valid = true;
01378 return opcentry;
01379 }
01380
01381
01382
01383
01384
01385
01386
01387
01388
01389
01390
01391
01392
01393
01394
01395
01396
01397
01398
01399
01400
01401
01402
01403
01404 static void
01405 formrdesc(const char *relationName, Oid relationReltype,
01406 bool isshared, bool hasoids,
01407 int natts, const FormData_pg_attribute *attrs)
01408 {
01409 Relation relation;
01410 int i;
01411 bool has_not_null;
01412
01413
01414
01415
01416 relation = (Relation) palloc0(sizeof(RelationData));
01417
01418
01419 relation->rd_smgr = NULL;
01420
01421
01422
01423
01424 relation->rd_refcnt = 1;
01425
01426
01427
01428
01429
01430 relation->rd_isnailed = true;
01431 relation->rd_createSubid = InvalidSubTransactionId;
01432 relation->rd_newRelfilenodeSubid = InvalidSubTransactionId;
01433 relation->rd_backend = InvalidBackendId;
01434 relation->rd_islocaltemp = false;
01435
01436
01437
01438
01439
01440
01441
01442
01443
01444
01445 relation->rd_rel = (Form_pg_class) palloc0(CLASS_TUPLE_SIZE);
01446
01447 namestrcpy(&relation->rd_rel->relname, relationName);
01448 relation->rd_rel->relnamespace = PG_CATALOG_NAMESPACE;
01449 relation->rd_rel->reltype = relationReltype;
01450
01451
01452
01453
01454
01455 relation->rd_rel->relisshared = isshared;
01456 if (isshared)
01457 relation->rd_rel->reltablespace = GLOBALTABLESPACE_OID;
01458
01459
01460 relation->rd_rel->relpersistence = RELPERSISTENCE_PERMANENT;
01461
01462 relation->rd_rel->relpages = 0;
01463 relation->rd_rel->reltuples = 0;
01464 relation->rd_rel->relallvisible = 0;
01465 relation->rd_rel->relkind = RELKIND_RELATION;
01466 relation->rd_rel->relhasoids = hasoids;
01467 relation->rd_rel->relnatts = (int16) natts;
01468
01469
01470
01471
01472
01473
01474
01475
01476 relation->rd_att = CreateTemplateTupleDesc(natts, hasoids);
01477 relation->rd_att->tdrefcount = 1;
01478
01479 relation->rd_att->tdtypeid = relationReltype;
01480 relation->rd_att->tdtypmod = -1;
01481
01482
01483
01484
01485 has_not_null = false;
01486 for (i = 0; i < natts; i++)
01487 {
01488 memcpy(relation->rd_att->attrs[i],
01489 &attrs[i],
01490 ATTRIBUTE_FIXED_PART_SIZE);
01491 has_not_null |= attrs[i].attnotnull;
01492
01493 relation->rd_att->attrs[i]->attcacheoff = -1;
01494 }
01495
01496
01497 relation->rd_att->attrs[0]->attcacheoff = 0;
01498
01499
01500 if (has_not_null)
01501 {
01502 TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr));
01503
01504 constr->has_not_null = true;
01505 relation->rd_att->constr = constr;
01506 }
01507
01508
01509
01510
01511 RelationGetRelid(relation) = relation->rd_att->attrs[0]->attrelid;
01512
01513
01514
01515
01516
01517
01518
01519 relation->rd_rel->relfilenode = InvalidOid;
01520 if (IsBootstrapProcessingMode())
01521 RelationMapUpdateMap(RelationGetRelid(relation),
01522 RelationGetRelid(relation),
01523 isshared, true);
01524
01525
01526
01527
01528 RelationInitLockInfo(relation);
01529
01530
01531
01532
01533 RelationInitPhysicalAddr(relation);
01534 relation->rd_ispopulated = true;
01535
01536
01537
01538
01539 if (IsBootstrapProcessingMode())
01540 {
01541
01542 relation->rd_rel->relhasindex = false;
01543 }
01544 else
01545 {
01546
01547 relation->rd_rel->relhasindex = true;
01548 }
01549
01550
01551
01552
01553 RelationCacheInsert(relation);
01554
01555
01556 relation->rd_isvalid = true;
01557 }
01558
01559
01560
01561
01562
01563
01564
01565
01566
01567
01568
01569
01570
01571
01572
01573
01574
01575
01576
01577
01578
01579
01580
01581 Relation
01582 RelationIdGetRelation(Oid relationId)
01583 {
01584 Relation rd;
01585
01586
01587
01588
01589 RelationIdCacheLookup(relationId, rd);
01590
01591 if (RelationIsValid(rd))
01592 {
01593 RelationIncrementReferenceCount(rd);
01594
01595 if (!rd->rd_isvalid)
01596 {
01597
01598
01599
01600
01601
01602 if (rd->rd_rel->relkind == RELKIND_INDEX)
01603 RelationReloadIndexInfo(rd);
01604 else
01605 RelationClearRelation(rd, true);
01606 }
01607 return rd;
01608 }
01609
01610
01611
01612
01613
01614 rd = RelationBuildDesc(relationId, true);
01615 if (RelationIsValid(rd))
01616 RelationIncrementReferenceCount(rd);
01617 return rd;
01618 }
01619
01620
01621
01622
01623
01624
01625
01626
01627
01628
01629
01630
01631
01632
01633 void
01634 RelationIncrementReferenceCount(Relation rel)
01635 {
01636 ResourceOwnerEnlargeRelationRefs(CurrentResourceOwner);
01637 rel->rd_refcnt += 1;
01638 if (!IsBootstrapProcessingMode())
01639 ResourceOwnerRememberRelationRef(CurrentResourceOwner, rel);
01640 }
01641
01642
01643
01644
01645
01646 void
01647 RelationDecrementReferenceCount(Relation rel)
01648 {
01649 Assert(rel->rd_refcnt > 0);
01650 rel->rd_refcnt -= 1;
01651 if (!IsBootstrapProcessingMode())
01652 ResourceOwnerForgetRelationRef(CurrentResourceOwner, rel);
01653 }
01654
01655
01656
01657
01658
01659
01660
01661
01662
01663
01664
01665
01666 void
01667 RelationClose(Relation relation)
01668 {
01669
01670 RelationDecrementReferenceCount(relation);
01671
01672 #ifdef RELCACHE_FORCE_RELEASE
01673 if (RelationHasReferenceCountZero(relation) &&
01674 relation->rd_createSubid == InvalidSubTransactionId &&
01675 relation->rd_newRelfilenodeSubid == InvalidSubTransactionId)
01676 RelationClearRelation(relation, false);
01677 #endif
01678 }
01679
01680
01681
01682
01683
01684
01685
01686
01687
01688
01689
01690
01691
01692
01693
01694
01695
01696
01697
01698
01699
01700
01701
01702
01703
01704
01705
01706
01707 static void
01708 RelationReloadIndexInfo(Relation relation)
01709 {
01710 bool indexOK;
01711 HeapTuple pg_class_tuple;
01712 Form_pg_class relp;
01713
01714
01715 Assert(relation->rd_rel->relkind == RELKIND_INDEX &&
01716 !relation->rd_isvalid);
01717
01718 Assert(relation->rd_smgr == NULL);
01719
01720
01721 if (relation->rd_amcache)
01722 pfree(relation->rd_amcache);
01723 relation->rd_amcache = NULL;
01724
01725
01726
01727
01728
01729
01730
01731
01732 if (relation->rd_rel->relisshared && !criticalRelcachesBuilt)
01733 {
01734 relation->rd_isvalid = true;
01735 return;
01736 }
01737
01738
01739
01740
01741
01742
01743
01744 indexOK = (RelationGetRelid(relation) != ClassOidIndexId);
01745 pg_class_tuple = ScanPgRelation(RelationGetRelid(relation), indexOK);
01746 if (!HeapTupleIsValid(pg_class_tuple))
01747 elog(ERROR, "could not find pg_class tuple for index %u",
01748 RelationGetRelid(relation));
01749 relp = (Form_pg_class) GETSTRUCT(pg_class_tuple);
01750 memcpy(relation->rd_rel, relp, CLASS_TUPLE_SIZE);
01751
01752 if (relation->rd_options)
01753 pfree(relation->rd_options);
01754 RelationParseRelOptions(relation, pg_class_tuple);
01755
01756 heap_freetuple(pg_class_tuple);
01757
01758 RelationInitPhysicalAddr(relation);
01759 relation->rd_ispopulated = true;
01760
01761
01762
01763
01764
01765
01766
01767
01768
01769 if (!IsSystemRelation(relation))
01770 {
01771 HeapTuple tuple;
01772 Form_pg_index index;
01773
01774 tuple = SearchSysCache1(INDEXRELID,
01775 ObjectIdGetDatum(RelationGetRelid(relation)));
01776 if (!HeapTupleIsValid(tuple))
01777 elog(ERROR, "cache lookup failed for index %u",
01778 RelationGetRelid(relation));
01779 index = (Form_pg_index) GETSTRUCT(tuple);
01780
01781
01782
01783
01784
01785
01786
01787 relation->rd_index->indisunique = index->indisunique;
01788 relation->rd_index->indisprimary = index->indisprimary;
01789 relation->rd_index->indisexclusion = index->indisexclusion;
01790 relation->rd_index->indimmediate = index->indimmediate;
01791 relation->rd_index->indisclustered = index->indisclustered;
01792 relation->rd_index->indisvalid = index->indisvalid;
01793 relation->rd_index->indcheckxmin = index->indcheckxmin;
01794 relation->rd_index->indisready = index->indisready;
01795 relation->rd_index->indislive = index->indislive;
01796
01797
01798 HeapTupleHeaderSetXmin(relation->rd_indextuple->t_data,
01799 HeapTupleHeaderGetXmin(tuple->t_data));
01800
01801 ReleaseSysCache(tuple);
01802 }
01803
01804
01805 relation->rd_isvalid = true;
01806 }
01807
01808
01809
01810
01811
01812
01813
01814 static void
01815 RelationDestroyRelation(Relation relation)
01816 {
01817 Assert(RelationHasReferenceCountZero(relation));
01818
01819
01820
01821
01822
01823
01824 RelationCloseSmgr(relation);
01825
01826
01827
01828
01829
01830 if (relation->rd_rel)
01831 pfree(relation->rd_rel);
01832
01833 Assert(relation->rd_att->tdrefcount > 0);
01834 if (--relation->rd_att->tdrefcount == 0)
01835 FreeTupleDesc(relation->rd_att);
01836 list_free(relation->rd_indexlist);
01837 bms_free(relation->rd_indexattr);
01838 FreeTriggerDesc(relation->trigdesc);
01839 if (relation->rd_options)
01840 pfree(relation->rd_options);
01841 if (relation->rd_indextuple)
01842 pfree(relation->rd_indextuple);
01843 if (relation->rd_am)
01844 pfree(relation->rd_am);
01845 if (relation->rd_indexcxt)
01846 MemoryContextDelete(relation->rd_indexcxt);
01847 if (relation->rd_rulescxt)
01848 MemoryContextDelete(relation->rd_rulescxt);
01849 if (relation->rd_fdwroutine)
01850 pfree(relation->rd_fdwroutine);
01851 pfree(relation);
01852 }
01853
01854
01855
01856
01857
01858
01859
01860
01861
01862
01863
01864
01865
01866
01867
01868
01869
01870
01871
01872
01873 static void
01874 RelationClearRelation(Relation relation, bool rebuild)
01875 {
01876
01877
01878
01879
01880 Assert(rebuild ?
01881 !RelationHasReferenceCountZero(relation) :
01882 RelationHasReferenceCountZero(relation));
01883
01884
01885
01886
01887
01888
01889
01890
01891 RelationCloseSmgr(relation);
01892
01893
01894
01895
01896
01897
01898
01899
01900
01901
01902
01903
01904
01905 if (relation->rd_isnailed)
01906 {
01907 RelationInitPhysicalAddr(relation);
01908 if (relation->rd_rel->relkind == RELKIND_MATVIEW &&
01909 heap_is_matview_init_state(relation))
01910 relation->rd_ispopulated = false;
01911 else
01912 relation->rd_ispopulated = true;
01913
01914 if (relation->rd_rel->relkind == RELKIND_INDEX)
01915 {
01916 relation->rd_isvalid = false;
01917 if (relation->rd_refcnt > 1)
01918 RelationReloadIndexInfo(relation);
01919 }
01920 return;
01921 }
01922
01923
01924
01925
01926
01927
01928
01929
01930 if (relation->rd_rel->relkind == RELKIND_INDEX &&
01931 relation->rd_refcnt > 0 &&
01932 relation->rd_indexcxt != NULL)
01933 {
01934 relation->rd_isvalid = false;
01935 RelationReloadIndexInfo(relation);
01936 return;
01937 }
01938
01939
01940 relation->rd_isvalid = false;
01941
01942
01943
01944
01945
01946
01947
01948 if (!rebuild)
01949 {
01950
01951 RelationCacheDelete(relation);
01952
01953
01954 RelationDestroyRelation(relation);
01955 }
01956 else
01957 {
01958
01959
01960
01961
01962
01963
01964
01965
01966
01967
01968
01969
01970
01971
01972
01973
01974
01975
01976
01977
01978
01979
01980
01981
01982
01983
01984
01985
01986
01987 Relation newrel;
01988 Oid save_relid = RelationGetRelid(relation);
01989 bool keep_tupdesc;
01990 bool keep_rules;
01991
01992
01993 newrel = RelationBuildDesc(save_relid, false);
01994 if (newrel == NULL)
01995 {
01996
01997 RelationCacheDelete(relation);
01998 RelationDestroyRelation(relation);
01999 elog(ERROR, "relation %u deleted while still in use", save_relid);
02000 }
02001
02002 keep_tupdesc = equalTupleDescs(relation->rd_att, newrel->rd_att);
02003 keep_rules = equalRuleLocks(relation->rd_rules, newrel->rd_rules);
02004
02005
02006
02007
02008
02009
02010
02011
02012
02013
02014
02015 #define SWAPFIELD(fldtype, fldname) \
02016 do { \
02017 fldtype _tmp = newrel->fldname; \
02018 newrel->fldname = relation->fldname; \
02019 relation->fldname = _tmp; \
02020 } while (0)
02021
02022
02023 {
02024 RelationData tmpstruct;
02025
02026 memcpy(&tmpstruct, newrel, sizeof(RelationData));
02027 memcpy(newrel, relation, sizeof(RelationData));
02028 memcpy(relation, &tmpstruct, sizeof(RelationData));
02029 }
02030
02031
02032 SWAPFIELD(SMgrRelation, rd_smgr);
02033
02034 SWAPFIELD(int, rd_refcnt);
02035
02036 Assert(newrel->rd_isnailed == relation->rd_isnailed);
02037
02038 SWAPFIELD(SubTransactionId, rd_createSubid);
02039 SWAPFIELD(SubTransactionId, rd_newRelfilenodeSubid);
02040
02041 SWAPFIELD(Form_pg_class, rd_rel);
02042
02043 memcpy(relation->rd_rel, newrel->rd_rel, CLASS_TUPLE_SIZE);
02044
02045 if (keep_tupdesc)
02046 SWAPFIELD(TupleDesc, rd_att);
02047 if (keep_rules)
02048 {
02049 SWAPFIELD(RuleLock *, rd_rules);
02050 SWAPFIELD(MemoryContext, rd_rulescxt);
02051 }
02052
02053 SWAPFIELD(Oid, rd_toastoid);
02054
02055 SWAPFIELD(struct PgStat_TableStatus *, pgstat_info);
02056
02057 #undef SWAPFIELD
02058
02059
02060 RelationDestroyRelation(newrel);
02061 }
02062 }
02063
02064
02065
02066
02067
02068
02069 static void
02070 RelationFlushRelation(Relation relation)
02071 {
02072 if (relation->rd_createSubid != InvalidSubTransactionId ||
02073 relation->rd_newRelfilenodeSubid != InvalidSubTransactionId)
02074 {
02075
02076
02077
02078
02079
02080
02081
02082
02083
02084 RelationIncrementReferenceCount(relation);
02085 RelationClearRelation(relation, true);
02086 RelationDecrementReferenceCount(relation);
02087 }
02088 else
02089 {
02090
02091
02092
02093 bool rebuild = !RelationHasReferenceCountZero(relation);
02094
02095 RelationClearRelation(relation, rebuild);
02096 }
02097 }
02098
02099
02100
02101
02102
02103
02104
02105 void
02106 RelationForgetRelation(Oid rid)
02107 {
02108 Relation relation;
02109
02110 RelationIdCacheLookup(rid, relation);
02111
02112 if (!PointerIsValid(relation))
02113 return;
02114
02115 if (!RelationHasReferenceCountZero(relation))
02116 elog(ERROR, "relation %u is still open", rid);
02117
02118
02119 RelationClearRelation(relation, false);
02120 }
02121
02122
02123
02124
02125
02126
02127
02128
02129
02130
02131
02132
02133
02134
02135
02136
02137 void
02138 RelationCacheInvalidateEntry(Oid relationId)
02139 {
02140 Relation relation;
02141
02142 RelationIdCacheLookup(relationId, relation);
02143
02144 if (PointerIsValid(relation))
02145 {
02146 relcacheInvalsReceived++;
02147 RelationFlushRelation(relation);
02148 }
02149 }
02150
02151
02152
02153
02154
02155
02156
02157
02158
02159
02160
02161
02162
02163
02164
02165
02166
02167
02168
02169
02170
02171
02172
02173
02174
02175
02176
02177
02178
02179
02180
02181 void
02182 RelationCacheInvalidate(void)
02183 {
02184 HASH_SEQ_STATUS status;
02185 RelIdCacheEnt *idhentry;
02186 Relation relation;
02187 List *rebuildFirstList = NIL;
02188 List *rebuildList = NIL;
02189 ListCell *l;
02190
02191
02192
02193
02194 RelationMapInvalidateAll();
02195
02196
02197 hash_seq_init(&status, RelationIdCache);
02198
02199 while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
02200 {
02201 relation = idhentry->reldesc;
02202
02203
02204 RelationCloseSmgr(relation);
02205
02206
02207
02208
02209
02210
02211
02212 if (relation->rd_createSubid != InvalidSubTransactionId ||
02213 relation->rd_newRelfilenodeSubid != InvalidSubTransactionId)
02214 continue;
02215
02216 relcacheInvalsReceived++;
02217
02218 if (RelationHasReferenceCountZero(relation))
02219 {
02220
02221 Assert(!relation->rd_isnailed);
02222 RelationClearRelation(relation, false);
02223 }
02224 else
02225 {
02226
02227
02228
02229
02230
02231
02232
02233 if (RelationIsMapped(relation))
02234 RelationInitPhysicalAddr(relation);
02235
02236
02237
02238
02239
02240
02241
02242
02243
02244
02245 if (RelationGetRelid(relation) == RelationRelationId)
02246 rebuildFirstList = lcons(relation, rebuildFirstList);
02247 else if (RelationGetRelid(relation) == ClassOidIndexId)
02248 rebuildFirstList = lappend(rebuildFirstList, relation);
02249 else if (relation->rd_isnailed)
02250 rebuildList = lcons(relation, rebuildList);
02251 else
02252 rebuildList = lappend(rebuildList, relation);
02253 }
02254 }
02255
02256
02257
02258
02259
02260
02261 smgrcloseall();
02262
02263
02264 foreach(l, rebuildFirstList)
02265 {
02266 relation = (Relation) lfirst(l);
02267 RelationClearRelation(relation, true);
02268 }
02269 list_free(rebuildFirstList);
02270 foreach(l, rebuildList)
02271 {
02272 relation = (Relation) lfirst(l);
02273 RelationClearRelation(relation, true);
02274 }
02275 list_free(rebuildList);
02276 }
02277
02278
02279
02280
02281
02282
02283
02284 void
02285 RelationCloseSmgrByOid(Oid relationId)
02286 {
02287 Relation relation;
02288
02289 RelationIdCacheLookup(relationId, relation);
02290
02291 if (!PointerIsValid(relation))
02292 return;
02293
02294 RelationCloseSmgr(relation);
02295 }
02296
02297
02298
02299
02300
02301
02302
02303
02304
02305
02306
02307
02308
02309
02310
02311
02312
02313 void
02314 AtEOXact_RelationCache(bool isCommit)
02315 {
02316 HASH_SEQ_STATUS status;
02317 RelIdCacheEnt *idhentry;
02318 int i;
02319
02320
02321
02322
02323
02324
02325
02326
02327
02328
02329
02330
02331 if (eoxact_list_overflowed)
02332 {
02333 hash_seq_init(&status, RelationIdCache);
02334 while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
02335 {
02336 AtEOXact_cleanup(idhentry->reldesc, isCommit);
02337 }
02338 }
02339 else
02340 {
02341 for (i = 0; i < eoxact_list_len; i++)
02342 {
02343 idhentry = (RelIdCacheEnt *) hash_search(RelationIdCache,
02344 (void *) &eoxact_list[i],
02345 HASH_FIND,
02346 NULL);
02347 if (idhentry != NULL)
02348 AtEOXact_cleanup(idhentry->reldesc, isCommit);
02349 }
02350 }
02351
02352
02353 eoxact_list_len = 0;
02354 eoxact_list_overflowed = false;
02355 }
02356
02357
02358
02359
02360
02361
02362
02363
02364
02365 static void
02366 AtEOXact_cleanup(Relation relation, bool isCommit)
02367 {
02368
02369
02370
02371
02372
02373
02374
02375
02376
02377
02378
02379
02380
02381
02382 #ifdef USE_ASSERT_CHECKING
02383 if (!IsBootstrapProcessingMode())
02384 {
02385 int expected_refcnt;
02386
02387 expected_refcnt = relation->rd_isnailed ? 1 : 0;
02388 Assert(relation->rd_refcnt == expected_refcnt);
02389 }
02390 #endif
02391
02392
02393
02394
02395
02396
02397
02398
02399
02400
02401
02402 if (relation->rd_createSubid != InvalidSubTransactionId)
02403 {
02404 if (isCommit)
02405 relation->rd_createSubid = InvalidSubTransactionId;
02406 else
02407 {
02408 RelationClearRelation(relation, false);
02409 return;
02410 }
02411 }
02412
02413
02414
02415
02416 relation->rd_newRelfilenodeSubid = InvalidSubTransactionId;
02417
02418
02419
02420
02421 if (relation->rd_indexvalid == 2)
02422 {
02423 list_free(relation->rd_indexlist);
02424 relation->rd_indexlist = NIL;
02425 relation->rd_oidindex = InvalidOid;
02426 relation->rd_indexvalid = 0;
02427 }
02428 }
02429
02430
02431
02432
02433
02434
02435
02436
02437 void
02438 AtEOSubXact_RelationCache(bool isCommit, SubTransactionId mySubid,
02439 SubTransactionId parentSubid)
02440 {
02441 HASH_SEQ_STATUS status;
02442 RelIdCacheEnt *idhentry;
02443 int i;
02444
02445
02446
02447
02448
02449
02450 if (eoxact_list_overflowed)
02451 {
02452 hash_seq_init(&status, RelationIdCache);
02453 while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
02454 {
02455 AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
02456 mySubid, parentSubid);
02457 }
02458 }
02459 else
02460 {
02461 for (i = 0; i < eoxact_list_len; i++)
02462 {
02463 idhentry = (RelIdCacheEnt *) hash_search(RelationIdCache,
02464 (void *) &eoxact_list[i],
02465 HASH_FIND,
02466 NULL);
02467 if (idhentry != NULL)
02468 AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
02469 mySubid, parentSubid);
02470 }
02471 }
02472
02473
02474 }
02475
02476
02477
02478
02479
02480
02481
02482
02483
02484 static void
02485 AtEOSubXact_cleanup(Relation relation, bool isCommit,
02486 SubTransactionId mySubid, SubTransactionId parentSubid)
02487 {
02488
02489
02490
02491
02492
02493
02494 if (relation->rd_createSubid == mySubid)
02495 {
02496 if (isCommit)
02497 relation->rd_createSubid = parentSubid;
02498 else
02499 {
02500 RelationClearRelation(relation, false);
02501 return;
02502 }
02503 }
02504
02505
02506
02507
02508
02509 if (relation->rd_newRelfilenodeSubid == mySubid)
02510 {
02511 if (isCommit)
02512 relation->rd_newRelfilenodeSubid = parentSubid;
02513 else
02514 relation->rd_newRelfilenodeSubid = InvalidSubTransactionId;
02515 }
02516
02517
02518
02519
02520 if (relation->rd_indexvalid == 2)
02521 {
02522 list_free(relation->rd_indexlist);
02523 relation->rd_indexlist = NIL;
02524 relation->rd_oidindex = InvalidOid;
02525 relation->rd_indexvalid = 0;
02526 }
02527 }
02528
02529
02530
02531
02532
02533
02534
02535 Relation
02536 RelationBuildLocalRelation(const char *relname,
02537 Oid relnamespace,
02538 TupleDesc tupDesc,
02539 Oid relid,
02540 Oid relfilenode,
02541 Oid reltablespace,
02542 bool shared_relation,
02543 bool mapped_relation,
02544 char relpersistence,
02545 char relkind)
02546 {
02547 Relation rel;
02548 MemoryContext oldcxt;
02549 int natts = tupDesc->natts;
02550 int i;
02551 bool has_not_null;
02552 bool nailit;
02553
02554 AssertArg(natts >= 0);
02555
02556
02557
02558
02559
02560
02561
02562 switch (relid)
02563 {
02564 case DatabaseRelationId:
02565 case AuthIdRelationId:
02566 case AuthMemRelationId:
02567 case RelationRelationId:
02568 case AttributeRelationId:
02569 case ProcedureRelationId:
02570 case TypeRelationId:
02571 nailit = true;
02572 break;
02573 default:
02574 nailit = false;
02575 break;
02576 }
02577
02578
02579
02580
02581
02582
02583
02584 if (shared_relation != IsSharedRelation(relid))
02585 elog(ERROR, "shared_relation flag for \"%s\" does not match IsSharedRelation(%u)",
02586 relname, relid);
02587
02588
02589 Assert(mapped_relation || !shared_relation);
02590
02591
02592
02593
02594 if (!CacheMemoryContext)
02595 CreateCacheMemoryContext();
02596
02597 oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
02598
02599
02600
02601
02602 rel = (Relation) palloc0(sizeof(RelationData));
02603
02604
02605 rel->rd_smgr = NULL;
02606
02607
02608 rel->rd_isnailed = nailit;
02609
02610 rel->rd_refcnt = nailit ? 1 : 0;
02611
02612
02613 rel->rd_createSubid = GetCurrentSubTransactionId();
02614 rel->rd_newRelfilenodeSubid = InvalidSubTransactionId;
02615
02616
02617
02618
02619
02620
02621
02622
02623 rel->rd_att = CreateTupleDescCopy(tupDesc);
02624 rel->rd_att->tdrefcount = 1;
02625 has_not_null = false;
02626 for (i = 0; i < natts; i++)
02627 {
02628 rel->rd_att->attrs[i]->attnotnull = tupDesc->attrs[i]->attnotnull;
02629 has_not_null |= tupDesc->attrs[i]->attnotnull;
02630 }
02631
02632 if (has_not_null)
02633 {
02634 TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr));
02635
02636 constr->has_not_null = true;
02637 rel->rd_att->constr = constr;
02638 }
02639
02640
02641
02642
02643 rel->rd_rel = (Form_pg_class) palloc0(CLASS_TUPLE_SIZE);
02644
02645 namestrcpy(&rel->rd_rel->relname, relname);
02646 rel->rd_rel->relnamespace = relnamespace;
02647
02648 rel->rd_rel->relkind = relkind;
02649 rel->rd_rel->relhasoids = rel->rd_att->tdhasoid;
02650 rel->rd_rel->relnatts = natts;
02651 rel->rd_rel->reltype = InvalidOid;
02652
02653 rel->rd_rel->relowner = BOOTSTRAP_SUPERUSERID;
02654
02655
02656 rel->rd_rel->relpersistence = relpersistence;
02657 switch (relpersistence)
02658 {
02659 case RELPERSISTENCE_UNLOGGED:
02660 case RELPERSISTENCE_PERMANENT:
02661 rel->rd_backend = InvalidBackendId;
02662 rel->rd_islocaltemp = false;
02663 break;
02664 case RELPERSISTENCE_TEMP:
02665 Assert(isTempOrToastNamespace(relnamespace));
02666 rel->rd_backend = MyBackendId;
02667 rel->rd_islocaltemp = true;
02668 break;
02669 default:
02670 elog(ERROR, "invalid relpersistence: %c", relpersistence);
02671 break;
02672 }
02673
02674
02675
02676
02677
02678
02679 rel->rd_rel->relisshared = shared_relation;
02680
02681 RelationGetRelid(rel) = relid;
02682
02683 for (i = 0; i < natts; i++)
02684 rel->rd_att->attrs[i]->attrelid = relid;
02685
02686 rel->rd_rel->reltablespace = reltablespace;
02687
02688 if (mapped_relation)
02689 {
02690 rel->rd_rel->relfilenode = InvalidOid;
02691
02692 RelationMapUpdateMap(relid, relfilenode, shared_relation, true);
02693 }
02694 else
02695 rel->rd_rel->relfilenode = relfilenode;
02696
02697 RelationInitLockInfo(rel);
02698
02699 RelationInitPhysicalAddr(rel);
02700
02701
02702 if (relkind == RELKIND_MATVIEW)
02703 rel->rd_ispopulated = false;
02704 else
02705 rel->rd_ispopulated = true;
02706
02707
02708
02709
02710 RelationCacheInsert(rel);
02711
02712
02713
02714
02715
02716 EOXactListAdd(rel);
02717
02718
02719
02720
02721 MemoryContextSwitchTo(oldcxt);
02722
02723
02724 rel->rd_isvalid = true;
02725
02726
02727
02728
02729 RelationIncrementReferenceCount(rel);
02730
02731 return rel;
02732 }
02733
02734
02735
02736
02737
02738
02739
02740
02741
02742
02743
02744
02745
02746
02747
02748
02749
02750
02751
02752 void
02753 RelationSetNewRelfilenode(Relation relation, TransactionId freezeXid,
02754 MultiXactId minmulti)
02755 {
02756 Oid newrelfilenode;
02757 RelFileNodeBackend newrnode;
02758 Relation pg_class;
02759 HeapTuple tuple;
02760 Form_pg_class classform;
02761
02762
02763 Assert((relation->rd_rel->relkind == RELKIND_INDEX ||
02764 relation->rd_rel->relkind == RELKIND_SEQUENCE) ?
02765 freezeXid == InvalidTransactionId :
02766 TransactionIdIsNormal(freezeXid));
02767 Assert(TransactionIdIsNormal(freezeXid) == MultiXactIdIsValid(minmulti));
02768
02769
02770 newrelfilenode = GetNewRelFileNode(relation->rd_rel->reltablespace, NULL,
02771 relation->rd_rel->relpersistence);
02772
02773
02774
02775
02776 pg_class = heap_open(RelationRelationId, RowExclusiveLock);
02777
02778 tuple = SearchSysCacheCopy1(RELOID,
02779 ObjectIdGetDatum(RelationGetRelid(relation)));
02780 if (!HeapTupleIsValid(tuple))
02781 elog(ERROR, "could not find tuple for relation %u",
02782 RelationGetRelid(relation));
02783 classform = (Form_pg_class) GETSTRUCT(tuple);
02784
02785
02786
02787
02788
02789
02790
02791 newrnode.node = relation->rd_node;
02792 newrnode.node.relNode = newrelfilenode;
02793 newrnode.backend = relation->rd_backend;
02794 RelationCreateStorage(newrnode.node, relation->rd_rel->relpersistence);
02795 smgrclosenode(newrnode);
02796
02797
02798
02799
02800 RelationDropStorage(relation);
02801
02802
02803
02804
02805
02806
02807 if (RelationIsMapped(relation))
02808 RelationMapUpdateMap(RelationGetRelid(relation),
02809 newrelfilenode,
02810 relation->rd_rel->relisshared,
02811 false);
02812 else
02813 classform->relfilenode = newrelfilenode;
02814
02815
02816 if (relation->rd_rel->relkind != RELKIND_SEQUENCE)
02817 {
02818 classform->relpages = 0;
02819 classform->reltuples = 0;
02820 classform->relallvisible = 0;
02821 }
02822 classform->relfrozenxid = freezeXid;
02823 classform->relminmxid = minmulti;
02824
02825 simple_heap_update(pg_class, &tuple->t_self, tuple);
02826 CatalogUpdateIndexes(pg_class, tuple);
02827
02828 heap_freetuple(tuple);
02829
02830 heap_close(pg_class, RowExclusiveLock);
02831
02832
02833
02834
02835
02836 CommandCounterIncrement();
02837
02838
02839
02840
02841
02842
02843 relation->rd_newRelfilenodeSubid = GetCurrentSubTransactionId();
02844
02845
02846 EOXactListAdd(relation);
02847 }
02848
02849
02850
02851
02852
02853
02854
02855
02856
02857
02858
02859
02860
02861
02862 #define INITRELCACHESIZE 400
02863
02864 void
02865 RelationCacheInitialize(void)
02866 {
02867 HASHCTL ctl;
02868
02869
02870
02871
02872 if (!CacheMemoryContext)
02873 CreateCacheMemoryContext();
02874
02875
02876
02877
02878 MemSet(&ctl, 0, sizeof(ctl));
02879 ctl.keysize = sizeof(Oid);
02880 ctl.entrysize = sizeof(RelIdCacheEnt);
02881 ctl.hash = oid_hash;
02882 RelationIdCache = hash_create("Relcache by OID", INITRELCACHESIZE,
02883 &ctl, HASH_ELEM | HASH_FUNCTION);
02884
02885
02886
02887
02888 RelationMapInitialize();
02889 }
02890
02891
02892
02893
02894
02895
02896
02897
02898
02899
02900
02901
02902 void
02903 RelationCacheInitializePhase2(void)
02904 {
02905 MemoryContext oldcxt;
02906
02907
02908
02909
02910 RelationMapInitializePhase2();
02911
02912
02913
02914
02915
02916 if (IsBootstrapProcessingMode())
02917 return;
02918
02919
02920
02921
02922 oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
02923
02924
02925
02926
02927
02928 if (!load_relcache_init_file(true))
02929 {
02930 formrdesc("pg_database", DatabaseRelation_Rowtype_Id, true,
02931 true, Natts_pg_database, Desc_pg_database);
02932 formrdesc("pg_authid", AuthIdRelation_Rowtype_Id, true,
02933 true, Natts_pg_authid, Desc_pg_authid);
02934 formrdesc("pg_auth_members", AuthMemRelation_Rowtype_Id, true,
02935 false, Natts_pg_auth_members, Desc_pg_auth_members);
02936
02937 #define NUM_CRITICAL_SHARED_RELS 3
02938 }
02939
02940 MemoryContextSwitchTo(oldcxt);
02941 }
02942
02943
02944
02945
02946
02947
02948
02949
02950
02951
02952
02953
02954
02955
02956
02957 void
02958 RelationCacheInitializePhase3(void)
02959 {
02960 HASH_SEQ_STATUS status;
02961 RelIdCacheEnt *idhentry;
02962 MemoryContext oldcxt;
02963 bool needNewCacheFile = !criticalSharedRelcachesBuilt;
02964
02965
02966
02967
02968 RelationMapInitializePhase3();
02969
02970
02971
02972
02973 oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
02974
02975
02976
02977
02978
02979
02980 if (IsBootstrapProcessingMode() ||
02981 !load_relcache_init_file(false))
02982 {
02983 needNewCacheFile = true;
02984
02985 formrdesc("pg_class", RelationRelation_Rowtype_Id, false,
02986 true, Natts_pg_class, Desc_pg_class);
02987 formrdesc("pg_attribute", AttributeRelation_Rowtype_Id, false,
02988 false, Natts_pg_attribute, Desc_pg_attribute);
02989 formrdesc("pg_proc", ProcedureRelation_Rowtype_Id, false,
02990 true, Natts_pg_proc, Desc_pg_proc);
02991 formrdesc("pg_type", TypeRelation_Rowtype_Id, false,
02992 true, Natts_pg_type, Desc_pg_type);
02993
02994 #define NUM_CRITICAL_LOCAL_RELS 4
02995 }
02996
02997 MemoryContextSwitchTo(oldcxt);
02998
02999
03000 if (IsBootstrapProcessingMode())
03001 return;
03002
03003
03004
03005
03006
03007
03008
03009
03010
03011
03012
03013
03014
03015
03016
03017
03018
03019
03020
03021
03022
03023
03024
03025
03026
03027
03028 if (!criticalRelcachesBuilt)
03029 {
03030 load_critical_index(ClassOidIndexId,
03031 RelationRelationId);
03032 load_critical_index(AttributeRelidNumIndexId,
03033 AttributeRelationId);
03034 load_critical_index(IndexRelidIndexId,
03035 IndexRelationId);
03036 load_critical_index(OpclassOidIndexId,
03037 OperatorClassRelationId);
03038 load_critical_index(AccessMethodProcedureIndexId,
03039 AccessMethodProcedureRelationId);
03040 load_critical_index(RewriteRelRulenameIndexId,
03041 RewriteRelationId);
03042 load_critical_index(TriggerRelidNameIndexId,
03043 TriggerRelationId);
03044
03045 #define NUM_CRITICAL_LOCAL_INDEXES 7
03046
03047 criticalRelcachesBuilt = true;
03048 }
03049
03050
03051
03052
03053
03054
03055
03056
03057
03058
03059
03060 if (!criticalSharedRelcachesBuilt)
03061 {
03062 load_critical_index(DatabaseNameIndexId,
03063 DatabaseRelationId);
03064 load_critical_index(DatabaseOidIndexId,
03065 DatabaseRelationId);
03066 load_critical_index(AuthIdRolnameIndexId,
03067 AuthIdRelationId);
03068 load_critical_index(AuthIdOidIndexId,
03069 AuthIdRelationId);
03070 load_critical_index(AuthMemMemRoleIndexId,
03071 AuthMemRelationId);
03072
03073 #define NUM_CRITICAL_SHARED_INDEXES 5
03074
03075 criticalSharedRelcachesBuilt = true;
03076 }
03077
03078
03079
03080
03081
03082
03083
03084
03085
03086
03087
03088
03089
03090
03091
03092
03093
03094 hash_seq_init(&status, RelationIdCache);
03095
03096 while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
03097 {
03098 Relation relation = idhentry->reldesc;
03099 bool restart = false;
03100
03101
03102
03103
03104 RelationIncrementReferenceCount(relation);
03105
03106
03107
03108
03109 if (relation->rd_rel->relowner == InvalidOid)
03110 {
03111 HeapTuple htup;
03112 Form_pg_class relp;
03113
03114 htup = SearchSysCache1(RELOID,
03115 ObjectIdGetDatum(RelationGetRelid(relation)));
03116 if (!HeapTupleIsValid(htup))
03117 elog(FATAL, "cache lookup failed for relation %u",
03118 RelationGetRelid(relation));
03119 relp = (Form_pg_class) GETSTRUCT(htup);
03120
03121
03122
03123
03124
03125 memcpy((char *) relation->rd_rel, (char *) relp, CLASS_TUPLE_SIZE);
03126
03127
03128 if (relation->rd_options)
03129 pfree(relation->rd_options);
03130 RelationParseRelOptions(relation, htup);
03131
03132
03133
03134
03135
03136
03137
03138 Assert(relation->rd_att->tdtypeid == relp->reltype);
03139 Assert(relation->rd_att->tdtypmod == -1);
03140 Assert(relation->rd_att->tdhasoid == relp->relhasoids);
03141
03142 ReleaseSysCache(htup);
03143
03144
03145 if (relation->rd_rel->relowner == InvalidOid)
03146 elog(ERROR, "invalid relowner in pg_class entry for \"%s\"",
03147 RelationGetRelationName(relation));
03148
03149 restart = true;
03150 }
03151
03152
03153
03154
03155
03156
03157
03158
03159
03160 if (relation->rd_rel->relhasrules && relation->rd_rules == NULL)
03161 {
03162 RelationBuildRuleLock(relation);
03163 if (relation->rd_rules == NULL)
03164 relation->rd_rel->relhasrules = false;
03165 restart = true;
03166 }
03167 if (relation->rd_rel->relhastriggers && relation->trigdesc == NULL)
03168 {
03169 RelationBuildTriggers(relation);
03170 if (relation->trigdesc == NULL)
03171 relation->rd_rel->relhastriggers = false;
03172 restart = true;
03173 }
03174
03175
03176 RelationDecrementReferenceCount(relation);
03177
03178
03179 if (restart)
03180 {
03181 hash_seq_term(&status);
03182 hash_seq_init(&status, RelationIdCache);
03183 }
03184 }
03185
03186
03187
03188
03189
03190 if (needNewCacheFile)
03191 {
03192
03193
03194
03195
03196
03197
03198 InitCatalogCachePhase2();
03199
03200
03201 initFileRelationIds = NIL;
03202
03203
03204 write_relcache_init_file(true);
03205 write_relcache_init_file(false);
03206 }
03207 }
03208
03209
03210
03211
03212
03213
03214
03215 static void
03216 load_critical_index(Oid indexoid, Oid heapoid)
03217 {
03218 Relation ird;
03219
03220
03221
03222
03223
03224
03225
03226 LockRelationOid(heapoid, AccessShareLock);
03227 LockRelationOid(indexoid, AccessShareLock);
03228 ird = RelationBuildDesc(indexoid, true);
03229 if (ird == NULL)
03230 elog(PANIC, "could not open critical system index %u", indexoid);
03231 ird->rd_isnailed = true;
03232 ird->rd_refcnt = 1;
03233 UnlockRelationOid(indexoid, AccessShareLock);
03234 UnlockRelationOid(heapoid, AccessShareLock);
03235 }
03236
03237
03238
03239
03240
03241
03242
03243
03244
03245
03246
03247
03248
03249 static TupleDesc
03250 BuildHardcodedDescriptor(int natts, const FormData_pg_attribute *attrs,
03251 bool hasoids)
03252 {
03253 TupleDesc result;
03254 MemoryContext oldcxt;
03255 int i;
03256
03257 oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
03258
03259 result = CreateTemplateTupleDesc(natts, hasoids);
03260 result->tdtypeid = RECORDOID;
03261 result->tdtypmod = -1;
03262
03263 for (i = 0; i < natts; i++)
03264 {
03265 memcpy(result->attrs[i], &attrs[i], ATTRIBUTE_FIXED_PART_SIZE);
03266
03267 result->attrs[i]->attcacheoff = -1;
03268 }
03269
03270
03271 result->attrs[0]->attcacheoff = 0;
03272
03273
03274
03275 MemoryContextSwitchTo(oldcxt);
03276
03277 return result;
03278 }
03279
03280 static TupleDesc
03281 GetPgClassDescriptor(void)
03282 {
03283 static TupleDesc pgclassdesc = NULL;
03284
03285
03286 if (pgclassdesc == NULL)
03287 pgclassdesc = BuildHardcodedDescriptor(Natts_pg_class,
03288 Desc_pg_class,
03289 true);
03290
03291 return pgclassdesc;
03292 }
03293
03294 static TupleDesc
03295 GetPgIndexDescriptor(void)
03296 {
03297 static TupleDesc pgindexdesc = NULL;
03298
03299
03300 if (pgindexdesc == NULL)
03301 pgindexdesc = BuildHardcodedDescriptor(Natts_pg_index,
03302 Desc_pg_index,
03303 false);
03304
03305 return pgindexdesc;
03306 }
03307
03308
03309
03310
03311 static void
03312 AttrDefaultFetch(Relation relation)
03313 {
03314 AttrDefault *attrdef = relation->rd_att->constr->defval;
03315 int ndef = relation->rd_att->constr->num_defval;
03316 Relation adrel;
03317 SysScanDesc adscan;
03318 ScanKeyData skey;
03319 HeapTuple htup;
03320 Datum val;
03321 bool isnull;
03322 int found;
03323 int i;
03324
03325 ScanKeyInit(&skey,
03326 Anum_pg_attrdef_adrelid,
03327 BTEqualStrategyNumber, F_OIDEQ,
03328 ObjectIdGetDatum(RelationGetRelid(relation)));
03329
03330 adrel = heap_open(AttrDefaultRelationId, AccessShareLock);
03331 adscan = systable_beginscan(adrel, AttrDefaultIndexId, true,
03332 SnapshotNow, 1, &skey);
03333 found = 0;
03334
03335 while (HeapTupleIsValid(htup = systable_getnext(adscan)))
03336 {
03337 Form_pg_attrdef adform = (Form_pg_attrdef) GETSTRUCT(htup);
03338
03339 for (i = 0; i < ndef; i++)
03340 {
03341 if (adform->adnum != attrdef[i].adnum)
03342 continue;
03343 if (attrdef[i].adbin != NULL)
03344 elog(WARNING, "multiple attrdef records found for attr %s of rel %s",
03345 NameStr(relation->rd_att->attrs[adform->adnum - 1]->attname),
03346 RelationGetRelationName(relation));
03347 else
03348 found++;
03349
03350 val = fastgetattr(htup,
03351 Anum_pg_attrdef_adbin,
03352 adrel->rd_att, &isnull);
03353 if (isnull)
03354 elog(WARNING, "null adbin for attr %s of rel %s",
03355 NameStr(relation->rd_att->attrs[adform->adnum - 1]->attname),
03356 RelationGetRelationName(relation));
03357 else
03358 attrdef[i].adbin = MemoryContextStrdup(CacheMemoryContext,
03359 TextDatumGetCString(val));
03360 break;
03361 }
03362
03363 if (i >= ndef)
03364 elog(WARNING, "unexpected attrdef record found for attr %d of rel %s",
03365 adform->adnum, RelationGetRelationName(relation));
03366 }
03367
03368 systable_endscan(adscan);
03369 heap_close(adrel, AccessShareLock);
03370
03371 if (found != ndef)
03372 elog(WARNING, "%d attrdef record(s) missing for rel %s",
03373 ndef - found, RelationGetRelationName(relation));
03374 }
03375
03376
03377
03378
03379 static void
03380 CheckConstraintFetch(Relation relation)
03381 {
03382 ConstrCheck *check = relation->rd_att->constr->check;
03383 int ncheck = relation->rd_att->constr->num_check;
03384 Relation conrel;
03385 SysScanDesc conscan;
03386 ScanKeyData skey[1];
03387 HeapTuple htup;
03388 Datum val;
03389 bool isnull;
03390 int found = 0;
03391
03392 ScanKeyInit(&skey[0],
03393 Anum_pg_constraint_conrelid,
03394 BTEqualStrategyNumber, F_OIDEQ,
03395 ObjectIdGetDatum(RelationGetRelid(relation)));
03396
03397 conrel = heap_open(ConstraintRelationId, AccessShareLock);
03398 conscan = systable_beginscan(conrel, ConstraintRelidIndexId, true,
03399 SnapshotNow, 1, skey);
03400
03401 while (HeapTupleIsValid(htup = systable_getnext(conscan)))
03402 {
03403 Form_pg_constraint conform = (Form_pg_constraint) GETSTRUCT(htup);
03404
03405
03406 if (conform->contype != CONSTRAINT_CHECK)
03407 continue;
03408
03409 if (found >= ncheck)
03410 elog(ERROR, "unexpected constraint record found for rel %s",
03411 RelationGetRelationName(relation));
03412
03413 check[found].ccvalid = conform->convalidated;
03414 check[found].ccnoinherit = conform->connoinherit;
03415 check[found].ccname = MemoryContextStrdup(CacheMemoryContext,
03416 NameStr(conform->conname));
03417
03418
03419 val = fastgetattr(htup,
03420 Anum_pg_constraint_conbin,
03421 conrel->rd_att, &isnull);
03422 if (isnull)
03423 elog(ERROR, "null conbin for rel %s",
03424 RelationGetRelationName(relation));
03425
03426 check[found].ccbin = MemoryContextStrdup(CacheMemoryContext,
03427 TextDatumGetCString(val));
03428 found++;
03429 }
03430
03431 systable_endscan(conscan);
03432 heap_close(conrel, AccessShareLock);
03433
03434 if (found != ncheck)
03435 elog(ERROR, "%d constraint record(s) missing for rel %s",
03436 ncheck - found, RelationGetRelationName(relation));
03437 }
03438
03439
03440
03441
03442
03443
03444
03445
03446
03447
03448
03449
03450
03451
03452
03453
03454
03455
03456
03457
03458
03459
03460
03461
03462
03463
03464
03465
03466
03467
03468
03469
03470 List *
03471 RelationGetIndexList(Relation relation)
03472 {
03473 Relation indrel;
03474 SysScanDesc indscan;
03475 ScanKeyData skey;
03476 HeapTuple htup;
03477 List *result;
03478 Oid oidIndex;
03479 MemoryContext oldcxt;
03480
03481
03482 if (relation->rd_indexvalid != 0)
03483 return list_copy(relation->rd_indexlist);
03484
03485
03486
03487
03488
03489
03490
03491 result = NIL;
03492 oidIndex = InvalidOid;
03493
03494
03495 ScanKeyInit(&skey,
03496 Anum_pg_index_indrelid,
03497 BTEqualStrategyNumber, F_OIDEQ,
03498 ObjectIdGetDatum(RelationGetRelid(relation)));
03499
03500 indrel = heap_open(IndexRelationId, AccessShareLock);
03501 indscan = systable_beginscan(indrel, IndexIndrelidIndexId, true,
03502 SnapshotNow, 1, &skey);
03503
03504 while (HeapTupleIsValid(htup = systable_getnext(indscan)))
03505 {
03506 Form_pg_index index = (Form_pg_index) GETSTRUCT(htup);
03507 Datum indclassDatum;
03508 oidvector *indclass;
03509 bool isnull;
03510
03511
03512
03513
03514
03515
03516
03517 if (!IndexIsLive(index))
03518 continue;
03519
03520
03521 result = insert_ordered_oid(result, index->indexrelid);
03522
03523
03524
03525
03526
03527
03528 indclassDatum = heap_getattr(htup,
03529 Anum_pg_index_indclass,
03530 GetPgIndexDescriptor(),
03531 &isnull);
03532 Assert(!isnull);
03533 indclass = (oidvector *) DatumGetPointer(indclassDatum);
03534
03535
03536 if (IndexIsValid(index) &&
03537 index->indnatts == 1 &&
03538 index->indisunique && index->indimmediate &&
03539 index->indkey.values[0] == ObjectIdAttributeNumber &&
03540 indclass->values[0] == OID_BTREE_OPS_OID &&
03541 heap_attisnull(htup, Anum_pg_index_indpred))
03542 oidIndex = index->indexrelid;
03543 }
03544
03545 systable_endscan(indscan);
03546 heap_close(indrel, AccessShareLock);
03547
03548
03549 oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
03550 relation->rd_indexlist = list_copy(result);
03551 relation->rd_oidindex = oidIndex;
03552 relation->rd_indexvalid = 1;
03553 MemoryContextSwitchTo(oldcxt);
03554
03555 return result;
03556 }
03557
03558
03559
03560
03561
03562
03563
03564
03565
03566
03567 static List *
03568 insert_ordered_oid(List *list, Oid datum)
03569 {
03570 ListCell *prev;
03571
03572
03573 if (list == NIL || datum < linitial_oid(list))
03574 return lcons_oid(datum, list);
03575
03576 prev = list_head(list);
03577 for (;;)
03578 {
03579 ListCell *curr = lnext(prev);
03580
03581 if (curr == NULL || datum < lfirst_oid(curr))
03582 break;
03583
03584 prev = curr;
03585 }
03586
03587 lappend_cell_oid(list, prev, datum);
03588 return list;
03589 }
03590
03591
03592
03593
03594
03595
03596
03597
03598
03599
03600
03601
03602
03603
03604
03605
03606
03607
03608
03609
03610
03611 void
03612 RelationSetIndexList(Relation relation, List *indexIds, Oid oidIndex)
03613 {
03614 MemoryContext oldcxt;
03615
03616 Assert(relation->rd_isnailed);
03617
03618 oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
03619 indexIds = list_copy(indexIds);
03620 MemoryContextSwitchTo(oldcxt);
03621
03622 list_free(relation->rd_indexlist);
03623 relation->rd_indexlist = indexIds;
03624 relation->rd_oidindex = oidIndex;
03625 relation->rd_indexvalid = 2;
03626
03627 EOXactListAdd(relation);
03628 }
03629
03630
03631
03632
03633
03634
03635 Oid
03636 RelationGetOidIndex(Relation relation)
03637 {
03638 List *ilist;
03639
03640
03641
03642
03643
03644
03645 Assert(relation->rd_rel->relhasoids);
03646
03647 if (relation->rd_indexvalid == 0)
03648 {
03649
03650 ilist = RelationGetIndexList(relation);
03651 list_free(ilist);
03652 Assert(relation->rd_indexvalid != 0);
03653 }
03654
03655 return relation->rd_oidindex;
03656 }
03657
03658
03659
03660
03661
03662
03663
03664
03665
03666
03667 List *
03668 RelationGetIndexExpressions(Relation relation)
03669 {
03670 List *result;
03671 Datum exprsDatum;
03672 bool isnull;
03673 char *exprsString;
03674 MemoryContext oldcxt;
03675
03676
03677 if (relation->rd_indexprs)
03678 return (List *) copyObject(relation->rd_indexprs);
03679
03680
03681 if (relation->rd_indextuple == NULL ||
03682 heap_attisnull(relation->rd_indextuple, Anum_pg_index_indexprs))
03683 return NIL;
03684
03685
03686
03687
03688
03689
03690 exprsDatum = heap_getattr(relation->rd_indextuple,
03691 Anum_pg_index_indexprs,
03692 GetPgIndexDescriptor(),
03693 &isnull);
03694 Assert(!isnull);
03695 exprsString = TextDatumGetCString(exprsDatum);
03696 result = (List *) stringToNode(exprsString);
03697 pfree(exprsString);
03698
03699
03700
03701
03702
03703
03704
03705 result = (List *) eval_const_expressions(NULL, (Node *) result);
03706
03707
03708 fix_opfuncids((Node *) result);
03709
03710
03711 oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
03712 relation->rd_indexprs = (List *) copyObject(result);
03713 MemoryContextSwitchTo(oldcxt);
03714
03715 return result;
03716 }
03717
03718
03719
03720
03721
03722
03723
03724
03725
03726
03727
03728 List *
03729 RelationGetIndexPredicate(Relation relation)
03730 {
03731 List *result;
03732 Datum predDatum;
03733 bool isnull;
03734 char *predString;
03735 MemoryContext oldcxt;
03736
03737
03738 if (relation->rd_indpred)
03739 return (List *) copyObject(relation->rd_indpred);
03740
03741
03742 if (relation->rd_indextuple == NULL ||
03743 heap_attisnull(relation->rd_indextuple, Anum_pg_index_indpred))
03744 return NIL;
03745
03746
03747
03748
03749
03750
03751 predDatum = heap_getattr(relation->rd_indextuple,
03752 Anum_pg_index_indpred,
03753 GetPgIndexDescriptor(),
03754 &isnull);
03755 Assert(!isnull);
03756 predString = TextDatumGetCString(predDatum);
03757 result = (List *) stringToNode(predString);
03758 pfree(predString);
03759
03760
03761
03762
03763
03764
03765
03766
03767
03768
03769 result = (List *) eval_const_expressions(NULL, (Node *) result);
03770
03771 result = (List *) canonicalize_qual((Expr *) result);
03772
03773
03774 result = make_ands_implicit((Expr *) result);
03775
03776
03777 fix_opfuncids((Node *) result);
03778
03779
03780 oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
03781 relation->rd_indpred = (List *) copyObject(result);
03782 MemoryContextSwitchTo(oldcxt);
03783
03784 return result;
03785 }
03786
03787
03788
03789
03790
03791
03792
03793
03794
03795
03796
03797
03798
03799
03800
03801
03802
03803
03804
03805
03806
03807
03808 Bitmapset *
03809 RelationGetIndexAttrBitmap(Relation relation, bool keyAttrs)
03810 {
03811 Bitmapset *indexattrs;
03812 Bitmapset *uindexattrs;
03813 List *indexoidlist;
03814 ListCell *l;
03815 MemoryContext oldcxt;
03816
03817
03818 if (relation->rd_indexattr != NULL)
03819 return bms_copy(keyAttrs ? relation->rd_keyattr : relation->rd_indexattr);
03820
03821
03822 if (!RelationGetForm(relation)->relhasindex)
03823 return NULL;
03824
03825
03826
03827
03828 indexoidlist = RelationGetIndexList(relation);
03829
03830
03831 if (indexoidlist == NIL)
03832 return NULL;
03833
03834
03835
03836
03837
03838
03839
03840
03841
03842
03843
03844 indexattrs = NULL;
03845 uindexattrs = NULL;
03846 foreach(l, indexoidlist)
03847 {
03848 Oid indexOid = lfirst_oid(l);
03849 Relation indexDesc;
03850 IndexInfo *indexInfo;
03851 int i;
03852 bool isKey;
03853
03854 indexDesc = index_open(indexOid, AccessShareLock);
03855
03856
03857 indexInfo = BuildIndexInfo(indexDesc);
03858
03859
03860 isKey = indexInfo->ii_Unique &&
03861 indexInfo->ii_Expressions == NIL &&
03862 indexInfo->ii_Predicate == NIL;
03863
03864
03865 for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
03866 {
03867 int attrnum = indexInfo->ii_KeyAttrNumbers[i];
03868
03869 if (attrnum != 0)
03870 {
03871 indexattrs = bms_add_member(indexattrs,
03872 attrnum - FirstLowInvalidHeapAttributeNumber);
03873 if (isKey)
03874 uindexattrs = bms_add_member(uindexattrs,
03875 attrnum - FirstLowInvalidHeapAttributeNumber);
03876 }
03877 }
03878
03879
03880 pull_varattnos((Node *) indexInfo->ii_Expressions, 1, &indexattrs);
03881
03882
03883 pull_varattnos((Node *) indexInfo->ii_Predicate, 1, &indexattrs);
03884
03885 index_close(indexDesc, AccessShareLock);
03886 }
03887
03888 list_free(indexoidlist);
03889
03890
03891 oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
03892 relation->rd_indexattr = bms_copy(indexattrs);
03893 relation->rd_keyattr = bms_copy(uindexattrs);
03894 MemoryContextSwitchTo(oldcxt);
03895
03896
03897 return keyAttrs ? uindexattrs : indexattrs;
03898 }
03899
03900
03901
03902
03903
03904
03905
03906
03907
03908
03909 void
03910 RelationGetExclusionInfo(Relation indexRelation,
03911 Oid **operators,
03912 Oid **procs,
03913 uint16 **strategies)
03914 {
03915 int ncols = indexRelation->rd_rel->relnatts;
03916 Oid *ops;
03917 Oid *funcs;
03918 uint16 *strats;
03919 Relation conrel;
03920 SysScanDesc conscan;
03921 ScanKeyData skey[1];
03922 HeapTuple htup;
03923 bool found;
03924 MemoryContext oldcxt;
03925 int i;
03926
03927
03928 *operators = ops = (Oid *) palloc(sizeof(Oid) * ncols);
03929 *procs = funcs = (Oid *) palloc(sizeof(Oid) * ncols);
03930 *strategies = strats = (uint16 *) palloc(sizeof(uint16) * ncols);
03931
03932
03933 if (indexRelation->rd_exclstrats != NULL)
03934 {
03935 memcpy(ops, indexRelation->rd_exclops, sizeof(Oid) * ncols);
03936 memcpy(funcs, indexRelation->rd_exclprocs, sizeof(Oid) * ncols);
03937 memcpy(strats, indexRelation->rd_exclstrats, sizeof(uint16) * ncols);
03938 return;
03939 }
03940
03941
03942
03943
03944
03945
03946 ScanKeyInit(&skey[0],
03947 Anum_pg_constraint_conrelid,
03948 BTEqualStrategyNumber, F_OIDEQ,
03949 ObjectIdGetDatum(indexRelation->rd_index->indrelid));
03950
03951 conrel = heap_open(ConstraintRelationId, AccessShareLock);
03952 conscan = systable_beginscan(conrel, ConstraintRelidIndexId, true,
03953 SnapshotNow, 1, skey);
03954 found = false;
03955
03956 while (HeapTupleIsValid(htup = systable_getnext(conscan)))
03957 {
03958 Form_pg_constraint conform = (Form_pg_constraint) GETSTRUCT(htup);
03959 Datum val;
03960 bool isnull;
03961 ArrayType *arr;
03962 int nelem;
03963
03964
03965 if (conform->contype != CONSTRAINT_EXCLUSION ||
03966 conform->conindid != RelationGetRelid(indexRelation))
03967 continue;
03968
03969
03970 if (found)
03971 elog(ERROR, "unexpected exclusion constraint record found for rel %s",
03972 RelationGetRelationName(indexRelation));
03973 found = true;
03974
03975
03976 val = fastgetattr(htup,
03977 Anum_pg_constraint_conexclop,
03978 conrel->rd_att, &isnull);
03979 if (isnull)
03980 elog(ERROR, "null conexclop for rel %s",
03981 RelationGetRelationName(indexRelation));
03982
03983 arr = DatumGetArrayTypeP(val);
03984 nelem = ARR_DIMS(arr)[0];
03985 if (ARR_NDIM(arr) != 1 ||
03986 nelem != ncols ||
03987 ARR_HASNULL(arr) ||
03988 ARR_ELEMTYPE(arr) != OIDOID)
03989 elog(ERROR, "conexclop is not a 1-D Oid array");
03990
03991 memcpy(ops, ARR_DATA_PTR(arr), sizeof(Oid) * ncols);
03992 }
03993
03994 systable_endscan(conscan);
03995 heap_close(conrel, AccessShareLock);
03996
03997 if (!found)
03998 elog(ERROR, "exclusion constraint record missing for rel %s",
03999 RelationGetRelationName(indexRelation));
04000
04001
04002 for (i = 0; i < ncols; i++)
04003 {
04004 funcs[i] = get_opcode(ops[i]);
04005 strats[i] = get_op_opfamily_strategy(ops[i],
04006 indexRelation->rd_opfamily[i]);
04007
04008 if (strats[i] == InvalidStrategy)
04009 elog(ERROR, "could not find strategy for operator %u in family %u",
04010 ops[i], indexRelation->rd_opfamily[i]);
04011 }
04012
04013
04014 oldcxt = MemoryContextSwitchTo(indexRelation->rd_indexcxt);
04015 indexRelation->rd_exclops = (Oid *) palloc(sizeof(Oid) * ncols);
04016 indexRelation->rd_exclprocs = (Oid *) palloc(sizeof(Oid) * ncols);
04017 indexRelation->rd_exclstrats = (uint16 *) palloc(sizeof(uint16) * ncols);
04018 memcpy(indexRelation->rd_exclops, ops, sizeof(Oid) * ncols);
04019 memcpy(indexRelation->rd_exclprocs, funcs, sizeof(Oid) * ncols);
04020 memcpy(indexRelation->rd_exclstrats, strats, sizeof(uint16) * ncols);
04021 MemoryContextSwitchTo(oldcxt);
04022 }
04023
04024
04025
04026
04027
04028
04029
04030
04031
04032
04033
04034
04035
04036
04037 int
04038 errtable(Relation rel)
04039 {
04040 err_generic_string(PG_DIAG_SCHEMA_NAME,
04041 get_namespace_name(RelationGetNamespace(rel)));
04042 err_generic_string(PG_DIAG_TABLE_NAME, RelationGetRelationName(rel));
04043
04044 return 0;
04045 }
04046
04047
04048
04049
04050
04051
04052
04053
04054 int
04055 errtablecol(Relation rel, int attnum)
04056 {
04057 TupleDesc reldesc = RelationGetDescr(rel);
04058 const char *colname;
04059
04060
04061 if (attnum > 0 && attnum <= reldesc->natts)
04062 colname = NameStr(reldesc->attrs[attnum - 1]->attname);
04063 else
04064 colname = get_relid_attribute_name(RelationGetRelid(rel), attnum);
04065
04066 return errtablecolname(rel, colname);
04067 }
04068
04069
04070
04071
04072
04073
04074
04075
04076
04077
04078 int
04079 errtablecolname(Relation rel, const char *colname)
04080 {
04081 errtable(rel);
04082 err_generic_string(PG_DIAG_COLUMN_NAME, colname);
04083
04084 return 0;
04085 }
04086
04087
04088
04089
04090
04091 int
04092 errtableconstraint(Relation rel, const char *conname)
04093 {
04094 errtable(rel);
04095 err_generic_string(PG_DIAG_CONSTRAINT_NAME, conname);
04096
04097 return 0;
04098 }
04099
04100
04101
04102
04103
04104
04105
04106
04107
04108
04109
04110
04111
04112
04113
04114
04115
04116
04117
04118
04119
04120
04121
04122
04123
04124
04125
04126
04127
04128
04129
04130
04131
04132
04133
04134
04135
04136
04137
04138
04139
04140
04141
04142
04143
04144
04145
04146
04147
04148
04149
04150
04151
04152
04153
04154
04155 static bool
04156 load_relcache_init_file(bool shared)
04157 {
04158 FILE *fp;
04159 char initfilename[MAXPGPATH];
04160 Relation *rels;
04161 int relno,
04162 num_rels,
04163 max_rels,
04164 nailed_rels,
04165 nailed_indexes,
04166 magic;
04167 int i;
04168
04169 if (shared)
04170 snprintf(initfilename, sizeof(initfilename), "global/%s",
04171 RELCACHE_INIT_FILENAME);
04172 else
04173 snprintf(initfilename, sizeof(initfilename), "%s/%s",
04174 DatabasePath, RELCACHE_INIT_FILENAME);
04175
04176 fp = AllocateFile(initfilename, PG_BINARY_R);
04177 if (fp == NULL)
04178 return false;
04179
04180
04181
04182
04183
04184
04185 max_rels = 100;
04186 rels = (Relation *) palloc(max_rels * sizeof(Relation));
04187 num_rels = 0;
04188 nailed_rels = nailed_indexes = 0;
04189
04190
04191 if (fread(&magic, 1, sizeof(magic), fp) != sizeof(magic))
04192 goto read_failed;
04193 if (magic != RELCACHE_INIT_FILEMAGIC)
04194 goto read_failed;
04195
04196 for (relno = 0;; relno++)
04197 {
04198 Size len;
04199 size_t nread;
04200 Relation rel;
04201 Form_pg_class relform;
04202 bool has_not_null;
04203
04204
04205 nread = fread(&len, 1, sizeof(len), fp);
04206 if (nread != sizeof(len))
04207 {
04208 if (nread == 0)
04209 break;
04210 goto read_failed;
04211 }
04212
04213
04214 if (len != sizeof(RelationData))
04215 goto read_failed;
04216
04217
04218 if (num_rels >= max_rels)
04219 {
04220 max_rels *= 2;
04221 rels = (Relation *) repalloc(rels, max_rels * sizeof(Relation));
04222 }
04223
04224 rel = rels[num_rels++] = (Relation) palloc(len);
04225
04226
04227 if (fread(rel, 1, len, fp) != len)
04228 goto read_failed;
04229
04230
04231 if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
04232 goto read_failed;
04233
04234 relform = (Form_pg_class) palloc(len);
04235 if (fread(relform, 1, len, fp) != len)
04236 goto read_failed;
04237
04238 rel->rd_rel = relform;
04239
04240
04241 rel->rd_att = CreateTemplateTupleDesc(relform->relnatts,
04242 relform->relhasoids);
04243 rel->rd_att->tdrefcount = 1;
04244
04245 rel->rd_att->tdtypeid = relform->reltype;
04246 rel->rd_att->tdtypmod = -1;
04247
04248
04249 has_not_null = false;
04250 for (i = 0; i < relform->relnatts; i++)
04251 {
04252 if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
04253 goto read_failed;
04254 if (len != ATTRIBUTE_FIXED_PART_SIZE)
04255 goto read_failed;
04256 if (fread(rel->rd_att->attrs[i], 1, len, fp) != len)
04257 goto read_failed;
04258
04259 has_not_null |= rel->rd_att->attrs[i]->attnotnull;
04260 }
04261
04262
04263 if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
04264 goto read_failed;
04265 if (len > 0)
04266 {
04267 rel->rd_options = palloc(len);
04268 if (fread(rel->rd_options, 1, len, fp) != len)
04269 goto read_failed;
04270 if (len != VARSIZE(rel->rd_options))
04271 goto read_failed;
04272 }
04273 else
04274 {
04275 rel->rd_options = NULL;
04276 }
04277
04278
04279 if (has_not_null)
04280 {
04281 TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr));
04282
04283 constr->has_not_null = true;
04284 rel->rd_att->constr = constr;
04285 }
04286
04287
04288 if (rel->rd_rel->relkind == RELKIND_INDEX)
04289 {
04290 Form_pg_am am;
04291 MemoryContext indexcxt;
04292 Oid *opfamily;
04293 Oid *opcintype;
04294 RegProcedure *support;
04295 int nsupport;
04296 int16 *indoption;
04297 Oid *indcollation;
04298
04299
04300 if (rel->rd_isnailed)
04301 nailed_indexes++;
04302
04303
04304 if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
04305 goto read_failed;
04306
04307 rel->rd_indextuple = (HeapTuple) palloc(len);
04308 if (fread(rel->rd_indextuple, 1, len, fp) != len)
04309 goto read_failed;
04310
04311
04312 rel->rd_indextuple->t_data = (HeapTupleHeader) ((char *) rel->rd_indextuple + HEAPTUPLESIZE);
04313 rel->rd_index = (Form_pg_index) GETSTRUCT(rel->rd_indextuple);
04314
04315
04316 if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
04317 goto read_failed;
04318
04319 am = (Form_pg_am) palloc(len);
04320 if (fread(am, 1, len, fp) != len)
04321 goto read_failed;
04322 rel->rd_am = am;
04323
04324
04325
04326
04327
04328 indexcxt = AllocSetContextCreate(CacheMemoryContext,
04329 RelationGetRelationName(rel),
04330 ALLOCSET_SMALL_MINSIZE,
04331 ALLOCSET_SMALL_INITSIZE,
04332 ALLOCSET_SMALL_MAXSIZE);
04333 rel->rd_indexcxt = indexcxt;
04334
04335
04336 if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
04337 goto read_failed;
04338
04339 opfamily = (Oid *) MemoryContextAlloc(indexcxt, len);
04340 if (fread(opfamily, 1, len, fp) != len)
04341 goto read_failed;
04342
04343 rel->rd_opfamily = opfamily;
04344
04345
04346 if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
04347 goto read_failed;
04348
04349 opcintype = (Oid *) MemoryContextAlloc(indexcxt, len);
04350 if (fread(opcintype, 1, len, fp) != len)
04351 goto read_failed;
04352
04353 rel->rd_opcintype = opcintype;
04354
04355
04356 if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
04357 goto read_failed;
04358 support = (RegProcedure *) MemoryContextAlloc(indexcxt, len);
04359 if (fread(support, 1, len, fp) != len)
04360 goto read_failed;
04361
04362 rel->rd_support = support;
04363
04364
04365 if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
04366 goto read_failed;
04367
04368 indcollation = (Oid *) MemoryContextAlloc(indexcxt, len);
04369 if (fread(indcollation, 1, len, fp) != len)
04370 goto read_failed;
04371
04372 rel->rd_indcollation = indcollation;
04373
04374
04375 if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
04376 goto read_failed;
04377
04378 indoption = (int16 *) MemoryContextAlloc(indexcxt, len);
04379 if (fread(indoption, 1, len, fp) != len)
04380 goto read_failed;
04381
04382 rel->rd_indoption = indoption;
04383
04384
04385 rel->rd_aminfo = (RelationAmInfo *)
04386 MemoryContextAllocZero(indexcxt, sizeof(RelationAmInfo));
04387 nsupport = relform->relnatts * am->amsupport;
04388 rel->rd_supportinfo = (FmgrInfo *)
04389 MemoryContextAllocZero(indexcxt, nsupport * sizeof(FmgrInfo));
04390 }
04391 else
04392 {
04393
04394 if (rel->rd_isnailed)
04395 nailed_rels++;
04396
04397 Assert(rel->rd_index == NULL);
04398 Assert(rel->rd_indextuple == NULL);
04399 Assert(rel->rd_am == NULL);
04400 Assert(rel->rd_indexcxt == NULL);
04401 Assert(rel->rd_aminfo == NULL);
04402 Assert(rel->rd_opfamily == NULL);
04403 Assert(rel->rd_opcintype == NULL);
04404 Assert(rel->rd_support == NULL);
04405 Assert(rel->rd_supportinfo == NULL);
04406 Assert(rel->rd_indoption == NULL);
04407 Assert(rel->rd_indcollation == NULL);
04408 }
04409
04410
04411
04412
04413
04414
04415
04416
04417 rel->rd_rules = NULL;
04418 rel->rd_rulescxt = NULL;
04419 rel->trigdesc = NULL;
04420 rel->rd_indexprs = NIL;
04421 rel->rd_indpred = NIL;
04422 rel->rd_exclops = NULL;
04423 rel->rd_exclprocs = NULL;
04424 rel->rd_exclstrats = NULL;
04425 rel->rd_fdwroutine = NULL;
04426
04427
04428
04429
04430 rel->rd_smgr = NULL;
04431 if (rel->rd_isnailed)
04432 rel->rd_refcnt = 1;
04433 else
04434 rel->rd_refcnt = 0;
04435 rel->rd_indexvalid = 0;
04436 rel->rd_indexlist = NIL;
04437 rel->rd_indexattr = NULL;
04438 rel->rd_oidindex = InvalidOid;
04439 rel->rd_createSubid = InvalidSubTransactionId;
04440 rel->rd_newRelfilenodeSubid = InvalidSubTransactionId;
04441 rel->rd_amcache = NULL;
04442 MemSet(&rel->pgstat_info, 0, sizeof(rel->pgstat_info));
04443
04444
04445
04446
04447
04448
04449 RelationInitLockInfo(rel);
04450 RelationInitPhysicalAddr(rel);
04451 if (rel->rd_rel->relkind == RELKIND_MATVIEW &&
04452 heap_is_matview_init_state(rel))
04453 rel->rd_ispopulated = false;
04454 else
04455 rel->rd_ispopulated = true;
04456 }
04457
04458
04459
04460
04461
04462
04463 if (shared)
04464 {
04465 if (nailed_rels != NUM_CRITICAL_SHARED_RELS ||
04466 nailed_indexes != NUM_CRITICAL_SHARED_INDEXES)
04467 goto read_failed;
04468 }
04469 else
04470 {
04471 if (nailed_rels != NUM_CRITICAL_LOCAL_RELS ||
04472 nailed_indexes != NUM_CRITICAL_LOCAL_INDEXES)
04473 goto read_failed;
04474 }
04475
04476
04477
04478
04479
04480
04481 for (relno = 0; relno < num_rels; relno++)
04482 {
04483 RelationCacheInsert(rels[relno]);
04484
04485 if (!shared)
04486 initFileRelationIds = lcons_oid(RelationGetRelid(rels[relno]),
04487 initFileRelationIds);
04488 }
04489
04490 pfree(rels);
04491 FreeFile(fp);
04492
04493 if (shared)
04494 criticalSharedRelcachesBuilt = true;
04495 else
04496 criticalRelcachesBuilt = true;
04497 return true;
04498
04499
04500
04501
04502
04503
04504 read_failed:
04505 pfree(rels);
04506 FreeFile(fp);
04507
04508 return false;
04509 }
04510
04511
04512
04513
04514
04515 static void
04516 write_relcache_init_file(bool shared)
04517 {
04518 FILE *fp;
04519 char tempfilename[MAXPGPATH];
04520 char finalfilename[MAXPGPATH];
04521 int magic;
04522 HASH_SEQ_STATUS status;
04523 RelIdCacheEnt *idhentry;
04524 MemoryContext oldcxt;
04525 int i;
04526
04527
04528
04529
04530
04531
04532 if (shared)
04533 {
04534 snprintf(tempfilename, sizeof(tempfilename), "global/%s.%d",
04535 RELCACHE_INIT_FILENAME, MyProcPid);
04536 snprintf(finalfilename, sizeof(finalfilename), "global/%s",
04537 RELCACHE_INIT_FILENAME);
04538 }
04539 else
04540 {
04541 snprintf(tempfilename, sizeof(tempfilename), "%s/%s.%d",
04542 DatabasePath, RELCACHE_INIT_FILENAME, MyProcPid);
04543 snprintf(finalfilename, sizeof(finalfilename), "%s/%s",
04544 DatabasePath, RELCACHE_INIT_FILENAME);
04545 }
04546
04547 unlink(tempfilename);
04548
04549 fp = AllocateFile(tempfilename, PG_BINARY_W);
04550 if (fp == NULL)
04551 {
04552
04553
04554
04555
04556 ereport(WARNING,
04557 (errcode_for_file_access(),
04558 errmsg("could not create relation-cache initialization file \"%s\": %m",
04559 tempfilename),
04560 errdetail("Continuing anyway, but there's something wrong.")));
04561 return;
04562 }
04563
04564
04565
04566
04567
04568 magic = RELCACHE_INIT_FILEMAGIC;
04569 if (fwrite(&magic, 1, sizeof(magic), fp) != sizeof(magic))
04570 elog(FATAL, "could not write init file");
04571
04572
04573
04574
04575 hash_seq_init(&status, RelationIdCache);
04576
04577 while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
04578 {
04579 Relation rel = idhentry->reldesc;
04580 Form_pg_class relform = rel->rd_rel;
04581
04582
04583 if (relform->relisshared != shared)
04584 continue;
04585
04586
04587 write_item(rel, sizeof(RelationData), fp);
04588
04589
04590 write_item(relform, CLASS_TUPLE_SIZE, fp);
04591
04592
04593 for (i = 0; i < relform->relnatts; i++)
04594 {
04595 write_item(rel->rd_att->attrs[i], ATTRIBUTE_FIXED_PART_SIZE, fp);
04596 }
04597
04598
04599 write_item(rel->rd_options,
04600 (rel->rd_options ? VARSIZE(rel->rd_options) : 0),
04601 fp);
04602
04603
04604 if (rel->rd_rel->relkind == RELKIND_INDEX)
04605 {
04606 Form_pg_am am = rel->rd_am;
04607
04608
04609
04610 write_item(rel->rd_indextuple,
04611 HEAPTUPLESIZE + rel->rd_indextuple->t_len,
04612 fp);
04613
04614
04615 write_item(am, sizeof(FormData_pg_am), fp);
04616
04617
04618 write_item(rel->rd_opfamily,
04619 relform->relnatts * sizeof(Oid),
04620 fp);
04621
04622
04623 write_item(rel->rd_opcintype,
04624 relform->relnatts * sizeof(Oid),
04625 fp);
04626
04627
04628 write_item(rel->rd_support,
04629 relform->relnatts * (am->amsupport * sizeof(RegProcedure)),
04630 fp);
04631
04632
04633 write_item(rel->rd_indcollation,
04634 relform->relnatts * sizeof(Oid),
04635 fp);
04636
04637
04638 write_item(rel->rd_indoption,
04639 relform->relnatts * sizeof(int16),
04640 fp);
04641 }
04642
04643
04644 if (!shared)
04645 {
04646 oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
04647 initFileRelationIds = lcons_oid(RelationGetRelid(rel),
04648 initFileRelationIds);
04649 MemoryContextSwitchTo(oldcxt);
04650 }
04651 }
04652
04653 if (FreeFile(fp))
04654 elog(FATAL, "could not write init file");
04655
04656
04657
04658
04659
04660
04661
04662
04663
04664
04665
04666
04667 LWLockAcquire(RelCacheInitLock, LW_EXCLUSIVE);
04668
04669
04670 AcceptInvalidationMessages();
04671
04672
04673
04674
04675
04676 if (relcacheInvalsReceived == 0L)
04677 {
04678
04679
04680
04681
04682
04683
04684
04685
04686
04687 if (rename(tempfilename, finalfilename) < 0)
04688 unlink(tempfilename);
04689 }
04690 else
04691 {
04692
04693 unlink(tempfilename);
04694 }
04695
04696 LWLockRelease(RelCacheInitLock);
04697 }
04698
04699
04700 static void
04701 write_item(const void *data, Size len, FILE *fp)
04702 {
04703 if (fwrite(&len, 1, sizeof(len), fp) != sizeof(len))
04704 elog(FATAL, "could not write init file");
04705 if (fwrite(data, 1, len, fp) != len)
04706 elog(FATAL, "could not write init file");
04707 }
04708
04709
04710
04711
04712
04713
04714
04715
04716
04717
04718 bool
04719 RelationIdIsInInitFile(Oid relationId)
04720 {
04721 return list_member_oid(initFileRelationIds, relationId);
04722 }
04723
04724
04725
04726
04727
04728
04729
04730
04731
04732
04733
04734
04735
04736
04737
04738
04739
04740
04741
04742
04743
04744
04745
04746
04747
04748
04749
04750
04751
04752
04753 void
04754 RelationCacheInitFilePreInvalidate(void)
04755 {
04756 char initfilename[MAXPGPATH];
04757
04758 snprintf(initfilename, sizeof(initfilename), "%s/%s",
04759 DatabasePath, RELCACHE_INIT_FILENAME);
04760
04761 LWLockAcquire(RelCacheInitLock, LW_EXCLUSIVE);
04762
04763 if (unlink(initfilename) < 0)
04764 {
04765
04766
04767
04768
04769
04770
04771 if (errno != ENOENT)
04772 ereport(ERROR,
04773 (errcode_for_file_access(),
04774 errmsg("could not remove cache file \"%s\": %m",
04775 initfilename)));
04776 }
04777 }
04778
04779 void
04780 RelationCacheInitFilePostInvalidate(void)
04781 {
04782 LWLockRelease(RelCacheInitLock);
04783 }
04784
04785
04786
04787
04788
04789
04790
04791
04792
04793
04794 void
04795 RelationCacheInitFileRemove(void)
04796 {
04797 const char *tblspcdir = "pg_tblspc";
04798 DIR *dir;
04799 struct dirent *de;
04800 char path[MAXPGPATH];
04801
04802
04803
04804
04805
04806 snprintf(path, sizeof(path), "global/%s",
04807 RELCACHE_INIT_FILENAME);
04808 unlink_initfile(path);
04809
04810
04811 RelationCacheInitFileRemoveInDir("base");
04812
04813
04814 dir = AllocateDir(tblspcdir);
04815 if (dir == NULL)
04816 {
04817 elog(LOG, "could not open tablespace link directory \"%s\": %m",
04818 tblspcdir);
04819 return;
04820 }
04821
04822 while ((de = ReadDir(dir, tblspcdir)) != NULL)
04823 {
04824 if (strspn(de->d_name, "0123456789") == strlen(de->d_name))
04825 {
04826
04827 snprintf(path, sizeof(path), "%s/%s/%s",
04828 tblspcdir, de->d_name, TABLESPACE_VERSION_DIRECTORY);
04829 RelationCacheInitFileRemoveInDir(path);
04830 }
04831 }
04832
04833 FreeDir(dir);
04834 }
04835
04836
04837 static void
04838 RelationCacheInitFileRemoveInDir(const char *tblspcpath)
04839 {
04840 DIR *dir;
04841 struct dirent *de;
04842 char initfilename[MAXPGPATH];
04843
04844
04845 dir = AllocateDir(tblspcpath);
04846 if (dir == NULL)
04847 {
04848 elog(LOG, "could not open tablespace directory \"%s\": %m",
04849 tblspcpath);
04850 return;
04851 }
04852
04853 while ((de = ReadDir(dir, tblspcpath)) != NULL)
04854 {
04855 if (strspn(de->d_name, "0123456789") == strlen(de->d_name))
04856 {
04857
04858 snprintf(initfilename, sizeof(initfilename), "%s/%s/%s",
04859 tblspcpath, de->d_name, RELCACHE_INIT_FILENAME);
04860 unlink_initfile(initfilename);
04861 }
04862 }
04863
04864 FreeDir(dir);
04865 }
04866
04867 static void
04868 unlink_initfile(const char *initfilename)
04869 {
04870 if (unlink(initfilename) < 0)
04871 {
04872
04873 if (errno != ENOENT)
04874 elog(LOG, "could not remove cache file \"%s\": %m", initfilename);
04875 }
04876 }