PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
bootstrap.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * bootstrap.c
4  * routines to support running postgres in 'bootstrap' mode
5  * bootstrap mode is used to create the initial template database
6  *
7  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  * IDENTIFICATION
11  * src/backend/bootstrap/bootstrap.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16 
17 #include <unistd.h>
18 #include <signal.h>
19 
20 #include "access/htup_details.h"
21 #include "bootstrap/bootstrap.h"
22 #include "catalog/index.h"
23 #include "catalog/pg_collation.h"
24 #include "catalog/pg_type.h"
25 #include "libpq/pqsignal.h"
26 #include "miscadmin.h"
27 #include "nodes/makefuncs.h"
28 #include "pg_getopt.h"
29 #include "pgstat.h"
30 #include "postmaster/bgwriter.h"
31 #include "postmaster/startup.h"
32 #include "postmaster/walwriter.h"
34 #include "storage/bufmgr.h"
35 #include "storage/bufpage.h"
37 #include "storage/ipc.h"
38 #include "storage/proc.h"
39 #include "tcop/tcopprot.h"
40 #include "utils/builtins.h"
41 #include "utils/fmgroids.h"
42 #include "utils/memutils.h"
43 #include "utils/ps_status.h"
44 #include "utils/rel.h"
45 #include "utils/relmapper.h"
46 #include "utils/tqual.h"
47 
49 
50 
51 #define ALLOC(t, c) \
52  ((t *) MemoryContextAllocZero(TopMemoryContext, (unsigned)(c) * sizeof(t)))
53 
54 static void CheckerModeMain(void);
55 static void BootstrapModeMain(void);
56 static void bootstrap_signals(void);
57 static void ShutdownAuxiliaryProcess(int code, Datum arg);
59 static Oid gettype(char *type);
60 static void cleanup(void);
61 
62 /* ----------------
63  * global variables
64  * ----------------
65  */
66 
67 AuxProcType MyAuxProcType = NotAnAuxProcess; /* declared in miscadmin.h */
68 
69 Relation boot_reldesc; /* current relation descriptor */
70 
71 Form_pg_attribute attrtypes[MAXATTR]; /* points to attribute info */
72 int numattr; /* number of attributes for cur. rel */
73 
74 
75 /*
76  * Basic information associated with each type. This is used before
77  * pg_type is filled, so it has to cover the datatypes used as column types
78  * in the core "bootstrapped" catalogs.
79  *
80  * XXX several of these input/output functions do catalog scans
81  * (e.g., F_REGPROCIN scans pg_proc). this obviously creates some
82  * order dependencies in the catalog creation process.
83  */
84 struct typinfo
85 {
90  bool byval;
91  char align;
92  char storage;
96 };
97 
98 static const struct typinfo TypInfo[] = {
99  {"bool", BOOLOID, 0, 1, true, 'c', 'p', InvalidOid,
100  F_BOOLIN, F_BOOLOUT},
101  {"bytea", BYTEAOID, 0, -1, false, 'i', 'x', InvalidOid,
102  F_BYTEAIN, F_BYTEAOUT},
103  {"char", CHAROID, 0, 1, true, 'c', 'p', InvalidOid,
104  F_CHARIN, F_CHAROUT},
105  {"int2", INT2OID, 0, 2, true, 's', 'p', InvalidOid,
106  F_INT2IN, F_INT2OUT},
107  {"int4", INT4OID, 0, 4, true, 'i', 'p', InvalidOid,
108  F_INT4IN, F_INT4OUT},
109  {"float4", FLOAT4OID, 0, 4, FLOAT4PASSBYVAL, 'i', 'p', InvalidOid,
110  F_FLOAT4IN, F_FLOAT4OUT},
111  {"name", NAMEOID, CHAROID, NAMEDATALEN, false, 'c', 'p', InvalidOid,
112  F_NAMEIN, F_NAMEOUT},
113  {"regclass", REGCLASSOID, 0, 4, true, 'i', 'p', InvalidOid,
114  F_REGCLASSIN, F_REGCLASSOUT},
115  {"regproc", REGPROCOID, 0, 4, true, 'i', 'p', InvalidOid,
116  F_REGPROCIN, F_REGPROCOUT},
117  {"regtype", REGTYPEOID, 0, 4, true, 'i', 'p', InvalidOid,
118  F_REGTYPEIN, F_REGTYPEOUT},
119  {"regrole", REGROLEOID, 0, 4, true, 'i', 'p', InvalidOid,
120  F_REGROLEIN, F_REGROLEOUT},
121  {"regnamespace", REGNAMESPACEOID, 0, 4, true, 'i', 'p', InvalidOid,
122  F_REGNAMESPACEIN, F_REGNAMESPACEOUT},
123  {"text", TEXTOID, 0, -1, false, 'i', 'x', DEFAULT_COLLATION_OID,
124  F_TEXTIN, F_TEXTOUT},
125  {"oid", OIDOID, 0, 4, true, 'i', 'p', InvalidOid,
126  F_OIDIN, F_OIDOUT},
127  {"tid", TIDOID, 0, 6, false, 's', 'p', InvalidOid,
128  F_TIDIN, F_TIDOUT},
129  {"xid", XIDOID, 0, 4, true, 'i', 'p', InvalidOid,
130  F_XIDIN, F_XIDOUT},
131  {"cid", CIDOID, 0, 4, true, 'i', 'p', InvalidOid,
132  F_CIDIN, F_CIDOUT},
133  {"pg_node_tree", PGNODETREEOID, 0, -1, false, 'i', 'x', DEFAULT_COLLATION_OID,
134  F_PG_NODE_TREE_IN, F_PG_NODE_TREE_OUT},
135  {"int2vector", INT2VECTOROID, INT2OID, -1, false, 'i', 'p', InvalidOid,
136  F_INT2VECTORIN, F_INT2VECTOROUT},
137  {"oidvector", OIDVECTOROID, OIDOID, -1, false, 'i', 'p', InvalidOid,
138  F_OIDVECTORIN, F_OIDVECTOROUT},
139  {"_int4", INT4ARRAYOID, INT4OID, -1, false, 'i', 'x', InvalidOid,
140  F_ARRAY_IN, F_ARRAY_OUT},
141  {"_text", 1009, TEXTOID, -1, false, 'i', 'x', DEFAULT_COLLATION_OID,
142  F_ARRAY_IN, F_ARRAY_OUT},
143  {"_oid", 1028, OIDOID, -1, false, 'i', 'x', InvalidOid,
144  F_ARRAY_IN, F_ARRAY_OUT},
145  {"_char", 1002, CHAROID, -1, false, 'i', 'x', InvalidOid,
146  F_ARRAY_IN, F_ARRAY_OUT},
147  {"_aclitem", 1034, ACLITEMOID, -1, false, 'i', 'x', InvalidOid,
148  F_ARRAY_IN, F_ARRAY_OUT}
149 };
150 
151 static const int n_types = sizeof(TypInfo) / sizeof(struct typinfo);
152 
153 struct typmap
154 { /* a hack */
157 };
158 
159 static struct typmap **Typ = NULL;
160 static struct typmap *Ap = NULL;
161 
162 static Datum values[MAXATTR]; /* current row's attribute values */
163 static bool Nulls[MAXATTR];
164 
165 static MemoryContext nogc = NULL; /* special no-gc mem context */
166 
167 /*
168  * At bootstrap time, we first declare all the indices to be built, and
169  * then build them. The IndexList structure stores enough information
170  * to allow us to build the indices after they've been declared.
171  */
172 
173 typedef struct _IndexList
174 {
179 } IndexList;
180 
182 
183 
184 /*
185  * AuxiliaryProcessMain
186  *
187  * The main entry point for auxiliary processes, such as the bgwriter,
188  * walwriter, walreceiver, bootstrapper and the shared memory checker code.
189  *
190  * This code is here just because of historical reasons.
191  */
192 void
193 AuxiliaryProcessMain(int argc, char *argv[])
194 {
195  char *progname = argv[0];
196  int flag;
197  char *userDoption = NULL;
198 
199  /*
200  * Initialize process environment (already done if under postmaster, but
201  * not if standalone).
202  */
203  if (!IsUnderPostmaster)
204  InitStandaloneProcess(argv[0]);
205 
206  /*
207  * process command arguments
208  */
209 
210  /* Set defaults, to be overridden by explicit options below */
211  if (!IsUnderPostmaster)
213 
214  /* Ignore the initial --boot argument, if present */
215  if (argc > 1 && strcmp(argv[1], "--boot") == 0)
216  {
217  argv++;
218  argc--;
219  }
220 
221  /* If no -x argument, we are a CheckerProcess */
223 
224  while ((flag = getopt(argc, argv, "B:c:d:D:Fkr:x:-:")) != -1)
225  {
226  switch (flag)
227  {
228  case 'B':
229  SetConfigOption("shared_buffers", optarg, PGC_POSTMASTER, PGC_S_ARGV);
230  break;
231  case 'D':
232  userDoption = pstrdup(optarg);
233  break;
234  case 'd':
235  {
236  /* Turn on debugging for the bootstrap process. */
237  char *debugstr;
238 
239  debugstr = psprintf("debug%s", optarg);
240  SetConfigOption("log_min_messages", debugstr,
242  SetConfigOption("client_min_messages", debugstr,
244  pfree(debugstr);
245  }
246  break;
247  case 'F':
248  SetConfigOption("fsync", "false", PGC_POSTMASTER, PGC_S_ARGV);
249  break;
250  case 'k':
252  break;
253  case 'r':
255  break;
256  case 'x':
257  MyAuxProcType = atoi(optarg);
258  break;
259  case 'c':
260  case '-':
261  {
262  char *name,
263  *value;
264 
265  ParseLongOption(optarg, &name, &value);
266  if (!value)
267  {
268  if (flag == '-')
269  ereport(ERROR,
270  (errcode(ERRCODE_SYNTAX_ERROR),
271  errmsg("--%s requires a value",
272  optarg)));
273  else
274  ereport(ERROR,
275  (errcode(ERRCODE_SYNTAX_ERROR),
276  errmsg("-c %s requires a value",
277  optarg)));
278  }
279 
281  free(name);
282  if (value)
283  free(value);
284  break;
285  }
286  default:
287  write_stderr("Try \"%s --help\" for more information.\n",
288  progname);
289  proc_exit(1);
290  break;
291  }
292  }
293 
294  if (argc != optind)
295  {
296  write_stderr("%s: invalid command-line arguments\n", progname);
297  proc_exit(1);
298  }
299 
300  /*
301  * Identify myself via ps
302  */
303  if (IsUnderPostmaster)
304  {
305  const char *statmsg;
306 
307  switch (MyAuxProcType)
308  {
309  case StartupProcess:
310  statmsg = "startup process";
311  break;
312  case BgWriterProcess:
313  statmsg = "writer process";
314  break;
315  case CheckpointerProcess:
316  statmsg = "checkpointer process";
317  break;
318  case WalWriterProcess:
319  statmsg = "wal writer process";
320  break;
321  case WalReceiverProcess:
322  statmsg = "wal receiver process";
323  break;
324  default:
325  statmsg = "??? process";
326  break;
327  }
328  init_ps_display(statmsg, "", "", "");
329  }
330 
331  /* Acquire configuration parameters, unless inherited from postmaster */
332  if (!IsUnderPostmaster)
333  {
334  if (!SelectConfigFiles(userDoption, progname))
335  proc_exit(1);
336  }
337 
338  /* Validate we have been given a reasonable-looking DataDir */
339  Assert(DataDir);
341 
342  /* Change into DataDir (if under postmaster, should be done already) */
343  if (!IsUnderPostmaster)
344  ChangeToDataDir();
345 
346  /* If standalone, create lockfile for data directory */
347  if (!IsUnderPostmaster)
348  CreateDataDirLockFile(false);
349 
351  IgnoreSystemIndexes = true;
352 
353  /* Initialize MaxBackends (if under postmaster, was done already) */
354  if (!IsUnderPostmaster)
356 
357  BaseInit();
358 
359  /*
360  * When we are an auxiliary process, we aren't going to do the full
361  * InitPostgres pushups, but there are a couple of things that need to get
362  * lit up even in an auxiliary process.
363  */
364  if (IsUnderPostmaster)
365  {
366  /*
367  * Create a PGPROC so we can use LWLocks. In the EXEC_BACKEND case,
368  * this was already done by SubPostmasterMain().
369  */
370 #ifndef EXEC_BACKEND
372 #endif
373 
374  /*
375  * Assign the ProcSignalSlot for an auxiliary process. Since it
376  * doesn't have a BackendId, the slot is statically allocated based on
377  * the auxiliary process type (MyAuxProcType). Backends use slots
378  * indexed in the range from 1 to MaxBackends (inclusive), so we use
379  * MaxBackends + AuxProcType + 1 as the index of the slot for an
380  * auxiliary process.
381  *
382  * This will need rethinking if we ever want more than one of a
383  * particular auxiliary process type.
384  */
386 
387  /* finish setting up bufmgr.c */
389 
390  /* Initialize backend status information */
392  pgstat_bestart();
393 
394  /* register a before-shutdown callback for LWLock cleanup */
396  }
397 
398  /*
399  * XLOG operations
400  */
402 
403  switch (MyAuxProcType)
404  {
405  case CheckerProcess:
406  /* don't set signals, they're useless here */
407  CheckerModeMain();
408  proc_exit(1); /* should never return */
409 
410  case BootstrapProcess:
411 
412  /*
413  * There was a brief instant during which mode was Normal; this is
414  * okay. We need to be in bootstrap mode during BootStrapXLOG for
415  * the sake of multixact initialization.
416  */
419  BootStrapXLOG();
421  proc_exit(1); /* should never return */
422 
423  case StartupProcess:
424  /* don't set signals, startup process has its own agenda */
426  proc_exit(1); /* should never return */
427 
428  case BgWriterProcess:
429  /* don't set signals, bgwriter has its own agenda */
431  proc_exit(1); /* should never return */
432 
433  case CheckpointerProcess:
434  /* don't set signals, checkpointer has its own agenda */
436  proc_exit(1); /* should never return */
437 
438  case WalWriterProcess:
439  /* don't set signals, walwriter has its own agenda */
440  InitXLOGAccess();
441  WalWriterMain();
442  proc_exit(1); /* should never return */
443 
444  case WalReceiverProcess:
445  /* don't set signals, walreceiver has its own agenda */
446  WalReceiverMain();
447  proc_exit(1); /* should never return */
448 
449  default:
450  elog(PANIC, "unrecognized process type: %d", (int) MyAuxProcType);
451  proc_exit(1);
452  }
453 }
454 
455 /*
456  * In shared memory checker mode, all we really want to do is create shared
457  * memory and semaphores (just to prove we can do it with the current GUC
458  * settings). Since, in fact, that was already done by BaseInit(),
459  * we have nothing more to do here.
460  */
461 static void
463 {
464  proc_exit(0);
465 }
466 
467 /*
468  * The main entry point for running the backend in bootstrap mode
469  *
470  * The bootstrap mode is used to initialize the template database.
471  * The bootstrap backend doesn't speak SQL, but instead expects
472  * commands in a special bootstrap language.
473  */
474 static void
476 {
477  int i;
478 
481 
482  /*
483  * Do backend-like initialization for bootstrap mode
484  */
485  InitProcess();
486 
488 
489  /* Initialize stuff for bootstrap-file processing */
490  for (i = 0; i < MAXATTR; i++)
491  {
492  attrtypes[i] = NULL;
493  Nulls[i] = false;
494  }
495 
496  /*
497  * Process bootstrap input.
498  */
499  boot_yyparse();
500 
501  /*
502  * We should now know about all mapped relations, so it's okay to write
503  * out the initial relation mapping files.
504  */
506 
507  /* Clean up and exit */
508  cleanup();
509  proc_exit(0);
510 }
511 
512 
513 /* ----------------------------------------------------------------
514  * misc functions
515  * ----------------------------------------------------------------
516  */
517 
518 /*
519  * Set up signal handling for a bootstrap process
520  */
521 static void
523 {
525 
526  /* Set up appropriately for interactive use */
527  pqsignal(SIGHUP, die);
528  pqsignal(SIGINT, die);
529  pqsignal(SIGTERM, die);
530  pqsignal(SIGQUIT, die);
531 }
532 
533 /*
534  * Begin shutdown of an auxiliary process. This is approximately the equivalent
535  * of ShutdownPostgres() in postinit.c. We can't run transactions in an
536  * auxiliary process, so most of the work of AbortTransaction() is not needed,
537  * but we do need to make sure we've released any LWLocks we are holding.
538  * (This is only critical during an error exit.)
539  */
540 static void
542 {
546 }
547 
548 /* ----------------------------------------------------------------
549  * MANUAL BACKEND INTERACTIVE INTERFACE COMMANDS
550  * ----------------------------------------------------------------
551  */
552 
553 /* ----------------
554  * boot_openrel
555  * ----------------
556  */
557 void
558 boot_openrel(char *relname)
559 {
560  int i;
561  struct typmap **app;
562  Relation rel;
563  HeapScanDesc scan;
564  HeapTuple tup;
565 
566  if (strlen(relname) >= NAMEDATALEN)
567  relname[NAMEDATALEN - 1] = '\0';
568 
569  if (Typ == NULL)
570  {
571  /* We can now load the pg_type data */
573  scan = heap_beginscan_catalog(rel, 0, NULL);
574  i = 0;
575  while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL)
576  ++i;
577  heap_endscan(scan);
578  app = Typ = ALLOC(struct typmap *, i + 1);
579  while (i-- > 0)
580  *app++ = ALLOC(struct typmap, 1);
581  *app = NULL;
582  scan = heap_beginscan_catalog(rel, 0, NULL);
583  app = Typ;
584  while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL)
585  {
586  (*app)->am_oid = HeapTupleGetOid(tup);
587  memcpy((char *) &(*app)->am_typ,
588  (char *) GETSTRUCT(tup),
589  sizeof((*app)->am_typ));
590  app++;
591  }
592  heap_endscan(scan);
593  heap_close(rel, NoLock);
594  }
595 
596  if (boot_reldesc != NULL)
597  closerel(NULL);
598 
599  elog(DEBUG4, "open relation %s, attrsize %d",
600  relname, (int) ATTRIBUTE_FIXED_PART_SIZE);
601 
602  boot_reldesc = heap_openrv(makeRangeVar(NULL, relname, -1), NoLock);
603  numattr = boot_reldesc->rd_rel->relnatts;
604  for (i = 0; i < numattr; i++)
605  {
606  if (attrtypes[i] == NULL)
608  memmove((char *) attrtypes[i],
609  (char *) boot_reldesc->rd_att->attrs[i],
610  ATTRIBUTE_FIXED_PART_SIZE);
611 
612  {
614 
615  elog(DEBUG4, "create attribute %d name %s len %d num %d type %u",
616  i, NameStr(at->attname), at->attlen, at->attnum,
617  at->atttypid);
618  }
619  }
620 }
621 
622 /* ----------------
623  * closerel
624  * ----------------
625  */
626 void
628 {
629  if (name)
630  {
631  if (boot_reldesc)
632  {
633  if (strcmp(RelationGetRelationName(boot_reldesc), name) != 0)
634  elog(ERROR, "close of %s when %s was expected",
635  name, RelationGetRelationName(boot_reldesc));
636  }
637  else
638  elog(ERROR, "close of %s before any relation was opened",
639  name);
640  }
641 
642  if (boot_reldesc == NULL)
643  elog(ERROR, "no open relation to close");
644  else
645  {
646  elog(DEBUG4, "close relation %s",
647  RelationGetRelationName(boot_reldesc));
648  heap_close(boot_reldesc, NoLock);
649  boot_reldesc = NULL;
650  }
651 }
652 
653 
654 
655 /* ----------------
656  * DEFINEATTR()
657  *
658  * define a <field,type> pair
659  * if there are n fields in a relation to be created, this routine
660  * will be called n times
661  * ----------------
662  */
663 void
664 DefineAttr(char *name, char *type, int attnum, int nullness)
665 {
666  Oid typeoid;
667 
668  if (boot_reldesc != NULL)
669  {
670  elog(WARNING, "no open relations allowed with CREATE command");
671  closerel(NULL);
672  }
673 
674  if (attrtypes[attnum] == NULL)
675  attrtypes[attnum] = AllocateAttribute();
677 
678  namestrcpy(&attrtypes[attnum]->attname, name);
679  elog(DEBUG4, "column %s %s", NameStr(attrtypes[attnum]->attname), type);
680  attrtypes[attnum]->attnum = attnum + 1; /* fillatt */
681 
682  typeoid = gettype(type);
683 
684  if (Typ != NULL)
685  {
686  attrtypes[attnum]->atttypid = Ap->am_oid;
687  attrtypes[attnum]->attlen = Ap->am_typ.typlen;
688  attrtypes[attnum]->attbyval = Ap->am_typ.typbyval;
689  attrtypes[attnum]->attstorage = Ap->am_typ.typstorage;
690  attrtypes[attnum]->attalign = Ap->am_typ.typalign;
691  attrtypes[attnum]->attcollation = Ap->am_typ.typcollation;
692  /* if an array type, assume 1-dimensional attribute */
693  if (Ap->am_typ.typelem != InvalidOid && Ap->am_typ.typlen < 0)
694  attrtypes[attnum]->attndims = 1;
695  else
696  attrtypes[attnum]->attndims = 0;
697  }
698  else
699  {
700  attrtypes[attnum]->atttypid = TypInfo[typeoid].oid;
701  attrtypes[attnum]->attlen = TypInfo[typeoid].len;
702  attrtypes[attnum]->attbyval = TypInfo[typeoid].byval;
703  attrtypes[attnum]->attstorage = TypInfo[typeoid].storage;
704  attrtypes[attnum]->attalign = TypInfo[typeoid].align;
705  attrtypes[attnum]->attcollation = TypInfo[typeoid].collation;
706  /* if an array type, assume 1-dimensional attribute */
707  if (TypInfo[typeoid].elem != InvalidOid &&
708  attrtypes[attnum]->attlen < 0)
709  attrtypes[attnum]->attndims = 1;
710  else
711  attrtypes[attnum]->attndims = 0;
712  }
713 
714  attrtypes[attnum]->attstattarget = -1;
715  attrtypes[attnum]->attcacheoff = -1;
716  attrtypes[attnum]->atttypmod = -1;
717  attrtypes[attnum]->attislocal = true;
718 
719  if (nullness == BOOTCOL_NULL_FORCE_NOT_NULL)
720  {
721  attrtypes[attnum]->attnotnull = true;
722  }
723  else if (nullness == BOOTCOL_NULL_FORCE_NULL)
724  {
725  attrtypes[attnum]->attnotnull = false;
726  }
727  else
728  {
729  Assert(nullness == BOOTCOL_NULL_AUTO);
730 
731  /*
732  * Mark as "not null" if type is fixed-width and prior columns are
733  * too. This corresponds to case where column can be accessed
734  * directly via C struct declaration.
735  *
736  * oidvector and int2vector are also treated as not-nullable, even
737  * though they are no longer fixed-width.
738  */
739 #define MARKNOTNULL(att) \
740  ((att)->attlen > 0 || \
741  (att)->atttypid == OIDVECTOROID || \
742  (att)->atttypid == INT2VECTOROID)
743 
744  if (MARKNOTNULL(attrtypes[attnum]))
745  {
746  int i;
747 
748  /* check earlier attributes */
749  for (i = 0; i < attnum; i++)
750  {
751  if (!attrtypes[i]->attnotnull)
752  break;
753  }
754  if (i == attnum)
755  attrtypes[attnum]->attnotnull = true;
756  }
757  }
758 }
759 
760 
761 /* ----------------
762  * InsertOneTuple
763  *
764  * If objectid is not zero, it is a specific OID to assign to the tuple.
765  * Otherwise, an OID will be assigned (if necessary) by heap_insert.
766  * ----------------
767  */
768 void
770 {
771  HeapTuple tuple;
772  TupleDesc tupDesc;
773  int i;
774 
775  elog(DEBUG4, "inserting row oid %u, %d columns", objectid, numattr);
776 
777  tupDesc = CreateTupleDesc(numattr,
778  RelationGetForm(boot_reldesc)->relhasoids,
779  attrtypes);
780  tuple = heap_form_tuple(tupDesc, values, Nulls);
781  if (objectid != (Oid) 0)
782  HeapTupleSetOid(tuple, objectid);
783  pfree(tupDesc); /* just free's tupDesc, not the attrtypes */
784 
785  simple_heap_insert(boot_reldesc, tuple);
786  heap_freetuple(tuple);
787  elog(DEBUG4, "row inserted");
788 
789  /*
790  * Reset null markers for next tuple
791  */
792  for (i = 0; i < numattr; i++)
793  Nulls[i] = false;
794 }
795 
796 /* ----------------
797  * InsertOneValue
798  * ----------------
799  */
800 void
801 InsertOneValue(char *value, int i)
802 {
803  Oid typoid;
804  int16 typlen;
805  bool typbyval;
806  char typalign;
807  char typdelim;
808  Oid typioparam;
809  Oid typinput;
810  Oid typoutput;
811 
812  AssertArg(i >= 0 && i < MAXATTR);
813 
814  elog(DEBUG4, "inserting column %d value \"%s\"", i, value);
815 
816  typoid = boot_reldesc->rd_att->attrs[i]->atttypid;
817 
818  boot_get_type_io_data(typoid,
819  &typlen, &typbyval, &typalign,
820  &typdelim, &typioparam,
821  &typinput, &typoutput);
822 
823  values[i] = OidInputFunctionCall(typinput, value, typioparam, -1);
824 
825  /*
826  * We use ereport not elog here so that parameters aren't evaluated unless
827  * the message is going to be printed, which generally it isn't
828  */
829  ereport(DEBUG4,
830  (errmsg_internal("inserted -> %s",
831  OidOutputFunctionCall(typoutput, values[i]))));
832 }
833 
834 /* ----------------
835  * InsertOneNull
836  * ----------------
837  */
838 void
840 {
841  elog(DEBUG4, "inserting column %d NULL", i);
842  Assert(i >= 0 && i < MAXATTR);
843  values[i] = PointerGetDatum(NULL);
844  Nulls[i] = true;
845 }
846 
847 /* ----------------
848  * cleanup
849  * ----------------
850  */
851 static void
852 cleanup(void)
853 {
854  if (boot_reldesc != NULL)
855  closerel(NULL);
856 }
857 
858 /* ----------------
859  * gettype
860  *
861  * NB: this is really ugly; it will return an integer index into TypInfo[],
862  * and not an OID at all, until the first reference to a type not known in
863  * TypInfo[]. At that point it will read and cache pg_type in the Typ array,
864  * and subsequently return a real OID (and set the global pointer Ap to
865  * point at the found row in Typ). So caller must check whether Typ is
866  * still NULL to determine what the return value is!
867  * ----------------
868  */
869 static Oid
870 gettype(char *type)
871 {
872  int i;
873  Relation rel;
874  HeapScanDesc scan;
875  HeapTuple tup;
876  struct typmap **app;
877 
878  if (Typ != NULL)
879  {
880  for (app = Typ; *app != NULL; app++)
881  {
882  if (strncmp(NameStr((*app)->am_typ.typname), type, NAMEDATALEN) == 0)
883  {
884  Ap = *app;
885  return (*app)->am_oid;
886  }
887  }
888  }
889  else
890  {
891  for (i = 0; i < n_types; i++)
892  {
893  if (strncmp(type, TypInfo[i].name, NAMEDATALEN) == 0)
894  return i;
895  }
896  elog(DEBUG4, "external type: %s", type);
898  scan = heap_beginscan_catalog(rel, 0, NULL);
899  i = 0;
900  while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL)
901  ++i;
902  heap_endscan(scan);
903  app = Typ = ALLOC(struct typmap *, i + 1);
904  while (i-- > 0)
905  *app++ = ALLOC(struct typmap, 1);
906  *app = NULL;
907  scan = heap_beginscan_catalog(rel, 0, NULL);
908  app = Typ;
909  while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL)
910  {
911  (*app)->am_oid = HeapTupleGetOid(tup);
912  memmove((char *) &(*app++)->am_typ,
913  (char *) GETSTRUCT(tup),
914  sizeof((*app)->am_typ));
915  }
916  heap_endscan(scan);
917  heap_close(rel, NoLock);
918  return gettype(type);
919  }
920  elog(ERROR, "unrecognized type \"%s\"", type);
921  /* not reached, here to make compiler happy */
922  return 0;
923 }
924 
925 /* ----------------
926  * boot_get_type_io_data
927  *
928  * Obtain type I/O information at bootstrap time. This intentionally has
929  * almost the same API as lsyscache.c's get_type_io_data, except that
930  * we only support obtaining the typinput and typoutput routines, not
931  * the binary I/O routines. It is exported so that array_in and array_out
932  * can be made to work during early bootstrap.
933  * ----------------
934  */
935 void
937  int16 *typlen,
938  bool *typbyval,
939  char *typalign,
940  char *typdelim,
941  Oid *typioparam,
942  Oid *typinput,
943  Oid *typoutput)
944 {
945  if (Typ != NULL)
946  {
947  /* We have the boot-time contents of pg_type, so use it */
948  struct typmap **app;
949  struct typmap *ap;
950 
951  app = Typ;
952  while (*app && (*app)->am_oid != typid)
953  ++app;
954  ap = *app;
955  if (ap == NULL)
956  elog(ERROR, "type OID %u not found in Typ list", typid);
957 
958  *typlen = ap->am_typ.typlen;
959  *typbyval = ap->am_typ.typbyval;
960  *typalign = ap->am_typ.typalign;
961  *typdelim = ap->am_typ.typdelim;
962 
963  /* XXX this logic must match getTypeIOParam() */
964  if (OidIsValid(ap->am_typ.typelem))
965  *typioparam = ap->am_typ.typelem;
966  else
967  *typioparam = typid;
968 
969  *typinput = ap->am_typ.typinput;
970  *typoutput = ap->am_typ.typoutput;
971  }
972  else
973  {
974  /* We don't have pg_type yet, so use the hard-wired TypInfo array */
975  int typeindex;
976 
977  for (typeindex = 0; typeindex < n_types; typeindex++)
978  {
979  if (TypInfo[typeindex].oid == typid)
980  break;
981  }
982  if (typeindex >= n_types)
983  elog(ERROR, "type OID %u not found in TypInfo", typid);
984 
985  *typlen = TypInfo[typeindex].len;
986  *typbyval = TypInfo[typeindex].byval;
987  *typalign = TypInfo[typeindex].align;
988  /* We assume typdelim is ',' for all boot-time types */
989  *typdelim = ',';
990 
991  /* XXX this logic must match getTypeIOParam() */
992  if (OidIsValid(TypInfo[typeindex].elem))
993  *typioparam = TypInfo[typeindex].elem;
994  else
995  *typioparam = typid;
996 
997  *typinput = TypInfo[typeindex].inproc;
998  *typoutput = TypInfo[typeindex].outproc;
999  }
1000 }
1001 
1002 /* ----------------
1003  * AllocateAttribute
1004  *
1005  * Note: bootstrap never sets any per-column ACLs, so we only need
1006  * ATTRIBUTE_FIXED_PART_SIZE space per attribute.
1007  * ----------------
1008  */
1009 static Form_pg_attribute
1011 {
1012  return (Form_pg_attribute)
1014 }
1015 
1016 /*
1017  * MapArrayTypeName
1018  *
1019  * Given a type name, produce the corresponding array type name by prepending
1020  * '_' and truncating as needed to fit in NAMEDATALEN-1 bytes. This is only
1021  * used in bootstrap mode, so we can get away with assuming that the input is
1022  * ASCII and we don't need multibyte-aware truncation.
1023  *
1024  * The given string normally ends with '[]' or '[digits]'; we discard that.
1025  *
1026  * The result is a palloc'd string.
1027  */
1028 char *
1029 MapArrayTypeName(const char *s)
1030 {
1031  int i,
1032  j;
1033  char newStr[NAMEDATALEN];
1034 
1035  newStr[0] = '_';
1036  j = 1;
1037  for (i = 0; i < NAMEDATALEN - 2 && s[i] != '['; i++, j++)
1038  newStr[j] = s[i];
1039 
1040  newStr[j] = '\0';
1041 
1042  return pstrdup(newStr);
1043 }
1044 
1045 
1046 /*
1047  * index_register() -- record an index that has been set up for building
1048  * later.
1049  *
1050  * At bootstrap time, we define a bunch of indexes on system catalogs.
1051  * We postpone actually building the indexes until just before we're
1052  * finished with initialization, however. This is because the indexes
1053  * themselves have catalog entries, and those have to be included in the
1054  * indexes on those catalogs. Doing it in two phases is the simplest
1055  * way of making sure the indexes have the right contents at the end.
1056  */
1057 void
1059  Oid ind,
1060  IndexInfo *indexInfo)
1061 {
1062  IndexList *newind;
1063  MemoryContext oldcxt;
1064 
1065  /*
1066  * XXX mao 10/31/92 -- don't gc index reldescs, associated info at
1067  * bootstrap time. we'll declare the indexes now, but want to create them
1068  * later.
1069  */
1070 
1071  if (nogc == NULL)
1072  nogc = AllocSetContextCreate(NULL,
1073  "BootstrapNoGC",
1075 
1076  oldcxt = MemoryContextSwitchTo(nogc);
1077 
1078  newind = (IndexList *) palloc(sizeof(IndexList));
1079  newind->il_heap = heap;
1080  newind->il_ind = ind;
1081  newind->il_info = (IndexInfo *) palloc(sizeof(IndexInfo));
1082 
1083  memcpy(newind->il_info, indexInfo, sizeof(IndexInfo));
1084  /* expressions will likely be null, but may as well copy it */
1085  newind->il_info->ii_Expressions = (List *)
1086  copyObject(indexInfo->ii_Expressions);
1087  newind->il_info->ii_ExpressionsState = NIL;
1088  /* predicate will likely be null, but may as well copy it */
1089  newind->il_info->ii_Predicate = (List *)
1090  copyObject(indexInfo->ii_Predicate);
1091  newind->il_info->ii_PredicateState = NULL;
1092  /* no exclusion constraints at bootstrap time, so no need to copy */
1093  Assert(indexInfo->ii_ExclusionOps == NULL);
1094  Assert(indexInfo->ii_ExclusionProcs == NULL);
1095  Assert(indexInfo->ii_ExclusionStrats == NULL);
1096 
1097  newind->il_next = ILHead;
1098  ILHead = newind;
1099 
1100  MemoryContextSwitchTo(oldcxt);
1101 }
1102 
1103 
1104 /*
1105  * build_indices -- fill in all the indexes registered earlier
1106  */
1107 void
1109 {
1110  for (; ILHead != NULL; ILHead = ILHead->il_next)
1111  {
1112  Relation heap;
1113  Relation ind;
1114 
1115  /* need not bother with locks during bootstrap */
1116  heap = heap_open(ILHead->il_heap, NoLock);
1117  ind = index_open(ILHead->il_ind, NoLock);
1118 
1119  index_build(heap, ind, ILHead->il_info, false, false);
1120 
1121  index_close(ind, NoLock);
1122  heap_close(heap, NoLock);
1123  }
1124 }
AuxProcType
Definition: miscadmin.h:386
void InitAuxiliaryProcess(void)
Definition: proc.c:482
struct _IndexList * il_next
Definition: bootstrap.c:178
signed short int16
Definition: c.h:255
#define NIL
Definition: pg_list.h:69
void RelationMapFinishBootstrap(void)
Definition: relmapper.c:538
#define REGCLASSOID
Definition: pg_type.h:573
#define BOOTCOL_NULL_FORCE_NULL
Definition: bootstrap.h:27
#define INT2VECTOROID
Definition: pg_type.h:312
Oid il_ind
Definition: bootstrap.c:176
int16 len
Definition: bootstrap.c:89
#define NAMEOID
Definition: pg_type.h:300
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
List * ii_Predicate
Definition: execnodes.h:137
void heap_endscan(HeapScanDesc scan)
Definition: heapam.c:1581
void WalWriterMain(void)
Definition: walwriter.c:98
char align
Definition: bootstrap.c:91
#define REGROLEOID
Definition: pg_type.h:581
int numattr
Definition: bootstrap.c:72
char name[NAMEDATALEN]
Definition: bootstrap.c:86
#define OIDOID
Definition: pg_type.h:328
#define TEXTOID
Definition: pg_type.h:324
#define PointerGetDatum(X)
Definition: postgres.h:562
void InsertOneTuple(Oid objectid)
Definition: bootstrap.c:769
ExprState * ii_PredicateState
Definition: execnodes.h:138
#define RelationGetForm(relation)
Definition: rel.h:411
char * pstrdup(const char *in)
Definition: mcxt.c:1077
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
void InitStandaloneProcess(const char *argv0)
Definition: miscinit.c:219
Relation boot_reldesc
Definition: bootstrap.c:69
void ParseLongOption(const char *string, char **name, char **value)
Definition: guc.c:9349
#define BOOTCOL_NULL_AUTO
Definition: bootstrap.h:26
void StartupProcessMain(void)
Definition: startup.c:179
void ValidatePgVersion(const char *path)
Definition: miscinit.c:1349
#define MARKNOTNULL(att)
Form_pg_attribute * attrs
Definition: tupdesc.h:74
int boot_yyparse(void)
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define write_stderr(str)
Definition: parallel.c:180
#define INT4OID
Definition: pg_type.h:316
static IndexList * ILHead
Definition: bootstrap.c:181
Oid * ii_ExclusionProcs
Definition: execnodes.h:140
void proc_exit(int code)
Definition: ipc.c:99
int errcode(int sqlerrcode)
Definition: elog.c:575
#define MemSet(start, val, len)
Definition: c.h:857
#define SetProcessingMode(mode)
Definition: miscadmin.h:371
void BootStrapXLOG(void)
Definition: xlog.c:4943
void BaseInit(void)
Definition: postinit.c:517
bool IgnoreSystemIndexes
Definition: miscinit.c:73
#define XIDOID
Definition: pg_type.h:336
static MemoryContext nogc
Definition: bootstrap.c:165
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:692
Oid inproc
Definition: bootstrap.c:94
#define heap_close(r, l)
Definition: heapam.h:97
TupleDesc CreateTupleDesc(int natts, bool hasoid, Form_pg_attribute *attrs)
Definition: tupdesc.c:112
Form_pg_class rd_rel
Definition: rel.h:114
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1374
unsigned int Oid
Definition: postgres_ext.h:31
void closerel(char *name)
Definition: bootstrap.c:627
FormData_pg_type
Definition: pg_type.h:226
static void bootstrap_signals(void)
Definition: bootstrap.c:522
#define REGTYPEOID
Definition: pg_type.h:577
static struct typmap * Ap
Definition: bootstrap.c:160
#define TypeRelationId
Definition: pg_type.h:34
int namestrcpy(Name name, const char *str)
Definition: name.c:217
const char * progname
Definition: pg_standby.c:37
#define DEBUG4
Definition: elog.h:22
#define OidIsValid(objectId)
Definition: c.h:538
#define BOOTCOL_NULL_FORCE_NOT_NULL
Definition: bootstrap.h:28
#define PANIC
Definition: elog.h:53
#define SIGQUIT
Definition: win32.h:197
static void BootstrapModeMain(void)
Definition: bootstrap.c:475
int getopt(int nargc, char *const *nargv, const char *ostr)
Definition: getopt.c:72
void * copyObject(const void *from)
Definition: copyfuncs.c:4619
#define HeapTupleSetOid(tuple, oid)
Definition: htup_details.h:698
#define NAMEDATALEN
static struct @114 value
void WalReceiverMain(void)
Definition: walreceiver.c:187
List * ii_ExpressionsState
Definition: execnodes.h:136
#define OIDVECTOROID
Definition: pg_type.h:344
#define TIDOID
Definition: pg_type.h:332
void pfree(void *pointer)
Definition: mcxt.c:950
int optind
Definition: getopt.c:51
void ConditionVariableCancelSleep(void)
void InsertOneValue(char *value, int i)
Definition: bootstrap.c:801
#define ERROR
Definition: elog.h:43
void CreateDataDirLockFile(bool amPostmaster)
Definition: miscinit.c:1080
void InitXLOGAccess(void)
Definition: xlog.c:8127
Oid elem
Definition: bootstrap.c:88
#define MAXPGPATH
int MaxBackends
Definition: globals.c:126
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:165
#define INT2OID
Definition: pg_type.h:308
void InitProcess(void)
Definition: proc.c:287
struct _IndexList IndexList
#define PGNODETREEOID
Definition: pg_type.h:365
#define NoLock
Definition: lockdefs.h:34
char OutputFileName[MAXPGPATH]
Definition: globals.c:61
void SetConfigOption(const char *name, const char *value, GucContext context, GucSource source)
Definition: guc.c:6651
#define memmove(d, s, c)
Definition: c.h:1058
#define DEFAULT_COLLATION_OID
Definition: pg_collation.h:74
bool IsUnderPostmaster
Definition: globals.c:100
IndexInfo * il_info
Definition: bootstrap.c:177
char * flag(int b)
Definition: test-ctype.c:33
void before_shmem_exit(pg_on_exit_callback function, Datum arg)
Definition: ipc.c:320
#define RelationGetRelationName(relation)
Definition: rel.h:437
void ChangeToDataDir(void)
Definition: miscinit.c:115
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:184
unsigned int uint32
Definition: c.h:268
void boot_openrel(char *relname)
Definition: bootstrap.c:558
void pgstat_initialize(void)
Definition: pgstat.c:2708
static void pgstat_report_wait_end(void)
Definition: pgstat.h:1231
HeapScanDesc heap_beginscan_catalog(Relation relation, int nkeys, ScanKey key)
Definition: heapam.c:1402
#define MAXATTR
Definition: bootstrap.h:24
#define ATTRIBUTE_FIXED_PART_SIZE
Definition: pg_attribute.h:176
void index_register(Oid heap, Oid ind, IndexInfo *indexInfo)
Definition: bootstrap.c:1058
#define ereport(elevel, rest)
Definition: elog.h:122
void DefineAttr(char *name, char *type, int attnum, int nullness)
Definition: bootstrap.c:664
#define AssertArg(condition)
Definition: c.h:677
MemoryContext TopMemoryContext
Definition: mcxt.c:43
#define WARNING
Definition: elog.h:40
void index_build(Relation heapRelation, Relation indexRelation, IndexInfo *indexInfo, bool isprimary, bool isreindex)
Definition: index.c:1999
Oid collation
Definition: bootstrap.c:93
#define FLOAT4OID
Definition: pg_type.h:412
#define CIDOID
Definition: pg_type.h:340
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:322
static struct typmap ** Typ
Definition: bootstrap.c:159
static void ShutdownAuxiliaryProcess(int code, Datum arg)
Definition: bootstrap.c:541
uintptr_t Datum
Definition: postgres.h:372
bool SelectConfigFiles(const char *userDoption, const char *progname)
Definition: guc.c:4668
AuxProcType MyAuxProcType
Definition: bootstrap.c:67
static void cleanup(void)
Definition: bootstrap.c:852
Oid simple_heap_insert(Relation relation, HeapTuple tup)
Definition: heapam.c:2942
HeapTuple heap_getnext(HeapScanDesc scan, ScanDirection direction)
Definition: heapam.c:1797
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1287
TupleDesc rd_att
Definition: rel.h:115
#define CHAROID
Definition: pg_type.h:296
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:742
#define SIGHUP
Definition: win32.h:196
Relation heap_openrv(const RangeVar *relation, LOCKMODE lockmode)
Definition: heapam.c:1315
#define InvalidOid
Definition: postgres_ext.h:36
void CheckpointerMain(void)
Definition: checkpointer.c:193
pqsigfunc pqsignal(int signum, pqsigfunc handler)
Definition: signal.c:168
#define free(a)
Definition: header.h:65
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
int errmsg_internal(const char *fmt,...)
Definition: elog.c:827
#define NULL
Definition: c.h:229
List * ii_Expressions
Definition: execnodes.h:135
#define Assert(condition)
Definition: c.h:675
#define ALLOC(t, c)
Definition: bootstrap.c:51
char storage
Definition: bootstrap.c:92
#define ACLITEMOID
Definition: pg_type.h:489
FormData_pg_type am_typ
Definition: bootstrap.c:156
void InitializeMaxBackends(void)
Definition: postinit.c:495
static Form_pg_attribute AllocateAttribute(void)
Definition: bootstrap.c:1010
static const int n_types
Definition: bootstrap.c:151
static const struct typinfo TypInfo[]
Definition: bootstrap.c:98
#define BOOLOID
Definition: pg_type.h:288
const char * name
Definition: encode.c:521
void BackgroundWriterMain(void)
Definition: bgwriter.c:110
bool byval
Definition: bootstrap.c:90
Oid il_heap
Definition: bootstrap.c:175
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:176
#define BYTEAOID
Definition: pg_type.h:292
static const char * userDoption
Definition: postgres.c:159
static Datum values[MAXATTR]
Definition: bootstrap.c:162
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:365
void ProcSignalInit(int pss_idx)
Definition: procsignal.c:104
#define PG_DATA_CHECKSUM_VERSION
Definition: bufpage.h:197
static Oid gettype(char *type)
Definition: bootstrap.c:870
Oid * ii_ExclusionOps
Definition: execnodes.h:139
void InitPostgres(const char *in_dbname, Oid dboid, const char *username, Oid useroid, char *out_dbname)
Definition: postinit.c:558
char * OidOutputFunctionCall(Oid functionId, Datum val)
Definition: fmgr.c:2056
Oid am_oid
Definition: bootstrap.c:155
void * palloc(Size size)
Definition: mcxt.c:849
int errmsg(const char *fmt,...)
Definition: elog.c:797
void pgstat_bestart(void)
Definition: pgstat.c:2748
char * optarg
Definition: getopt.c:53
void die(SIGNAL_ARGS)
Definition: postgres.c:2619
int i
#define NameStr(name)
Definition: c.h:499
static void CheckerModeMain(void)
Definition: bootstrap.c:462
void * arg
char * DataDir
Definition: globals.c:59
void AuxiliaryProcessMain(int argc, char *argv[])
Definition: bootstrap.c:193
void InitBufferPoolBackend(void)
Definition: bufmgr.c:2461
uint32 bootstrap_data_checksum_version
Definition: bootstrap.c:48
Oid outproc
Definition: bootstrap.c:95
Oid oid
Definition: bootstrap.c:87
char * MapArrayTypeName(const char *s)
Definition: bootstrap.c:1029
#define elog
Definition: elog.h:219
void build_indices(void)
Definition: bootstrap.c:1108
void LWLockReleaseAll(void)
Definition: lwlock.c:1814
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:695
#define INT4ARRAYOID
Definition: pg_type.h:463
uint16 * ii_ExclusionStrats
Definition: execnodes.h:141
void InsertOneNull(int i)
Definition: bootstrap.c:839
Definition: pg_list.h:45
#define REGNAMESPACEOID
Definition: pg_type.h:585
Datum OidInputFunctionCall(Oid functionId, char *str, Oid typioparam, int32 typmod)
Definition: fmgr.c:2047
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:151
RangeVar * makeRangeVar(char *schemaname, char *relname, int location)
Definition: makefuncs.c:419
#define REGPROCOID
Definition: pg_type.h:320
void init_ps_display(const char *username, const char *dbname, const char *host_info, const char *initial_str)
Definition: ps_status.c:244
void InitializeGUCOptions(void)
Definition: guc.c:4446
void boot_get_type_io_data(Oid typid, int16 *typlen, bool *typbyval, char *typalign, char *typdelim, Oid *typioparam, Oid *typinput, Oid *typoutput)
Definition: bootstrap.c:936
static bool Nulls[MAXATTR]
Definition: bootstrap.c:163
Form_pg_attribute attrtypes[MAXATTR]
Definition: bootstrap.c:71