genbki.sh 11.4 KB
Newer Older
1
#! /bin/sh
2 3 4 5 6 7 8
#-------------------------------------------------------------------------
#
# genbki.sh--
#    shell script which generates .bki files from specially formatted .h
#    files.  These .bki files are used to initialize the postgres template
#    database.
#
9
# Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
10
# Portions Copyright (c) 1994, Regents of the University of California
11 12 13
#
#
# IDENTIFICATION
14
#    $PostgreSQL: pgsql/src/backend/catalog/genbki.sh,v 1.44 2008/04/21 00:26:45 tgl Exp $
15 16 17 18
#
# NOTES
#    non-essential whitespace is removed from the generated file.
#    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.
20 21
#
#-------------------------------------------------------------------------
22

23
: ${AWK='awk'}
24

25
CMDNAME=`basename $0`
26

27
INCLUDE_DIRS=
28 29
OUTPUT_PREFIX=
INFILES=
P
Peter Eisentraut 已提交
30
major_version=
31

32 33 34 35
#
# Process command line switches.
#
while [ $# -gt 0 ]
36
do
37 38
    case $1 in
        -I)
39
            INCLUDE_DIRS="$INCLUDE_DIRS $2"
40 41
            shift;;
        -I*)
42 43
            arg=`echo $1 | sed -e 's/^-I//'`
            INCLUDE_DIRS="$INCLUDE_DIRS $arg"
44 45 46 47 48
            ;;
        -o)
            OUTPUT_PREFIX="$2"
            shift;;
        -o*)
49
            OUTPUT_PREFIX=`echo $1 | sed -e 's/^-o//'`
50
            ;;
P
Peter Eisentraut 已提交
51 52 53 54
        --set-version=*)
            arg=`expr x"$1" : x"--set-version=\(.*\)"`
            major_version=`expr x"$arg" : x'\([0-9][0-9]*\.[0-9][0-9]*\)'`
            ;;
55 56 57 58
        --help)
            echo "$CMDNAME generates system catalog bootstrapping files."
            echo
            echo "Usage:"
59
            echo "  $CMDNAME [ -I dir ] --set-version=VERSION -o prefix files..."
60 61
            echo
            echo "Options:"
62
            echo "  -I  path to pg_config_manual.h file"
63
            echo "  -o  prefix of output files"
P
Peter Eisentraut 已提交
64
            echo "  --set-version  PostgreSQL version number for initdb cross-check"
65
            echo
66 67
            echo "The environment variable AWK determines which Awk program"
            echo "to use. The default is \`awk'."
68 69 70 71
            echo
            echo "Report bugs to <pgsql-bugs@postgresql.org>."
            exit 0
            ;;
72
        -*)
73 74 75 76 77 78
            echo "$CMDNAME: invalid option: $1"
            exit 1
            ;;
        *)
            INFILES="$INFILES $1"
            ;;
79 80 81 82
    esac
    shift
done

83 84 85 86 87 88 89 90 91 92
if [ x"$INFILES" = x"" ] ; then
    echo "$CMDNAME: no input files" 1>&2
    exit 1
fi

if [ x"$OUTPUT_PREFIX" = x"" ] ; then
    echo "$CMDNAME: no output prefix specified" 1>&2
    exit 1
fi

93
if [ x"$INCLUDE_DIRS" = x"" ] ; then
94 95 96 97
    echo "$CMDNAME: path to include directory unknown" 1>&2
    exit 1
fi

P
Peter Eisentraut 已提交
98 99 100 101
if [ x"$major_version" = x"" ] ; then
    echo "$CMDNAME: invalid or no version number specified" 1>&2
    exit 1
fi
102 103


104
TMPFILE="genbkitmp$$.c"
105

106
trap "rm -f $TMPFILE ${OUTPUT_PREFIX}.bki.$$ ${OUTPUT_PREFIX}.description.$$ ${OUTPUT_PREFIX}.shdescription.$$" 0 1 2 3 15
107 108


109
# Get NAMEDATALEN from pg_config_manual.h
110
for dir in $INCLUDE_DIRS; do
111 112
    if [ -f "$dir/pg_config_manual.h" ]; then
        NAMEDATALEN=`grep '^#define[ 	]*NAMEDATALEN' $dir/pg_config_manual.h | $AWK '{ print $3 }'`
