2 #----------------------------------------------------------------------
5 # Perl script that generates postgres.bki, postgres.description,
6 # postgres.shdescription, and symbol definition headers from specially
7 # formatted header files and data files. The BKI files are used to
8 # initialize the postgres template database.
10 # Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
11 # Portions Copyright (c) 1994, Regents of the University of California
13 # src/backend/catalog/genbki.pl
15 #----------------------------------------------------------------------
26 # Process command line switches.
29 my $arg = shift @ARGV;
32 push @input_files, $arg;
36 $output_path = length($arg) > 2 ? substr($arg, 2) : shift @ARGV;
38 elsif ($arg =~ /^--set-version=(.*)$/)
41 die "Invalid version string.\n"
42 if !($major_version =~ /^\d+$/);
50 # Sanity check arguments.
51 die "No input files.\n" if !@input_files;
52 die "--set-version must be specified.\n" if !defined $major_version;
54 # Make sure output_path ends in a slash.
55 if ($output_path ne '' && substr($output_path, -1) ne '/')
60 # Read all the files into internal data structures.
68 foreach my $header (@input_files)
71 or die "Input files need to be header files.\n";
72 my $datfile = "$1.dat";
74 my $catalog = Catalog::ParseHeader($header);
75 my $catname = $catalog->{catname};
76 my $schema = $catalog->{columns};
80 push @catnames, $catname;
81 $catalogs{$catname} = $catalog;
84 # While checking for duplicated OIDs, we ignore the pg_class OID and
85 # rowtype OID of bootstrap catalogs, as those are expected to appear
86 # in the initial data for pg_class and pg_type. For regular catalogs,
87 # include these OIDs. (See also Catalog::FindAllOidsFromHeaders
88 # if you change this logic.)
89 if (!$catalog->{bootstrap})
91 $oidcounts{ $catalog->{relation_oid} }++
92 if ($catalog->{relation_oid});
93 $oidcounts{ $catalog->{rowtype_oid} }++
94 if ($catalog->{rowtype_oid});
97 # Not all catalogs have a data file.
100 my $data = Catalog::ParseData($datfile, $schema, 0);
101 $catalog_data{$catname} = $data;
103 # Check for duplicated OIDs while we're at it.
104 foreach my $row (@$data)
106 $oidcounts{ $row->{oid} }++ if defined $row->{oid};
110 # If the header file contained toast or index info, build BKI
111 # commands for those, which we'll output later.
112 foreach my $toast (@{ $catalog->{toasting} })
115 sprintf "declare toast %s %s on %s\n",
116 $toast->{toast_oid}, $toast->{toast_index_oid},
117 $toast->{parent_table};
118 $oidcounts{ $toast->{toast_oid} }++;
119 $oidcounts{ $toast->{toast_index_oid} }++;
121 foreach my $index (@{ $catalog->{indexing} })
124 sprintf "declare %sindex %s %s %s\n",
125 $index->{is_unique} ? 'unique ' : '',
126 $index->{index_name}, $index->{index_oid},
127 $index->{index_decl};
128 $oidcounts{ $index->{index_oid} }++;
132 # Complain and exit if we found any duplicate OIDs.
133 # While duplicate OIDs would only cause a failure if they appear in
134 # the same catalog, our project policy is that manually assigned OIDs
135 # should be globally unique, to avoid confusion.
137 foreach my $oid (keys %oidcounts)
139 next unless $oidcounts{$oid} > 1;
140 print STDERR "Duplicate OIDs detected:\n" if !$found;
141 print STDERR "$oid\n";
144 die "found $found duplicate OID(s) in catalog data\n" if $found;
146 # Fetch some special data that we will substitute into the output file.
147 # CAUTION: be wary about what symbols you substitute into the .bki file here!
148 # It's okay to substitute things that are expected to be really constant
149 # within a given Postgres release, such as fixed OIDs. Do not substitute
150 # anything that could depend on platform or configuration. (The right place
151 # to handle those sorts of things is in initdb.c's bootstrap_template1().)
152 my $BOOTSTRAP_SUPERUSERID =
153 Catalog::FindDefinedSymbolFromData($catalog_data{pg_authid},
154 'BOOTSTRAP_SUPERUSERID');
155 my $PG_CATALOG_NAMESPACE =
156 Catalog::FindDefinedSymbolFromData($catalog_data{pg_namespace},
157 'PG_CATALOG_NAMESPACE');
160 # Build lookup tables for OID macro substitutions and for pg_attribute
161 # copies of pg_type values.
163 # index access method OID lookup
165 foreach my $row (@{ $catalog_data{pg_am} })
167 $amoids{ $row->{amname} } = $row->{oid};
172 foreach my $row (@{ $catalog_data{pg_opclass} })
174 # There is no unique name, so we need to combine access method
176 my $key = sprintf "%s/%s", $row->{opcmethod}, $row->{opcname};
177 $opcoids{$key} = $row->{oid};
180 # operator OID lookup
182 foreach my $row (@{ $catalog_data{pg_operator} })
184 # There is no unique name, so we need to invent one that contains
185 # the relevant type names.
186 my $key = sprintf "%s(%s,%s)",
187 $row->{oprname}, $row->{oprleft}, $row->{oprright};
188 $operoids{$key} = $row->{oid};
191 # opfamily OID lookup
193 foreach my $row (@{ $catalog_data{pg_opfamily} })
195 # There is no unique name, so we need to combine access method
197 my $key = sprintf "%s/%s", $row->{opfmethod}, $row->{opfname};
198 $opfoids{$key} = $row->{oid};
201 # procedure OID lookup
203 foreach my $row (@{ $catalog_data{pg_proc} })
205 # Generate an entry under just the proname (corresponds to regproc lookup)
206 my $prokey = $row->{proname};
207 if (defined $procoids{$prokey})
209 $procoids{$prokey} = 'MULTIPLE';
213 $procoids{$prokey} = $row->{oid};
216 # Also generate an entry using proname(proargtypes). This is not quite
217 # identical to regprocedure lookup because we don't worry much about
218 # special SQL names for types etc; we just use the names in the source
219 # proargtypes field. These *should* be unique, but do a multiplicity
221 $prokey .= '(' . join(',', split(/\s+/, $row->{proargtypes})) . ')';
222 if (defined $procoids{$prokey})
224 $procoids{$prokey} = 'MULTIPLE';
228 $procoids{$prokey} = $row->{oid};
235 foreach my $row (@{ $catalog_data{pg_type} })
237 $typeoids{ $row->{typname} } = $row->{oid};
238 $types{ $row->{typname} } = $row;
241 # Map catalog name to OID lookup.
244 pg_opclass => \%opcoids,
245 pg_operator => \%operoids,
246 pg_opfamily => \%opfoids,
247 pg_proc => \%procoids,
248 pg_type => \%typeoids);
252 my $tmpext = ".tmp$$";
253 my $bkifile = $output_path . 'postgres.bki';
254 open my $bki, '>', $bkifile . $tmpext
255 or die "can't open $bkifile$tmpext: $!";
256 my $schemafile = $output_path . 'schemapg.h';
257 open my $schemapg, '>', $schemafile . $tmpext
258 or die "can't open $schemafile$tmpext: $!";
259 my $descrfile = $output_path . 'postgres.description';
260 open my $descr, '>', $descrfile . $tmpext
261 or die "can't open $descrfile$tmpext: $!";
262 my $shdescrfile = $output_path . 'postgres.shdescription';
263 open my $shdescr, '>', $shdescrfile . $tmpext
264 or die "can't open $shdescrfile$tmpext: $!";
266 # Generate postgres.bki, postgres.description, postgres.shdescription,
267 # and pg_*_d.h headers.
269 # version marker for .bki file
270 print $bki "# PostgreSQL $major_version\n";
272 # vars to hold data needed for schemapg.h
273 my %schemapg_entries;
274 my @tables_needing_macros;
276 # produce output, one catalog at a time
277 foreach my $catname (@catnames)
279 my $catalog = $catalogs{$catname};
281 # Create one definition header with macro definitions for each catalog.
282 my $def_file = $output_path . $catname . '_d.h';
283 open my $def, '>', $def_file . $tmpext
284 or die "can't open $def_file$tmpext: $!";
286 # Opening boilerplate for pg_*_d.h
287 printf $def <<EOM, $catname, $catname, uc $catname, uc $catname;
288 /*-------------------------------------------------------------------------
291 * Macro definitions for %s
293 * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
294 * Portions Copyright (c) 1994, Regents of the University of California
297 * ******************************
298 * *** DO NOT EDIT THIS FILE! ***
299 * ******************************
301 * It has been GENERATED by src/backend/catalog/genbki.pl
303 *-------------------------------------------------------------------------
310 # Emit OID macros for catalog's OID and rowtype OID, if wanted
311 printf $def "#define %s %s\n",
312 $catalog->{relation_oid_macro}, $catalog->{relation_oid}
313 if $catalog->{relation_oid_macro};
314 printf $def "#define %s %s\n",
315 $catalog->{rowtype_oid_macro}, $catalog->{rowtype_oid}
316 if $catalog->{rowtype_oid_macro};
319 # .bki CREATE command for this catalog
320 print $bki "create $catname $catalog->{relation_oid}"
321 . $catalog->{shared_relation}
322 . $catalog->{bootstrap}
323 . $catalog->{without_oids}
324 . $catalog->{rowtype_oid_clause};
329 my $schema = $catalog->{columns};
332 foreach my $column (@$schema)
335 my $attname = $column->{name};
336 my $atttype = $column->{type};
338 # Build hash of column names for use later
339 $attnames{$attname} = 1;
341 # Emit column definitions
348 print $bki " $attname = $atttype";
350 if (defined $column->{forcenotnull})
352 print $bki " FORCE NOT NULL";
354 elsif (defined $column->{forcenull})
356 print $bki " FORCE NULL";
359 # Emit Anum_* constants
360 printf $def "#define Anum_%s_%s %s\n", $catname, $attname, $attnum;
364 # Emit Natts_* constant
365 print $def "\n#define Natts_$catname $attnum\n\n";
367 # Emit client code copied from source header
368 foreach my $line (@{ $catalog->{client_code} })
373 # Open it, unless it's a bootstrap catalog (create bootstrap does this
375 if (!$catalog->{bootstrap})
377 print $bki "open $catname\n";
380 # For pg_attribute.h, we generate data entries ourselves.
381 if ($catname eq 'pg_attribute')
383 gen_pg_attribute($schema);
386 # Ordinary catalog with a data file
387 foreach my $row (@{ $catalog_data{$catname} })
389 my %bki_values = %$row;
391 # Complain about unrecognized keys; they are presumably misspelled
392 foreach my $key (keys %bki_values)
396 || $key eq "oid_symbol"
398 || $key eq "line_number";
399 die sprintf "unrecognized field name \"%s\" in %s.dat line %s\n",
400 $key, $catname, $bki_values{line_number}
401 if (!exists($attnames{$key}));
404 # Perform required substitutions on fields
405 foreach my $column (@$schema)
407 my $attname = $column->{name};
408 my $atttype = $column->{type};
410 # Substitute constant values we acquired above.
411 # (It's intentional that this can apply to parts of a field).
412 $bki_values{$attname} =~ s/\bPGUID\b/$BOOTSTRAP_SUPERUSERID/g;
413 $bki_values{$attname} =~ s/\bPGNSP\b/$PG_CATALOG_NAMESPACE/g;
415 # Replace OID synonyms with OIDs per the appropriate lookup rule.
417 # If the column type is oidvector or _oid, we have to replace
418 # each element of the array as per the lookup rule.
419 if ($column->{lookup})
421 my $lookup = $lookup_kind{ $column->{lookup} };
425 die "unrecognized BKI_LOOKUP type " . $column->{lookup}
426 if !defined($lookup);
428 if ($atttype eq 'oidvector')
430 @lookupnames = split /\s+/, $bki_values{$attname};
431 @lookupoids = lookup_oids($lookup, $catname, \%bki_values,
433 $bki_values{$attname} = join(' ', @lookupoids);
435 elsif ($atttype eq '_oid')
437 if ($bki_values{$attname} ne '_null_')
439 $bki_values{$attname} =~ s/[{}]//g;
440 @lookupnames = split /,/, $bki_values{$attname};
442 lookup_oids($lookup, $catname, \%bki_values,
444 $bki_values{$attname} = sprintf "{%s}",
445 join(',', @lookupoids);
450 $lookupnames[0] = $bki_values{$attname};
451 @lookupoids = lookup_oids($lookup, $catname, \%bki_values,
453 $bki_values{$attname} = $lookupoids[0];
458 # Special hack to generate OID symbols for pg_type entries
460 if ($catname eq 'pg_type' and !exists $bki_values{oid_symbol})
462 my $symbol = form_pg_type_symbol($bki_values{typname});
463 $bki_values{oid_symbol} = $symbol
467 # Write to postgres.bki
468 print_bki_insert(\%bki_values, $schema);
470 # Write comments to postgres.description and
471 # postgres.shdescription
472 if (defined $bki_values{descr})
474 if ($catalog->{shared_relation})
476 printf $shdescr "%s\t%s\t%s\n",
477 $bki_values{oid}, $catname, $bki_values{descr};
481 printf $descr "%s\t%s\t0\t%s\n",
482 $bki_values{oid}, $catname, $bki_values{descr};
487 if (defined $bki_values{oid_symbol})
489 printf $def "#define %s %s\n",
490 $bki_values{oid_symbol}, $bki_values{oid};
494 print $bki "close $catname\n";
495 printf $def "\n#endif\t\t\t\t\t\t\t/* %s_D_H */\n", uc $catname;
497 # Close and rename definition header
499 Catalog::RenameTempFile($def_file, $tmpext);
502 # Any information needed for the BKI that is not contained in a pg_*.h header
503 # (i.e., not contained in a header with a CATALOG() statement) comes here
505 # Write out declare toast/index statements
506 foreach my $declaration (@toast_decls)
508 print $bki $declaration;
511 foreach my $declaration (@index_decls)
513 print $bki $declaration;
516 # last command in the BKI file: build the indexes declared above
517 print $bki "build indices\n";
520 # Now generate schemapg.h
522 # Opening boilerplate for schemapg.h
523 print $schemapg <<EOM;
524 /*-------------------------------------------------------------------------
527 * Schema_pg_xxx macros for use by relcache.c
529 * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
530 * Portions Copyright (c) 1994, Regents of the University of California
533 * ******************************
534 * *** DO NOT EDIT THIS FILE! ***
535 * ******************************
537 * It has been GENERATED by src/backend/catalog/genbki.pl
539 *-------------------------------------------------------------------------
545 # Emit schemapg declarations
546 foreach my $table_name (@tables_needing_macros)
548 print $schemapg "\n#define Schema_$table_name \\\n";
549 print $schemapg join ", \\\n", @{ $schemapg_entries{$table_name} };
550 print $schemapg "\n";
553 # Closing boilerplate for schemapg.h
554 print $schemapg "\n#endif\t\t\t\t\t\t\t/* SCHEMAPG_H */\n";
556 # We're done emitting data
562 # Finally, rename the completed files into place.
563 Catalog::RenameTempFile($bkifile, $tmpext);
564 Catalog::RenameTempFile($schemafile, $tmpext);
565 Catalog::RenameTempFile($descrfile, $tmpext);
566 Catalog::RenameTempFile($shdescrfile, $tmpext);
570 #################### Subroutines ########################
573 # For each catalog marked as needing a schema macro, generate the
574 # per-user-attribute data to be incorporated into schemapg.h. Also, for
575 # bootstrap catalogs, emit pg_attribute entries into the .bki file
576 # for both user and system attributes.
582 foreach my $column (@$schema)
584 push @attnames, $column->{name};
587 foreach my $table_name (@catnames)
589 my $table = $catalogs{$table_name};
591 # Currently, all bootstrap catalogs also need schemapg.h
592 # entries, so skip if it isn't to be in schemapg.h.
593 next if !$table->{schema_macro};
595 $schemapg_entries{$table_name} = [];
596 push @tables_needing_macros, $table_name;
598 # Generate entries for user attributes.
600 my $priornotnull = 1;
601 foreach my $attr (@{ $table->{columns} })
605 $row{attnum} = $attnum;
606 $row{attrelid} = $table->{relation_oid};
608 morph_row_for_pgattr(\%row, $schema, $attr, $priornotnull);
609 $priornotnull &= ($row{attnotnull} eq 't');
611 # If it's bootstrapped, put an entry in postgres.bki.
612 print_bki_insert(\%row, $schema) if $table->{bootstrap};
614 # Store schemapg entries for later.
615 morph_row_for_schemapg(\%row, $schema);
616 push @{ $schemapg_entries{$table_name} },
618 join(', ', grep { defined $_ } @row{@attnames});
621 # Generate entries for system attributes.
622 # We only need postgres.bki entries, not schemapg.h entries.
623 if ($table->{bootstrap})
627 { name => 'ctid', type => 'tid' },
628 { name => 'oid', type => 'oid' },
629 { name => 'xmin', type => 'xid' },
630 { name => 'cmin', type => 'cid' },
631 { name => 'xmax', type => 'xid' },
632 { name => 'cmax', type => 'cid' },
633 { name => 'tableoid', type => 'oid' });
634 foreach my $attr (@SYS_ATTRS)
638 $row{attnum} = $attnum;
639 $row{attrelid} = $table->{relation_oid};
640 $row{attstattarget} = '0';
642 # Omit the oid column if the catalog doesn't have them
644 if $table->{without_oids}
645 && $attr->{name} eq 'oid';
647 morph_row_for_pgattr(\%row, $schema, $attr, 1);
648 print_bki_insert(\%row, $schema);
654 # Given $pgattr_schema (the pg_attribute schema for a catalog sufficient for
655 # AddDefaultValues), $attr (the description of a catalog row), and
656 # $priornotnull (whether all prior attributes in this catalog are not null),
657 # modify the $row hashref for print_bki_insert. This includes setting data
658 # from the corresponding pg_type element and filling in any default values.
659 # Any value not handled here must be supplied by caller.
660 sub morph_row_for_pgattr
662 my ($row, $pgattr_schema, $attr, $priornotnull) = @_;
663 my $attname = $attr->{name};
664 my $atttype = $attr->{type};
666 $row->{attname} = $attname;
668 # Copy the type data from pg_type, and add some type-dependent items
669 my $type = $types{$atttype};
671 $row->{atttypid} = $type->{oid};
672 $row->{attlen} = $type->{typlen};
673 $row->{attbyval} = $type->{typbyval};
674 $row->{attstorage} = $type->{typstorage};
675 $row->{attalign} = $type->{typalign};
677 # set attndims if it's an array type
678 $row->{attndims} = $type->{typcategory} eq 'A' ? '1' : '0';
679 $row->{attcollation} = $type->{typcollation};
681 if (defined $attr->{forcenotnull})
683 $row->{attnotnull} = 't';
685 elsif (defined $attr->{forcenull})
687 $row->{attnotnull} = 'f';
689 elsif ($priornotnull)
692 # attnotnull will automatically be set if the type is
693 # fixed-width and prior columns are all NOT NULL ---
694 # compare DefineAttr in bootstrap.c. oidvector and
695 # int2vector are also treated as not-nullable.
697 $type->{typname} eq 'oidvector' ? 't'
698 : $type->{typname} eq 'int2vector' ? 't'
699 : $type->{typlen} eq 'NAMEDATALEN' ? 't'
700 : $type->{typlen} > 0 ? 't'
705 $row->{attnotnull} = 'f';
708 Catalog::AddDefaultValues($row, $pgattr_schema, 'pg_attribute');
711 # Write an entry to postgres.bki.
718 my $oid = $row->{oid} ? "OID = $row->{oid} " : '';
720 foreach my $column (@$schema)
722 my $attname = $column->{name};
723 my $atttype = $column->{type};
724 my $bki_value = $row->{$attname};
726 # Fold backslash-zero to empty string if it's the entire string,
727 # since that represents a NUL char in C code.
728 $bki_value = '' if $bki_value eq '\0';
730 # Handle single quotes by doubling them, and double quotes by
731 # converting them to octal escapes, because that's what the
732 # bootstrap scanner requires. We do not process backslashes
733 # specially; this allows escape-string-style backslash escapes
734 # to be used in catalog data.
735 $bki_value =~ s/'/''/g;
736 $bki_value =~ s/"/\\042/g;
738 # Quote value if needed. We need not quote values that satisfy
739 # the "id" pattern in bootscanner.l, currently "[-A-Za-z0-9_]+".
740 $bki_value = sprintf(qq'"%s"', $bki_value)
741 if length($bki_value) == 0
742 or $bki_value =~ /[^-A-Za-z0-9_]/;
744 push @bki_values, $bki_value;
746 printf $bki "insert %s( %s )\n", $oid, join(' ', @bki_values);
749 # Given a row reference, modify it so that it becomes a valid entry for
750 # a catalog schema declaration in schemapg.h.
752 # The field values of a Schema_pg_xxx declaration are similar, but not
753 # quite identical, to the corresponding values in postgres.bki.
754 sub morph_row_for_schemapg
757 my $pgattr_schema = shift;
759 foreach my $column (@$pgattr_schema)
761 my $attname = $column->{name};
762 my $atttype = $column->{type};
764 # Some data types have special formatting rules.
765 if ($atttype eq 'name')
767 # add {" ... "} quoting
768 $row->{$attname} = sprintf(qq'{"%s"}', $row->{$attname});
770 elsif ($atttype eq 'char')
773 $row->{$attname} = sprintf("'%s'", $row->{$attname});
776 # Expand booleans from 'f'/'t' to 'false'/'true'.
777 # Some values might be other macros (eg FLOAT4PASSBYVAL),
779 elsif ($atttype eq 'bool')
781 $row->{$attname} = 'true' if $row->{$attname} eq 't';
782 $row->{$attname} = 'false' if $row->{$attname} eq 'f';
785 # We don't emit initializers for the variable length fields at all.
786 # Only the fixed-size portions of the descriptors are ever used.
787 delete $row->{$attname} if $column->{is_varlen};
791 # Perform OID lookups on an array of OID names.
792 # If we don't have a unique value to substitute, warn and
793 # leave the entry unchanged.
794 # (A warning seems sufficient because the bootstrap backend will reject
795 # non-numeric values anyway. So we might as well detect multiple problems
796 # within this genbki.pl run.)
799 my ($lookup, $catname, $bki_values, @lookupnames) = @_;
802 foreach my $lookupname (@lookupnames)
804 my $lookupoid = $lookup->{$lookupname};
805 if (defined($lookupoid) and $lookupoid ne 'MULTIPLE')
807 push @lookupoids, $lookupoid;
811 push @lookupoids, $lookupname;
813 "unresolved OID reference \"%s\" in %s.dat line %s\n",
814 $lookupname, $catname, $bki_values->{line_number}
815 if $lookupname ne '-' and $lookupname ne '0';
821 # Determine canonical pg_type OID #define symbol from the type name.
822 sub form_pg_type_symbol
824 my $typename = shift;
826 # Skip for rowtypes of bootstrap catalogs, since they have their
827 # own naming convention defined elsewhere.
829 if $typename eq 'pg_type'
830 or $typename eq 'pg_proc'
831 or $typename eq 'pg_attribute'
832 or $typename eq 'pg_class';
835 # foo_bar -> FOO_BAROID
836 # _foo_bar -> FOO_BARARRAYOID
837 $typename =~ /(_)?(.+)/;
838 my $arraystr = $1 ? 'ARRAY' : '';
840 return $name . $arraystr . 'OID';
846 Usage: genbki.pl [options] header...
850 --set-version PostgreSQL version number for initdb cross-check
852 genbki.pl generates BKI files and symbol definition
853 headers from specially formatted header files and .dat
854 files. The BKI files are used to initialize the
855 postgres template database.
857 Report bugs to <pgsql-bugs\@postgresql.org>.