use strict;
use warnings;
my @infile;
my $output_path = '';
my %catalog;
$catalog{builtindata} = [];
my $nfuncs = 0;
my $nfmgrfuncs = 0;
while (@ARGV)
{
my $arg = shift @ARGV;
if ($arg !~ /^-/)
{
push @infile, $arg;
}
elsif ($arg =~ /^-o/)
{
$output_path = length($arg) > 2 ? substr($arg, 2) : shift @ARGV;
}
else
{
usage();
}
}
if ($output_path ne '' && substr($output_path, -1) ne '/')
{
$output_path .= '/';
}
foreach my $singlefile (@infile)
{
open(INPUT_FILE, '<', $singlefile) || die "$singlefile: $!";
while (<INPUT_FILE>)
{
s;/\*(.|\n)*\*/;;g;
if (m;/\*;)
{
# handle multi-line comments properly.
my $next_line = <INPUT_FILE>;
die "$singlefile: ends within C-style comment\n"
if !defined $next_line;
$_ .= $next_line;
redo;
}
# Strip useless whitespace and trailing semicolons.
chomp;
s/^\s+//;
s/;\s*$//;
s/\s+/ /g;
if (/AddBuiltinFunc\((.+?)\)\)/)
{
push @{ $catalog{builtindata} }, $1;
$nfuncs = $nfuncs + 1;
}
}
}
my @fmgr = ();
my $foid;
my $funcName;
my $nargs;
my $strict;
my $retset;
my $prosrc;
my $prorettype;
foreach my $row (@{ $catalog{builtindata} })
{
if ($row =~ /_0\(([0-9A-Z]+)\),\s+_1\(\"(\S+)\"\),\s+_2\((\d+)\),\s+_3\((\w+)\),\s+_4\((\w+)\),\s+.+?_6\((\d+)\),.+?_25\(\"(\w+)\"\),/)
{
$foid = $1;
$funcName = $2;
$nargs = $3;
$strict = $4;
$retset = $5;
$prosrc = $7;
$prorettype = $6;
push @fmgr,
{ oid => $foid,
proname =>$funcName,
strict => $strict,
retset => $retset,
nargs => $nargs,
prosrc => $prosrc,
prorettype => $prorettype
};
}
$row = undef;
}
my $tmpext = ".tmp$$";
my $oidsfile = $output_path . 'fmgroids.h';
my $tabfile = $output_path . 'fmgrtab.cpp';
my $builtinfile = $output_path . 'pg_builtin_proc.h';
open H, '>', $oidsfile . $tmpext or die "Could not open $oidsfile$tmpext: $!";
open T, '>', $tabfile . $tmpext or die "Could not open $tabfile$tmpext: $!";
open B, '>', $builtinfile . $tmpext or die "Could not open $builtinfile$tmpext: $!";
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-2012, 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[0]
*
*-------------------------------------------------------------------------
*/
#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.
*/
|;
print T
qq|/*-------------------------------------------------------------------------
*
* fmgrtab.c
* The function manager's table of internal functions.
*
* Portions Copyright (c) 1996-2012, 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[0]
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "knl/knl_variable.h"
#include "utils/fmgrtab.h"
|;
print B
qq|/*-------------------------------------------------------------------------
*
* pg_builtin_proc.h
* Macros that define the declares of built-in functions.
*
* NOTES
* ******************************
* *** DO NOT EDIT THIS FILE! ***
* ******************************
*
* It has been GENERATED by $0
* from $infile[0]
*
*-------------------------------------------------------------------------
*/
|;
my %seenit;
foreach my $s (sort { $a->{proname} cmp $b->{proname} } @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 B "extern Datum $s->{prosrc} (PG_FUNCTION_ARGS);\n";
}
print T "\nconst FmgrBuiltin fmgr_builtins[] = {\n";
foreach my $s (sort { $a->{prosrc} cmp $b->{prosrc} } @fmgr)
{
print T
" { $s->{oid}, \"$s->{prosrc}\", $s->{nargs}, $s->{strict}, $s->{retset}, $s->{prosrc}, $s->{prorettype} },\n";
$nfmgrfuncs = $nfmgrfuncs + 1;
}
print H "\n#define nBuiltinFuncs $nfuncs\n";
print H "\n#define NFMGRFUNCS $nfmgrfuncs\n";
print H "\n#endif /* FMGROIDS_H */\n";
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, InvalidOid}
};
/* Note fmgr_nbuiltins excludes the dummy entry */
const int fmgr_nbuiltins = (sizeof(fmgr_builtins) / sizeof(FmgrBuiltin)) - 1;
|;
close(H);
close(T);
close(B);
RenameTempFile($oidsfile, $tmpext);
RenameTempFile($tabfile, $tmpext);
RenameTempFile($builtinfile, $tmpext);
sub RenameTempFile
{
my $final_name = shift;
my $extension = shift;
my $temp_name = $final_name . $extension;
print "Writing $final_name\n";
rename($temp_name, $final_name) || die "rename: $temp_name: $!";
}
sub usage
{
die <<EOM;
Usage: perl -I [directory of Catalog.pm] Gen_fmgrtab.pl [path to pg_proc.h]
Gen_fmgrtab.pl generates fmgroids.h and fmgrtab.c from pg_builtin_proc.cpp
Report bugs to <pgsql-bugs\@postgresql.org>.
EOM
}
exit 0;