renumber_oids.pl 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. #!/usr/bin/perl
  2. #----------------------------------------------------------------------
  3. #
  4. # renumber_oids.pl
  5. # Perl script that shifts a range of OIDs in the Postgres catalog data
  6. # to a different range, skipping any OIDs that are already in use.
  7. #
  8. # Note: This does not reformat the .dat files, so you may want
  9. # to run reformat_dat_file.pl afterwards.
  10. #
  11. # Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
  12. # Portions Copyright (c) 1994, Regents of the University of California
  13. #
  14. # src/include/catalog/renumber_oids.pl
  15. #
  16. #----------------------------------------------------------------------
  17. use strict;
  18. use warnings;
  19. use FindBin;
  20. use Getopt::Long;
  21. # Must run in src/include/catalog
  22. chdir $FindBin::RealBin or die "could not cd to $FindBin::RealBin: $!\n";
  23. use lib "$FindBin::RealBin/../../backend/catalog/";
  24. use Catalog;
  25. # We'll need this number.
  26. my $FirstGenbkiObjectId =
  27. Catalog::FindDefinedSymbol('access/transam.h', '..', 'FirstGenbkiObjectId');
  28. # Process command line switches.
  29. my $output_path = '';
  30. my $first_mapped_oid = 0;
  31. my $last_mapped_oid = $FirstGenbkiObjectId - 1;
  32. my $target_oid = 0;
  33. GetOptions(
  34. 'output=s' => \$output_path,
  35. 'first-mapped-oid=i' => \$first_mapped_oid,
  36. 'last-mapped-oid=i' => \$last_mapped_oid,
  37. 'target-oid=i' => \$target_oid) || usage();
  38. # Sanity check arguments.
  39. die "Unexpected non-switch arguments.\n" if @ARGV;
  40. die "--first-mapped-oid must be specified.\n"
  41. if $first_mapped_oid <= 0;
  42. die "Empty mapped OID range.\n"
  43. if $last_mapped_oid < $first_mapped_oid;
  44. die "--target-oid must be specified.\n"
  45. if $target_oid <= 0;
  46. die "--target-oid must not be within mapped OID range.\n"
  47. if $target_oid >= $first_mapped_oid && $target_oid <= $last_mapped_oid;
  48. # Make sure output_path ends in a slash.
  49. if ($output_path ne '' && substr($output_path, -1) ne '/')
  50. {
  51. $output_path .= '/';
  52. }
  53. # Collect all the existing assigned OIDs (including those to be remapped).
  54. my @header_files = glob("pg_*.h");
  55. my $oids = Catalog::FindAllOidsFromHeaders(@header_files);
  56. # Hash-ify the existing OIDs for convenient lookup.
  57. my %oidhash;
  58. @oidhash{@$oids} = undef;
  59. # Select new OIDs for existing OIDs in the mapped range.
  60. # We do this first so that we preserve the ordering of the mapped OIDs
  61. # (for reproducibility's sake), and so that if we fail due to running out
  62. # of OID room, that happens before we've overwritten any files.
  63. my %maphash;
  64. my $next_oid = $target_oid;
  65. for (
  66. my $mapped_oid = $first_mapped_oid;
  67. $mapped_oid <= $last_mapped_oid;
  68. $mapped_oid++)
  69. {
  70. next if !exists $oidhash{$mapped_oid};
  71. $next_oid++
  72. while (
  73. exists $oidhash{$next_oid}
  74. || ( $next_oid >= $first_mapped_oid
  75. && $next_oid <= $last_mapped_oid));
  76. die "Reached FirstGenbkiObjectId before assigning all OIDs.\n"
  77. if $next_oid >= $FirstGenbkiObjectId;
  78. $maphash{$mapped_oid} = $next_oid;
  79. $next_oid++;
  80. }
  81. die "There are no OIDs in the mapped range.\n" if $next_oid == $target_oid;
  82. # Read each .h file and write out modified data.
  83. foreach my $input_file (@header_files)
  84. {
  85. $input_file =~ /(\w+)\.h$/
  86. or die "Input file $input_file needs to be a .h file.\n";
  87. my $catname = $1;
  88. # Ignore generated *_d.h files.
  89. next if $catname =~ /_d$/;
  90. open(my $ifd, '<', $input_file) || die "$input_file: $!";
  91. # Write output files to specified directory.
  92. # Use a .tmp suffix, then rename into place, in case we're overwriting.
  93. my $output_file = "$output_path$catname.h";
  94. my $tmp_output_file = "$output_file.tmp";
  95. open my $ofd, '>', $tmp_output_file
  96. or die "can't open $tmp_output_file: $!";
  97. my $changed = 0;
  98. # Scan the input file.
  99. while (<$ifd>)
  100. {
  101. my $line = $_;
  102. # Check for OID-defining macros that Catalog::ParseHeader knows about,
  103. # and update OIDs as needed.
  104. if ($line =~ m/^(DECLARE_TOAST\(\s*\w+,\s*)(\d+)(,\s*)(\d+)\)/)
  105. {
  106. my $oid2 = $2;
  107. my $oid4 = $4;
  108. if (exists $maphash{$oid2})
  109. {
  110. $oid2 = $maphash{$oid2};
  111. my $repl = $1 . $oid2 . $3 . $oid4 . ")";
  112. $line =~ s/^DECLARE_TOAST\(\s*\w+,\s*\d+,\s*\d+\)/$repl/;
  113. $changed = 1;
  114. }
  115. if (exists $maphash{$oid4})
  116. {
  117. $oid4 = $maphash{$oid4};
  118. my $repl = $1 . $oid2 . $3 . $oid4 . ")";
  119. $line =~ s/^DECLARE_TOAST\(\s*\w+,\s*\d+,\s*\d+\)/$repl/;
  120. $changed = 1;
  121. }
  122. }
  123. elsif ($line =~
  124. m/^(DECLARE_TOAST_WITH_MACRO\(\s*\w+,\s*)(\d+)(,\s*)(\d+)(,\s*\w+,\s*\w+)\)/
  125. )
  126. {
  127. my $oid2 = $2;
  128. my $oid4 = $4;
  129. if (exists $maphash{$oid2})
  130. {
  131. $oid2 = $maphash{$oid2};
  132. my $repl = $1 . $oid2 . $3 . $oid4 . $5 . ")";
  133. $line =~
  134. s/^DECLARE_TOAST_WITH_MACRO\(\s*\w+,\s*\d+,\s*\d+,\s*\w+,\s*\w+\)/$repl/;
  135. $changed = 1;
  136. }
  137. if (exists $maphash{$oid4})
  138. {
  139. $oid4 = $maphash{$oid4};
  140. my $repl = $1 . $oid2 . $3 . $oid4 . $5 . ")";
  141. $line =~
  142. s/^DECLARE_TOAST_WITH_MACRO\(\s*\w+,\s*\d+,\s*\d+,\s*\w+,\s*\w+\)/$repl/;
  143. $changed = 1;
  144. }
  145. }
  146. elsif ($line =~
  147. m/^(DECLARE_(UNIQUE_)?INDEX(_PKEY)?\(\s*\w+,\s*)(\d+)(,\s*.+)\)/)
  148. {
  149. if (exists $maphash{$4})
  150. {
  151. my $repl = $1 . $maphash{$4} . $5 . ")";
  152. $line =~
  153. s/^DECLARE_(UNIQUE_)?INDEX(_PKEY)?\(\s*\w+,\s*\d+,\s*.+\)/$repl/;
  154. $changed = 1;
  155. }
  156. }
  157. elsif (/^(DECLARE_OID_DEFINING_MACRO\(\s*\w+,\s*)(\d+)\)/)
  158. {
  159. if (exists $maphash{$2})
  160. {
  161. my $repl = $1 . $maphash{$2} . ")";
  162. $line =~
  163. s/^DECLARE_OID_DEFINING_MACRO\(\s*\w+,\s*\d+\)/$repl/;
  164. $changed = 1;
  165. }
  166. }
  167. elsif ($line =~ m/^CATALOG\((\w+),(\d+),(\w+)\)/)
  168. {
  169. if (exists $maphash{$2})
  170. {
  171. my $repl =
  172. "CATALOG(" . $1 . "," . $maphash{$2} . "," . $3 . ")";
  173. $line =~ s/^CATALOG\(\w+,\d+,\w+\)/$repl/;
  174. $changed = 1;
  175. }
  176. if ($line =~ m/BKI_ROWTYPE_OID\((\d+),(\w+)\)/)
  177. {
  178. if (exists $maphash{$1})
  179. {
  180. my $repl =
  181. "BKI_ROWTYPE_OID(" . $maphash{$1} . "," . $2 . ")";
  182. $line =~ s/BKI_ROWTYPE_OID\(\d+,\w+\)/$repl/;
  183. $changed = 1;
  184. }
  185. }
  186. }
  187. print $ofd $line;
  188. }
  189. close $ifd;
  190. close $ofd;
  191. # Avoid updating files if we didn't change them.
  192. if ($changed || $output_path ne '')
  193. {
  194. rename $tmp_output_file, $output_file
  195. or die "can't rename $tmp_output_file to $output_file: $!";
  196. }
  197. else
  198. {
  199. unlink $tmp_output_file
  200. or die "can't unlink $tmp_output_file: $!";
  201. }
  202. }
  203. # Likewise, read each .dat file and write out modified data.
  204. foreach my $input_file (glob("pg_*.dat"))
  205. {
  206. $input_file =~ /(\w+)\.dat$/
  207. or die "Input file $input_file needs to be a .dat file.\n";
  208. my $catname = $1;
  209. open(my $ifd, '<', $input_file) || die "$input_file: $!";
  210. # Write output files to specified directory.
  211. # Use a .tmp suffix, then rename into place, in case we're overwriting.
  212. my $output_file = "$output_path$catname.dat";
  213. my $tmp_output_file = "$output_file.tmp";
  214. open my $ofd, '>', $tmp_output_file
  215. or die "can't open $tmp_output_file: $!";
  216. my $changed = 0;
  217. # Scan the input file.
  218. while (<$ifd>)
  219. {
  220. my $line = $_;
  221. # Check for oid => 'nnnn', and replace if within mapped range.
  222. if ($line =~ m/\b(oid\s*=>\s*)'(\d+)'/)
  223. {
  224. if (exists $maphash{$2})
  225. {
  226. my $repl = $1 . "'" . $maphash{$2} . "'";
  227. $line =~ s/\boid\s*=>\s*'\d+'/$repl/;
  228. $changed = 1;
  229. }
  230. }
  231. # Likewise for array_type_oid.
  232. if ($line =~ m/\b(array_type_oid\s*=>\s*)'(\d+)'/)
  233. {
  234. if (exists $maphash{$2})
  235. {
  236. my $repl = $1 . "'" . $maphash{$2} . "'";
  237. $line =~ s/\barray_type_oid\s*=>\s*'\d+'/$repl/;
  238. $changed = 1;
  239. }
  240. }
  241. print $ofd $line;
  242. }
  243. close $ifd;
  244. close $ofd;
  245. # Avoid updating files if we didn't change them.
  246. if ($changed || $output_path ne '')
  247. {
  248. rename $tmp_output_file, $output_file
  249. or die "can't rename $tmp_output_file to $output_file: $!";
  250. }
  251. else
  252. {
  253. unlink $tmp_output_file
  254. or die "can't unlink $tmp_output_file: $!";
  255. }
  256. }
  257. sub usage
  258. {
  259. my $last = $FirstGenbkiObjectId - 1;
  260. die <<EOM;
  261. Usage: renumber_oids.pl [--output PATH] --first-mapped-oid X [--last-mapped-oid Y] --target-oid Z
  262. Options:
  263. --output PATH output directory (default '.')
  264. --first-mapped-oid X first OID to be moved
  265. --last-mapped-oid Y last OID to be moved (default $last)
  266. --target-oid Z first OID to move to
  267. Catalog *.h and *.dat files are updated and written to the
  268. output directory; by default, this overwrites the input files.
  269. Caution: the output PATH will be interpreted relative to
  270. src/include/catalog, even if you start the script
  271. in some other directory.
  272. EOM
  273. }