Fix Gen_fmgrtab.sh to not rely on hard-wired knowledge of the column numbers

in pg_proc.  Also make it not emit duplicate extern declarations, and make it
a bit more bulletproof in some other small ways.  Likewise fix the equally
hard-wired, and utterly undocumented, knowledge in the MSVC build scripts.
For testing purposes and perhaps other uses in future, pull out that portion
of the MSVC scripts into a standalone perl script equivalent to
Gen_fmgrtab.sh, and make it generate actually identical output, rather than
just more-or-less-the-same output.

Motivated by looking at Pavel's variadic function patch.  Whether or not
that gets accepted, we can be sure that pg_proc's column set will change
again in the future; it's time to not have to deal with this gotcha.
This commit is contained in:
Tom Lane 2008-06-23 17:54:30 +00:00
parent dab421d2f0
commit eeee06919f
3 changed files with 237 additions and 83 deletions

View File

@ -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 (<I>)
{
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 (<I>)
{
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;

View File

@ -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" <<FuNkYfMgRsTuFf
*
*-------------------------------------------------------------------------
*/
#ifndef $cpp_define
#ifndef $cpp_define
#define $cpp_define
/*
@ -136,12 +153,9 @@ cat > "$$-$OIDSFILE" <<FuNkYfMgRsTuFf
*/
FuNkYfMgRsTuFf
# Note assumption here that prosrc == $(NF-3).
tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' < $SORTEDFILE | \
$AWK '
BEGIN { OFS = ""; }
{ if (seenit[$(NF-3)]++ == 0) print "#define F_", $(NF-3), " ", $1; }' >> "$$-$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" <<FuNkYfMgRsTuFf
#endif /* $cpp_define */
#endif /* $cpp_define */
FuNkYfMgRsTuFf
#
@ -186,9 +200,8 @@ cat > "$$-$TABLEFILE" <<FuNkYfMgRtAbStUfF
FuNkYfMgRtAbStUfF
# Note assumption here that prosrc == $(NF-3).
$AWK '{ print "extern Datum", $(NF-3), "(PG_FUNCTION_ARGS);"; }' $SORTEDFILE >> "$$-$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" <<FuNkYfMgRtAbStUfF
/* Note fmgr_nbuiltins excludes the dummy entry */
const int fmgr_nbuiltins = (sizeof(fmgr_builtins) / sizeof(FmgrBuiltin)) - 1;
FuNkYfMgRtAbStUfF
# We use the temporary files to avoid problems with concurrent runs

View File

@ -3,7 +3,7 @@ package Solution;
#
# Package that encapsulates a Visual C++ solution file generation
#
# $PostgreSQL: pgsql/src/tools/msvc/Solution.pm,v 1.41 2008/05/03 00:24:06 adunstan Exp $
# $PostgreSQL: pgsql/src/tools/msvc/Solution.pm,v 1.42 2008/06/23 17:54:30 tgl Exp $
#
use Carp;
use strict;
@ -198,61 +198,12 @@ s{PG_VERSION_STR "[^"]+"}{__STRINGIFY(x) #x\n#define __STRINGIFY2(z) __STRINGIFY
$self->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 (<I>)
{
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'))