summaryrefslogtreecommitdiff
path: root/src/backend/utils/Gen_fmgrtab.pl
blob: a3f03d27348754f9414b54329fbd3b968e0125ec (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
#! /usr/bin/perl -w
#-------------------------------------------------------------------------
#
# Gen_fmgrtab.pl
#    Perl script that generates fmgroids.h and fmgrtab.c from pg_proc.h
#
# Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
# Portions Copyright (c) 1994, Regents of the University of California
#
#
# IDENTIFICATION
#    src/backend/utils/Gen_fmgrtab.pl
#
#-------------------------------------------------------------------------

use Catalog;

use strict;
use warnings;

# Collect arguments
my $infile;    # pg_proc.h
my $output_path = '';
while (@ARGV)
{
	my $arg = shift @ARGV;
	if ($arg !~ /^-/)
	{
		$infile = $arg;
	}
	elsif ($arg =~ /^-o/)
	{
		$output_path = length($arg) > 2 ? substr($arg, 2) : shift @ARGV;
	}
	else
	{
		usage();
	}
}

# Make sure output_path ends in a slash.
if ($output_path ne '' && substr($output_path, -1) ne '/')
{
	$output_path .= '/';
}

# Read all the data from the include/catalog files.
my $catalogs = Catalog::Catalogs($infile);

# Collect the raw data from pg_proc.h.
my @fmgr = ();
my @attnames;
foreach my $column (@{ $catalogs->{pg_proc}->{columns} })
{
	push @attnames, $column->{name};
}

my $data = $catalogs->{pg_proc}->{data};
foreach my $row (@$data)
{

	# To construct fmgroids.h and fmgrtab.c, we need to inspect some
	# of the individual data fields.  Just splitting on whitespace
	# won't work, because some quoted fields might contain internal
	# whitespace.  We handle this by folding them all to a simple
	# "xxx". Fortunately, this script doesn't need to look at any
	# fields that might need quoting, so this simple hack is
	# sufficient.
	$row->{bki_values} =~ s/"[^"]*"/"xxx"/g;
	@{$row}{@attnames} = split /\s+/, $row->{bki_values};

	# Select out just the rows for internal-language procedures.
	# Note assumption here that INTERNALlanguageId is 12.
	next if $row->{prolang} ne '12';

	push @fmgr,
	  { oid    => $row->{oid},
		strict => $row->{proisstrict},
		retset => $row->{proretset},
		nargs  => $row->{pronargs},
		prosrc => $row->{prosrc}, };

	# Hack to work around memory leak in some versions of Perl
	$row = undef;
}

# Emit headers for both files
my $tmpext   = ".tmp$$";
my $oidsfile = $output_path . 'fmgroids.h';
my $tabfile  = $output_path . 'fmgrtab.c';

open H, '>', $oidsfile . $tmpext or die "Could not open $oidsfile$tmpext: $!";
open T, '>', $tabfile . $tmpext  or die "Could not open $tabfile$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-2016, 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.
 */
|;

print T
qq|/*-------------------------------------------------------------------------
 *
 * fmgrtab.c
 *    The function manager's table of internal functions.
 *
 * Portions Copyright (c) 1996-2016, 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";

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(H);
close(T);

# Finally, rename the completed files into place.
Catalog::RenameTempFile($oidsfile, $tmpext);
Catalog::RenameTempFile($tabfile,  $tmpext);

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_proc.h

Report bugs to <pgsql-bugs\@postgresql.org>.
EOM
}

exit 0;