113 114 115
        break
    fi
done
116

117 118 119 120 121 122 123 124 125
# Get FLOAT4PASSBYVAL and FLOAT8PASSBYVAL from pg_config.h
for dir in $INCLUDE_DIRS; do
    if [ -f "$dir/pg_config.h" ]; then
        FLOAT4PASSBYVAL=`grep '^#define[ 	]*FLOAT4PASSBYVAL' $dir/pg_config.h | $AWK '{ print $3 }'`
        FLOAT8PASSBYVAL=`grep '^#define[ 	]*FLOAT8PASSBYVAL' $dir/pg_config.h | $AWK '{ print $3 }'`
        break
    fi
done

126 127 128 129 130 131 132 133
# Get BOOTSTRAP_SUPERUSERID from catalog/pg_authid.h
for dir in $INCLUDE_DIRS; do
    if [ -f "$dir/catalog/pg_authid.h" ]; then
        BOOTSTRAP_SUPERUSERID=`grep '^#define[ 	]*BOOTSTRAP_SUPERUSERID' $dir/catalog/pg_authid.h | $AWK '{ print $3 }'`
        break
    fi
done

134 135 136 137 138 139 140 141
# Get PG_CATALOG_NAMESPACE from catalog/pg_namespace.h
for dir in $INCLUDE_DIRS; do
    if [ -f "$dir/catalog/pg_namespace.h" ]; then
        PG_CATALOG_NAMESPACE=`grep '^#define[ 	]*PG_CATALOG_NAMESPACE' $dir/catalog/pg_namespace.h | $AWK '{ print $3 }'`
        break
    fi
done

P
Peter Eisentraut 已提交
142
touch ${OUTPUT_PREFIX}.description.$$
143
touch ${OUTPUT_PREFIX}.shdescription.$$
P
Peter Eisentraut 已提交
144

145
# ----------------
146 147 148 149 150 151 152
# 	Strip comments and other trash from .h
#
#	Put multi-line start/end comments on a separate line
#
#	Rename datatypes that have different names in .h files than in SQL
#
#	Substitute values of configuration constants
153 154
# ----------------
#
155
cat $INFILES | \
B
Bruce Momjian 已提交
156 157 158 159 160 161 162
sed -e 's;/\*.*\*/;;g' \
    -e 's;/\*;\
/*\
;g' \
    -e 's;\*/;\
*/\
;g' | # we must run a new sed here to see the newlines we added
B
Hi,  
Bruce Momjian 已提交
163 164
sed -e "s/;[ 	]*$//g" \
    -e "s/^[ 	]*//" \
165
    -e "s/[ 	]Oid/ oid/g" \
B
Hi,  
Bruce Momjian 已提交
166
    -e "s/^Oid/oid/g" \
167 168
    -e "s/(Oid/(oid/g" \
    -e "s/[ 	]NameData/ name/g" \
169
    -e "s/^NameData/name/g" \
B
Hi,  
Bruce Momjian 已提交
170
    -e "s/(NameData/(name/g" \
171 172 173
    -e "s/[ 	]TransactionId/ xid/g" \
    -e "s/^TransactionId/xid/g" \
    -e "s/(TransactionId/(xid/g" \
174
    -e "s/PGUID/$BOOTSTRAP_SUPERUSERID/g" \
175
    -e "s/NAMEDATALEN/$NAMEDATALEN/g" \
176 177
    -e "s/FLOAT4PASSBYVAL/$FLOAT4PASSBYVAL/g" \
    -e "s/FLOAT8PASSBYVAL/$FLOAT8PASSBYVAL/g" \
178
    -e "s/PGNSP/$PG_CATALOG_NAMESPACE/g" \
179
| $AWK '
180 181 182 183 184 185
# ----------------
#	now use awk to process remaining .h file..
#
#	nc is the number of catalogs
#	inside is a variable set to 1 when we are scanning the
#	   contents of a catalog definition.
186 187
#	reln_open is a flag indicating when we are processing DATA lines.
#	   (i.e. have a relation open and need to close it)
188
#	oid is the most recently seen oid, or 0 if none in the last DATA line.
189 190 191
# ----------------
BEGIN {
	inside = 0;
192
	bootstrap = "";
193
	shared_relation = "";
194
	without_oids = "";
195 196
	nc = 0;
	reln_open = 0;
197 198
	comment_level = 0;
	oid = 0;
199 200
}

