diff --git a/src/backend/utils/Gen_fmgrtab.pl b/src/backend/utils/Gen_fmgrtab.pl new file mode 100644 index 0000000000..6f67438d46 --- /dev/null +++ b/src/backend/utils/Gen_fmgrtab.pl @@ -0,0 +1,194 @@ +#! /usr/bin/perl -w +#------------------------------------------------------------------------- +# +# Gen_fmgrtab.pl +# Perl equivalent of Gen_fmgrtab.sh +# +# Usage: perl Gen_fmgrtab.pl path-to-pg_proc.h +# +# The reason for implementing this functionality twice is that we don't +# require people to have perl to build from a tarball, but on the other +# hand Windows can't deal with shell scripts. +# +# Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group +# Portions Copyright (c) 1994, Regents of the University of California +# +# +# IDENTIFICATION +# $PostgreSQL: pgsql/src/backend/utils/Gen_fmgrtab.pl,v 1.1 2008/06/23 17:54:29 tgl Exp $ +# +#------------------------------------------------------------------------- + +use strict; +use warnings; + +# Collect arguments +my $infile = shift; +defined($infile) || die "$0: missing required argument: pg_proc.h\n"; + +# Note: see Gen_fmgrtab.sh for detailed commentary on what this is doing + +# Collect column numbers for pg_proc columns we need +my ($proname, $prolang, $proisstrict, $proretset, $pronargs, $prosrc); + +open(I, $infile) || die "Could not open $infile: $!"; +while () +{ + if (m/#define Anum_pg_proc_proname\s+(\d+)/) { + $proname = $1; + } + if (m/#define Anum_pg_proc_prolang\s+(\d+)/) { + $prolang = $1; + } + if (m/#define Anum_pg_proc_proisstrict\s+(\d+)/) { + $proisstrict = $1; + } + if (m/#define Anum_pg_proc_proretset\s+(\d+)/) { + $proretset = $1; + } + if (m/#define Anum_pg_proc_pronargs\s+(\d+)/) { + $pronargs = $1; + } + if (m/#define Anum_pg_proc_prosrc\s+(\d+)/) { + $prosrc = $1; + } +} +close(I); + +# Collect the raw data +my @fmgr = (); + +open(I, $infile) || die "Could not open $infile: $!"; +while () +{ + next unless (/^DATA/); + s/^[^O]*OID[^=]*=[ \t]*//; + s/\(//; + s/"[^"]*"/"xxx"/g; + my @p = split; + next if ($p[$prolang] ne "12"); + push @fmgr, + { + oid => $p[0], + proname => $p[$proname], + strict => $p[$proisstrict], + retset => $p[$proretset], + nargs => $p[$pronargs], + prosrc => $p[$prosrc], + }; +} +close(I); + +# Emit headers for both files +open(H, '>', "$$-fmgroids.h") || die "Could not open $$-fmgroids.h: $!"; +print H +qq|/*------------------------------------------------------------------------- + * + * fmgroids.h + * Macros that define the OIDs of built-in functions. + * + * These macros can be used to avoid a catalog lookup when a specific + * fmgr-callable function needs to be referenced. + * + * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by $0 + * from $infile + * + *------------------------------------------------------------------------- + */ +#ifndef FMGROIDS_H +#define FMGROIDS_H + +/* + * Constant macros for the OIDs of entries in pg_proc. + * + * NOTE: macros are named after the prosrc value, ie the actual C name + * of the implementing function, not the proname which may be overloaded. + * For example, we want to be able to assign different macro names to both + * char_text() and name_text() even though these both appear with proname + * 'text'. If the same C function appears in more than one pg_proc entry, + * its equivalent macro will be defined with the lowest OID among those + * entries. + */ +|; + +open(T, '>', "$$-fmgrtab.c") || die "Could not open $$-fmgrtab.c: $!"; +print T +qq|/*------------------------------------------------------------------------- + * + * fmgrtab.c + * The function manager's table of internal functions. + * + * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by $0 + * from $infile + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "utils/fmgrtab.h" + +|; + +# Emit #define's and extern's -- only one per prosrc value +my %seenit; +foreach my $s (sort {$a->{oid} <=> $b->{oid}} @fmgr) +{ + next if $seenit{$s->{prosrc}}; + $seenit{$s->{prosrc}} = 1; + print H "#define F_" . uc $s->{prosrc} . " $s->{oid}\n"; + print T "extern Datum $s->{prosrc} (PG_FUNCTION_ARGS);\n"; +} + +# Create the fmgr_builtins table +print T "\nconst FmgrBuiltin fmgr_builtins[] = {\n"; +my %bmap; +$bmap{'t'} = 'true'; +$bmap{'f'} = 'false'; +foreach my $s (sort {$a->{oid} <=> $b->{oid}} @fmgr) +{ + print T + " { $s->{oid}, \"$s->{prosrc}\", $s->{nargs}, $bmap{$s->{strict}}, $bmap{$s->{retset}}, $s->{prosrc} },\n"; +} + +# And add the file footers. +print H "\n#endif /* FMGROIDS_H */\n"; +close(H); + +print T +qq| /* dummy entry is easier than getting rid of comma after last real one */ + /* (not that there has ever been anything wrong with *having* a + comma after the last field in an array initializer) */ + { 0, NULL, 0, false, false, NULL } +}; + +/* Note fmgr_nbuiltins excludes the dummy entry */ +const int fmgr_nbuiltins = (sizeof(fmgr_builtins) / sizeof(FmgrBuiltin)) - 1; +|; + +close(T); + +# Finally, rename the completed files into place. +rename "$$-fmgroids.h", "fmgroids.h" + || die "Could not rename $$-fmgroids.h to fmgroids.h: $!"; +rename "$$-fmgrtab.c", "fmgrtab.c" + || die "Could not rename $$-fmgrtab.c to fmgrtab.c: $!"; + +exit 0; diff --git a/src/backend/utils/Gen_fmgrtab.sh b/src/backend/utils/Gen_fmgrtab.sh index 1fda8a9939..abe6840d0a 100644 --- a/src/backend/utils/Gen_fmgrtab.sh +++ b/src/backend/utils/Gen_fmgrtab.sh @@ -4,12 +4,14 @@ # Gen_fmgrtab.sh # shell script to generate fmgroids.h and fmgrtab.c from pg_proc.h # +# NOTE: if you change this, you need to fix Gen_fmgrtab.pl too! +# # Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # # IDENTIFICATION -# $PostgreSQL: pgsql/src/backend/utils/Gen_fmgrtab.sh,v 1.39 2008/05/02 14:16:24 petere Exp $ +# $PostgreSQL: pgsql/src/backend/utils/Gen_fmgrtab.sh,v 1.40 2008/06/23 17:54:29 tgl Exp $ # #------------------------------------------------------------------------- @@ -70,20 +72,35 @@ TABLEFILE=fmgrtab.c trap 'echo "Caught signal." ; cleanup ; exit 1' 1 2 15 +# +# Collect the column numbers of the pg_proc columns we need. Because we will +# be looking at data that includes the OID as the first column, add one to +# each column number. +# +proname=`egrep '^#define Anum_pg_proc_proname[ ]' $INFILE | $AWK '{print $3+1}'` +prolang=`egrep '^#define Anum_pg_proc_prolang[ ]' $INFILE | $AWK '{print $3+1}'` +proisstrict=`egrep '^#define Anum_pg_proc_proisstrict[ ]' $INFILE | $AWK '{print $3+1}'` +proretset=`egrep '^#define Anum_pg_proc_proretset[ ]' $INFILE | $AWK '{print $3+1}'` +pronargs=`egrep '^#define Anum_pg_proc_pronargs[ ]' $INFILE | $AWK '{print $3+1}'` +prosrc=`egrep '^#define Anum_pg_proc_prosrc[ ]' $INFILE | $AWK '{print $3+1}'` # -# Generate the file containing raw pg_proc tuple data -# (but only for "internal" language procedures...). -# Basically we strip off the DATA macro call, leaving procedure OID as $1 +# Generate the file containing raw pg_proc data. We do three things here: +# 1. Strip off the DATA macro call, leaving procedure OID as $1 # and all the pg_proc field values as $2, $3, etc on each line. +# 2. Fold quoted fields to simple "xxx". We need this because such fields +# may contain whitespace, which would confuse awk's counting of fields. +# Fortunately, this script doesn't need to look at any fields that might +# need quoting, so this simple hack is sufficient. +# 3. Select out just the rows for internal-language procedures. # -# Note assumption here that prolang == $5 and INTERNALlanguageId == 12. +# Note assumption here that INTERNALlanguageId == 12. # egrep '^DATA' $INFILE | \ -sed -e 's/^.*OID[^=]*=[^0-9]*//' \ - -e 's/(//g' \ - -e 's/[ ]*).*$//' | \ -$AWK '$5 == "12" { print }' | \ +sed -e 's/^[^O]*OID[^=]*=[ ]*//' \ + -e 's/(//' \ + -e 's/"[^"]*"/"xxx"/g' | \ +$AWK "\$$prolang == \"12\" { print }" | \ sort -n > $SORTEDFILE if [ $? -ne 0 ]; then @@ -120,7 +137,7 @@ cat > "$$-$OIDSFILE" < "$$-$OIDSFILE" <> "$$-$OIDSFILE" +$AWK "{ if (seenit[\$$prosrc]++ == 0) + printf \"#define F_%s %s\\n\", \$$prosrc, \$1; }" >> "$$-$OIDSFILE" if [ $? -ne 0 ]; then cleanup @@ -151,7 +165,7 @@ fi cat >> "$$-$OIDSFILE" < "$$-$TABLEFILE" <> "$$-$TABLEFILE" +$AWK "{ if (seenit[\$$prosrc]++ == 0) + print \"extern Datum\", \$$prosrc, \"(PG_FUNCTION_ARGS);\"; }" $SORTEDFILE >> "$$-$TABLEFILE" if [ $? -ne 0 ]; then cleanup @@ -205,17 +218,14 @@ FuNkYfMgRtAbStUfF # Note: using awk arrays to translate from pg_proc values to fmgrtab values # may seem tedious, but avoid the temptation to write a quick x?y:z # conditional expression instead. Not all awks have conditional expressions. -# -# Note assumptions here that prosrc == $(NF-3), pronargs == $13, -# proisstrict == $10, proretset == $11 -$AWK 'BEGIN { - Bool["t"] = "true" - Bool["f"] = "false" +$AWK "BEGIN { + Bool[\"t\"] = \"true\"; + Bool[\"f\"] = \"false\"; } -{ printf (" { %d, \"%s\", %d, %s, %s, %s },\n"), \ - $1, $(NF-3), $13, Bool[$10], Bool[$11], $(NF-3) -}' $SORTEDFILE >> "$$-$TABLEFILE" +{ printf (\" { %d, \\\"%s\\\", %d, %s, %s, %s },\\n\"), + \$1, \$$prosrc, \$$pronargs, Bool[\$$proisstrict], Bool[\$$proretset], \$$prosrc ; +}" $SORTEDFILE >> "$$-$TABLEFILE" if [ $? -ne 0 ]; then cleanup @@ -232,7 +242,6 @@ cat >> "$$-$TABLEFILE" <GenerateDefFile("src\\interfaces\\ecpg\\compatlib\\compatlib.def","src\\interfaces\\ecpg\\compatlib\\exports.txt","LIBECPG_COMPAT"); $self->GenerateDefFile("src\\interfaces\\ecpg\\pgtypeslib\\pgtypeslib.def","src\\interfaces\\ecpg\\pgtypeslib\\exports.txt","LIBPGTYPES"); - if (IsNewer("src\\backend\\utils\\fmgrtab.c","src\\include\\catalog\\pg_proc.h")) + if (IsNewer('src\backend\utils\fmgrtab.c','src\include\catalog\pg_proc.h')) { print "Generating fmgrtab.c and fmgroids.h...\n"; - open(I,"src\\include\\catalog\\pg_proc.h") || confess "Could not open pg_proc.h"; - my @fmgr = (); - my %seenit; - while () - { - next unless (/^DATA/); - s/^.*OID[^=]*=[^0-9]*//; - s/\(//g; - s/[ \t]*\).*$//; - my @p = split; - next if ($p[4] ne "12"); - push @fmgr, - { - oid => $p[0], - proname => $p[1], - prosrc => $p[$#p-3], - nargs => $p[12], - strict => $p[9], - retset => $p[10], - }; - } - close(I); - - open(H,'>', 'src\include\utils\fmgroids.h') - ||confess "Could not open fmgroids.h"; - print H - "/* fmgroids.h generated for Visual C++ */\n#ifndef FMGROIDS_H\n#define FMGROIDS_H\n\n"; - open(T,">src\\backend\\utils\\fmgrtab.c") || confess "Could not open fmgrtab.c"; - print T -"/* fmgrtab.c generated for Visual C++ */\n#include \"postgres.h\"\n#include \"utils/fmgrtab.h\"\n\n"; - foreach my $s (sort {$a->{oid} <=> $b->{oid}} @fmgr) - { - next if $seenit{$s->{prosrc}}; - $seenit{$s->{prosrc}} = 1; - print H "#define F_" . uc $s->{prosrc} . " $s->{oid}\n"; - print T "extern Datum $s->{prosrc} (PG_FUNCTION_ARGS);\n"; - } - print H "\n#endif\n /* FMGROIDS_H */\n"; - close(H); - print T "const FmgrBuiltin fmgr_builtins[] = {\n"; - my %bmap; - $bmap{'t'} = 'true'; - $bmap{'f'} = 'false'; - foreach my $s (sort {$a->{oid} <=> $b->{oid}} @fmgr) - { - print T -" { $s->{oid}, \"$s->{prosrc}\", $s->{nargs}, $bmap{$s->{strict}}, $bmap{$s->{retset}}, $s->{prosrc} },\n"; - } - - print T -" { 0, NULL, 0, false, false, NULL }\n};\n\nconst int fmgr_nbuiltins = (sizeof(fmgr_builtins) / sizeof(FmgrBuiltin)) - 1;\n"; - close(T); + chdir('src\backend\utils'); + system("perl Gen_fmgrtab.pl ../../../src/include/catalog/pg_proc.h"); + chdir('..\..\..'); } if (IsNewer('src\include\utils\probes.h','src\backend\utils\pg_trace.d'))