OSDN Git Service

Ignore non-existent prepared statement in get_query_string.
[pghintplan/pg_hint_plan.git] / update_copied_funcs.pl
1 #! /usr/bin/perl
2
3 use strict;
4
5 my $srcpath;
6 my @sources = (
7         'src/backend/optimizer/path/allpaths.c',
8         'src/backend/optimizer/path/joinrels.c');
9 my %defs =
10   ('core.c'
11    => {protos => ['populate_joinrel_with_paths'],
12            funcs => ['set_plain_rel_pathlist',
13                                  'set_append_rel_pathlist',
14                                  'standard_join_search',
15                                  'create_plain_partial_paths',
16                                  'join_search_one_level',
17                                  'make_rels_by_clause_joins',
18                                  'make_rels_by_clauseless_joins',
19                                  'join_is_legal',
20                                  'has_join_restriction',
21                                  'mark_dummy_rel',
22                                  'restriction_is_constant_false',
23                                  'try_partitionwise_join'],
24            head => core_c_head()},
25    'make_join_rel.c'
26    => {protos => [],
27            funcs => ['make_join_rel',
28                                  'populate_joinrel_with_paths'],
29            head => make_join_rel_head()});
30         
31 open (my $in, '-|', "objdump -W `which postgres`") || die "failed to objdump";
32 while (<$in>)
33 {
34         if (/DW_AT_comp_dir .*: (.*\/)src\/backend\//)
35         {
36                 $srcpath = $1;
37                 last;
38         }
39 }
40 close($in);
41
42 die "source path not found" if (! defined $srcpath);
43 printf("Source path = %s\n", $srcpath);
44
45 my %protos;
46 my %funcs;
47 my %func_is_static;
48 my %func_source;
49
50 for my $fname (@sources)
51 {
52         my $f = $srcpath.$fname;
53         my $source;
54
55         open ($in, '<', $f) || die "failed to open $f: $!";
56         while (<$in>)
57         {
58                 $source .= $_;
59         }
60
61         ## Collect static prototypes
62
63         while ($source =~ /\n(static [^\(\)\{\}]*?(\w+)(\([^\{\);]+?\);))/gsm)
64         {
65                 #       print "Prototype found: $2\n";
66                 $protos{$2} = $1;
67         }
68
69         ## Collect function bodies
70
71         while ($source =~ /(\n\/\*\n.+?\*\/\n(static )?(.+?)\n(.+?) *\(.*?\)\n\{.+?\n\}\n)/gsm)
72         {
73                 $funcs{$4} = $1;
74                 $func_is_static{$4} = (defined $2);
75                 $func_source{$4} = $fname;
76
77                   #     printf("Function found: %s$4\n", $func_is_static{$4} ? "static " : "");
78         }
79
80         close($in);
81 }
82
83
84 # Generate files
85 for my $fname (keys %defs)
86 {
87         my %d = %{$defs{$fname}};
88
89         my @protonames = @{$d{'protos'}};
90         my @funcnames = @{$d{'funcs'}};
91         my $head = $d{'head'};
92
93         print "Generate $fname.\n";
94         open (my $out, '>', $fname) || die "could not open $fname: $!";
95
96         print $out $head;
97
98         for (@protonames)
99         {
100                 print " Prototype: $_\n";
101                 print $out "\n";
102                 die "Prototype for $_ not found" if (! defined $protos{$_});
103                 print $out $protos{$_};
104         }
105
106         for (@funcnames)
107         {
108                 printf(" %s function: $_@%s\n",
109                            $func_is_static{$_}?"static":"public", $func_source{$_});
110                 print $out "\n";
111                 die "Function body for $_ not found" if (! defined $funcs{$_});
112                 print $out $funcs{$_};
113         }
114
115         close($out);
116 }
117
118 # modify make_join_rel.c
119 patch_make_join_rel();
120
121 sub core_c_head()
122 {
123         return << "EOS";
124 /*-------------------------------------------------------------------------
125  *
126  * core.c
127  *        Routines copied from PostgreSQL core distribution.
128  *
129  * The main purpose of this files is having access to static functions in core.
130  * Another purpose is tweaking functions behavior by replacing part of them by
131  * macro definitions. See at the end of pg_hint_plan.c for details. Anyway,
132  * this file *must* contain required functions without making any change.
133  *
134  * This file contains the following functions from corresponding files.
135  *
136  * src/backend/optimizer/path/allpaths.c
137  *
138  *  public functions:
139  *     standard_join_search(): This funcion is not static. The reason for
140  *        including this function is make_rels_by_clause_joins. In order to
141  *        avoid generating apparently unwanted join combination, we decided to
142  *        change the behavior of make_join_rel, which is called under this
143  *        function.
144  *
145  *      static functions:
146  *         set_plain_rel_pathlist()
147  *         set_append_rel_pathlist()
148  *         create_plain_partial_paths()
149  *
150  * src/backend/optimizer/path/joinrels.c
151  *
152  *      public functions:
153  *     join_search_one_level(): We have to modify this to call my definition of
154  *                  make_rels_by_clause_joins.
155  *
156  *      static functions:
157  *     make_rels_by_clause_joins()
158  *     make_rels_by_clauseless_joins()
159  *     join_is_legal()
160  *     has_join_restriction()
161  *     mark_dummy_rel()
162  *     restriction_is_constant_false()
163  *     try_partitionwise_join()
164  *
165  * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
166  * Portions Copyright (c) 1994, Regents of the University of California
167  *
168  *-------------------------------------------------------------------------
169  */
170 EOS
171 }
172
173 sub make_join_rel_head
174 {
175         return << "EOS";
176 /*-------------------------------------------------------------------------
177  *
178  * make_join_rel.c
179  *        Routines copied from PostgreSQL core distribution with some
180  *        modifications.
181  *
182  * src/backend/optimizer/path/joinrels.c
183  *
184  * This file contains the following functions from corresponding files.
185  *
186  *      static functions:
187  *     make_join_rel()
188  *     populate_joinrel_with_paths()
189  *
190  * Portions Copyright (c) 2013-2020, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
191  * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
192  * Portions Copyright (c) 1994, Regents of the University of California
193  *
194  *-------------------------------------------------------------------------
195  */
196
197 /*
198  * adjust_rows: tweak estimated row numbers according to the hint.
199  */
200 static double
201 adjust_rows(double rows, RowsHint *hint)
202 {
203         double          result = 0.0;   /* keep compiler quiet */
204
205         if (hint->value_type == RVT_ABSOLUTE)
206                 result = hint->rows;
207         else if (hint->value_type == RVT_ADD)
208                 result = rows + hint->rows;
209         else if (hint->value_type == RVT_SUB)
210                 result =  rows - hint->rows;
211         else if (hint->value_type == RVT_MULTI)
212                 result = rows * hint->rows;
213         else
214                 Assert(false);  /* unrecognized rows value type */
215
216         hint->base.state = HINT_STATE_USED;
217         if (result < 1.0)
218                 ereport(WARNING,
219                                 (errmsg("Force estimate to be at least one row, to avoid possible divide-by-zero when interpolating costs : %s",
220                                         hint->base.hint_str)));
221         result = clamp_row_est(result);
222         elog(DEBUG1, "adjusted rows %d to %d", (int) rows, (int) result);
223
224         return result;
225 }
226 EOS
227 }
228    
229
230 sub patch_make_join_rel
231 {
232         open(my $out, '|-', 'patch') || die "failed to open pipe: $!";
233
234         print $out <<"EOS";
235 diff --git b/make_join_rel.c a/make_join_rel.c
236 index 0e7b99f..287e7f1 100644
237 --- b/make_join_rel.c
238 +++ a/make_join_rel.c
239 @@ -126,6 +126,84 @@ make_join_rel(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2)
240         joinrel = build_join_rel(root, joinrelids, rel1, rel2, sjinfo,
241                                                          &restrictlist);
242  
243 +       /* !!! START: HERE IS THE PART WHICH ADDED FOR PG_HINT_PLAN !!! */
244 +       {
245 +               RowsHint   *rows_hint = NULL;
246 +               int                     i;
247 +               RowsHint   *justforme = NULL;
248 +               RowsHint   *domultiply = NULL;
249 +
250 +               /* Search for applicable rows hint for this join node */
251 +               for (i = 0; i < current_hint_state->num_hints[HINT_TYPE_ROWS]; i++)
252 +               {
253 +                       rows_hint = current_hint_state->rows_hints[i];
254 +
255 +                       /*
256 +                        * Skip this rows_hint if it is invalid from the first or it
257 +                        * doesn't target any join rels.
258 +                        */
259 +                       if (!rows_hint->joinrelids ||
260 +                               rows_hint->base.state == HINT_STATE_ERROR)
261 +                               continue;
262 +
263 +                       if (bms_equal(joinrelids, rows_hint->joinrelids))
264 +                       {
265 +                               /*
266 +                                * This joinrel is just the target of this rows_hint, so tweak
267 +                                * rows estimation according to the hint.
268 +                                */
269 +                               justforme = rows_hint;
270 +                       }
271 +                       else if (!(bms_is_subset(rows_hint->joinrelids, rel1->relids) ||
272 +                                          bms_is_subset(rows_hint->joinrelids, rel2->relids)) &&
273 +                                        bms_is_subset(rows_hint->joinrelids, joinrelids) &&
274 +                                        rows_hint->value_type == RVT_MULTI)
275 +                       {
276 +                               /*
277 +                                * If the rows_hint's target relids is not a subset of both of
278 +                                * component rels and is a subset of this joinrel, ths hint's
279 +                                * targets spread over both component rels. This means that
280 +                                * this hint has been never applied so far and this joinrel is
281 +                                * the first (and only) chance to fire in current join tree.
282 +                                * Only the multiplication hint has the cumulative nature so we
283 +                                * apply only RVT_MULTI in this way.
284 +                                */
285 +                               domultiply = rows_hint;
286 +                       }
287 +               }
288 +
289 +               if (justforme)
290 +               {
291 +                       /*
292 +                        * If a hint just for me is found, no other adjust method is
293 +                        * useless, but this cannot be more than twice becuase this joinrel
294 +                        * is already adjusted by this hint.
295 +                        */
296 +                       if (justforme->base.state == HINT_STATE_NOTUSED)
297 +                               joinrel->rows = adjust_rows(joinrel->rows, justforme);
298 +               }
299 +               else
300 +               {
301 +                       if (domultiply)
302 +                       {
303 +                               /*
304 +                                * If we have multiple routes up to this joinrel which are not
305 +                                * applicable this hint, this multiply hint will applied more
306 +                                * than twice. But there's no means to know of that,
307 +                                * re-estimate the row number of this joinrel always just
308 +                                * before applying the hint. This is a bit different from
309 +                                * normal planner behavior but it doesn't harm so much.
310 +                                */
311 +                               set_joinrel_size_estimates(root, joinrel, rel1, rel2, sjinfo,
312 +                                                                                  restrictlist);
313 +                               
314 +                               joinrel->rows = adjust_rows(joinrel->rows, domultiply);
315 +                       }
316 +                       
317 +               }
318 +       }
319 +       /* !!! END: HERE IS THE PART WHICH ADDED FOR PG_HINT_PLAN !!! */
320 +
321         /*
322          * If we've already proven this join is empty, we needn't consider any
323          * more paths for it.
324 EOS
325 }