201 202 203 204 205 206 207
# ----------------
# Anything in a /* .. */ block should be ignored.
# Blank lines also go.
# Note that any /* */ comment on a line by itself was removed from the line
# by the sed above.
# ----------------
/^\/\*/           { comment_level += 1; next; }
208
/^\*\//           { comment_level -= 1; next; }
209 210 211 212
comment_level > 0 { next; }

/^[ 	]*$/      { next; }

213
# ----------------
214
#	DATA() statements are basically passed right through after
215
#	stripping off the DATA( and the ) on the end.
216
#	Remember the OID for use by DESCR() and SHDESCR().
217 218 219
# ----------------
/^DATA\(/ {
	data = substr($0, 6, length($0) - 6);
220
	oid = 0;
221 222
	nf = split(data, datafields);
	if (nf >= 4 && datafields[1] == "insert" && datafields[2] == "OID" && datafields[3] == "=")
223
	{
224
		oid = datafields[4];
225
	}
226
	print data;
227 228 229 230 231 232 233 234
	next;
}

/^DESCR\(/ {
	if (oid != 0)
	{
		data = substr($0, 8, length($0) - 9);
		if (data != "")
235
			printf "%d\t%s\t0\t%s\n", oid, catalog, data >>descriptionfile;
236
	}
237 238 239
	next;
}

240 241 242 243 244 245 246 247 248 249
/^SHDESCR\(/ {
	if (oid != 0)
	{
		data = substr($0, 10, length($0) - 11);
		if (data != "")
			printf "%d\t%s\t%s\n", oid, catalog, data >>shdescriptionfile;
	}
	next;
}

250 251 252 253 254 255 256 257 258 259
/^DECLARE_INDEX\(/ {
# ----
#  end any prior catalog data insertions before starting a define index
# ----
	if (reln_open == 1) {
		print "close " catalog;
		reln_open = 0;
	}

	data = substr($0, 15, length($0) - 15);
260 261 262 263
	pos = index(data, ",");
	iname = substr(data, 1, pos-1);
	data = substr(data, pos+1, length(data)-pos);
	pos = index(data, ",");
264
	oid = substr(data, 1, pos-1);
265 266
	data = substr(data, pos+1, length(data)-pos);

267
	print "declare index " iname " " oid " " data
268 269
}

270 271 272 273 274 275 276 277 278 279
/^DECLARE_UNIQUE_INDEX\(/ {
# ----
#  end any prior catalog data insertions before starting a define unique index
# ----
	if (reln_open == 1) {
		print "close " catalog;
		reln_open = 0;
	}

	data = substr($0, 22, length($0) - 22);
280 281 282 283
	pos = index(data, ",");
	iname = substr(data, 1, pos-1);
	data = substr(data, pos+1, length(data)-pos);
	pos = index(data, ",");
284
	oid = substr(data, 1, pos-1);
285 286
	data = substr(data, pos+1, length(data)-pos);

287
	print "declare unique index " iname " " oid " " data
288 289
}

290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311
/^DECLARE_TOAST\(/ {
# ----
#  end any prior catalog data insertions before starting a define toast
# ----
	if (reln_open == 1) {
		print "close " catalog;
		reln_open = 0;
	}

	data = substr($0, 15, length($0) - 15);
	pos = index(data, ",");
	tname = substr(data, 1, pos-1);
	data = substr(data, pos+1, length(data)-pos);
	pos = index(data, ",");
	toastoid = substr(data, 1, pos-1);
	data = substr(data, pos+1, length(data)-pos);
	# previous commands already removed the trailing );
	indexoid = data;

	print "declare toast " toastoid " " indexoid " on " tname
}

312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
/^BUILD_INDICES/	{ print "build indices"; }
	
# ----------------
#	CATALOG() definitions take some more work.
# ----------------
/^CATALOG\(/ { 
# ----
#  end any prior catalog data insertions before starting a new one..
# ----
	if (reln_open == 1) {
		print "close " catalog;
		reln_open = 0;
	}

# ----
327
#  get the name and properties of the new catalog
328 329
# ----
	pos = index($1,")");
330 331 332
	catalogandoid = substr($1,9,pos-9);
	pos = index(catalogandoid, ",");
	catalog = substr(catalogandoid, 1, pos-1);
333
	oid = substr(catalogandoid, pos+1, length(catalogandoid)-pos);
334

335
	if ($0 ~ /BKI_BOOTSTRAP/) {
336 337
		bootstrap = "bootstrap ";
	}
338 339 340
	if ($0 ~ /BKI_SHARED_RELATION/) {
		shared_relation = "shared_relation ";
	}
341 342
	if ($0 ~ /BKI_WITHOUT_OIDS/) {
		without_oids = "without_oids ";
343 344 345 346 347 348 349 350 351
	}

        i = 1;
	inside = 1;
        nc++;
	next;
}

# ----------------
352
#	process the columns of the catalog definition
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367
#
#	attname[ x ] contains the attribute name for attribute x
#	atttype[ x ] contains the attribute type fot attribute x
# ----------------
inside == 1 {
# ----
#  ignore a leading brace line..
# ----
        if ($1 ~ /\{/)
		next;

# ----
#  if this is the last line, then output the bki catalog stuff.
# ----
	if ($1 ~ /}/) {
368
		print "create " bootstrap shared_relation without_oids catalog " " oid;
369 370 371 372 373 374 375 376
		print "\t(";

		for (j=1; j<i-1; j++) {
			print "\t " attname[ j ] " = " atttype[ j ] " ,";
		}
		print "\t " attname[ j ] " = " atttype[ j ] ;
		print "\t)";

377
		if (bootstrap == "") {
378 379 380 381 382 383
			print "open " catalog;
		}

		i = 1;
		reln_open = 1;
		inside = 0;
384
		bootstrap = "";
385
		shared_relation = "";
386
		without_oids = "";
387 388 389 390
		next;
	}

# ----
391
#  we are inside the catalog definition, so keep sucking up
392
#  attribute names and types
393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411
# ----
	if ($2 ~ /\[.*\]/) {			# array attribute
		idlen = index($2,"[") - 1;
		atttype[ i ] = $1 "[]";		# variable-length only..
		attname[ i ] = substr($2,1,idlen);
	} else {
		atttype[ i ] = $1;
		attname[ i ] = $2;
	}
	i++;
	next;
}

END {
	if (reln_open == 1) {
		print "close " catalog;
		reln_open = 0;
	}
}
412
' "descriptionfile=${OUTPUT_PREFIX}.description.$$" "shdescriptionfile=${OUTPUT_PREFIX}.shdescription.$$" > $TMPFILE || exit
P
Peter Eisentraut 已提交
413 414

echo "# PostgreSQL $major_version" >${OUTPUT_PREFIX}.bki.$$
415

416
sed -e '/^[ 	]*$/d' \
417
    -e 's/[ 	][ 	]*/ /g' $TMPFILE >>${OUTPUT_PREFIX}.bki.$$ || exit
418

419 420 421 422 423 424 425 426 427 428 429 430 431 432
#
# Sanity check: if one of the sed/awk/etc commands fails, we'll probably
# end up with a .bki file that is empty or just a few lines.  Cross-check
# that the files are of reasonable size.  The numbers here are arbitrary,
# but are much smaller than the actual expected sizes as of Postgres 7.2.
#
if [ `wc -c < ${OUTPUT_PREFIX}.bki.$$` -lt 100000 ]; then
    echo "$CMDNAME: something seems to be wrong with the .bki file" >&2
    exit 1
fi
if [ `wc -c < ${OUTPUT_PREFIX}.description.$$` -lt 10000 ]; then
    echo "$CMDNAME: something seems to be wrong with the .description file" >&2
    exit 1
fi
433 434 435 436
if [ `wc -c < ${OUTPUT_PREFIX}.shdescription.$$` -lt 10 ]; then
    echo "$CMDNAME: something seems to be wrong with the .shdescription file" >&2
    exit 1
fi
437 438 439

# Looks good, commit ...

P
Peter Eisentraut 已提交
440 441
mv ${OUTPUT_PREFIX}.bki.$$ ${OUTPUT_PREFIX}.bki || exit
mv ${OUTPUT_PREFIX}.description.$$ ${OUTPUT_PREFIX}.description || exit
442
mv ${OUTPUT_PREFIX}.shdescription.$$ ${OUTPUT_PREFIX}.shdescription || exit
443

444
exit 0