Fix oversight in previous error-reporting patch; mustn't pfree path string
[PostgreSQL.git] / src / backend / catalog / genbki.sh
blob428228fba5667aa5e94df3aeffce957d12d9b417
1 #! /bin/sh
2 #-------------------------------------------------------------------------
4 # genbki.sh--
5 # shell script which generates .bki files from specially formatted .h
6 # files. These .bki files are used to initialize the postgres template
7 # database.
9 # Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
10 # Portions Copyright (c) 1994, Regents of the University of California
13 # IDENTIFICATION
14 # $PostgreSQL$
16 # NOTES
17 # non-essential whitespace is removed from the generated file.
18 # if this is ever a problem, then the sed script at the very
19 # end can be changed into another awk script or something smarter.
21 #-------------------------------------------------------------------------
23 : ${AWK='awk'}
25 CMDNAME=`basename $0`
27 INCLUDE_DIRS=
28 OUTPUT_PREFIX=
29 INFILES=
30 major_version=
33 # Process command line switches.
35 while [ $# -gt 0 ]
37 case $1 in
38 -I)
39 INCLUDE_DIRS="$INCLUDE_DIRS $2"
40 shift;;
41 -I*)
42 arg=`echo $1 | sed -e 's/^-I//'`
43 INCLUDE_DIRS="$INCLUDE_DIRS $arg"
45 -o)
46 OUTPUT_PREFIX="$2"
47 shift;;
48 -o*)
49 OUTPUT_PREFIX=`echo $1 | sed -e 's/^-o//'`
51 --set-version=*)
52 arg=`expr x"$1" : x"--set-version=\(.*\)"`
53 major_version=`expr x"$arg" : x'\([0-9][0-9]*\.[0-9][0-9]*\)'`
55 --help)
56 echo "$CMDNAME generates system catalog bootstrapping files."
57 echo
58 echo "Usage:"
59 echo " $CMDNAME [ -I dir ] --set-version=VERSION -o prefix files..."
60 echo
61 echo "Options:"
62 echo " -I path to include files"
63 echo " -o prefix of output files"
64 echo " --set-version PostgreSQL version number for initdb cross-check"
65 echo
66 echo "The environment variable AWK determines which Awk program"
67 echo "to use. The default is \`awk'."
68 echo
69 echo "Report bugs to <pgsql-bugs@postgresql.org>."
70 exit 0
72 -*)
73 echo "$CMDNAME: invalid option: $1"
74 exit 1
77 INFILES="$INFILES $1"
79 esac
80 shift
81 done
83 if [ x"$INFILES" = x"" ] ; then
84 echo "$CMDNAME: no input files" 1>&2
85 exit 1
88 if [ x"$OUTPUT_PREFIX" = x"" ] ; then
89 echo "$CMDNAME: no output prefix specified" 1>&2
90 exit 1
93 if [ x"$INCLUDE_DIRS" = x"" ] ; then
94 echo "$CMDNAME: path to include directory unknown" 1>&2
95 exit 1
98 if [ x"$major_version" = x"" ] ; then
99 echo "$CMDNAME: invalid or no version number specified" 1>&2
100 exit 1
104 TMPFILE="genbkitmp$$.c"
106 trap "rm -f $TMPFILE ${OUTPUT_PREFIX}.bki.$$ ${OUTPUT_PREFIX}.description.$$ ${OUTPUT_PREFIX}.shdescription.$$" 0 1 2 3 15
109 # CAUTION: be wary about what symbols you substitute into the .bki file here!
110 # It's okay to substitute things that are expected to be really constant
111 # within a given Postgres release, such as fixed OIDs. Do not substitute
112 # anything that could depend on platform or configuration. (The right place
113 # to handle those sorts of things is in initdb.c's bootstrap_template1().)
115 # Get BOOTSTRAP_SUPERUSERID from catalog/pg_authid.h
116 for dir in $INCLUDE_DIRS; do
117 if [ -f "$dir/catalog/pg_authid.h" ]; then
118 BOOTSTRAP_SUPERUSERID=`grep '^#define[ ]*BOOTSTRAP_SUPERUSERID' $dir/catalog/pg_authid.h | $AWK '{ print $3 }'`
119 break
121 done
123 # Get PG_CATALOG_NAMESPACE from catalog/pg_namespace.h
124 for dir in $INCLUDE_DIRS; do
125 if [ -f "$dir/catalog/pg_namespace.h" ]; then
126 PG_CATALOG_NAMESPACE=`grep '^#define[ ]*PG_CATALOG_NAMESPACE' $dir/catalog/pg_namespace.h | $AWK '{ print $3 }'`
127 break
129 done
131 touch ${OUTPUT_PREFIX}.description.$$
132 touch ${OUTPUT_PREFIX}.shdescription.$$
134 # ----------------
135 # Strip comments and other trash from .h
137 # Put multi-line start/end comments on a separate line
139 # Rename datatypes that have different names in .h files than in SQL
141 # Substitute values of configuration constants
142 # ----------------
144 cat $INFILES | \
145 sed -e 's;/\*.*\*/;;g' \
146 -e 's;/\*;\
148 ;g' \
149 -e 's;\*/;\
151 ;g' | # we must run a new sed here to see the newlines we added
152 sed -e "s/;[ ]*$//g" \
153 -e "s/^[ ]*//" \
154 -e "s/[ ]Oid/ oid/g" \
155 -e "s/^Oid/oid/g" \
156 -e "s/(Oid/(oid/g" \
157 -e "s/[ ]NameData/ name/g" \
158 -e "s/^NameData/name/g" \
159 -e "s/(NameData/(name/g" \
160 -e "s/[ ]TransactionId/ xid/g" \
161 -e "s/^TransactionId/xid/g" \
162 -e "s/(TransactionId/(xid/g" \
163 -e "s/PGUID/$BOOTSTRAP_SUPERUSERID/g" \
164 -e "s/PGNSP/$PG_CATALOG_NAMESPACE/g" \
165 | $AWK '
166 # ----------------
167 # now use awk to process remaining .h file..
169 # nc is the number of catalogs
170 # inside is a variable set to 1 when we are scanning the
171 # contents of a catalog definition.
172 # reln_open is a flag indicating when we are processing DATA lines.
173 # (i.e. have a relation open and need to close it)
174 # oid is the most recently seen oid, or 0 if none in the last DATA line.
175 # ----------------
176 BEGIN {
177 inside = 0;
178 bootstrap = "";
179 shared_relation = "";
180 without_oids = "";
181 nc = 0;
182 reln_open = 0;
183 comment_level = 0;
184 oid = 0;
187 # ----------------
188 # Anything in a /* .. */ block should be ignored.
189 # Blank lines also go.
190 # Note that any /* */ comment on a line by itself was removed from the line
191 # by the sed above.
192 # ----------------
193 /^\/\*/ { comment_level += 1; next; }
194 /^\*\// { comment_level -= 1; next; }
195 comment_level > 0 { next; }
197 /^[ ]*$/ { next; }
199 # ----------------
200 # DATA() statements are basically passed right through after
201 # stripping off the DATA( and the ) on the end.
202 # Remember the OID for use by DESCR() and SHDESCR().
203 # ----------------
204 /^DATA\(/ {
205 data = substr($0, 6, length($0) - 6);
206 oid = 0;
207 nf = split(data, datafields);
208 if (nf >= 4 && datafields[1] == "insert" && datafields[2] == "OID" && datafields[3] == "=")
210 oid = datafields[4];
212 print data;
213 next;
216 /^DESCR\(/ {
217 if (oid != 0)
219 data = substr($0, 8, length($0) - 9);
220 if (data != "")
221 printf "%d\t%s\t0\t%s\n", oid, catalog, data >>descriptionfile;
223 next;
226 /^SHDESCR\(/ {
227 if (oid != 0)
229 data = substr($0, 10, length($0) - 11);
230 if (data != "")
231 printf "%d\t%s\t%s\n", oid, catalog, data >>shdescriptionfile;
233 next;
236 /^DECLARE_INDEX\(/ {
237 # ----
238 # end any prior catalog data insertions before starting a define index
239 # ----
240 if (reln_open == 1) {
241 print "close " catalog;
242 reln_open = 0;
245 data = substr($0, 15, length($0) - 15);
246 pos = index(data, ",");
247 iname = substr(data, 1, pos-1);
248 data = substr(data, pos+1, length(data)-pos);
249 pos = index(data, ",");
250 oid = substr(data, 1, pos-1);
251 data = substr(data, pos+1, length(data)-pos);
253 print "declare index " iname " " oid " " data
256 /^DECLARE_UNIQUE_INDEX\(/ {
257 # ----
258 # end any prior catalog data insertions before starting a define unique index
259 # ----
260 if (reln_open == 1) {
261 print "close " catalog;
262 reln_open = 0;
265 data = substr($0, 22, length($0) - 22);
266 pos = index(data, ",");
267 iname = substr(data, 1, pos-1);
268 data = substr(data, pos+1, length(data)-pos);
269 pos = index(data, ",");
270 oid = substr(data, 1, pos-1);
271 data = substr(data, pos+1, length(data)-pos);
273 print "declare unique index " iname " " oid " " data
276 /^DECLARE_TOAST\(/ {
277 # ----
278 # end any prior catalog data insertions before starting a define toast
279 # ----
280 if (reln_open == 1) {
281 print "close " catalog;
282 reln_open = 0;
285 data = substr($0, 15, length($0) - 15);
286 pos = index(data, ",");
287 tname = substr(data, 1, pos-1);
288 data = substr(data, pos+1, length(data)-pos);
289 pos = index(data, ",");
290 toastoid = substr(data, 1, pos-1);
291 data = substr(data, pos+1, length(data)-pos);
292 # previous commands already removed the trailing );
293 indexoid = data;
295 print "declare toast " toastoid " " indexoid " on " tname
298 /^BUILD_INDICES/ { print "build indices"; }
300 # ----------------
301 # CATALOG() definitions take some more work.
302 # ----------------
303 /^CATALOG\(/ {
304 # ----
305 # end any prior catalog data insertions before starting a new one..
306 # ----
307 if (reln_open == 1) {
308 print "close " catalog;
309 reln_open = 0;
312 # ----
313 # get the name and properties of the new catalog
314 # ----
315 pos = index($1,")");
316 catalogandoid = substr($1,9,pos-9);
317 pos = index(catalogandoid, ",");
318 catalog = substr(catalogandoid, 1, pos-1);
319 oid = substr(catalogandoid, pos+1, length(catalogandoid)-pos);
321 if ($0 ~ /BKI_BOOTSTRAP/) {
322 bootstrap = "bootstrap ";
324 if ($0 ~ /BKI_SHARED_RELATION/) {
325 shared_relation = "shared_relation ";
327 if ($0 ~ /BKI_WITHOUT_OIDS/) {
328 without_oids = "without_oids ";
331 i = 1;
332 inside = 1;
333 nc++;
334 next;
337 # ----------------
338 # process the columns of the catalog definition
340 # attname[ x ] contains the attribute name for attribute x
341 # atttype[ x ] contains the attribute type fot attribute x
342 # ----------------
343 inside == 1 {
344 # ----
345 # ignore a leading brace line..
346 # ----
347 if ($1 ~ /\{/)
348 next;
350 # ----
351 # if this is the last line, then output the bki catalog stuff.
352 # ----
353 if ($1 ~ /}/) {
354 print "create " bootstrap shared_relation without_oids catalog " " oid;
355 print "\t(";
357 for (j=1; j<i-1; j++) {
358 print "\t " attname[ j ] " = " atttype[ j ] " ,";
360 print "\t " attname[ j ] " = " atttype[ j ] ;
361 print "\t)";
363 if (bootstrap == "") {
364 print "open " catalog;
367 i = 1;
368 reln_open = 1;
369 inside = 0;
370 bootstrap = "";
371 shared_relation = "";
372 without_oids = "";
373 next;
376 # ----
377 # we are inside the catalog definition, so keep sucking up
378 # attribute names and types
379 # ----
380 if ($2 ~ /\[.*\]/) { # array attribute
381 idlen = index($2,"[") - 1;
382 atttype[ i ] = $1 "[]"; # variable-length only..
383 attname[ i ] = substr($2,1,idlen);
384 } else {
385 atttype[ i ] = $1;
386 attname[ i ] = $2;
388 i++;
389 next;
392 END {
393 if (reln_open == 1) {
394 print "close " catalog;
395 reln_open = 0;
398 ' "descriptionfile=${OUTPUT_PREFIX}.description.$$" "shdescriptionfile=${OUTPUT_PREFIX}.shdescription.$$" > $TMPFILE || exit
400 echo "# PostgreSQL $major_version" >${OUTPUT_PREFIX}.bki.$$
402 sed -e '/^[ ]*$/d' \
403 -e 's/[ ][ ]*/ /g' $TMPFILE >>${OUTPUT_PREFIX}.bki.$$ || exit
406 # Sanity check: if one of the sed/awk/etc commands fails, we'll probably
407 # end up with a .bki file that is empty or just a few lines. Cross-check
408 # that the files are of reasonable size. The numbers here are arbitrary,
409 # but are much smaller than the actual expected sizes as of Postgres 7.2.
411 if [ `wc -c < ${OUTPUT_PREFIX}.bki.$$` -lt 100000 ]; then
412 echo "$CMDNAME: something seems to be wrong with the .bki file" >&2
413 exit 1
415 if [ `wc -c < ${OUTPUT_PREFIX}.description.$$` -lt 10000 ]; then
416 echo "$CMDNAME: something seems to be wrong with the .description file" >&2
417 exit 1
419 if [ `wc -c < ${OUTPUT_PREFIX}.shdescription.$$` -lt 10 ]; then
420 echo "$CMDNAME: something seems to be wrong with the .shdescription file" >&2
421 exit 1
424 # Looks good, commit ...
426 mv ${OUTPUT_PREFIX}.bki.$$ ${OUTPUT_PREFIX}.bki || exit
427 mv ${OUTPUT_PREFIX}.description.$$ ${OUTPUT_PREFIX}.description || exit
428 mv ${OUTPUT_PREFIX}.shdescription.$$ ${OUTPUT_PREFIX}.shdescription || exit
430 exit 0