OSDN Git Service

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