Added quantiling UDAFs
[com/gs-lite.git] / src / ftacmp / query_plan.cc
1 /* ------------------------------------------------\r
2 Copyright 2014 AT&T Intellectual Property\r
3    Licensed under the Apache License, Version 2.0 (the "License");\r
4    you may not use this file except in compliance with the License.\r
5    You may obtain a copy of the License at\r
6 \r
7      http://www.apache.org/licenses/LICENSE-2.0\r
8 \r
9    Unless required by applicable law or agreed to in writing, software\r
10    distributed under the License is distributed on an "AS IS" BASIS,\r
11    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
12    See the License for the specific language governing permissions and\r
13    limitations under the License.\r
14  ------------------------------------------- */\r
15 \r
16 //              Create, manipulate, and dump query plans.\r
17 \r
18 #include "query_plan.h"\r
19 #include "analyze_fta.h"\r
20 #include "generate_utils.h"\r
21 \r
22 #include<vector>\r
23 \r
24 using namespace std;\r
25 \r
26 extern string hash_nums[NRANDS];        // for fast hashing\r
27 \r
28 \r
29 char tmpstr[1000];\r
30 \r
31 void untaboo(string &s){\r
32         int c;\r
33         for(c=0;c<s.size();++c){\r
34                 if(s[c] == '.'){\r
35                         s[c] = '_';\r
36                 }\r
37         }\r
38 }\r
39 \r
40 //                      mrg_qpn constructor, define here to avoid\r
41 //                      circular references in the .h file\r
42 mrg_qpn::mrg_qpn(filter_join_qpn *spx, std::string n_name, std::vector<std::string> &sources, std::vector<std::pair<std::string, std::string> > &ifaces, ifq_t *ifdb){\r
43                 param_tbl = spx->param_tbl;\r
44                 int i;\r
45                 node_name = n_name;\r
46                 field_entry_list *fel = new field_entry_list();\r
47                 merge_fieldpos = -1;\r
48 \r
49                 disorder = 1;\r
50 \r
51                 for(i=0;i<spx->select_list.size();++i){\r
52                         data_type *dt = spx->select_list[i]->se->get_data_type()->duplicate();\r
53                         if(dt->is_temporal()){\r
54                                 if(merge_fieldpos < 0){\r
55                                         merge_fieldpos = i;\r
56                                 }else{\r
57                                         fprintf(stderr,"Warning: Merge subquery %s found two temporal fields (%s, %s), using %s\n", n_name.c_str(), spx->select_list[merge_fieldpos]->name.c_str(), spx->select_list[i]->name.c_str(), spx->select_list[merge_fieldpos]->name.c_str() );\r
58                                         dt->reset_temporal();\r
59                                 }\r
60                         }\r
61 \r
62                         field_entry *fe = dt->make_field_entry(spx->select_list[i]->name);\r
63                         fel->append_field(fe);\r
64                         delete dt;\r
65                 }\r
66                 if(merge_fieldpos<0){\r
67                         fprintf(stderr,"ERROR, no temporal attribute for merge subquery %s\n",n_name.c_str());\r
68                                 exit(1);\r
69                 }\r
70                 table_layout = new table_def( n_name.c_str(), NULL, NULL, fel, STREAM_SCHEMA);\r
71 \r
72 //                              NEED TO HANDLE USER_SPECIFIED SLACK\r
73                 this->resolve_slack(spx->select_list[merge_fieldpos]->se,\r
74                                 spx->select_list[merge_fieldpos]->name, ifaces, ifdb,NULL);\r
75 //      if(this->slack == NULL)\r
76 //              fprintf(stderr,"Zero slack.\n");\r
77 //      else\r
78 //              fprintf(stderr,"slack is %s\n",slack->to_string().c_str());\r
79 \r
80                 for(i=0;i<sources.size();i++){\r
81                         std::string rvar = "_m"+int_to_string(i);\r
82                         mvars.push_back(new colref_t(rvar.c_str(), spx->select_list[merge_fieldpos]->name.c_str()));\r
83                         mvars[i]->set_tablevar_ref(i);\r
84                         fm.push_back(new tablevar_t(sources[i].c_str()));\r
85                         fm[i]->set_range_var(rvar);\r
86                 }\r
87 \r
88                 param_tbl = new param_table();\r
89                 std::vector<std::string> param_names = spx->param_tbl->get_param_names();\r
90                 int pi;\r
91                 for(pi=0;pi<param_names.size();pi++){\r
92                         data_type *dt = spx->param_tbl->get_data_type(param_names[pi]);\r
93                         param_tbl->add_param(param_names[pi],dt->duplicate(),\r
94                                                         spx->param_tbl->handle_access(param_names[pi]));\r
95                 }\r
96                 definitions = spx->definitions;\r
97 \r
98 }\r
99 \r
100 \r
101 \r
102 //              This function translates an analyzed parse tree\r
103 //              into one or more query nodes (qp_node).\r
104 //              Currently only one node is created, but some query\r
105 //              fragments might create more than one query node,\r
106 //              e.g. aggregation over a joim, or nested subqueries\r
107 //              in the FROM clause (unless this is handles at parse tree\r
108 //              analysis time).  At this stage, they will be linked\r
109 //              by the names in the FROM clause.\r
110 //              INVARIANT : if mroe than one query node is returned,\r
111 //              the last one represents the output of the query.\r
112 vector<qp_node *> create_query_nodes(query_summary_class *qs,table_list *Schema){\r
113 \r
114 //              Classify the query.\r
115 \r
116         vector <qp_node *> local_plan;\r
117         qp_node *plan_root;\r
118 \r
119 //                      TODO\r
120 //                      I should probably move a lot of this code\r
121 //                      into the qp_node constructors,\r
122 //                      and have this code focus on building the query plan tree.\r
123 \r
124 //              MERGE node\r
125         if(qs->query_type == MERGE_QUERY){\r
126                 mrg_qpn *merge_node = new mrg_qpn(qs,Schema);\r
127 \r
128 //                      Done\r
129                 plan_root = merge_node;\r
130                 local_plan.push_back(merge_node);\r
131 \r
132                 /*\r
133                 Do not split sources until we are done with optimizations\r
134                 vector<mrg_qpn *> split_merge = merge_node->split_sources();\r
135                 local_plan.insert(local_plan.begin(), split_merge.begin(), split_merge.end());\r
136                 */\r
137 //                      If children are created, add them to the schema.\r
138 /*\r
139                 int i;\r
140 printf("split_merge size is %d\n",split_merge.size());\r
141                 for(i=1;i<split_merge.size();++i){\r
142                         Schema->add_table(split_merge[i]->get_fields());\r
143 printf("Adding split merge table %d\n",i);\r
144                 }\r
145 */\r
146 \r
147 /*\r
148 printf("Did split sources on %s:\n",qs->query_name.c_str());\r
149 int ss;\r
150 for(ss=0;ss<local_plan.size();ss++){\r
151 printf("node %d, name=%s, sources=",ss,local_plan[ss]->get_node_name().c_str());\r
152 vector<tablevar_t *> inv = local_plan[ss]->get_input_tbls();\r
153 int nn;\r
154 for(nn=0;nn<inv.size();nn++){\r
155 printf("%s ",inv[nn]->to_string().c_str());\r
156 }\r
157 printf("\n");\r
158 }\r
159 */\r
160 \r
161 \r
162         } else{\r
163 \r
164 //              Select / Aggregation / Join\r
165           if(qs->gb_tbl->size() == 0 && qs->aggr_tbl->size() == 0){\r
166 \r
167                 if(qs->fta_tree->get_from()->size() == 1){\r
168                         spx_qpn *spx_node = new spx_qpn(qs,Schema);\r
169 \r
170                         plan_root = spx_node;\r
171                         local_plan.push_back(spx_node);\r
172                 }else{\r
173                         if(qs->fta_tree->get_from()->get_properties() == FILTER_JOIN_PROPERTY){\r
174                                 filter_join_qpn *join_node = new filter_join_qpn(qs,Schema);\r
175                                 plan_root = join_node;\r
176                                 local_plan.push_back(join_node);\r
177                         }else{\r
178                                 join_eq_hash_qpn *join_node = new join_eq_hash_qpn(qs,Schema);\r
179                                 plan_root = join_node;\r
180                                 local_plan.push_back(join_node);\r
181                         }\r
182                 }\r
183           }else{\r
184 //                      aggregation\r
185 \r
186                 if(qs->states_refd.size() || qs->sg_tbl.size() || qs->cb_cnf.size()){\r
187                         sgahcwcb_qpn *sgahcwcb_node = new sgahcwcb_qpn(qs,Schema);\r
188                         plan_root = sgahcwcb_node;\r
189                         local_plan.push_back(sgahcwcb_node);\r
190                 }else{\r
191                         if(qs->closew_cnf.size()){\r
192                                 rsgah_qpn *rsgah_node = new rsgah_qpn(qs,Schema);\r
193                                 plan_root = rsgah_node;\r
194                                 local_plan.push_back(rsgah_node);\r
195                         }else{\r
196                                 sgah_qpn *sgah_node = new sgah_qpn(qs,Schema);\r
197                                 plan_root = sgah_node;\r
198                                 local_plan.push_back(sgah_node);\r
199                         }\r
200                 }\r
201           }\r
202         }\r
203 \r
204 \r
205 //              Get the query name and other definitions.\r
206         plan_root->set_node_name( qs->query_name);\r
207         plan_root->set_definitions( qs->definitions) ;\r
208 \r
209 \r
210 //      return(plan_root);\r
211         return(local_plan);\r
212 \r
213 }\r
214 \r
215 \r
216 string se_to_query_string(scalarexp_t *se, aggregate_table *aggr_tbl){\r
217   string l_str;\r
218   string r_str;\r
219   string ret;\r
220   int p;\r
221   vector<scalarexp_t *> operand_list;\r
222   string su_ind = "";\r
223 \r
224   if(se->is_superaggr())\r
225         su_ind = "$";\r
226 \r
227   switch(se->get_operator_type()){\r
228     case SE_LITERAL:\r
229                 l_str = se->get_literal()->to_query_string();\r
230                 return l_str;\r
231     case SE_PARAM:\r
232                 l_str = "$" + se->get_op();\r
233                 return l_str;\r
234     case SE_COLREF:\r
235                 l_str =  se->get_colref()->to_query_string() ;\r
236                 return l_str;\r
237     case SE_UNARY_OP:\r
238                  l_str = se_to_query_string(se->get_left_se(),aggr_tbl);\r
239 \r
240                 return se->get_op()+"( "+l_str+" )";;\r
241     case SE_BINARY_OP:\r
242                 l_str = se_to_query_string(se->get_left_se(),aggr_tbl);\r
243                 r_str = se_to_query_string(se->get_right_se(),aggr_tbl);\r
244                 return( "("+l_str+")"+se->get_op()+"("+r_str+")" );\r
245     case SE_AGGR_STAR:\r
246                 return( se->get_op() + su_ind + "(*)");\r
247     case SE_AGGR_SE:\r
248                 l_str = se_to_query_string(aggr_tbl->get_aggr_se(se->get_aggr_ref()),aggr_tbl);\r
249                 return( se->get_op() + su_ind + "(" + l_str + ")" );\r
250         case SE_FUNC:\r
251                 if(se->get_aggr_ref() >= 0)\r
252                         operand_list = aggr_tbl->get_operand_list(se->get_aggr_ref());\r
253                 else\r
254                         operand_list = se->get_operands();\r
255 \r
256                 ret = se->get_op() + su_ind + "(";\r
257                 for(p=0;p<operand_list.size();p++){\r
258                         l_str = se_to_query_string(operand_list[p],aggr_tbl);\r
259                         if(p>0) ret += ", ";\r
260                         ret += l_str;\r
261                 }\r
262                 ret += ")";\r
263                 return(ret);\r
264         break;\r
265   }\r
266   return "ERROR SE op type not recognized in se_to_query_string.\n";\r
267 }\r
268 \r
269 \r
270 string pred_to_query_str(predicate_t *pr, aggregate_table *aggr_tbl){\r
271   string l_str;\r
272   string r_str;\r
273   string ret;\r
274   int o,l;\r
275   vector<literal_t *> llist;\r
276   vector<scalarexp_t *> op_list;\r
277 \r
278         switch(pr->get_operator_type()){\r
279         case PRED_IN:\r
280                 l_str = se_to_query_string(pr->get_left_se(),aggr_tbl);\r
281                 ret = l_str + " IN [";\r
282                 llist = pr->get_lit_vec();\r
283                 for(l=0;l<llist.size();l++){\r
284                         if(l>0) ret += ", ";\r
285                         ret += llist[l]->to_query_string();\r
286                 }\r
287                 ret += "]";\r
288 \r
289                 return(ret);\r
290         case PRED_COMPARE:\r
291                 l_str = se_to_query_string(pr->get_left_se(),aggr_tbl);\r
292                 r_str = se_to_query_string(pr->get_right_se(),aggr_tbl);\r
293                 return( l_str + " " + pr->get_op() + " " + r_str );\r
294         case PRED_UNARY_OP:\r
295                 l_str = pred_to_query_str(pr->get_left_pr(),aggr_tbl);\r
296                 return(pr->get_op() + "( " + l_str + " )");\r
297         case PRED_BINARY_OP:\r
298                 l_str = pred_to_query_str(pr->get_left_pr(),aggr_tbl);\r
299                 r_str = pred_to_query_str(pr->get_right_pr(),aggr_tbl);\r
300                 return("( " + r_str + " )" + pr->get_op() + "( " + l_str + " )");\r
301         case PRED_FUNC:\r
302                 ret = pr->get_op()+"[";\r
303                 op_list = pr->get_op_list();\r
304                 for(o=0;o<op_list.size();++o){\r
305                         if(o>0) ret += ", ";\r
306                         ret += se_to_query_string(op_list[o],aggr_tbl);\r
307                 }\r
308                 ret += "]";\r
309                 return(ret);\r
310         default:\r
311                 fprintf(stderr,"INTERNAL ERROR in pred_to_query_str, line %d, character %d, unknown predicate operator type %d\n",\r
312                         pr->get_lineno(), pr->get_charno(), pr->get_operator_type() );\r
313                 exit(1);\r
314         }\r
315 \r
316         return(0);\r
317 }\r
318 \r
319 \r
320 \r
321 //                      Build a selection list,\r
322 //                      but avoid adding duplicate SEs.\r
323 \r
324 \r
325 int add_select_list_nodup(vector<select_element *> &lfta_select_list, scalarexp_t *se,\r
326                                 bool &new_element){\r
327         new_element = false;\r
328         int s;\r
329         for(s=0;s<lfta_select_list.size();s++){\r
330                 if(is_equivalent_se(lfta_select_list[s]->se, se)){\r
331                         return(s);\r
332                 }\r
333         }\r
334         new_element = true;\r
335         lfta_select_list.push_back(new select_element(se,"NoNameIn:add_select_list_nodup"));\r
336         return(lfta_select_list.size()-1);\r
337 }\r
338 \r
339 \r
340 \r
341 //              TODO: The generated colref should be tied to the tablevar\r
342 //              representing the lfta output.  For now, always 0.\r
343 \r
344 scalarexp_t *make_fta_se_ref(vector<select_element *> &lfta_select_list, scalarexp_t *se, int h_tvref){\r
345         bool new_element;\r
346         int fta_se_nbr = add_select_list_nodup(lfta_select_list, se, new_element);\r
347         string colname;\r
348         if(!new_element){\r
349                 colname = lfta_select_list[fta_se_nbr]->name;\r
350         }else{\r
351                 colname = impute_colname(lfta_select_list, se);\r
352                 lfta_select_list[fta_se_nbr]->name = colname;\r
353         }\r
354 //\r
355 //              TODO: fill in the tablevar and schema of the colref here.\r
356         colref_t *new_cr = new colref_t(colname.c_str());\r
357         new_cr->set_tablevar_ref(h_tvref);\r
358 \r
359 \r
360         scalarexp_t *new_se= new scalarexp_t(new_cr);\r
361         new_se->use_decorations_of(se);\r
362 \r
363         return(new_se);\r
364 }\r
365 \r
366 \r
367 //                      Build a selection list,\r
368 //                      but avoid adding duplicate SEs.\r
369 \r
370 \r
371 int add_select_list_nodup(vector<select_element *> *lfta_select_list, scalarexp_t *se,\r
372                                 bool &new_element){\r
373         new_element = false;\r
374         int s;\r
375         for(s=0;s<lfta_select_list->size();s++){\r
376                 if(is_equivalent_se((*lfta_select_list)[s]->se, se)){\r
377                         return(s);\r
378                 }\r
379         }\r
380         new_element = true;\r
381         lfta_select_list->push_back(new select_element(se,"NoNameIn:add_select_list_nodup"));\r
382         return(lfta_select_list->size()-1);\r
383 }\r
384 \r
385 \r
386 \r
387 //              TODO: The generated colref should be tied to the tablevar\r
388 //              representing the lfta output.  For now, always 0.\r
389 \r
390 scalarexp_t *make_fta_se_ref(vector<vector<select_element *> *> &lfta_select_list, scalarexp_t *se, int h_tvref){\r
391         bool new_element;\r
392     vector<select_element *> *the_sel_list = lfta_select_list[h_tvref];\r
393         int fta_se_nbr = add_select_list_nodup(the_sel_list, se, new_element);\r
394         string colname;\r
395         if(!new_element){\r
396                 colname = (*the_sel_list)[fta_se_nbr]->name;\r
397         }else{\r
398                 colname = impute_colname(*the_sel_list, se);\r
399                 (*the_sel_list)[fta_se_nbr]->name = colname;\r
400         }\r
401 //\r
402 //              TODO: fill in the tablevar and schema of the colref here.\r
403         colref_t *new_cr = new colref_t(colname.c_str());\r
404         new_cr->set_tablevar_ref(h_tvref);\r
405 \r
406 \r
407         scalarexp_t *new_se= new scalarexp_t(new_cr);\r
408         new_se->use_decorations_of(se);\r
409 \r
410         return(new_se);\r
411 }\r
412 \r
413 \r
414 \r
415 \r
416 //\r
417 //                      Test if a se can be evaluated at the fta.\r
418 //                      check forbidden types (e.g. float), forbidden operations\r
419 //                      between types (e.g. divide a long long), forbidden operations\r
420 //                      (too expensive, not implemented).\r
421 //\r
422 //                      Return true if not forbidden, false if forbidden\r
423 //\r
424 //                      TODO: the parameter aggr_tbl is not used, delete it.\r
425 \r
426 bool check_fta_forbidden_se(scalarexp_t *se,\r
427                                                  aggregate_table *aggr_tbl,\r
428                                                  ext_fcn_list *Ext_fcns\r
429                                                  ){\r
430 \r
431   int p, fcn_id;\r
432   vector<scalarexp_t *> operand_list;\r
433   vector<data_type *> dt_signature;\r
434   data_type *dt = se->get_data_type();\r
435 \r
436 \r
437 \r
438   switch(se->get_operator_type()){\r
439     case SE_LITERAL:\r
440     case SE_PARAM:\r
441     case SE_COLREF:\r
442                 return( se->get_data_type()->fta_legal_type() );\r
443         case SE_IFACE_PARAM:\r
444                 return true;\r
445     case SE_UNARY_OP:\r
446                 if(!check_fta_forbidden_se(se->get_left_se(), aggr_tbl, Ext_fcns))\r
447                          return(false);\r
448                 return(\r
449                    dt->fta_legal_operation(se->get_left_se()->get_data_type(), se->get_op())\r
450                 );\r
451     case SE_BINARY_OP:\r
452                  if(!check_fta_forbidden_se(se->get_left_se(),aggr_tbl, Ext_fcns))\r
453                          return(false);\r
454                  if(!check_fta_forbidden_se(se->get_right_se(),aggr_tbl, Ext_fcns))\r
455                          return(false);\r
456                  return(dt->fta_legal_operation(se->get_left_se()->get_data_type(),\r
457                                                                         se->get_right_se()->get_data_type(),\r
458                                                                         se->get_op()\r
459                                                                         )\r
460                 );\r
461 \r
462 //                      return true, aggregate fta-safeness is determined elsewhere.\r
463     case SE_AGGR_STAR:\r
464                 return(true);\r
465     case SE_AGGR_SE:\r
466                 return(true);\r
467 \r
468         case SE_FUNC:\r
469                 if(se->get_aggr_ref() >= 0) return true;\r
470 \r
471                 operand_list = se->get_operands();\r
472                 for(p=0;p<operand_list.size();p++){\r
473                         if(!check_fta_forbidden_se(operand_list[p],aggr_tbl, Ext_fcns))\r
474                                 return(false);\r
475                         dt_signature.push_back(operand_list[p]->get_data_type() );\r
476                 }\r
477                 fcn_id = Ext_fcns->lookup_fcn(se->get_op(), dt_signature);\r
478                 if( fcn_id < 0 ){\r
479                         fprintf(stderr,"ERROR, no external function %s(",se->get_op().c_str());\r
480                         int o;\r
481                         for(o=0;o<operand_list.size();o++){\r
482                                 if(o>0) fprintf(stderr,", ");\r
483                                 fprintf(stderr,"%s",operand_list[o]->get_data_type()->to_string().c_str());\r
484                         }\r
485                         fprintf(stderr,") is defined, line %d, char %d\n", se->get_lineno(), se->get_charno() );\r
486                         if(fcn_id == -2) fprintf(stderr,"(multiple subsuming functions found)\n");\r
487                         return(false);\r
488                 }\r
489 \r
490                 return(Ext_fcns->fta_legal(fcn_id) );\r
491         default:\r
492                 printf("INTERNAL ERROR in check_fta_forbidden_se: operator type %d\n",se->get_operator_type());\r
493                 exit(1);\r
494         break;\r
495   }\r
496   return(false);\r
497 \r
498 }\r
499 \r
500 \r
501 //              test if a pr can be executed at the fta.\r
502 //\r
503 //                      Return true if not forbidden, false if forbidden\r
504 \r
505 bool check_fta_forbidden_pr(predicate_t *pr,\r
506                                                  aggregate_table *aggr_tbl,\r
507                                                  ext_fcn_list *Ext_fcns\r
508                                                  ){\r
509 \r
510   vector<literal_t *> llist;\r
511   data_type *dt;\r
512   int l,o, fcn_id;\r
513   vector<scalarexp_t *> op_list;\r
514   vector<data_type *> dt_signature;\r
515 \r
516 \r
517 \r
518         switch(pr->get_operator_type()){\r
519         case PRED_IN:\r
520                 if(! check_fta_forbidden_se(pr->get_left_se(), aggr_tbl, Ext_fcns) )\r
521                         return(false);\r
522                 llist = pr->get_lit_vec();\r
523                 for(l=0;l<llist.size();l++){\r
524                         dt = new data_type(llist[l]->get_type());\r
525                         if(! dt->fta_legal_type()){\r
526                                 delete dt;\r
527                                 return(false);\r
528                         }\r
529                         delete dt;\r
530                 }\r
531                 return(true);\r
532         case PRED_COMPARE:\r
533                 if(! check_fta_forbidden_se(pr->get_left_se(), aggr_tbl, Ext_fcns))\r
534                         return(false);\r
535                 if(! check_fta_forbidden_se(pr->get_right_se(), aggr_tbl, Ext_fcns))\r
536                         return(false);\r
537                 return(true);\r
538         case PRED_UNARY_OP:\r
539                 return( check_fta_forbidden_pr(pr->get_left_pr(), aggr_tbl, Ext_fcns) );\r
540         case PRED_BINARY_OP:\r
541                 if(! check_fta_forbidden_pr(pr->get_left_pr(), aggr_tbl, Ext_fcns))\r
542                         return(false);\r
543                 if(! check_fta_forbidden_pr(pr->get_right_pr(), aggr_tbl, Ext_fcns))\r
544                         return(false);\r
545                 return(true);\r
546         case PRED_FUNC:\r
547                 op_list = pr->get_op_list();\r
548                 for(o=0;o<op_list.size();o++){\r
549                         if(!check_fta_forbidden_se(op_list[o],aggr_tbl, Ext_fcns))\r
550                                 return(false);\r
551                         dt_signature.push_back(op_list[o]->get_data_type() );\r
552                 }\r
553                 fcn_id = Ext_fcns->lookup_pred(pr->get_op(), dt_signature);\r
554                 if( fcn_id < 0 ){\r
555                         fprintf(stderr,"ERROR, no external predicate %s(",pr->get_op().c_str());\r
556                         int o;\r
557                         for(o=0;o<op_list.size();o++){\r
558                                 if(o>0) fprintf(stderr,", ");\r
559                                 fprintf(stderr,"%s",op_list[o]->get_data_type()->to_string().c_str());\r
560                         }\r
561                         fprintf(stderr,") is defined, line %d, char %d\n", pr->get_lineno(), pr->get_charno() );\r
562                         if(fcn_id == -2) fprintf(stderr,"(multiple subsuming predicates found)\n");\r
563                         return(false);\r
564                 }\r
565 \r
566                 return(Ext_fcns->fta_legal(fcn_id) );\r
567         default:\r
568                 fprintf(stderr,"INTERNAL ERROR in check_fta_forbidden_pr, line %d, character %d, unknown predicate operator type %d\n",\r
569                         pr->get_lineno(), pr->get_charno(), pr->get_operator_type() );\r
570                 exit(1);\r
571         }\r
572 \r
573         return(0);\r
574 \r
575 }\r
576 \r
577 \r
578 //              Split the aggregates in orig_aggr_tbl, into superaggregates and\r
579 //              subaggregates.\r
580 //              (the value of the HFTA aggregate might be a SE of several LFTA\r
581 //               subaggregates, e.g. avg : sum / count )\r
582 //              Register the superaggregates in hfta_aggr_tbl, and the\r
583 //              subaggregates in lfta_aggr_tbl.\r
584 //              Insert references to the subaggregates into lfta_select_list.\r
585 //              (and record their names in the currnames list)\r
586 //              Create a SE for the superaggregate, put it in hfta_aggr_se,\r
587 //              keyed on agr_id.\r
588 \r
589 void split_fta_aggr(aggregate_table *orig_aggr_tbl, int agr_id,\r
590                                         aggregate_table *hfta_aggr_tbl,\r
591                                         aggregate_table *lfta_aggr_tbl,\r
592                                         vector<select_element *> &lfta_select_list,\r
593                                         map<int,scalarexp_t *> &hfta_aggr_se,\r
594                                     ext_fcn_list *Ext_fcns\r
595                                         ){\r
596         bool new_element;\r
597         scalarexp_t *subaggr_se;\r
598         int fta_se_nbr;\r
599         string colname;\r
600         int ano;\r
601         colref_t *new_cr;\r
602         scalarexp_t *new_se, *l_se;\r
603         vector<scalarexp_t *> subaggr_ref_se;\r
604 \r
605 //              UDAF processing\r
606         if(! orig_aggr_tbl->is_builtin(agr_id)){\r
607 //                      Construct the subaggregate\r
608                 int fcn_id = orig_aggr_tbl->get_fcn_id(agr_id);\r
609                 vector<scalarexp_t *> opl = orig_aggr_tbl->get_operand_list(agr_id);\r
610                 vector<scalarexp_t *> subopl;\r
611                 int o;\r
612                 for(o=0;o<opl.size();++o){\r
613                         subopl.push_back(dup_se(opl[o], NULL));\r
614                 }\r
615                 int sub_id = Ext_fcns->get_subaggr_id(fcn_id);\r
616                 subaggr_se = new scalarexp_t(Ext_fcns->get_fcn_name(sub_id).c_str(), subopl);\r
617                 subaggr_se->set_fcn_id(sub_id);\r
618                 subaggr_se->set_data_type(Ext_fcns->get_fcn_dt(sub_id));\r
619 //                      Add it to the lfta select list.\r
620                 fta_se_nbr = add_select_list_nodup(lfta_select_list, subaggr_se,new_element);\r
621                 if(!new_element){\r
622                         colname = lfta_select_list[fta_se_nbr]->name;\r
623                 }else{\r
624                         colname = impute_colname(lfta_select_list, subaggr_se);\r
625                         lfta_select_list[fta_se_nbr]->name = colname;\r
626                         ano = lfta_aggr_tbl->add_aggr(Ext_fcns->get_fcn_name(sub_id), sub_id, subopl,Ext_fcns->get_storage_dt(sub_id), false, false,Ext_fcns->has_lfta_bailout(sub_id));\r
627                         subaggr_se->set_aggr_id(ano);\r
628                 }\r
629 \r
630 //                      Construct a reference to the subaggregate\r
631                 new_cr = new colref_t(colname.c_str());\r
632                 new_se = new scalarexp_t(new_cr);\r
633 //                              I'm not certain what the types should be ....\r
634 //                              This will need to be filled in by later analysis.\r
635 //                              NOTE: this might not capture all the meaning of data_type ...\r
636                 new_se->set_data_type(Ext_fcns->get_fcn_dt(sub_id));\r
637                 subaggr_ref_se.push_back(new_se);\r
638 \r
639 //                      Construct the superaggregate\r
640                 int super_id = Ext_fcns->get_superaggr_id(fcn_id);\r
641                 scalarexp_t *ret_se = new scalarexp_t(Ext_fcns->get_fcn_name(super_id).c_str(), subaggr_ref_se);\r
642                 ret_se->set_fcn_id(super_id);\r
643                 ret_se->set_data_type(Ext_fcns->get_fcn_dt(super_id));\r
644 //                      Register it in the hfta aggregate table\r
645                 ano = hfta_aggr_tbl->add_aggr(ret_se->get_op(), super_id, subaggr_ref_se,Ext_fcns->get_storage_dt(super_id), false, Ext_fcns->is_running_aggr(sub_id),false);\r
646                 ret_se->set_aggr_id(ano);\r
647                 hfta_aggr_se[agr_id] = ret_se;\r
648 \r
649                 return;\r
650         }\r
651 \r
652 \r
653 //              builtin aggregate processing\r
654         bool l_forbid;\r
655 \r
656         vector<bool> use_se;\r
657         vector<string> subaggr_names = orig_aggr_tbl->get_subaggr_fcns(agr_id, use_se);\r
658         vector<data_type *> subaggr_dt = orig_aggr_tbl->get_subaggr_dt(agr_id);\r
659         int sa;\r
660 \r
661         if(orig_aggr_tbl->is_star_aggr(agr_id)){\r
662           for(sa=0;sa<subaggr_names.size();sa++){\r
663                 subaggr_se = scalarexp_t::make_star_aggr(subaggr_names[sa].c_str());\r
664                 subaggr_se->set_data_type(subaggr_dt[sa]);\r
665 \r
666 //                      The following sequence is similar to the code in make_fta_se_ref,\r
667 //                      but there is special processing for the aggregate tables.\r
668                 int fta_se_nbr = add_select_list_nodup(lfta_select_list, subaggr_se,new_element);\r
669                 if(!new_element){\r
670                         colname = lfta_select_list[fta_se_nbr]->name;\r
671                 }else{\r
672                         colname = impute_colname(lfta_select_list, subaggr_se);\r
673                         lfta_select_list[fta_se_nbr]->name = colname;\r
674                         ano = lfta_aggr_tbl->add_aggr(subaggr_names[sa].c_str(),NULL, false);\r
675                         subaggr_se->set_aggr_id(ano);\r
676                 }\r
677                 new_cr = new colref_t(colname.c_str());\r
678                 new_cr->set_tablevar_ref(0);\r
679                 new_se = new scalarexp_t(new_cr);\r
680 \r
681 //                                      I'm not certain what the types should be ....\r
682 //                                      This will need to be filled in by later analysis.\r
683 //                                              Actually, this is causing a problem.\r
684 //                                              I will assume a UINT data type. / change to INT\r
685 //                                              (consistent with assign_data_types in analyze_fta.cc)\r
686 //                      TODO: why can't I use subaggr_dt, as I do in the other IF branch?\r
687                 data_type *ndt = new data_type("Int");  // used to be Uint\r
688                 new_se->set_data_type(ndt);\r
689 \r
690                 subaggr_ref_se.push_back(new_se);\r
691           }\r
692         }else{\r
693           for(sa=0;sa<subaggr_names.size();sa++){\r
694                 if(use_se[sa]){\r
695                         scalarexp_t *aggr_operand = orig_aggr_tbl->get_aggr_se(agr_id);\r
696                         l_se = dup_se(aggr_operand,  NULL);\r
697                         subaggr_se = scalarexp_t::make_se_aggr(subaggr_names[sa].c_str(),l_se);\r
698                 }else{\r
699                         subaggr_se = scalarexp_t::make_star_aggr(subaggr_names[sa].c_str());\r
700                 }\r
701                 subaggr_se->set_data_type(subaggr_dt[sa]);\r
702 \r
703 //                      again, similar to make_fta_se_ref.\r
704                 fta_se_nbr = add_select_list_nodup(lfta_select_list, subaggr_se,new_element);\r
705                 if(!new_element){\r
706                         colname = lfta_select_list[fta_se_nbr]->name;\r
707                 }else{\r
708                         colname = impute_colname(lfta_select_list, subaggr_se);\r
709                         lfta_select_list[fta_se_nbr]->name = colname;\r
710                         if(use_se[sa])\r
711                                 ano = lfta_aggr_tbl->add_aggr(subaggr_names[sa].c_str(),l_se, false);\r
712                         else\r
713                                 ano = lfta_aggr_tbl->add_aggr(subaggr_names[sa].c_str(),NULL,false);\r
714                         subaggr_se->set_aggr_id(ano);\r
715                 }\r
716                 new_cr = new colref_t(colname.c_str());\r
717                 new_se = new scalarexp_t(new_cr);\r
718 //                              I'm not certain what the types should be ....\r
719 //                              This will need to be filled in by later analysis.\r
720 //                              NOTE: this might not capture all the meaning of data_type ...\r
721                 new_se->set_data_type(subaggr_dt[sa]);\r
722                 subaggr_ref_se.push_back(new_se);\r
723           }\r
724         }\r
725         scalarexp_t *ret_se = orig_aggr_tbl->make_superaggr_se(agr_id, subaggr_ref_se);\r
726         ret_se->set_data_type(orig_aggr_tbl->get_data_type(agr_id));\r
727 \r
728 // ASSUME either the return value is an aggregation,\r
729 // or a binary_op between two aggregations\r
730         if(ret_se->get_operator_type() == SE_AGGR_SE || ret_se->get_operator_type() == SE_AGGR_SE){\r
731                 ano = hfta_aggr_tbl->add_aggr(ret_se->get_op(), ret_se->get_left_se(), false );\r
732                 ret_se->set_aggr_id(ano);\r
733         }else{\r
734 // Basically processing for AVG. \r
735 // set the data type of the superagg to that of the subagg.\r
736                 scalarexp_t *left_se = ret_se->get_left_se();\r
737                 left_se->set_data_type(subaggr_dt[0]);\r
738                 ano = hfta_aggr_tbl->add_aggr(left_se->get_op(), left_se->get_left_se(), false );\r
739                 left_se->set_aggr_id(ano);\r
740 \r
741                 scalarexp_t *right_se = ret_se->get_right_se();\r
742                 right_se->set_data_type(subaggr_dt[1]);\r
743                 ano = hfta_aggr_tbl->add_aggr(right_se->get_op(), right_se->get_left_se(), false );\r
744                 right_se->set_aggr_id(ano);\r
745         }\r
746 \r
747         hfta_aggr_se[agr_id] = ret_se;\r
748 \r
749 }\r
750 \r
751 \r
752 //              Split the aggregates in orig_aggr_tbl, into hfta_superaggregates and\r
753 //              hfta_subaggregates.\r
754 //              Register the superaggregates in hi_aggr_tbl, and the\r
755 //              subaggregates in loq_aggr_tbl.\r
756 //              Insert references to the subaggregates into low_select_list.\r
757 //              (and record their names in the currnames list)\r
758 //              Create a SE for the superaggregate, put it in hfta_aggr_se,\r
759 //              keyed on agr_id.\r
760 \r
761 void split_hfta_aggr(aggregate_table *orig_aggr_tbl, int agr_id,\r
762                                         aggregate_table *hi_aggr_tbl,\r
763                                         aggregate_table *low_aggr_tbl,\r
764                                         vector<select_element *> &low_select_list,\r
765                                         map<int,scalarexp_t *> &hi_aggr_se,\r
766                                     ext_fcn_list *Ext_fcns\r
767                                         ){\r
768         bool new_element;\r
769         scalarexp_t *subaggr_se;\r
770         int fta_se_nbr;\r
771         string colname;\r
772         int ano;\r
773         colref_t *new_cr;\r
774         scalarexp_t *new_se, *l_se;\r
775         vector<scalarexp_t *> subaggr_ref_se;\r
776 \r
777 //              UDAF processing\r
778         if(! orig_aggr_tbl->is_builtin(agr_id)){\r
779 //                      Construct the subaggregate\r
780                 int fcn_id = orig_aggr_tbl->get_fcn_id(agr_id);\r
781                 vector<scalarexp_t *> opl = orig_aggr_tbl->get_operand_list(agr_id);\r
782                 vector<scalarexp_t *> subopl;\r
783                 int o;\r
784                 for(o=0;o<opl.size();++o){\r
785                         subopl.push_back(dup_se(opl[o], NULL));\r
786                 }\r
787                 int sub_id = Ext_fcns->get_hfta_subaggr_id(fcn_id);\r
788                 subaggr_se = new scalarexp_t(Ext_fcns->get_fcn_name(sub_id).c_str(), subopl);\r
789                 subaggr_se->set_fcn_id(sub_id);\r
790                 subaggr_se->set_data_type(Ext_fcns->get_fcn_dt(sub_id));\r
791 //                      Add it to the low select list.\r
792                 fta_se_nbr = add_select_list_nodup(low_select_list, subaggr_se,new_element);\r
793                 if(!new_element){\r
794                         colname = low_select_list[fta_se_nbr]->name;\r
795                 }else{\r
796                         colname = impute_colname(low_select_list, subaggr_se);\r
797                         low_select_list[fta_se_nbr]->name = colname;\r
798                         ano = low_aggr_tbl->add_aggr(Ext_fcns->get_fcn_name(sub_id), sub_id, subopl,Ext_fcns->get_storage_dt(sub_id), false, false,false);\r
799                         subaggr_se->set_aggr_id(ano);\r
800                 }\r
801 \r
802 //                      Construct a reference to the subaggregate\r
803                 new_cr = new colref_t(colname.c_str());\r
804                 new_se = new scalarexp_t(new_cr);\r
805 //                              I'm not certain what the types should be ....\r
806 //                              This will need to be filled in by later analysis.\r
807 //                              NOTE: this might not capture all the meaning of data_type ...\r
808                 new_se->set_data_type(Ext_fcns->get_fcn_dt(sub_id));\r
809                 subaggr_ref_se.push_back(new_se);\r
810 \r
811 //                      Construct the superaggregate\r
812                 int super_id = Ext_fcns->get_hfta_superaggr_id(fcn_id);\r
813                 scalarexp_t *ret_se = new scalarexp_t(Ext_fcns->get_fcn_name(super_id).c_str(), subaggr_ref_se);\r
814                 ret_se->set_fcn_id(super_id);\r
815                 ret_se->set_data_type(Ext_fcns->get_fcn_dt(super_id));\r
816 //                      Register it in the high aggregate table\r
817                 ano = hi_aggr_tbl->add_aggr(ret_se->get_op(), super_id, subaggr_ref_se,Ext_fcns->get_storage_dt(super_id), false, false,false);\r
818                 ret_se->set_aggr_id(ano);\r
819                 hi_aggr_se[agr_id] = ret_se;\r
820 \r
821                 return;\r
822         }\r
823 \r
824 \r
825 //              builtin aggregate processing\r
826         bool l_forbid;\r
827 \r
828         vector<bool> use_se;\r
829         vector<string> subaggr_names = orig_aggr_tbl->get_subaggr_fcns(agr_id, use_se);\r
830         vector<data_type *> subaggr_dt = orig_aggr_tbl->get_subaggr_dt(agr_id);\r
831         int sa;\r
832 \r
833         if(orig_aggr_tbl->is_star_aggr(agr_id)){\r
834           for(sa=0;sa<subaggr_names.size();sa++){\r
835                 subaggr_se = scalarexp_t::make_star_aggr(subaggr_names[sa].c_str());\r
836                 subaggr_se->set_data_type(subaggr_dt[sa]);\r
837 \r
838 //                      The following sequence is similar to the code in make_fta_se_ref,\r
839 //                      but there is special processing for the aggregate tables.\r
840                 int fta_se_nbr = add_select_list_nodup(low_select_list, subaggr_se,new_element);\r
841                 if(!new_element){\r
842                         colname = low_select_list[fta_se_nbr]->name;\r
843                 }else{\r
844                         colname = impute_colname(low_select_list, subaggr_se);\r
845                         low_select_list[fta_se_nbr]->name = colname;\r
846                         ano = low_aggr_tbl->add_aggr(subaggr_names[sa].c_str(),NULL, false);\r
847                         subaggr_se->set_aggr_id(ano);\r
848                 }\r
849                 new_cr = new colref_t(colname.c_str());\r
850                 new_cr->set_tablevar_ref(0);\r
851                 new_se = new scalarexp_t(new_cr);\r
852 \r
853 //                                      I'm not certain what the types should be ....\r
854 //                                      This will need to be filled in by later analysis.\r
855 //                                              Actually, this is causing a problem.\r
856 //                                              I will assume a UINT data type.\r
857 //                                              (consistent with assign_data_types in analyze_fta.cc)\r
858 //                      TODO: why can't I use subaggr_dt, as I do in the other IF branch?\r
859                 data_type *ndt = new data_type("Int");  // was Uint\r
860                 new_se->set_data_type(ndt);\r
861 \r
862                 subaggr_ref_se.push_back(new_se);\r
863           }\r
864         }else{\r
865           for(sa=0;sa<subaggr_names.size();sa++){\r
866                 if(use_se[sa]){\r
867                         scalarexp_t *aggr_operand = orig_aggr_tbl->get_aggr_se(agr_id);\r
868                         l_se = dup_se(aggr_operand,  NULL);\r
869                         subaggr_se = scalarexp_t::make_se_aggr(subaggr_names[sa].c_str(),l_se);\r
870                 }else{\r
871                         subaggr_se = scalarexp_t::make_star_aggr(subaggr_names[sa].c_str());\r
872                 }\r
873                 subaggr_se->set_data_type(subaggr_dt[sa]);\r
874 \r
875 //                      again, similar to make_fta_se_ref.\r
876                 fta_se_nbr = add_select_list_nodup(low_select_list, subaggr_se,new_element);\r
877                 if(!new_element){\r
878                         colname = low_select_list[fta_se_nbr]->name;\r
879                 }else{\r
880                         colname = impute_colname(low_select_list, subaggr_se);\r
881                         low_select_list[fta_se_nbr]->name = colname;\r
882                         if(use_se[sa])\r
883                                 ano = low_aggr_tbl->add_aggr(subaggr_names[sa].c_str(),l_se, false);\r
884                         else\r
885                                 ano = low_aggr_tbl->add_aggr(subaggr_names[sa].c_str(),NULL,false);\r
886                         subaggr_se->set_aggr_id(ano);\r
887                 }\r
888                 new_cr = new colref_t(colname.c_str());\r
889                 new_se = new scalarexp_t(new_cr);\r
890 //                              I'm not certain what the types should be ....\r
891 //                              This will need to be filled in by later analysis.\r
892 //                              NOTE: this might not capture all the meaning of data_type ...\r
893                 new_se->set_data_type(subaggr_dt[sa]);\r
894                 subaggr_ref_se.push_back(new_se);\r
895           }\r
896         }\r
897         scalarexp_t *ret_se = orig_aggr_tbl->make_superaggr_se(agr_id, subaggr_ref_se);\r
898 // ASSUME either the return value is an aggregation,\r
899 // or a binary_op between two aggregations\r
900         if(ret_se->get_operator_type() == SE_AGGR_SE || ret_se->get_operator_type() == SE_AGGR_SE){\r
901                 ret_se->set_data_type(orig_aggr_tbl->get_data_type(agr_id));\r
902                 ano = hi_aggr_tbl->add_aggr(ret_se->get_op(), ret_se->get_left_se(), false );\r
903         }else{\r
904 // Basically processing for AVG. \r
905 // set the data type of the superagg to that of the subagg.\r
906                 scalarexp_t *left_se = ret_se->get_left_se();\r
907                 left_se->set_data_type(subaggr_dt[0]);\r
908                 ano = hi_aggr_tbl->add_aggr(left_se->get_op(), left_se->get_left_se(), false );\r
909                 left_se->set_aggr_id(ano);\r
910 \r
911                 scalarexp_t *right_se = ret_se->get_right_se();\r
912                 right_se->set_data_type(subaggr_dt[1]);\r
913                 ano = hi_aggr_tbl->add_aggr(right_se->get_op(), right_se->get_left_se(), false );\r
914                 right_se->set_aggr_id(ano);\r
915         }\r
916 \r
917         ret_se->set_aggr_id(ano);\r
918         hi_aggr_se[agr_id] = ret_se;\r
919 \r
920 }\r
921 \r
922 \r
923 \r
924 \r
925 \r
926 //              Split a scalar expression into one part which executes\r
927 //              at the stream and another set of parts which execute\r
928 //              at the FTA.\r
929 //              Because I'm actually modifying the SEs, I will make\r
930 //              copies.  But I will assume that literals, params, and\r
931 //              colrefs are immutable at this point.\r
932 //              (if there is ever a need to change one, must make a\r
933 //               new value).\r
934 //              NOTE : if se is constant (only refrences literals),\r
935 //                      avoid making the fta compute it.\r
936 //\r
937 //              NOTE : This will need to be generalized to\r
938 //              handle join expressions, namely to handle a vector\r
939 //              of lftas.\r
940 //\r
941 //              Return value is the HFTA se.\r
942 //              Add lftas select_elements to the fta_select_list.\r
943 //              set fta_forbidden if this node or any child cannot\r
944 //              execute at the lfta.\r
945 \r
946 /*\r
947 \r
948 scalarexp_t *split_fta_se(scalarexp_t *se,\r
949                                   bool &fta_forbidden,\r
950                                   vector<select_element *> &lfta_select_list,\r
951                                   ext_fcn_list *Ext_fcns\r
952                                  ){\r
953 \r
954   int p, fcn_id;\r
955   vector<scalarexp_t *> operand_list;\r
956   vector<data_type *> dt_signature;\r
957   scalarexp_t *ret_se, *l_se, *r_se;\r
958   bool l_forbid, r_forbid, this_forbid;\r
959   colref_t *new_cr;\r
960   scalarexp_t *new_se;\r
961   data_type *dt = se->get_data_type();\r
962 \r
963   switch(se->get_operator_type()){\r
964     case SE_LITERAL:\r
965                 fta_forbidden = ! se->get_data_type()->fta_legal_type();\r
966                 ret_se = new scalarexp_t(se->get_literal());\r
967                 ret_se->use_decorations_of(se);\r
968                 return(ret_se);\r
969 \r
970     case SE_PARAM:\r
971                 fta_forbidden = ! se->get_data_type()->fta_legal_type();\r
972                 ret_se = scalarexp_t::make_param_reference(se->get_op().c_str());\r
973                 ret_se->use_decorations_of(se);\r
974                 return(ret_se);\r
975 \r
976     case SE_COLREF:\r
977 //                      No colref should be forbidden,\r
978 //                      the schema is wrong, the fta_legal_type() fcn is wrong,\r
979 //                      or the source table is actually a stream.\r
980 //                      Issue a warning, but proceed with processing.\r
981 //                      Also, should not be a ref to a gbvar.\r
982 //                      (a gbvar ref only occurs in an aggregation node,\r
983 //                      and these SEs are rehomed, not split.\r
984                 fta_forbidden = ! se->get_data_type()->fta_legal_type();\r
985 \r
986                 if(fta_forbidden){\r
987                         fprintf(stderr,"WARNING, a colref is a forbidden data type in split_fta_se,"\r
988                                                         " colref is %s,"\r
989                                                         " type is %s, line=%d, col=%d\n",\r
990                                                         se->get_colref()->to_string().c_str(),\r
991                                                         se->get_data_type()->get_type_str().c_str(),\r
992                                                         se->lineno, se->charno\r
993                                         );\r
994                 }\r
995 \r
996                 if(se->is_gb()){\r
997                         fprintf(stderr,"INTERNAL ERROR, a colref is a gbvar ref in split_fta_se,"\r
998                                                         " type is %s, line=%d, col=%d\n",\r
999                                                         se->get_data_type()->get_type_str().c_str(),\r
1000                                                         se->lineno, se->charno\r
1001                                         );\r
1002                         exit(1);\r
1003                 }\r
1004 \r
1005                 ret_se = new scalarexp_t(se->get_colref());\r
1006                 ret_se->use_decorations_of(se);\r
1007                 return(ret_se);\r
1008 \r
1009     case SE_UNARY_OP:\r
1010                  l_se = split_fta_se(se->get_left_se(), l_forbid, lfta_select_list, Ext_fcns);\r
1011 \r
1012                  this_forbid = ! dt->fta_legal_operation(l_se->get_data_type(), se->get_op());\r
1013 \r
1014 //                      If this operation is forbidden but the child SE is not,\r
1015 //                      put the child se on the lfta_select_list, create a colref\r
1016 //                      which accesses this se, and make it the child of this op.\r
1017 //                      Exception : the child se is constant (only literal refs).\r
1018                  if(this_forbid && !l_forbid){\r
1019                          if(!is_literal_or_param_only(l_se)){\r
1020                                  new_se = make_fta_se_ref(lfta_select_list, l_se,0);\r
1021                                  ret_se = new scalarexp_t(se->get_op().c_str(), new_se);\r
1022                          }\r
1023                  }else{\r
1024                          ret_se = new scalarexp_t(se->get_op().c_str(), l_se);\r
1025                  }\r
1026                  ret_se->use_decorations_of(se);\r
1027                  fta_forbidden = this_forbid | l_forbid;\r
1028                  return(ret_se);\r
1029 \r
1030     case SE_BINARY_OP:\r
1031                  l_se = split_fta_se(se->get_left_se(), l_forbid, lfta_select_list, Ext_fcns);\r
1032                  r_se = split_fta_se(se->get_right_se(), r_forbid, lfta_select_list, Ext_fcns);\r
1033 \r
1034                  this_forbid = ! dt->fta_legal_operation(l_se->get_data_type(), r_se->get_data_type(), se->get_op());\r
1035 \r
1036 //                      Replace the left se if it is not forbidden, but something else is.\r
1037                  if((this_forbid || r_forbid) & !l_forbid){\r
1038                          if(!is_literal_or_param_only(l_se)){\r
1039                                  new_se = make_fta_se_ref(lfta_select_list, l_se,0);\r
1040                                  l_se = new_se;\r
1041                          }\r
1042                  }\r
1043 \r
1044 //                      Replace the right se if it is not forbidden, but something else is.\r
1045                  if((this_forbid || l_forbid) & !r_forbid){\r
1046                          if(!is_literal_or_param_only(r_se)){\r
1047                                  new_se = make_fta_se_ref(lfta_select_list, r_se,0);\r
1048                                  r_se = new_se;\r
1049                          }\r
1050                  }\r
1051 \r
1052                  ret_se = new scalarexp_t(se->get_op().c_str(), l_se, r_se);\r
1053                  ret_se->use_decorations_of(se);\r
1054                  fta_forbidden = this_forbid || r_forbid || l_forbid;\r
1055 \r
1056                  return(ret_se);\r
1057 \r
1058     case SE_AGGR_STAR:\r
1059     case SE_AGGR_SE:\r
1060 \r
1061                 fprintf(stderr,"INTERNAL ERROR, aggregate ref (%s) in split_fta_se."\r
1062                                                 " line=%d, col=%d\n",\r
1063                                                 se->get_op().c_str(),\r
1064                                                 se->lineno, se->charno\r
1065                                 );\r
1066                 exit(1);\r
1067                 break;\r
1068 \r
1069         case SE_FUNC:\r
1070                 {\r
1071                         fta_forbidden = false;\r
1072                         operand_list = se->get_operands();\r
1073                         vector<scalarexp_t *> new_operands;\r
1074                         vector<bool> forbidden_op;\r
1075                         for(p=0;p<operand_list.size();p++){\r
1076                                 l_se = split_fta_se(operand_list[p], l_forbid, lfta_select_list, Ext_fcns);\r
1077 \r
1078                                 fta_forbidden |= l_forbid;\r
1079                                 new_operands.push_back(l_se);\r
1080                                 forbidden_op.push_back(l_forbid);\r
1081                                 dt_signature.push_back(operand_list[p]->get_data_type() );\r
1082                         }\r
1083 \r
1084                         fcn_id = Ext_fcns->lookup_fcn(se->get_op(), dt_signature);\r
1085                         if( fcn_id < 0 ){\r
1086                                 fprintf(stderr,"ERROR, no external function %s(",se->get_op().c_str());\r
1087                                 int o;\r
1088                                 for(o=0;o<operand_list.size();o++){\r
1089                                         if(o>0) fprintf(stderr,", ");\r
1090                                         fprintf(stderr,"%s",operand_list[o]->get_data_type()->get_type_str().c_str());\r
1091                                 }\r
1092                                 fprintf(stderr,") is defined, line %d, char %d\n", se->get_lineno(), se->get_charno() );\r
1093                         if(fcn_id == -2) fprintf(stderr,"(multiple subsuming functions found)\n");\r
1094                                 return(false);\r
1095                         }\r
1096 \r
1097                         fta_forbidden |= (! Ext_fcns->fta_legal(fcn_id));\r
1098 \r
1099 //                              Replace the non-forbidden operands.\r
1100 //                              the forbidden ones are already replaced.\r
1101                         if(fta_forbidden){\r
1102                                 for(p=0;p<new_operands.size();p++){\r
1103                                         if(! forbidden_op[p]){\r
1104 //                                        if(new_operands[p]->get_data_type()->get_temporal() != constant_t){\r
1105                                                 if(!is_literal_or_param_only(new_operands[p])){\r
1106                                                 new_se = make_fta_se_ref(lfta_select_list, new_operands[p],0);\r
1107                                                 new_operands[p] = new_se;\r
1108                                           }\r
1109                                         }\r
1110                                 }\r
1111                         }\r
1112 \r
1113                         ret_se = new scalarexp_t(se->get_op().c_str(), new_operands);\r
1114                         ret_se->use_decorations_of(se);\r
1115 \r
1116                         return(ret_se);\r
1117 \r
1118                 }\r
1119         default:\r
1120                 printf("INTERNAL ERROR in check_fta_forbidden_se: operator type %d\n",se->get_operator_type());\r
1121                 exit(1);\r
1122         break;\r
1123   }\r
1124   return(false);\r
1125 \r
1126 }\r
1127 \r
1128 */\r
1129 \r
1130 \r
1131 //              The predicates have already been\r
1132 //              broken into conjunctions.\r
1133 //              If any part of a conjunction is fta-forbidden,\r
1134 //              it must be executed in the stream operator.\r
1135 //              Else it is executed in the FTA.\r
1136 //              A pre-analysis should determine whether this\r
1137 //              predicate is fta-safe.  This procedure will\r
1138 //              assume that it is fta-forbidden and will\r
1139 //              prepare it for execution in the stream.\r
1140 \r
1141 /*\r
1142 \r
1143 predicate_t *split_fta_pr(predicate_t *pr,\r
1144                                                  vector<select_element *> &lfta_select_list,\r
1145                                                  ext_fcn_list *Ext_fcns\r
1146                                                  ){\r
1147 \r
1148   vector<literal_t *> llist;\r
1149   scalarexp_t *se_l, *se_r;\r
1150   bool l_forbid, r_forbid;\r
1151   predicate_t *ret_pr, *pr_l, *pr_r;\r
1152   vector<scalarexp_t *> op_list, new_op_list;\r
1153   int o;\r
1154   vector<data_type *> dt_signature;\r
1155 \r
1156 \r
1157         switch(pr->get_operator_type()){\r
1158         case PRED_IN:\r
1159                 se_l = split_fta_se(pr->get_left_se(), l_forbid, lfta_select_list, Ext_fcns);\r
1160 \r
1161                 if(!l_forbid){\r
1162                   if(!is_literal_or_param_only(se_l)){\r
1163                         scalarexp_t *new_se = make_fta_se_ref(lfta_select_list, se_l,0);\r
1164                         se_l = new_se;\r
1165                   }\r
1166                 }\r
1167                 ret_pr = new predicate_t(se_l, pr->get_lit_vec());\r
1168 \r
1169                 return(ret_pr);\r
1170 \r
1171         case PRED_COMPARE:\r
1172                 se_l = split_fta_se(pr->get_left_se(), l_forbid, lfta_select_list, Ext_fcns);\r
1173                 if(!l_forbid){\r
1174                   if(!is_literal_or_param_only(se_l)){\r
1175                         scalarexp_t *new_se = make_fta_se_ref(lfta_select_list, se_l,0);\r
1176                         se_l = new_se;\r
1177                   }\r
1178                 }\r
1179 \r
1180                 se_r = split_fta_se(pr->get_right_se(), r_forbid, lfta_select_list, Ext_fcns);\r
1181                 if(!r_forbid){\r
1182                   if(!is_literal_or_param_only(se_r)){\r
1183                         scalarexp_t *new_se = make_fta_se_ref(lfta_select_list, se_r,0);\r
1184                         se_r = new_se;\r
1185                   }\r
1186                 }\r
1187 \r
1188                 ret_pr = new predicate_t(se_l, pr->get_op().c_str(), se_r);\r
1189                 return(ret_pr);\r
1190 \r
1191         case PRED_UNARY_OP:\r
1192                 pr_l = split_fta_pr(pr->get_left_pr(), lfta_select_list, Ext_fcns);\r
1193                 ret_pr = new predicate_t(pr->get_op().c_str(), pr_l);\r
1194                 return(ret_pr);\r
1195 \r
1196         case PRED_BINARY_OP:\r
1197                 pr_l = split_fta_pr(pr->get_left_pr(), lfta_select_list, Ext_fcns);\r
1198                 pr_r = split_fta_pr(pr->get_right_pr(), lfta_select_list, Ext_fcns);\r
1199                 ret_pr = new predicate_t(pr->get_op().c_str(), pr_l, pr_r);\r
1200                 return(ret_pr);\r
1201 \r
1202         case PRED_FUNC:\r
1203 //                      I can't push the predicate into the lfta, except by\r
1204 //                      returning a bool value, and that is not worth the trouble,\r
1205                 op_list = pr->get_op_list();\r
1206                 for(o=0;o<op_list.size();++o){\r
1207                         se_l = split_fta_se(op_list[o],l_forbid,lfta_select_list,Ext_fcns);\r
1208                         if(!l_forbid){\r
1209                           if(!is_literal_or_param_only(se_l)){\r
1210                                 scalarexp_t *new_se = make_fta_se_ref(lfta_select_list, se_l,0);\r
1211                                 se_l = new_se;\r
1212                           }\r
1213                         }\r
1214                         new_op_list.push_back(se_l);\r
1215                 }\r
1216 \r
1217                 ret_pr =  new predicate_t(pr->get_op().c_str(), new_op_list);\r
1218                 ret_pr->set_fcn_id(pr->get_fcn_id());\r
1219                 return(ret_pr);\r
1220         default:\r
1221                 fprintf(stderr,"INTERNAL ERROR in split_fta_pr, line %d, character %d, unknown predicate operator type %d\n",\r
1222                         pr->get_lineno(), pr->get_charno(), pr->get_operator_type() );\r
1223                 exit(1);\r
1224         }\r
1225 \r
1226         return(0);\r
1227 \r
1228 }\r
1229 \r
1230 */\r
1231 \r
1232 \r
1233 //--------------------------------------------------------------------\r
1234 \r
1235 \r
1236 \r
1237 //              Split a scalar expression into one part which executes\r
1238 //              at the stream and another set of parts which execute\r
1239 //              at the FTA.\r
1240 //              Because I'm actually modifying the SEs, I will make\r
1241 //              copies.  But I will assume that literals, params, and\r
1242 //              colrefs are immutable at this point.\r
1243 //              (if there is ever a need to change one, must make a\r
1244 //               new value).\r
1245 //              NOTE : if se is constant (only refrences literals),\r
1246 //                      avoid making the fta compute it.\r
1247 //\r
1248 //              NOTE : This will need to be generalized to\r
1249 //              handle join expressions, namely to handle a vector\r
1250 //              of lftas.\r
1251 //\r
1252 //              Return value is the HFTA se.\r
1253 //              Add lftas select_elements to the fta_select_list.\r
1254 //              set fta_forbidden if this node or any child cannot\r
1255 //              execute at the lfta.\r
1256 \r
1257 #define SPLIT_FTAVEC_NOTBLVAR -1\r
1258 #define SPLIT_FTAVEC_MIXED -2\r
1259 \r
1260 bool is_PROTOCOL_source(int colref_source,\r
1261                         vector< vector<select_element *> *> &lfta_select_list){\r
1262         if(colref_source>=0 && lfta_select_list[colref_source]!=NULL) return true;\r
1263         return false;\r
1264 }\r
1265 \r
1266 int combine_colref_source(int s1, int s2){\r
1267         if(s1==s2) return(s1);\r
1268         if(s1==SPLIT_FTAVEC_NOTBLVAR) return s2;\r
1269         if(s2==SPLIT_FTAVEC_NOTBLVAR) return s1;\r
1270         return SPLIT_FTAVEC_MIXED;\r
1271 }\r
1272 \r
1273 scalarexp_t *split_ftavec_se(\r
1274                                   scalarexp_t *se,      // the SE to split\r
1275                                   bool &fta_forbidden,  // return true if some part of se\r
1276                                                                                 // is fta-unsafe\r
1277                                   int &colref_source,   // the tblvar which sources the\r
1278                                                                                 // colref, or NOTBLVAR, or MIXED\r
1279                                   vector< vector<select_element *> *> &lfta_select_list,\r
1280                                                                                 // NULL if the tblvar is not PROTOCOL,\r
1281                                                                                 // else build the select list.\r
1282                                   ext_fcn_list *Ext_fcns // is the fcn lfta-safe?\r
1283                                  ){\r
1284 //              Return value is the HFTA SE, unless fta_forbidden is true and\r
1285 //              colref_source>=0 and the indicated source is PROTOCOL.\r
1286 //              In that case no split was done, the make_fta_se_ref must\r
1287 //              be done by the caller.\r
1288 \r
1289   int p, fcn_id;\r
1290   vector<scalarexp_t *> operand_list;\r
1291   vector<data_type *> dt_signature;\r
1292   scalarexp_t *ret_se, *l_se, *r_se;\r
1293   bool l_forbid, r_forbid, this_forbid;\r
1294   int l_csource, r_csource, this_csource;\r
1295   colref_t *new_cr;\r
1296   scalarexp_t *new_se;\r
1297   data_type *dt = se->get_data_type();\r
1298 \r
1299   switch(se->get_operator_type()){\r
1300     case SE_LITERAL:\r
1301                 fta_forbidden = ! se->get_data_type()->fta_legal_type();\r
1302                 colref_source = SPLIT_FTAVEC_NOTBLVAR;\r
1303                 ret_se = new scalarexp_t(se->get_literal());\r
1304                 ret_se->use_decorations_of(se);\r
1305                 return(ret_se);\r
1306 \r
1307     case SE_PARAM:\r
1308                 fta_forbidden = ! se->get_data_type()->fta_legal_type();\r
1309                 colref_source = SPLIT_FTAVEC_NOTBLVAR;\r
1310                 ret_se = scalarexp_t::make_param_reference(se->get_op().c_str());\r
1311                 ret_se->use_decorations_of(se);\r
1312                 return(ret_se);\r
1313 \r
1314         case SE_IFACE_PARAM:\r
1315                 fta_forbidden = false;\r
1316                 colref_source = se->get_ifpref()->get_tablevar_ref();\r
1317                 ret_se = scalarexp_t::make_iface_param_reference(se->get_ifpref());\r
1318                 ret_se->use_decorations_of(se);\r
1319                 return(ret_se);\r
1320 \r
1321     case SE_COLREF:\r
1322 //                      No colref should be forbidden,\r
1323 //                      the schema is wrong, the fta_legal_type() fcn is wrong,\r
1324 //                      or the source table is actually a stream.\r
1325 //                      Issue a warning, but proceed with processing.\r
1326 //                      Also, should not be a ref to a gbvar.\r
1327 //                      (a gbvar ref only occurs in an aggregation node,\r
1328 //                      and these SEs are rehomed, not split.\r
1329                 fta_forbidden = ! se->get_data_type()->fta_legal_type();\r
1330                 colref_source = se->get_colref()->get_tablevar_ref();\r
1331 \r
1332                 if(fta_forbidden && is_PROTOCOL_source(colref_source, lfta_select_list)){\r
1333                         fprintf(stderr,"WARNING, a PROTOCOL colref is a forbidden data type in split_ftavec_se,"\r
1334                                                         " colref is %s,"\r
1335                                                         " type is %s, line=%d, col=%d\n",\r
1336                                                         se->get_colref()->to_string().c_str(),\r
1337                                                         se->get_data_type()->to_string().c_str(),\r
1338                                                         se->lineno, se->charno\r
1339                                         );\r
1340                 }\r
1341 \r
1342                 if(se->is_gb()){\r
1343                         fta_forbidden = true;   // eval in hfta.  ASSUME make copy as below.\r
1344                 }\r
1345 \r
1346                 ret_se = new scalarexp_t(se->get_colref());\r
1347                 ret_se->use_decorations_of(se);\r
1348                 return(ret_se);\r
1349 \r
1350     case SE_UNARY_OP:\r
1351                  l_se = split_ftavec_se(se->get_left_se(), l_forbid, colref_source, lfta_select_list, Ext_fcns);\r
1352 \r
1353                  this_forbid = ! dt->fta_legal_operation(l_se->get_data_type(), se->get_op());\r
1354 \r
1355 //                      If this operation is forbidden but the child SE is not,\r
1356 //                      AND the colref source in the se is a single PROTOCOL source\r
1357 //                      put the child se on the lfta_select_list, create a colref\r
1358 //                      which accesses this se, and make it the child of this op.\r
1359 //                      Exception : the child se is constant (only literal refs).\r
1360 //                      TODO: I think the exception is expressed by is_PROTOCOL_source\r
1361                  if(this_forbid && !l_forbid && is_PROTOCOL_source(colref_source, lfta_select_list)){\r
1362                          if(!is_literal_or_param_only(l_se)){\r
1363                                  new_se = make_fta_se_ref(lfta_select_list, l_se,colref_source);\r
1364                                  ret_se = new scalarexp_t(se->get_op().c_str(), new_se);\r
1365                          }\r
1366                  }else{\r
1367                          ret_se = new scalarexp_t(se->get_op().c_str(), l_se);\r
1368                  }\r
1369                  ret_se->use_decorations_of(se);\r
1370                  fta_forbidden = this_forbid | l_forbid;\r
1371                  return(ret_se);\r
1372 \r
1373     case SE_BINARY_OP:\r
1374                  l_se = split_ftavec_se(se->get_left_se(), l_forbid, l_csource, lfta_select_list, Ext_fcns);\r
1375                  r_se = split_ftavec_se(se->get_right_se(), r_forbid, r_csource, lfta_select_list, Ext_fcns);\r
1376 \r
1377                  this_forbid = ! dt->fta_legal_operation(l_se->get_data_type(), r_se->get_data_type(), se->get_op());\r
1378                  colref_source=combine_colref_source(l_csource, r_csource);\r
1379 \r
1380 //                      Replace the left se if the parent must be hfta but the child can\r
1381 //                      be lfta. This translates to\r
1382 //                      a) result is PROTOCOL and forbidden, but left SE is not forbidden\r
1383 //                      OR b) if result is mixed but the left se is PROTOCOL, not forbidden\r
1384                  if( ((this_forbid || r_forbid) && !l_forbid && is_PROTOCOL_source(colref_source, lfta_select_list) ) ||\r
1385                                 (colref_source==SPLIT_FTAVEC_MIXED && !l_forbid &&\r
1386                                  is_PROTOCOL_source(l_csource, lfta_select_list)) ){\r
1387                          if(!is_literal_or_param_only(l_se)){\r
1388                                  new_se = make_fta_se_ref(lfta_select_list, l_se,l_csource);\r
1389                                  l_se = new_se;\r
1390                          }\r
1391                  }\r
1392 \r
1393 //                      same logic as for right se.\r
1394                  if( ((this_forbid || l_forbid) && !r_forbid && is_PROTOCOL_source(colref_source, lfta_select_list) ) ||\r
1395                                 (colref_source==SPLIT_FTAVEC_MIXED && !r_forbid &&\r
1396                                  is_PROTOCOL_source(r_csource, lfta_select_list)) ){\r
1397                          if(!is_literal_or_param_only(r_se)){\r
1398                                  new_se = make_fta_se_ref(lfta_select_list, r_se,r_csource);\r
1399                                  r_se = new_se;\r
1400                          }\r
1401                  }\r
1402 \r
1403                  ret_se = new scalarexp_t(se->get_op().c_str(), l_se, r_se);\r
1404                  ret_se->use_decorations_of(se);\r
1405                  fta_forbidden = this_forbid || r_forbid || l_forbid;\r
1406 \r
1407                  return(ret_se);\r
1408 \r
1409     case SE_AGGR_STAR:\r
1410     case SE_AGGR_SE:\r
1411 \r
1412                 fprintf(stderr,"INTERNAL ERROR, aggregate ref (%s) in split_ftavec_se."\r
1413                                                 " line=%d, col=%d\n",\r
1414                                                 se->get_op().c_str(),\r
1415                                                 se->lineno, se->charno\r
1416                                 );\r
1417                 exit(1);\r
1418                 break;\r
1419 \r
1420         case SE_FUNC:\r
1421                 {\r
1422                         operand_list = se->get_operands();\r
1423                         vector<scalarexp_t *> new_operands;\r
1424                         vector<bool> forbidden_op;\r
1425                         vector<int> csource;\r
1426 \r
1427                         fta_forbidden = false;\r
1428                         colref_source = SPLIT_FTAVEC_NOTBLVAR;\r
1429                         for(p=0;p<operand_list.size();p++){\r
1430                                 l_se = split_ftavec_se(operand_list[p], l_forbid, l_csource, lfta_select_list, Ext_fcns);\r
1431 \r
1432                                 fta_forbidden |= l_forbid;\r
1433                                 colref_source = combine_colref_source(colref_source, l_csource);\r
1434                                 new_operands.push_back(l_se);\r
1435                                 forbidden_op.push_back(l_forbid);\r
1436                                 csource.push_back(l_csource);\r
1437                                 dt_signature.push_back(operand_list[p]->get_data_type() );\r
1438                         }\r
1439 \r
1440                         fcn_id = Ext_fcns->lookup_fcn(se->get_op(), dt_signature);\r
1441                         if( fcn_id < 0 ){\r
1442                                 fprintf(stderr,"ERROR, no external function %s(",se->get_op().c_str());\r
1443                                 int o;\r
1444                                 for(o=0;o<operand_list.size();o++){\r
1445                                         if(o>0) fprintf(stderr,", ");\r
1446                                         fprintf(stderr,"%s",operand_list[o]->get_data_type()->to_string().c_str());\r
1447                                 }\r
1448                                 fprintf(stderr,") is defined, line %d, char %d\n", se->get_lineno(), se->get_charno() );\r
1449                         if(fcn_id == -2) fprintf(stderr,"(multiple subsuming functions found)\n");\r
1450                                 return NULL;\r
1451                         }\r
1452 \r
1453                         fta_forbidden |= (! Ext_fcns->fta_legal(fcn_id));\r
1454 \r
1455 //                              Replace the non-forbidden operands.\r
1456 //                              the forbidden ones are already replaced.\r
1457                         if(fta_forbidden || colref_source == SPLIT_FTAVEC_MIXED){\r
1458                                 for(p=0;p<new_operands.size();p++){\r
1459                                         if(! forbidden_op[p] && is_PROTOCOL_source(csource[p], lfta_select_list)){\r
1460                                                 if(!is_literal_or_param_only(new_operands[p])){\r
1461                                                 new_se = make_fta_se_ref(lfta_select_list, new_operands[p],csource[p]);\r
1462                                                 new_operands[p] = new_se;\r
1463                                           }\r
1464                                         }\r
1465                                 }\r
1466                         }\r
1467 \r
1468                         ret_se = new scalarexp_t(se->get_op().c_str(), new_operands);\r
1469                         ret_se->use_decorations_of(se);\r
1470 \r
1471                         return(ret_se);\r
1472 \r
1473                 }\r
1474         default:\r
1475                 printf("INTERNAL ERROR in split_ftavec_se: operator type %d\n",se->get_operator_type());\r
1476                 exit(1);\r
1477         break;\r
1478   }\r
1479   return(NULL);\r
1480 \r
1481 }\r
1482 \r
1483 \r
1484 //              The predicates have already been\r
1485 //              broken into conjunctions.\r
1486 //              If any part of a conjunction is fta-forbidden,\r
1487 //              it must be executed in the stream operator.\r
1488 //              Else it is executed in the FTA.\r
1489 //              A pre-analysis should determine whether this\r
1490 //              predicate is fta-safe.  This procedure will\r
1491 //              assume that it is fta-forbidden and will\r
1492 //              prepare it for execution in the stream.\r
1493 \r
1494 predicate_t *split_ftavec_pr(predicate_t *pr,\r
1495                                   vector< vector<select_element *> *> &lfta_select_list,\r
1496                                                  ext_fcn_list *Ext_fcns\r
1497                                                  ){\r
1498 \r
1499   vector<literal_t *> llist;\r
1500   scalarexp_t *se_l, *se_r;\r
1501   bool l_forbid, r_forbid;\r
1502   int l_csource, r_csource;\r
1503   predicate_t *ret_pr, *pr_l, *pr_r;\r
1504   vector<scalarexp_t *> op_list, new_op_list;\r
1505   int o;\r
1506   vector<data_type *> dt_signature;\r
1507 \r
1508 \r
1509         switch(pr->get_operator_type()){\r
1510         case PRED_IN:\r
1511                 se_l = split_ftavec_se(pr->get_left_se(), l_forbid, l_csource, lfta_select_list, Ext_fcns);\r
1512 \r
1513 //                              TODO: checking that the se is a PROTOCOL source should\r
1514 //                              take care of literal_or_param_only.\r
1515                 if(!l_forbid && is_PROTOCOL_source(l_csource, lfta_select_list)){\r
1516                   if(!is_literal_or_param_only(se_l)){\r
1517                         scalarexp_t *new_se = make_fta_se_ref(lfta_select_list, se_l,l_csource);\r
1518                         se_l = new_se;\r
1519                   }\r
1520                 }\r
1521                 ret_pr = new predicate_t(se_l, pr->get_lit_vec());\r
1522 \r
1523                 return(ret_pr);\r
1524 \r
1525         case PRED_COMPARE:\r
1526                 se_l = split_ftavec_se(pr->get_left_se(), l_forbid, l_csource, lfta_select_list, Ext_fcns);\r
1527                 if(!l_forbid  && is_PROTOCOL_source(l_csource, lfta_select_list)){\r
1528                   if(!is_literal_or_param_only(se_l)){\r
1529                         scalarexp_t *new_se = make_fta_se_ref(lfta_select_list, se_l,l_csource);\r
1530                         se_l = new_se;\r
1531                   }\r
1532                 }\r
1533 \r
1534                 se_r = split_ftavec_se(pr->get_right_se(), r_forbid, r_csource, lfta_select_list, Ext_fcns);\r
1535                 if(!r_forbid  && is_PROTOCOL_source(r_csource, lfta_select_list)){\r
1536                   if(!is_literal_or_param_only(se_r)){\r
1537                         scalarexp_t *new_se = make_fta_se_ref(lfta_select_list, se_r,r_csource);\r
1538                         se_r = new_se;\r
1539                   }\r
1540                 }\r
1541 \r
1542                 ret_pr = new predicate_t(se_l, pr->get_op().c_str(), se_r);\r
1543                 return(ret_pr);\r
1544 \r
1545         case PRED_UNARY_OP:\r
1546                 pr_l = split_ftavec_pr(pr->get_left_pr(), lfta_select_list, Ext_fcns);\r
1547                 ret_pr = new predicate_t(pr->get_op().c_str(), pr_l);\r
1548                 return(ret_pr);\r
1549 \r
1550         case PRED_BINARY_OP:\r
1551                 pr_l = split_ftavec_pr(pr->get_left_pr(), lfta_select_list, Ext_fcns);\r
1552                 pr_r = split_ftavec_pr(pr->get_right_pr(), lfta_select_list, Ext_fcns);\r
1553                 ret_pr = new predicate_t(pr->get_op().c_str(), pr_l, pr_r);\r
1554                 return(ret_pr);\r
1555 \r
1556         case PRED_FUNC:\r
1557 //                      I can't push the predicate into the lfta, except by\r
1558 //                      returning a bool value, and that is not worth the trouble,\r
1559                 op_list = pr->get_op_list();\r
1560                 for(o=0;o<op_list.size();++o){\r
1561                         se_l = split_ftavec_se(op_list[o],l_forbid,l_csource,lfta_select_list,Ext_fcns);\r
1562                         if(!l_forbid && is_PROTOCOL_source(l_csource, lfta_select_list)){\r
1563                           if(!is_literal_or_param_only(se_l)){\r
1564                                 scalarexp_t *new_se = make_fta_se_ref(lfta_select_list, se_l,l_csource);\r
1565                                 se_l = new_se;\r
1566                           }\r
1567                         }\r
1568                         new_op_list.push_back(se_l);\r
1569                 }\r
1570 \r
1571                 ret_pr =  new predicate_t(pr->get_op().c_str(), new_op_list);\r
1572                 ret_pr->set_fcn_id(pr->get_fcn_id());\r
1573                 return(ret_pr);\r
1574         default:\r
1575                 fprintf(stderr,"INTERNAL ERROR in split_fta_pr, line %d, character %d, unknown predicate operator type %d\n",\r
1576                         pr->get_lineno(), pr->get_charno(), pr->get_operator_type() );\r
1577                 exit(1);\r
1578         }\r
1579 \r
1580         return(0);\r
1581 \r
1582 }\r
1583 \r
1584 \r
1585 \r
1586 ////////////////////////////////////////////////////////////////////////\r
1587 ///             rehome_hfta_se rehome_hfta_pr\r
1588 ///             This is use to split an sgah operator (aggregation),\r
1589 ///             I just need to make gb, aggr references point to the\r
1590 ///             new gb, aggr table entries.\r
1591 \r
1592 \r
1593 scalarexp_t *rehome_fta_se(scalarexp_t *se,\r
1594                                   map< int, scalarexp_t * > *aggr_map\r
1595                                  ){\r
1596 \r
1597   int p, fcn_id;\r
1598   int agr_id;\r
1599   vector<scalarexp_t *> operand_list;\r
1600   scalarexp_t *ret_se, *l_se, *r_se;\r
1601   colref_t *new_cr;\r
1602   scalarexp_t *new_se;\r
1603   data_type *dt = se->get_data_type();\r
1604   vector<scalarexp_t *> new_operands;\r
1605 \r
1606   switch(se->get_operator_type()){\r
1607     case SE_LITERAL:\r
1608                 ret_se = new scalarexp_t(se->get_literal());\r
1609                 ret_se->use_decorations_of(se);\r
1610                 return(ret_se);\r
1611 \r
1612     case SE_PARAM:\r
1613                 ret_se = scalarexp_t::make_param_reference(se->get_op().c_str());\r
1614                 ret_se->use_decorations_of(se);\r
1615                 return(ret_se);\r
1616 \r
1617         case SE_IFACE_PARAM:\r
1618                 ret_se = scalarexp_t::make_iface_param_reference(se->get_ifpref());\r
1619                 ret_se->use_decorations_of(se);\r
1620                 return(ret_se);\r
1621 \r
1622 \r
1623 \r
1624     case SE_COLREF:\r
1625 //                      Must be a GB REF ...\r
1626 //                      I'm assuming that the hfta gbvar table has the\r
1627 //                      same sequence of entries as the input query's gbvar table.\r
1628 //                      Else I'll need some kind of translation table.\r
1629 \r
1630                 if(! se->is_gb()){\r
1631                         fprintf(stderr,"WARNING, a colref is not a gbver ref in rehome_hfta_se"\r
1632                                                         " type is %s, line=%d, col=%d\n",\r
1633                                                         se->get_data_type()->to_string().c_str(),\r
1634                                                         se->lineno, se->charno\r
1635                                         );\r
1636                 }\r
1637 \r
1638                 ret_se = new scalarexp_t(se->get_colref());\r
1639                 ret_se->use_decorations_of(se);         // just inherit the gbref\r
1640                 return(ret_se);\r
1641 \r
1642     case SE_UNARY_OP:\r
1643                  l_se = rehome_fta_se(se->get_left_se(), aggr_map);\r
1644 \r
1645                  ret_se = new scalarexp_t(se->get_op().c_str(), l_se);\r
1646                  ret_se->use_decorations_of(se);\r
1647                  return(ret_se);\r
1648 \r
1649     case SE_BINARY_OP:\r
1650                  l_se = rehome_fta_se(se->get_left_se(), aggr_map);\r
1651                  r_se = rehome_fta_se(se->get_right_se(), aggr_map);\r
1652 \r
1653                  ret_se = new scalarexp_t(se->get_op().c_str(), l_se, r_se);\r
1654                  ret_se->use_decorations_of(se);\r
1655 \r
1656                  return(ret_se);\r
1657 \r
1658     case SE_AGGR_STAR:\r
1659     case SE_AGGR_SE:\r
1660                 agr_id = se->get_aggr_ref();\r
1661                 return (*aggr_map)[agr_id];\r
1662                 break;\r
1663 \r
1664         case SE_FUNC:\r
1665                 agr_id = se->get_aggr_ref();\r
1666                 if(agr_id >= 0) return (*aggr_map)[agr_id];\r
1667 \r
1668                 operand_list = se->get_operands();\r
1669                 for(p=0;p<operand_list.size();p++){\r
1670                         l_se = rehome_fta_se(operand_list[p], aggr_map);\r
1671 \r
1672                         new_operands.push_back(l_se);\r
1673                 }\r
1674 \r
1675 \r
1676                 ret_se = new scalarexp_t(se->get_op().c_str(), new_operands);\r
1677                 ret_se->use_decorations_of(se);\r
1678 \r
1679                 return(ret_se);\r
1680 \r
1681         default:\r
1682                 printf("INTERNAL ERROR in rehome_fta_se: operator type %d\n",se->get_operator_type());\r
1683                 exit(1);\r
1684         break;\r
1685   }\r
1686   return(NULL);\r
1687 \r
1688 }\r
1689 \r
1690 \r
1691 //              The predicates have already been\r
1692 //              broken into conjunctions.\r
1693 //              If any part of a conjunction is fta-forbidden,\r
1694 //              it must be executed in the stream operator.\r
1695 //              Else it is executed in the FTA.\r
1696 //              A pre-analysis should determine whether this\r
1697 //              predicate is fta-safe.  This procedure will\r
1698 //              assume that it is fta-forbidden and will\r
1699 //              prepare it for execution in the stream.\r
1700 \r
1701 predicate_t *rehome_fta_pr(predicate_t *pr,\r
1702                                                  map<int, scalarexp_t *> *aggr_map\r
1703                                                  ){\r
1704 \r
1705   vector<literal_t *> llist;\r
1706   scalarexp_t *se_l, *se_r;\r
1707   predicate_t *ret_pr, *pr_l, *pr_r;\r
1708   vector<scalarexp_t *> op_list, new_op_list;\r
1709   int o;\r
1710 \r
1711         switch(pr->get_operator_type()){\r
1712         case PRED_IN:\r
1713                 se_l = rehome_fta_se(pr->get_left_se(), aggr_map);\r
1714                 ret_pr = new predicate_t(se_l, pr->get_lit_vec());\r
1715                 return(ret_pr);\r
1716 \r
1717         case PRED_COMPARE:\r
1718                 se_l = rehome_fta_se(pr->get_left_se(), aggr_map);\r
1719                 se_r = rehome_fta_se(pr->get_right_se(), aggr_map);\r
1720                 ret_pr = new predicate_t(se_l, pr->get_op().c_str(), se_r);\r
1721                 return(ret_pr);\r
1722 \r
1723         case PRED_UNARY_OP:\r
1724                 pr_l = rehome_fta_pr(pr->get_left_pr(), aggr_map);\r
1725                 ret_pr = new predicate_t(pr->get_op().c_str(), pr_l);\r
1726                 return(ret_pr);\r
1727 \r
1728         case PRED_BINARY_OP:\r
1729                 pr_l = rehome_fta_pr(pr->get_left_pr(), aggr_map);\r
1730                 pr_r = rehome_fta_pr(pr->get_right_pr(), aggr_map);\r
1731                 ret_pr = new predicate_t(pr->get_op().c_str(), pr_l, pr_r);\r
1732                 return(ret_pr);\r
1733 \r
1734         case PRED_FUNC:\r
1735                 op_list = pr->get_op_list();\r
1736                 for(o=0;o<op_list.size();++o){\r
1737                         se_l = rehome_fta_se(op_list[o], aggr_map);\r
1738                         new_op_list.push_back(se_l);\r
1739                 }\r
1740                 ret_pr=  new predicate_t(pr->get_op().c_str(), new_op_list);\r
1741                 ret_pr->set_fcn_id(pr->get_fcn_id());\r
1742                 return(ret_pr);\r
1743 \r
1744         default:\r
1745                 fprintf(stderr,"INTERNAL ERROR in rehome_fta_pr, line %d, character %d, unknown predicate operator type %d\n",\r
1746                         pr->get_lineno(), pr->get_charno(), pr->get_operator_type() );\r
1747                 exit(1);\r
1748         }\r
1749 \r
1750         return(0);\r
1751 \r
1752 }\r
1753 \r
1754 \r
1755 ////////////////////////////////////////////////////////////////////\r
1756 /////////////////               Create a STREAM table to represent the FTA output.\r
1757 \r
1758 table_def *create_attributes(string tname, vector<select_element *> &select_list){\r
1759         int s;\r
1760 \r
1761 \r
1762 //                      Create a new STREAM schema for the output of the FTA.\r
1763 \r
1764         field_entry_list *fel = new field_entry_list();\r
1765         set<string> ufcns;\r
1766         for(s=0;s<select_list.size();s++){\r
1767                 scalarexp_t *sel_se = select_list[s]->se;\r
1768                 data_type *dt = sel_se->get_data_type();\r
1769 \r
1770 //                      Grab the annotations of the field.\r
1771 //                      As of this writing, the only meaningful annotations\r
1772 //                      are whether or not the attribute is temporal.\r
1773 //                      There can be an annotation of constant_t, but\r
1774 //                      I'll ignore this, it feels like an unsafe assumption\r
1775                 param_list *plist = new param_list();\r
1776 //              if(dt->is_temporal()){\r
1777                         vector<string> param_strings = dt->get_param_keys();\r
1778                         int p;\r
1779                         for(p=0;p<param_strings.size();++p){\r
1780                                 string v = dt->get_param_val(param_strings[p]);\r
1781                                 if(v != "")\r
1782                                         plist->append(param_strings[p].c_str(),v.c_str());\r
1783                                 else\r
1784                                         plist->append(param_strings[p].c_str());\r
1785                         }\r
1786 //              }\r
1787 \r
1788 //              char access_fcn_name[500];\r
1789                 string colname = select_list[s]->name;\r
1790 //              sprintf(access_fcn_name,"get_field_%s",colname.c_str());\r
1791                 string access_fcn_name = "get_field_"+colname;\r
1792                 field_entry *fe = new field_entry(\r
1793                         dt->get_type_str(), colname, access_fcn_name, plist, ufcns\r
1794                 );\r
1795 \r
1796                 fel->append_field(fe);\r
1797         }\r
1798 \r
1799         table_def *fta_tbl = new table_def(\r
1800                 tname.c_str(), NULL, NULL, fel, STREAM_SCHEMA\r
1801         );\r
1802 \r
1803         return(fta_tbl);\r
1804 \r
1805 }\r
1806 \r
1807 //------------------------------------------------------------------\r
1808 //              Textual representation of the query node.\r
1809 \r
1810 \r
1811 \r
1812 string spx_qpn::to_query_string(){\r
1813 \r
1814         string ret = "Select ";\r
1815         int s;\r
1816         for(s=0;s<select_list.size();s++){\r
1817                 if(s>0) ret+=", ";\r
1818                 ret += se_to_query_string(select_list[s]->se, NULL);\r
1819                 if(select_list[s]->name != "") ret += " AS "+select_list[s]->name;\r
1820         }\r
1821         ret += "\n";\r
1822 \r
1823         ret += "From "+table_name->to_string()+"\n";\r
1824 \r
1825         if(where.size() > 0){\r
1826                 ret += "Where ";\r
1827                 int w;\r
1828                 for(w=0;w<where.size();w++){\r
1829                         if(w>0) ret += " AND ";\r
1830                         ret += "(" + pred_to_query_str(where[w]->pr,NULL) + ")";\r
1831                 }\r
1832                 ret += "\n";\r
1833         }\r
1834 \r
1835         return(ret);\r
1836 }\r
1837 \r
1838 \r
1839 \r
1840 \r
1841 string sgah_qpn::to_query_string(){\r
1842 \r
1843         string ret = "Select ";\r
1844         int s;\r
1845         for(s=0;s<select_list.size();s++){\r
1846                 if(s>0) ret+=", ";\r
1847                 ret += se_to_query_string(select_list[s]->se, &aggr_tbl);\r
1848                 if(select_list[s]->name != "") ret += " AS "+select_list[s]->name;\r
1849         }\r
1850         ret += "\n";\r
1851 \r
1852         ret += "From "+table_name->to_string()+"\n";\r
1853 \r
1854         if(where.size() > 0){\r
1855                 ret += "Where ";\r
1856                 int w;\r
1857                 for(w=0;w<where.size();w++){\r
1858                         if(w>0) ret += " AND ";\r
1859                         ret += "(" + pred_to_query_str(where[w]->pr,&aggr_tbl) + ")";\r
1860                 }\r
1861                 ret += "\n";\r
1862         }\r
1863 \r
1864         if(gb_tbl.size() > 0){\r
1865                 ret += "Group By ";\r
1866                 int g;\r
1867                 if(gb_tbl.gb_patterns.size() <= 1 || gb_tbl.gb_entry_type.size()==0){\r
1868                         for(g=0;g<gb_tbl.size();g++){\r
1869                                 if(g>0) ret += ", ";\r
1870 //                      if(gb_tbl.get_reftype(g) == GBVAR_SE){\r
1871                                         ret += se_to_query_string(gb_tbl.get_def(g), &aggr_tbl) + " AS ";\r
1872 //                      }\r
1873                                 ret += gb_tbl.get_name(g);\r
1874                         }\r
1875                 }else{\r
1876                         int gb_pos = 0;\r
1877                         for(g=0;g<gb_tbl.gb_entry_type.size();++g){\r
1878                                 if(g>0) ret += ", ";\r
1879                                 if(gb_tbl.gb_entry_type[g] == ""){\r
1880                                         ret += se_to_query_string(gb_tbl.get_def(gb_pos),&aggr_tbl)+\r
1881                                                 " AS "+ gb_tbl.get_name(gb_pos);\r
1882                                         gb_pos++;\r
1883                                 }\r
1884                                 if(gb_tbl.gb_entry_type[g] == "CUBE" ||\r
1885                                                 gb_tbl.gb_entry_type[g] == "ROLLUP"){\r
1886                                         ret += gb_tbl.gb_entry_type[g] + "(";\r
1887                                         int gg = 0;\r
1888                                         for(gg=0;gg<gb_tbl.gb_entry_count[g];++gg){\r
1889                                                 if(gg>0) ret += ", ";\r
1890                                                 ret += se_to_query_string(gb_tbl.get_def(gb_pos),&aggr_tbl)+ " AS "+ gb_tbl.get_name(gb_pos);\r
1891                                                 gb_pos++;\r
1892                                         }\r
1893                                         ret += ")";\r
1894                                 }\r
1895                                 if(gb_tbl.gb_entry_type[g] == "GROUPING_SETS"){\r
1896                                         ret += gb_tbl.gb_entry_type[g] + "(";\r
1897                                         int g1, g2;\r
1898                                         vector<vector<bool> > &local_components = gb_tbl.pattern_components[g];\r
1899                                         for(g1=0;g1<local_components.size();++g1){\r
1900                                                 if(g1>0) ret+=",";\r
1901                                                 bool first_field = true;\r
1902                                                 ret += "\n\t\t(";\r
1903                                                 for(g2=0;g2<=gb_tbl.gb_entry_count[g];g2++){\r
1904                                                         if(local_components[g1][g2]){\r
1905                                                                 if(!first_field) ret+=", ";\r
1906                                                                 else first_field = false;\r
1907                                                                 ret +=  gb_tbl.get_name(gb_pos+g2);\r
1908                                                         }\r
1909                                                 }\r
1910                                                 ret += ")";\r
1911                                         }\r
1912                                         ret += ") ";\r
1913                                         gb_pos += gb_tbl.gb_entry_count[g];\r
1914                                 }\r
1915                         }\r
1916                 }\r
1917                 ret += "\n";\r
1918         }\r
1919 \r
1920         if(having.size() > 0){\r
1921                 ret += "Having ";\r
1922                 int h;\r
1923                 for(h=0;h<having.size();h++){\r
1924                         if(h>0) ret += " AND ";\r
1925                         ret += "(" + pred_to_query_str(having[h]->pr,&aggr_tbl) + ")";\r
1926                 }\r
1927                 ret += "\n";\r
1928         }\r
1929 \r
1930         return(ret);\r
1931 }\r
1932 \r
1933 \r
1934 string rsgah_qpn::to_query_string(){\r
1935 \r
1936         string ret = "Select ";\r
1937         int s;\r
1938         for(s=0;s<select_list.size();s++){\r
1939                 if(s>0) ret+=", ";\r
1940                 ret += se_to_query_string(select_list[s]->se, &aggr_tbl);\r
1941                 if(select_list[s]->name != "") ret += " AS "+select_list[s]->name;\r
1942         }\r
1943         ret += "\n";\r
1944 \r
1945         ret += "From "+table_name->to_string()+"\n";\r
1946 \r
1947         if(where.size() > 0){\r
1948                 ret += "Where ";\r
1949                 int w;\r
1950                 for(w=0;w<where.size();w++){\r
1951                         if(w>0) ret += " AND ";\r
1952                         ret += "(" + pred_to_query_str(where[w]->pr,&aggr_tbl) + ")";\r
1953                 }\r
1954                 ret += "\n";\r
1955         }\r
1956 \r
1957         if(gb_tbl.size() > 0){\r
1958                 ret += "Group By ";\r
1959                 int g;\r
1960                 for(g=0;g<gb_tbl.size();g++){\r
1961                         if(g>0) ret += ", ";\r
1962 //                      if(gb_tbl.get_reftype(g) == GBVAR_SE){\r
1963                                 ret += se_to_query_string(gb_tbl.get_def(g), &aggr_tbl)+" AS ";\r
1964 //                      }\r
1965                         ret += gb_tbl.get_name(g);\r
1966                 }\r
1967                 ret += "\n";\r
1968         }\r
1969 \r
1970         if(having.size() > 0){\r
1971                 ret += "Having ";\r
1972                 int h;\r
1973                 for(h=0;h<having.size();h++){\r
1974                         if(h>0) ret += " AND ";\r
1975                         ret += "(" + pred_to_query_str(having[h]->pr,&aggr_tbl) + ")";\r
1976                 }\r
1977                 ret += "\n";\r
1978         }\r
1979 \r
1980         if(closing_when.size() > 0){\r
1981                 ret += "Closing_When ";\r
1982                 int h;\r
1983                 for(h=0;h<closing_when.size();h++){\r
1984                         if(h>0) ret += " AND ";\r
1985                         ret += "(" + pred_to_query_str(closing_when[h]->pr,&aggr_tbl) + ")";\r
1986                 }\r
1987                 ret += "\n";\r
1988         }\r
1989 \r
1990         return(ret);\r
1991 }\r
1992 \r
1993 \r
1994 string sgahcwcb_qpn::to_query_string(){\r
1995 \r
1996         string ret = "Select ";\r
1997         int s;\r
1998         for(s=0;s<select_list.size();s++){\r
1999                 if(s>0) ret+=", ";\r
2000                 ret += se_to_query_string(select_list[s]->se, &aggr_tbl);\r
2001                 if(select_list[s]->name != "") ret += " AS "+select_list[s]->name;\r
2002         }\r
2003         ret += "\n";\r
2004 \r
2005         ret += "From "+table_name->to_string()+"\n";\r
2006 \r
2007         if(where.size() > 0){\r
2008                 ret += "Where ";\r
2009                 int w;\r
2010                 for(w=0;w<where.size();w++){\r
2011                         if(w>0) ret += " AND ";\r
2012                         ret += "(" + pred_to_query_str(where[w]->pr,&aggr_tbl) + ")";\r
2013                 }\r
2014                 ret += "\n";\r
2015         }\r
2016 \r
2017         if(gb_tbl.size() > 0){\r
2018                 ret += "Group By ";\r
2019                 int g;\r
2020                 for(g=0;g<gb_tbl.size();g++){\r
2021                         if(g>0) ret += ", ";\r
2022 //                      if(gb_tbl.get_reftype(g) == GBVAR_SE){\r
2023                                 ret += se_to_query_string(gb_tbl.get_def(g), &aggr_tbl) + " AS ";\r
2024 //                      }\r
2025                         ret += gb_tbl.get_name(g);\r
2026                 }\r
2027                 ret += "\n";\r
2028         }\r
2029 \r
2030         if(sg_tbl.size() > 0){\r
2031                 ret += "Supergroup ";\r
2032                 int g;\r
2033                 bool first_elem = true;\r
2034                 for(g=0;g<gb_tbl.size();g++){\r
2035                         if(sg_tbl.count(g)){\r
2036                                 if(first_elem){\r
2037                                         ret += ", ";\r
2038                                         first_elem = false;\r
2039                                 }\r
2040                                 ret += gb_tbl.get_name(g);\r
2041                         }\r
2042                 }\r
2043                 ret += "\n";\r
2044         }\r
2045 \r
2046         if(having.size() > 0){\r
2047                 ret += "Having ";\r
2048                 int h;\r
2049                 for(h=0;h<having.size();h++){\r
2050                         if(h>0) ret += " AND ";\r
2051                         ret += "(" + pred_to_query_str(having[h]->pr,&aggr_tbl) + ")";\r
2052                 }\r
2053                 ret += "\n";\r
2054         }\r
2055 \r
2056 \r
2057         if(cleanwhen.size() > 0){\r
2058                 ret += "Cleaning_When ";\r
2059                 int h;\r
2060                 for(h=0;h<cleanwhen.size();h++){\r
2061                         if(h>0) ret += " AND ";\r
2062                         ret += "(" + pred_to_query_str(cleanwhen[h]->pr,&aggr_tbl) + ")";\r
2063                 }\r
2064                 ret += "\n";\r
2065         }\r
2066 \r
2067         if(cleanby.size() > 0){\r
2068                 ret += "Cleaning_By ";\r
2069                 int h;\r
2070                 for(h=0;h<cleanby.size();h++){\r
2071                         if(h>0) ret += " AND ";\r
2072                         ret += "(" + pred_to_query_str(cleanby[h]->pr,&aggr_tbl) + ")";\r
2073                 }\r
2074                 ret += "\n";\r
2075         }\r
2076 \r
2077         return(ret);\r
2078 }\r
2079 \r
2080 \r
2081 string mrg_qpn::to_query_string(){\r
2082 \r
2083         string ret="Merge ";\r
2084         ret += mvars[0]->to_query_string() + " : " + mvars[1]->to_query_string();\r
2085         if(slack != NULL){\r
2086                 ret += " SLACK "+se_to_query_string(slack, NULL);\r
2087         }\r
2088 \r
2089         ret += "\nFrom ";\r
2090         int t;\r
2091         for(t=0;t<fm.size();++t){\r
2092                 if(t>0) ret += ", ";\r
2093                 ret += fm[t]->to_string();\r
2094         }\r
2095         ret += "\n";\r
2096 \r
2097         return(ret);\r
2098 }\r
2099 \r
2100 string join_eq_hash_qpn::to_query_string(){\r
2101 \r
2102         string ret = "Select ";\r
2103         int s;\r
2104         for(s=0;s<select_list.size();s++){\r
2105                 if(s>0) ret+=", ";\r
2106                 ret += se_to_query_string(select_list[s]->se, NULL);\r
2107                 if(select_list[s]->name != "") ret += " AS "+select_list[s]->name;\r
2108         }\r
2109         ret += "\n";\r
2110 \r
2111 //                      NOTE: assuming binary join.\r
2112         int properties = from[0]->get_property()+2*from[1]->get_property();\r
2113         switch(properties){\r
2114         case 0:\r
2115                 ret += "INNER_JOIN ";\r
2116                 break;\r
2117         case 1:\r
2118                 ret += "LEFT_OUTER_JOIN ";\r
2119                 break;\r
2120         case 2:\r
2121                 ret += "RIGHT_OUTER_JOIN ";\r
2122                 break;\r
2123         case 3:\r
2124                 ret += "OUTER_JOIN ";\r
2125                 break;\r
2126         }\r
2127 \r
2128         ret += "From ";\r
2129         int f;\r
2130         for(f=0;f<from.size();++f){\r
2131                 if(f>0) ret+=", ";\r
2132                 ret += from[f]->to_string();\r
2133         }\r
2134         ret += "\n";\r
2135 \r
2136         if(where.size() > 0){\r
2137                 ret += "Where ";\r
2138                 int w;\r
2139                 for(w=0;w<where.size();w++){\r
2140                         if(w>0) ret += " AND ";\r
2141                         ret += "(" + pred_to_query_str(where[w]->pr,NULL) + ")";\r
2142                 }\r
2143                 ret += "\n";\r
2144         }\r
2145 \r
2146         return(ret);\r
2147 }\r
2148 \r
2149 string filter_join_qpn::to_query_string(){\r
2150 \r
2151         string ret = "Select ";\r
2152         int s;\r
2153         for(s=0;s<select_list.size();s++){\r
2154                 if(s>0) ret+=", ";\r
2155                 ret += se_to_query_string(select_list[s]->se, NULL);\r
2156                 if(select_list[s]->name != "") ret += " AS "+select_list[s]->name;\r
2157         }\r
2158         ret += "\n";\r
2159 \r
2160 //                      NOTE: assuming binary join.\r
2161         ret += "FILTER_JOIN("+temporal_var->field+","+int_to_string(temporal_range)+") ";\r
2162 \r
2163         ret += "From ";\r
2164         int f;\r
2165         for(f=0;f<from.size();++f){\r
2166                 if(f>0) ret+=", ";\r
2167                 ret += from[f]->to_string();\r
2168         }\r
2169         ret += "\n";\r
2170 \r
2171         if(where.size() > 0){\r
2172                 ret += "Where ";\r
2173                 int w;\r
2174                 for(w=0;w<where.size();w++){\r
2175                         if(w>0) ret += " AND ";\r
2176                         ret += "(" + pred_to_query_str(where[w]->pr,NULL) + ")";\r
2177                 }\r
2178                 ret += "\n";\r
2179         }\r
2180 \r
2181         return(ret);\r
2182 }\r
2183 \r
2184 \r
2185 // -----------------------------------------------------------------\r
2186 //              Query node subclass specific processing.\r
2187 \r
2188 \r
2189 vector<mrg_qpn *> mrg_qpn::split_sources(){\r
2190   vector<mrg_qpn *> ret;\r
2191   int i;\r
2192 \r
2193 //                      sanity check\r
2194         if(fm.size() != mvars.size()){\r
2195                 fprintf(stderr,"INTERNAL ERROR in mrg_qpn::split_sources.  fm.size() = %lu, mvars.size() = %lu\n",fm.size(),mvars.size());\r
2196                 exit(1);\r
2197         }\r
2198         if(fm.size() == 1){\r
2199                 fprintf(stderr,"INTERNAL ERROR in mrg_qpn::split_sources, fm size is 1.\n");\r
2200                 exit(1);\r
2201         }\r
2202 \r
2203 /*\r
2204 int ff;\r
2205 printf("spliting sources merge node, name = %s, %d sources.\n\t",node_name.c_str(), fm.size());\r
2206 for(ff=0;ff<fm.size();++ff){\r
2207 printf("%s ",fm[ff]->to_string().c_str());\r
2208 }\r
2209 printf("\n");\r
2210 */\r
2211 \r
2212 //              Handle special cases.\r
2213         if(fm.size() == 2){\r
2214                 ret.push_back(this);\r
2215                 return ret;\r
2216         }\r
2217 \r
2218         if(fm.size() == 3){\r
2219                 mrg_qpn *new_mrg = (mrg_qpn *)this->make_copy("_cH1");\r
2220                 new_mrg->fm.push_back(this->fm[0]);\r
2221                 new_mrg->fm.push_back(this->fm[1]);\r
2222                 new_mrg->mvars.push_back(this->mvars[0]);\r
2223                 new_mrg->mvars.push_back(this->mvars[1]);\r
2224 \r
2225                 this->fm.erase(this->fm.begin());\r
2226                 this->mvars.erase(this->mvars.begin());\r
2227                 string vname = fm[0]->get_var_name();\r
2228                 this->fm[0] = new tablevar_t(new_mrg->node_name.c_str());\r
2229                 this->fm[0]->set_range_var(vname);\r
2230                 this->mvars[0]->set_field(table_layout->get_field_name(merge_fieldpos));\r
2231                 this->mvars[0]->set_tablevar_ref(0);\r
2232                 this->mvars[1]->set_tablevar_ref(1);\r
2233 \r
2234                 ret.push_back(new_mrg);\r
2235                 ret.push_back(this);\r
2236 \r
2237 /*\r
2238 printf("split sources %s (%s %s)\n",node_name.c_str(),new_mrg->node_name.c_str(),this->node_name.c_str());\r
2239 for(i=0;i<new_mrg->fm.size();++i)\r
2240 printf("\tsource %s var %d (%s, %s) \n",new_mrg->node_name.c_str(),i,new_mrg->fm[i]->to_string().c_str(), new_mrg->mvars[i]->to_string().c_str());\r
2241 for(i=0;i<this->fm.size();++i)\r
2242 printf("\tsource %s var %d (%s, %s) \n",this->node_name.c_str(),i,this->fm[i]->to_string().c_str(), this->mvars[i]->to_string().c_str());\r
2243 */\r
2244 \r
2245                 return ret;\r
2246         }\r
2247 \r
2248 //              General case.\r
2249 //              divide up the sources between two children.\r
2250 //              Then, recurse on the children.\r
2251 \r
2252                 mrg_qpn *new_mrg1 = (mrg_qpn *)this->make_copy("_cH1");\r
2253                 mrg_qpn *new_mrg2 = (mrg_qpn *)this->make_copy("_cH2");\r
2254                 for(i=0;i<this->fm.size()/2;++i){\r
2255                         new_mrg1->fm.push_back(this->fm[i]);\r
2256                         new_mrg1->mvars.push_back(this->mvars[i]);\r
2257 //printf("Pushing %d (%s, %s) to new_mrg1\n",i,fm[i]->to_string().c_str(), mvars[i]->to_string().c_str());\r
2258                 }\r
2259                 for(;i<this->fm.size();++i){\r
2260                         new_mrg2->fm.push_back(this->fm[i]);\r
2261                         new_mrg2->mvars.push_back(this->mvars[i]);\r
2262 //printf("Pushing %d (%s, %s) to new_mrg2\n",i,fm[i]->to_string().c_str(), mvars[i]->to_string().c_str());\r
2263                 }\r
2264                 for(i=0;i<new_mrg1->mvars.size();++i)\r
2265                         new_mrg1->mvars[i]->set_tablevar_ref(i);\r
2266                 for(i=0;i<new_mrg2->mvars.size();++i)\r
2267                         new_mrg2->mvars[i]->set_tablevar_ref(i);\r
2268 \r
2269 //                      Children created, make this merge them.\r
2270                 fm.clear();\r
2271                 mvars.clear();\r
2272 //                      var 1\r
2273                 tablevar_t *tmp_tblvar = new tablevar_t(new_mrg1->node_name.c_str());\r
2274                 tmp_tblvar->set_range_var("_mrg_var_1");\r
2275                 fm.push_back(tmp_tblvar);\r
2276                 colref_t *tmp_cref = new colref_t("_mrg_var_1",table_layout->get_field_name(merge_fieldpos).c_str());\r
2277                 tmp_cref->set_tablevar_ref(0);\r
2278                 mvars.push_back(tmp_cref);\r
2279 //                      var 2\r
2280                 tmp_tblvar = new tablevar_t(new_mrg2->node_name.c_str());\r
2281                 tmp_tblvar->set_range_var("_mrg_var_2");\r
2282                 fm.push_back(tmp_tblvar);\r
2283                 tmp_cref = new colref_t("_mrg_var_2",table_layout->get_field_name(merge_fieldpos).c_str());\r
2284                 tmp_cref->set_tablevar_ref(1);\r
2285                 mvars.push_back(tmp_cref);\r
2286 \r
2287 \r
2288 /*\r
2289 printf("split sources %s (%s %s)\n",node_name.c_str(),new_mrg1->node_name.c_str(),new_mrg2->node_name.c_str());\r
2290 for(i=0;i<new_mrg1->fm.size();++i)\r
2291 printf("\tsource %s var %d (%s, %s) \n",new_mrg1->node_name.c_str(),i,new_mrg1->fm[i]->to_string().c_str(), new_mrg1->mvars[i]->to_string().c_str());\r
2292 for(i=0;i<new_mrg2->fm.size();++i)\r
2293 printf("\tsource %s var %d (%s, %s) \n",new_mrg2->node_name.c_str(),i,new_mrg2->fm[i]->to_string().c_str(), new_mrg2->mvars[i]->to_string().c_str());\r
2294 */\r
2295 \r
2296 //              Recurse and put them together\r
2297                 vector<mrg_qpn *> st1 = new_mrg1->split_sources();\r
2298                 ret.insert(ret.end(), st1.begin(), st1.end());\r
2299                 vector<mrg_qpn *> st2 = new_mrg2->split_sources();\r
2300                 ret.insert(ret.end(), st2.begin(), st2.end());\r
2301 \r
2302                 ret.push_back(this);\r
2303 \r
2304                 return(ret);\r
2305 \r
2306 }\r
2307 \r
2308 \r
2309 \r
2310 ////////        Split helper function : resolve interfaces\r
2311 \r
2312 vector<pair<string,string> > get_ifaces(tablevar_t *table, ifq_t *ifdb, int n_virtual_ifaces, int hfta_parallelism, int hfta_idx){\r
2313         vector<pair<string,string> > basic_ifaces;\r
2314         int ierr;\r
2315         if(table->get_ifq()){\r
2316                 basic_ifaces= ifdb->eval(table->get_interface(),ierr);\r
2317                 if(ierr==1){\r
2318                 fprintf(stderr,"ERROR, Interface set %s not found.\n",table->get_interface().c_str());\r
2319                 }\r
2320                 if(ierr==2){\r
2321                         fprintf(stderr,"ERROR, interface definition file didn't parse.\n");\r
2322                 }\r
2323         }else{\r
2324                 basic_ifaces.push_back(make_pair(table->get_machine(), table->get_interface()));\r
2325         }\r
2326 \r
2327         if(n_virtual_ifaces == 1)\r
2328                 return basic_ifaces;\r
2329 \r
2330         int stride = n_virtual_ifaces / hfta_parallelism;\r
2331         int i,s;\r
2332         vector<pair<string,string> > ifaces;\r
2333 \r
2334         for(i=0;i<basic_ifaces.size();++i){\r
2335                 string mach = basic_ifaces[i].first;\r
2336                 string iface = basic_ifaces[i].second;\r
2337                 for(s=hfta_idx*stride;s<(hfta_idx+1)*stride;++s){\r
2338                         ifaces.push_back(pair<string, string>(mach,iface+"X"+int_to_string(2*s)));\r
2339                 }\r
2340         }\r
2341 \r
2342         return ifaces;\r
2343 }\r
2344 \r
2345 \r
2346 /////////       Split helper function : compute slack in a generated\r
2347 /////////       merge.\r
2348 \r
2349 void mrg_qpn::resolve_slack(scalarexp_t *t_se, string fname, vector<pair<string, string> > &sources, ifq_t *ifdb, gb_table *gbt){\r
2350         int s,e,v;\r
2351         string es;\r
2352 \r
2353 //              Find slack divisor, if any.\r
2354         string fnm;\r
2355         long long int slack_divisor = find_temporal_divisor(t_se,gbt, fnm);\r
2356         if(slack_divisor <= 0){\r
2357                 slack = NULL;\r
2358                 return;\r
2359         }\r
2360 \r
2361 //              find max slack in the iface spec\r
2362         long long int max_slacker = 0, this_slacker;\r
2363         string rname = "Slack_"+fnm;\r
2364         for(s=0;s<sources.size();++s){\r
2365                 string src_machine = sources[s].first;\r
2366                 string src_iface = sources[s].second;\r
2367                 vector<string> slack_vec = ifdb->get_iface_vals(src_machine, src_iface,rname,e,es);\r
2368                 for(v=0;v<slack_vec.size();++v){\r
2369                         if(sscanf(slack_vec[v].c_str(),"%qd",&this_slacker)){\r
2370                                 if(this_slacker > max_slacker)\r
2371                                         max_slacker = this_slacker;\r
2372                         }\r
2373                 }\r
2374         }\r
2375 \r
2376         if(max_slacker <= 0){\r
2377                 slack = NULL;\r
2378                 return;\r
2379         }\r
2380 \r
2381 //              convert to SE\r
2382         long long int the_slack=(long long int)(ceil(((double)max_slacker)/((double)slack_divisor)));\r
2383         char tmps[256];\r
2384         sprintf(tmps,"%lld",the_slack);\r
2385         literal_t *slack_lit = new literal_t(tmps, LITERAL_LONGINT);\r
2386         slack = new scalarexp_t(slack_lit);\r
2387 }\r
2388 \r
2389 \r
2390 //------------------------------------------------------------------\r
2391 //              split a node to extract LFTA components.\r
2392 \r
2393 \r
2394 vector<qp_node *> mrg_qpn::split_node_for_fta(ext_fcn_list *Ext_fcns, table_list *Schema, int &hfta_returned, ifq_t *ifdb, int n_virtual_ifaces, int hfta_parallelism, int hfta_idx){\r
2395         // nothing to do, nothing to split, return copy of self.\r
2396 \r
2397         hfta_returned = 1;\r
2398 \r
2399         vector<qp_node *> ret_vec;\r
2400 \r
2401         ret_vec.push_back(this);\r
2402         return(ret_vec);\r
2403 \r
2404 }\r
2405 \r
2406 vector<qp_node *> filter_join_qpn::split_node_for_fta(ext_fcn_list *Ext_fcns, table_list *Schema, int &hfta_returned, ifq_t *ifdb, int n_virtual_ifaces, int hfta_parallelism, int hfta_idx){\r
2407         vector<qp_node *> ret_vec;\r
2408 \r
2409 //              First check if the query can be pushed to the FTA.\r
2410         bool fta_ok = true;\r
2411         int s;\r
2412         for(s=0;s<select_list.size();s++){\r
2413                 fta_ok &= check_fta_forbidden_se(select_list[s]->se,NULL, Ext_fcns);\r
2414         }\r
2415         int p;\r
2416         for(p=0;p<where.size();p++){\r
2417                 fta_ok &= check_fta_forbidden_pr(where[p]->pr,NULL, Ext_fcns);\r
2418         }\r
2419 \r
2420         if(!fta_ok){\r
2421                 fprintf(stderr,"ERROR, filter join %s is fta-unsafe.\n",node_name.c_str());\r
2422                 exit(1);\r
2423         }\r
2424 \r
2425 //              Can it be done in a single lfta?\r
2426 //                      Get the set of interfaces it accesses.\r
2427         int ierr;\r
2428         int si;\r
2429         vector<string> sel_names;\r
2430         vector<pair<string,string> > ifaces = get_ifaces(from[0], ifdb, n_virtual_ifaces, hfta_parallelism, hfta_idx);\r
2431         if (ifaces.empty()) {\r
2432                 fprintf(stderr,"INTERNAL ERROR in filter_join_qpn::split_node_for_fta - empty interface set\n");\r
2433                 exit(1);\r
2434         }\r
2435 \r
2436         if(ifaces.size() == 1){\r
2437 //                              Single interface, no need to merge.\r
2438                 hfta_returned = 0;\r
2439                 ret_vec.push_back(this);\r
2440                 int i;\r
2441                 for(i=0;i<from.size();i++){\r
2442                         from[i]->set_machine(ifaces[0].first);\r
2443                         from[i]->set_interface(ifaces[0].second);\r
2444                         from[i]->set_ifq(false);\r
2445                 }\r
2446                 return(ret_vec);\r
2447         }else{\r
2448 //                              Multiple interfaces, generate the interface-specific queries plus\r
2449 //                              the merge.\r
2450                 hfta_returned = 1;\r
2451 \r
2452                 vector<string> sel_names;\r
2453                 for(si=0;si<ifaces.size();++si){\r
2454                         filter_join_qpn *fta_node = new filter_join_qpn();\r
2455 \r
2456 //                      Name the fta\r
2457                         if(ifaces.size()==1)\r
2458                                 fta_node->set_node_name( node_name );\r
2459                         else{\r
2460                                 string new_name =  "_"+node_name+"_"+ifaces[si].first+"_"+ifaces[si].second;\r
2461                                 untaboo(new_name);\r
2462                                 fta_node->set_node_name(new_name);\r
2463                         }\r
2464                         sel_names.push_back(fta_node->get_node_name());\r
2465 \r
2466 //                      Assign the table\r
2467                         int f;\r
2468                         for(f=0;f<from.size();f++){\r
2469                                 fta_node->from.push_back(from[f]->duplicate());\r
2470                                 fta_node->from[f]->set_machine(ifaces[si].first);\r
2471                                 fta_node->from[f]->set_interface(ifaces[si].second);\r
2472                                 fta_node->from[f]->set_ifq(false);\r
2473                         }\r
2474                         fta_node->temporal_var = temporal_var;\r
2475                         fta_node->temporal_range = temporal_range;\r
2476 \r
2477                         fta_node->use_bloom = use_bloom;\r
2478 \r
2479                         for(s=0;s<select_list.size();s++){\r
2480                                 fta_node->select_list.push_back( dup_select(select_list[s], NULL) );\r
2481                         }\r
2482 \r
2483                         for(p=0;p<shared_pred.size();p++){\r
2484                                 predicate_t *new_pr = dup_pr(where[p]->pr, NULL);\r
2485                                 cnf_elem *new_cnf = new cnf_elem(new_pr);\r
2486                                 analyze_cnf(new_cnf);\r
2487                                 fta_node->shared_pred.push_back(new_cnf);\r
2488                                 fta_node->where.push_back(new_cnf);\r
2489                         }\r
2490                         for(p=0;p<pred_t0.size();p++){\r
2491                                 predicate_t *new_pr = dup_pr(where[p]->pr, NULL);\r
2492                                 cnf_elem *new_cnf = new cnf_elem(new_pr);\r
2493                                 analyze_cnf(new_cnf);\r
2494                                 fta_node->pred_t0.push_back(new_cnf);\r
2495                                 fta_node->where.push_back(new_cnf);\r
2496                         }\r
2497                         for(p=0;p<pred_t1.size();p++){\r
2498                                 predicate_t *new_pr = dup_pr(where[p]->pr, NULL);\r
2499                                 cnf_elem *new_cnf = new cnf_elem(new_pr);\r
2500                                 analyze_cnf(new_cnf);\r
2501                                 fta_node->pred_t1.push_back(new_cnf);\r
2502                                 fta_node->where.push_back(new_cnf);\r
2503                         }\r
2504                         for(p=0;p<hash_eq.size();p++){\r
2505                                 predicate_t *new_pr = dup_pr(where[p]->pr, NULL);\r
2506                                 cnf_elem *new_cnf = new cnf_elem(new_pr);\r
2507                                 analyze_cnf(new_cnf);\r
2508                                 fta_node->hash_eq.push_back(new_cnf);\r
2509                                 fta_node->where.push_back(new_cnf);\r
2510                         }\r
2511                         for(p=0;p<postfilter.size();p++){\r
2512                                 predicate_t *new_pr = dup_pr(where[p]->pr, NULL);\r
2513                                 cnf_elem *new_cnf = new cnf_elem(new_pr);\r
2514                                 analyze_cnf(new_cnf);\r
2515                                 fta_node->postfilter.push_back(new_cnf);\r
2516                                 fta_node->where.push_back(new_cnf);\r
2517                         }\r
2518 \r
2519 //                      Xfer all of the parameters.\r
2520 //                      Use existing handle annotations.\r
2521                         vector<string> param_names = param_tbl->get_param_names();\r
2522                         int pi;\r
2523                         for(pi=0;pi<param_names.size();pi++){\r
2524                                 data_type *dt = param_tbl->get_data_type(param_names[pi]);\r
2525                                 fta_node->param_tbl->add_param(param_names[pi],dt->duplicate(),\r
2526                                                                         param_tbl->handle_access(param_names[pi]));\r
2527                         }\r
2528                         fta_node->definitions = definitions;\r
2529                         if(fta_node->resolve_if_params(ifdb, this->err_str)){\r
2530                                 this->error_code = 3;\r
2531                                 return ret_vec;\r
2532                         }\r
2533 \r
2534                         ret_vec.push_back(fta_node);\r
2535                 }\r
2536 \r
2537                 mrg_qpn *mrg_node = new mrg_qpn((filter_join_qpn *)ret_vec[0],\r
2538                          node_name,  sel_names,ifaces, ifdb);\r
2539                 ret_vec.push_back(mrg_node);\r
2540 \r
2541                 return(ret_vec);\r
2542         }\r
2543 \r
2544 }\r
2545 \r
2546 //              Use to search for unresolved interface param refs in an hfta.\r
2547 \r
2548 int spx_qpn::count_ifp_refs(set<string> &ifpnames){\r
2549         int ret = 0;\r
2550         int i;\r
2551         for(i=0;i<select_list.size();++i)\r
2552                 ret += count_se_ifp_refs(select_list[i]->se,ifpnames);\r
2553         for(i=0;i<where.size();++i)\r
2554                 ret += count_pr_ifp_refs(where[i]->pr,ifpnames);\r
2555         return ret;\r
2556 }\r
2557 \r
2558 int sgah_qpn::count_ifp_refs(set<string> &ifpnames){\r
2559         int ret = 0;\r
2560         int i,j;\r
2561         for(i=0;i<select_list.size();++i)\r
2562                 ret += count_se_ifp_refs(select_list[i]->se,ifpnames);\r
2563         for(i=0;i<where.size();++i)\r
2564                 ret += count_pr_ifp_refs(where[i]->pr,ifpnames);\r
2565         for(i=0;i<having.size();++i)\r
2566                 ret += count_pr_ifp_refs(having[i]->pr,ifpnames);\r
2567         for(i=0;i<aggr_tbl.size();++i){\r
2568                 if(aggr_tbl.is_builtin(i) && !aggr_tbl.is_star_aggr(i)){\r
2569                         ret += count_se_ifp_refs(aggr_tbl.get_aggr_se(i),ifpnames);\r
2570                 }else{\r
2571                         vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(i);\r
2572                         for(j=0;j<opl.size();++j)\r
2573                                 ret += count_se_ifp_refs(opl[j],ifpnames);\r
2574                 }\r
2575         }\r
2576         for(i=0;i<gb_tbl.size();++i){\r
2577                 ret += count_se_ifp_refs(gb_tbl.get_def(i), ifpnames);\r
2578         }\r
2579         return ret;\r
2580 }\r
2581 \r
2582 \r
2583 int rsgah_qpn::count_ifp_refs(set<string> &ifpnames){\r
2584         int ret = 0;\r
2585         int i,j;\r
2586         for(i=0;i<select_list.size();++i)\r
2587                 ret += count_se_ifp_refs(select_list[i]->se,ifpnames);\r
2588         for(i=0;i<where.size();++i)\r
2589                 ret += count_pr_ifp_refs(where[i]->pr,ifpnames);\r
2590         for(i=0;i<having.size();++i)\r
2591                 ret += count_pr_ifp_refs(having[i]->pr,ifpnames);\r
2592         for(i=0;i<closing_when.size();++i)\r
2593                 ret += count_pr_ifp_refs(closing_when[i]->pr,ifpnames);\r
2594         for(i=0;i<aggr_tbl.size();++i){\r
2595                 if(aggr_tbl.is_builtin(i) && !aggr_tbl.is_star_aggr(i)){\r
2596                         ret += count_se_ifp_refs(aggr_tbl.get_aggr_se(i),ifpnames);\r
2597                 }else{\r
2598                         vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(i);\r
2599                         for(j=0;j<opl.size();++j)\r
2600                                 ret += count_se_ifp_refs(opl[j],ifpnames);\r
2601                 }\r
2602         }\r
2603         for(i=0;i<gb_tbl.size();++i){\r
2604                 ret += count_se_ifp_refs(gb_tbl.get_def(i), ifpnames);\r
2605         }\r
2606         return ret;\r
2607 }\r
2608 \r
2609 int mrg_qpn::count_ifp_refs(set<string> &ifpnames){\r
2610         return 0;\r
2611 }\r
2612 \r
2613 int join_eq_hash_qpn::count_ifp_refs(set<string> &ifpnames){\r
2614         int ret = 0;\r
2615         int i;\r
2616         for(i=0;i<select_list.size();++i)\r
2617                 ret += count_se_ifp_refs(select_list[i]->se,ifpnames);\r
2618         for(i=0;i<prefilter[0].size();++i)\r
2619                 ret += count_pr_ifp_refs(prefilter[0][i]->pr,ifpnames);\r
2620         for(i=0;i<prefilter[1].size();++i)\r
2621                 ret += count_pr_ifp_refs(prefilter[1][i]->pr,ifpnames);\r
2622         for(i=0;i<temporal_eq.size();++i)\r
2623                 ret += count_pr_ifp_refs(temporal_eq[i]->pr,ifpnames);\r
2624         for(i=0;i<hash_eq.size();++i)\r
2625                 ret += count_pr_ifp_refs(hash_eq[i]->pr,ifpnames);\r
2626         for(i=0;i<postfilter.size();++i)\r
2627                 ret += count_pr_ifp_refs(postfilter[i]->pr,ifpnames);\r
2628         return ret;\r
2629 }\r
2630 \r
2631 int filter_join_qpn::count_ifp_refs(set<string> &ifpnames){\r
2632         int ret = 0;\r
2633         int i;\r
2634         for(i=0;i<select_list.size();++i)\r
2635                 ret += count_se_ifp_refs(select_list[i]->se,ifpnames);\r
2636         for(i=0;i<where.size();++i)\r
2637                 ret += count_pr_ifp_refs(where[i]->pr,ifpnames);\r
2638         return ret;\r
2639 }\r
2640 \r
2641 \r
2642 //              Resolve interface params to string literals\r
2643 int filter_join_qpn::resolve_if_params( ifq_t *ifdb, string &err){\r
2644         int ret = 0;\r
2645         int i;\r
2646         string ifname = from[0]->get_interface();\r
2647         string ifmach = from[0]->get_machine();\r
2648         for(i=0;i<select_list.size();++i)\r
2649                 if( resolve_se_ifp_refs(select_list[i]->se,ifmach, ifname, ifdb, err) )\r
2650                         ret = 1;\r
2651         for(i=0;i<where.size();++i)\r
2652                 if( resolve_pr_ifp_refs(where[i]->pr,ifmach, ifname, ifdb, err))\r
2653                         ret = 1;\r
2654         return ret;\r
2655 }\r
2656 \r
2657 \r
2658 int spx_qpn::resolve_if_params( ifq_t *ifdb, string &err){\r
2659         int ret = 0;\r
2660         int i;\r
2661         string ifname = table_name->get_interface();\r
2662         string ifmach = table_name->get_machine();\r
2663         for(i=0;i<select_list.size();++i)\r
2664                 if( resolve_se_ifp_refs(select_list[i]->se,ifmach, ifname, ifdb, err) )\r
2665                         ret = 1;\r
2666         for(i=0;i<where.size();++i)\r
2667                 if( resolve_pr_ifp_refs(where[i]->pr,ifmach, ifname, ifdb, err))\r
2668                         ret = 1;\r
2669         return ret;\r
2670 }\r
2671 \r
2672 int sgah_qpn::resolve_if_params( ifq_t *ifdb, string &err){\r
2673         int ret = 0;\r
2674         int i,j;\r
2675         string ifname = table_name->get_interface();\r
2676         string ifmach = table_name->get_machine();\r
2677 \r
2678 //printf("Select list has %d elements\n",select_list.size());\r
2679         for(i=0;i<select_list.size();++i){\r
2680 //printf("\tresolving elemet %d\n",i);\r
2681                 if( resolve_se_ifp_refs(select_list[i]->se,ifmach, ifname, ifdb, err) ){\r
2682                         ret = 1;\r
2683                 }\r
2684         }\r
2685         for(i=0;i<where.size();++i){\r
2686                 if( resolve_pr_ifp_refs(where[i]->pr,ifmach, ifname, ifdb, err) )\r
2687                         ret = 1;\r
2688         }\r
2689         for(i=0;i<having.size();++i){\r
2690                 if( resolve_pr_ifp_refs(having[i]->pr,ifmach, ifname, ifdb, err) )\r
2691                         ret = 1;\r
2692         }\r
2693 //printf("aggr list has %d elements\n",select_list.size());\r
2694         for(i=0;i<aggr_tbl.size();++i){\r
2695 //printf("\tresolving elemet %d\n",i);\r
2696                 if(aggr_tbl.is_builtin(i) && !aggr_tbl.is_star_aggr(i)){\r
2697 //printf("\t\t\tbuiltin\n");\r
2698                         if( resolve_se_ifp_refs(aggr_tbl.get_aggr_se(i),ifmach, ifname, ifdb, err) )\r
2699                                         ret = 1;\r
2700                 }else{\r
2701 //printf("\t\t\tudaf\n");\r
2702                         vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(i);\r
2703                         for(j=0;j<opl.size();++j)\r
2704                                 if( resolve_se_ifp_refs(opl[j],ifmach, ifname, ifdb, err) )\r
2705                                         ret = 1;\r
2706                 }\r
2707         }\r
2708         for(i=0;i<gb_tbl.size();++i){\r
2709                 if( resolve_se_ifp_refs(gb_tbl.get_def(i), ifmach, ifname, ifdb, err) )\r
2710                         ret = 1;\r
2711         }\r
2712         return ret;\r
2713 }\r
2714 \r
2715 \r
2716 \r
2717 /*\r
2718         SPLITTING A SELECTION_PROJECTION OPERATOR\r
2719 \r
2720         An SPX node may reference:\r
2721                 literals, parameters, colrefs, functions, operators\r
2722         An SPX node may not reference:\r
2723                 group-by variables, aggregates\r
2724 \r
2725         An SPX node contains\r
2726                 selection list of SEs\r
2727                 where list of CNF predicates\r
2728 \r
2729         Algorithm:\r
2730                 If each selection SE and each where predicate is fta-safe\r
2731                         execute entire operator as an LFTA.\r
2732                 Else\r
2733                         for each predicate in the where clause\r
2734                           if it is fta safe, execute it in the lfta\r
2735                           else, split each SE in the predicate, evaluate the\r
2736                                 top-level SEs in the hfta and eval the predicate on that.\r
2737                         For each SE in the se list\r
2738                           Split the SE, eval the high level part, push onto hfta\r
2739                                 selection list\r
2740 \r
2741         Splitting an SE:\r
2742                 A SE represents a value which must be computed.  The LFTA\r
2743                 must provide sub-values from which the HFTA can compute the\r
2744                 desired value.\r
2745                 1) the SE is fta-safe\r
2746                         Create an entry in the selection list of the LFTA which is\r
2747                         the SE itself.  Reference this LFTA selection list entry in\r
2748                         the HFTA (via a field name assigned to the lfta selection\r
2749                         list entry).\r
2750                 2) The SE is not fta-safe\r
2751                         Determine the boundary between the fta-safe and the fta-unsafe\r
2752                         portions of the SE.  The result is a rooted tree (which is\r
2753                         evaluated at the HFTA) which references sub-SEs (which are\r
2754                         evaluated at the LFTA).  Each of the sub-SEs is placed on\r
2755                         the selection list of the LFTA and assigned field names,\r
2756                         the top part is evaluated at the HFTA and references the\r
2757                         sub-SEs through their assigned field names.\r
2758                 The only SEs on the LFTA selection list are those created by\r
2759                 the above mechanism.  The collection of assigned field names becomes\r
2760                 the schema of the LFTA.\r
2761 \r
2762                 TODO: insert tablevar names into the colrefs.\r
2763 \r
2764 */\r
2765 \r
2766 vector<qp_node *> spx_qpn::split_node_for_fta(ext_fcn_list *Ext_fcns, table_list *Schema, int &hfta_returned, ifq_t *ifdb, int n_virtual_ifaces, int hfta_parallelism, int hfta_idx){\r
2767 \r
2768         int i;\r
2769         vector<qp_node *> ret_vec;\r
2770 \r
2771 //                      If the node reads from a stream, don't split.\r
2772 //      int t = Schema->get_table_ref(table_name->get_schema_name());\r
2773         int t = table_name->get_schema_ref();\r
2774         if(Schema->get_schema_type(t) != PROTOCOL_SCHEMA){\r
2775                 hfta_returned = 1;\r
2776                 ret_vec.push_back(this);\r
2777                 return(ret_vec);\r
2778         }\r
2779 \r
2780 \r
2781 //                      Get the set of interfaces it accesses.\r
2782         int ierr;\r
2783         int si;\r
2784         vector<string> sel_names;\r
2785         vector<pair<string,string> > ifaces = get_ifaces(table_name, ifdb, n_virtual_ifaces, hfta_parallelism, hfta_idx);\r
2786         if (ifaces.empty()) {\r
2787                 fprintf(stderr,"INTERNAL ERROR in spx_qpn::split_node_for_fta - empty interface set\n");\r
2788                 exit(1);\r
2789         }\r
2790 \r
2791 \r
2792 //                      The FTA node, it is always returned.\r
2793 \r
2794         spx_qpn *fta_node = new spx_qpn();\r
2795                 fta_node->table_name = table_name;\r
2796 \r
2797 //                      for colname imputation\r
2798 //      vector<string> fta_flds, stream_flds;\r
2799 \r
2800 \r
2801 //              First check if the query can be pushed to the FTA.\r
2802         bool fta_ok = true;\r
2803         int s;\r
2804         for(s=0;s<select_list.size();s++){\r
2805                 fta_ok &= check_fta_forbidden_se(select_list[s]->se,NULL, Ext_fcns);\r
2806         }\r
2807         int p;\r
2808         for(p=0;p<where.size();p++){\r
2809                 fta_ok &= check_fta_forbidden_pr(where[p]->pr,NULL, Ext_fcns);\r
2810         }\r
2811 \r
2812         if(fta_ok){\r
2813 ////////////////////////////////////////////////////////////\r
2814 //                      The query can be executed entirely in the FTA.\r
2815                 hfta_returned = 0;\r
2816 \r
2817                 for(si=0;si<ifaces.size();++si){\r
2818                         fta_node = new spx_qpn();\r
2819 \r
2820 //                      Name the fta\r
2821                         if(ifaces.size()==1)\r
2822                                 fta_node->set_node_name( node_name );\r
2823                         else{\r
2824                                 string new_name =  "_"+node_name+"_"+ifaces[si].first+"_"+ifaces[si].second;\r
2825                                 untaboo(new_name);\r
2826                                 fta_node->set_node_name(new_name);\r
2827                         }\r
2828                         sel_names.push_back(fta_node->get_node_name());\r
2829 \r
2830 //                      Assign the table\r
2831                         fta_node->table_name = table_name->duplicate();\r
2832                         fta_node->table_name->set_machine(ifaces[si].first);\r
2833                         fta_node->table_name->set_interface(ifaces[si].second);\r
2834                         fta_node->table_name->set_ifq(false);\r
2835 \r
2836                         for(s=0;s<select_list.size();s++){\r
2837                                 fta_node->select_list.push_back( dup_select(select_list[s], NULL) );\r
2838                         }\r
2839                         for(p=0;p<where.size();p++){\r
2840                                 predicate_t *new_pr = dup_pr(where[p]->pr, NULL);\r
2841                                 cnf_elem *new_cnf = new cnf_elem(new_pr);\r
2842                                 analyze_cnf(new_cnf);\r
2843 \r
2844                                 fta_node->where.push_back(new_cnf);\r
2845                         }\r
2846 \r
2847 //                      Xfer all of the parameters.\r
2848 //                      Use existing handle annotations.\r
2849                         vector<string> param_names = param_tbl->get_param_names();\r
2850                         int pi;\r
2851                         for(pi=0;pi<param_names.size();pi++){\r
2852                                 data_type *dt = param_tbl->get_data_type(param_names[pi]);\r
2853                                 fta_node->param_tbl->add_param(param_names[pi],dt->duplicate(),\r
2854                                                                         param_tbl->handle_access(param_names[pi]));\r
2855                         }\r
2856                         fta_node->definitions = definitions;\r
2857                         if(fta_node->resolve_if_params(ifdb, this->err_str)){\r
2858                                 this->error_code = 3;\r
2859                                 return ret_vec;\r
2860                         }\r
2861 \r
2862                         ret_vec.push_back(fta_node);\r
2863                 }\r
2864 \r
2865                 if(ifaces.size() > 1){\r
2866                 spx_qpn *tmp_spx = (spx_qpn *)(ret_vec[0]);\r
2867                         mrg_qpn *mrg_node = new mrg_qpn(tmp_spx,\r
2868                                  node_name,  sel_names,ifaces, ifdb);\r
2869                         /*\r
2870                         Do not split sources until we are done with optimizations\r
2871                         vector<mrg_qpn *> split_merge = mrg_node->split_sources();\r
2872                         for(i=0;i<split_merge.size();++i){\r
2873                                 ret_vec.push_back(split_merge[i]);\r
2874                         }\r
2875                         hfta_returned = split_merge.size();\r
2876                         */\r
2877                         ret_vec.push_back(mrg_node);\r
2878                         hfta_returned = 1;\r
2879                 }\r
2880 \r
2881 \r
2882 // printf("OK as FTA.\n");\r
2883 // printf("FTA node is:\n%s\n\n",fta_node->to_query_string().c_str() );\r
2884 \r
2885                 return(ret_vec);\r
2886         }\r
2887 \r
2888 ////////////////////////////////////////////////////\r
2889 //                      The fta must be split.  Create a stream node.\r
2890 //                      NOTE : I am counting on the single\r
2891 //                      table in the from list.  (Joins handled in a different operator).\r
2892 \r
2893         hfta_returned = 1;\r
2894 \r
2895         spx_qpn *stream_node = new spx_qpn();\r
2896         stream_node->set_node_name( node_name );\r
2897 //              Create the tablevar in the stream's FROM clause.\r
2898 //              set the schema name to the name of the LFTA,\r
2899 //              and use the same tablevar name.\r
2900         stream_node->table_name = new tablevar_t(\r
2901                          ("_fta_"+node_name).c_str()\r
2902          );\r
2903         stream_node->table_name->set_range_var(table_name->get_var_name());\r
2904 \r
2905 //                      Name the fta\r
2906         fta_node->set_node_name( "_fta_"+node_name );\r
2907 \r
2908 //                      table var names of fta, stream.\r
2909     string fta_var = fta_node->table_name->get_var_name();\r
2910     string stream_var = stream_node->table_name->get_var_name();\r
2911 \r
2912 //                      Set up select list vector\r
2913         vector< vector<select_element *> *> select_vec;\r
2914         select_vec.push_back(&(fta_node->select_list)); // only one child\r
2915 \r
2916 \r
2917 //                      Split the select list into its FTA and stream parts.\r
2918 //                      If any part of the SE is fta-unsafe, it will return\r
2919 //                      a SE to execute at the stream ref'ing SE's evaluated\r
2920 //                      at the fta (which are put on the FTA's select list as a side effect).\r
2921 //                      If the SE is fta-safe, put it on the fta select list, make\r
2922 //                      a ref to it and put the ref on the stream select list.\r
2923         for(s=0;s<select_list.size();s++){\r
2924                 bool fta_forbidden = false;\r
2925                 int se_src = SPLIT_FTAVEC_NOTBLVAR;\r
2926 //              scalarexp_t *root_se = split_fta_se(\r
2927 //                      select_list[s]->se,fta_forbidden, fta_node->select_list, Ext_fcns\r
2928 //              );\r
2929                 scalarexp_t *root_se = split_ftavec_se( select_list[s]->se,\r
2930                                         fta_forbidden, se_src, select_vec, Ext_fcns\r
2931                 );\r
2932 //              if(fta_forbidden){\r
2933                 if(fta_forbidden || se_src == SPLIT_FTAVEC_NOTBLVAR){\r
2934                         stream_node->select_list.push_back(\r
2935                                 new select_element(root_se, select_list[s]->name)\r
2936                         );\r
2937                 }else{\r
2938                         scalarexp_t *new_se=make_fta_se_ref(fta_node->select_list,root_se,0);\r
2939                         stream_node->select_list.push_back(\r
2940                                 new select_element(new_se, select_list[s]->name)\r
2941                         );\r
2942                 }\r
2943         }\r
2944 \r
2945 \r
2946 //              The WHERE clause has already been split into a set of clauses\r
2947 //              that are ANDED together.  For each clause, check if its FTA-safe.\r
2948 //              If not, split its SE's into fta-safe and stream-executing parts,\r
2949 //              then put a clause which ref's the SEs into the stream.\r
2950 //              Else put it into the LFTA.\r
2951         predicate_t *pr_root;\r
2952         bool fta_forbidden;\r
2953         for(p=0;p<where.size();p++){\r
2954                 if(! check_fta_forbidden_pr(where[p]->pr, NULL, Ext_fcns) ){\r
2955                         pr_root = split_ftavec_pr(where[p]->pr,select_vec,Ext_fcns);\r
2956 //                      pr_root = split_fta_pr( where[p]->pr, fta_node->select_list, Ext_fcns);\r
2957                         fta_forbidden = true;\r
2958                 }else{\r
2959                         pr_root = dup_pr(where[p]->pr, NULL);\r
2960                         fta_forbidden = false;\r
2961                 }\r
2962                 cnf_elem *cnf_root = new cnf_elem(pr_root);\r
2963                 analyze_cnf(cnf_root);\r
2964 \r
2965                 if(fta_forbidden){\r
2966                         stream_node->where.push_back(cnf_root);\r
2967                 }else{\r
2968                         fta_node->where.push_back(cnf_root);\r
2969                 }\r
2970         }\r
2971 \r
2972 \r
2973 \r
2974 //                      Divide the parameters among the stream, FTA.\r
2975 //                      Currently : assume that the stream receives all parameters\r
2976 //                      and parameter updates, incorporates them, then passes\r
2977 //                      all of the parameters to the FTA.\r
2978 //                      This will need to change (tables, fta-unsafe types. etc.)\r
2979 \r
2980 //                      I will pass on the use_handle_access marking, even\r
2981 //                      though the fcn call that requires handle access might\r
2982 //                      exist in only one of the parts of the query.\r
2983 //                      Parameter manipulation and handle access determination will\r
2984 //                      need to be revisited anyway.\r
2985         vector<string> param_names = param_tbl->get_param_names();\r
2986         int pi;\r
2987         for(pi=0;pi<param_names.size();pi++){\r
2988                 data_type *dt = param_tbl->get_data_type(param_names[pi]);\r
2989                 fta_node->param_tbl->add_param(param_names[pi],dt->duplicate(),\r
2990                                                                         param_tbl->handle_access(param_names[pi]));\r
2991                 stream_node->param_tbl->add_param(param_names[pi],dt->duplicate(),\r
2992                                                                         param_tbl->handle_access(param_names[pi]));\r
2993         }\r
2994 \r
2995         fta_node->definitions = definitions; fta_node->definitions.erase("_referenced_ifaces");\r
2996         stream_node->definitions = definitions;\r
2997 \r
2998 //              Now split by interfaces\r
2999         if(ifaces.size() > 1){\r
3000                 for(si=0;si<ifaces.size();++si){\r
3001                         spx_qpn *subq_node = new spx_qpn();\r
3002 \r
3003 //                      Name the subquery\r
3004                         string new_name =  "_"+node_name+"_"+ifaces[si].first+"_"+ifaces[si].second;\r
3005                         untaboo(new_name);\r
3006                         subq_node->set_node_name( new_name) ;\r
3007                         sel_names.push_back(subq_node->get_node_name());\r
3008 \r
3009 //                      Assign the table\r
3010                         subq_node->table_name = fta_node->table_name->duplicate();\r
3011                         subq_node->table_name->set_machine(ifaces[si].first);\r
3012                         subq_node->table_name->set_interface(ifaces[si].second);\r
3013                         subq_node->table_name->set_ifq(false);\r
3014 \r
3015                         for(s=0;s<fta_node->select_list.size();s++){\r
3016                                 subq_node->select_list.push_back( dup_select(fta_node->select_list[s], NULL) );\r
3017                         }\r
3018                         for(p=0;p<fta_node->where.size();p++){\r
3019                                 predicate_t *new_pr = dup_pr(fta_node->where[p]->pr, NULL);\r
3020                                 cnf_elem *new_cnf = new cnf_elem(new_pr);\r
3021                                 analyze_cnf(new_cnf);\r
3022 \r
3023                                 subq_node->where.push_back(new_cnf);\r
3024                         }\r
3025 //                      Xfer all of the parameters.\r
3026 //                      Use existing handle annotations.\r
3027                         vector<string> param_names = param_tbl->get_param_names();\r
3028                         int pi;\r
3029                         for(pi=0;pi<param_names.size();pi++){\r
3030                                 data_type *dt = param_tbl->get_data_type(param_names[pi]);\r
3031                                 subq_node->param_tbl->add_param(param_names[pi],dt->duplicate(),\r
3032                                                                         param_tbl->handle_access(param_names[pi]));\r
3033                         }\r
3034                         if(subq_node->resolve_if_params(ifdb, this->err_str)){\r
3035                                 this->error_code = 3;\r
3036                                 return ret_vec;\r
3037                         }\r
3038                         subq_node->definitions = definitions; subq_node->definitions.erase("_referenced_ifaces");\r
3039 \r
3040                         ret_vec.push_back(subq_node);\r
3041                 }\r
3042 \r
3043                 mrg_qpn *mrg_node = new mrg_qpn((spx_qpn *)(ret_vec[0]),\r
3044                          fta_node->node_name, sel_names, ifaces, ifdb);\r
3045                 /*\r
3046                 Do not split sources until we are done with optimizations\r
3047                 vector<mrg_qpn *> split_merge = mrg_node->split_sources();\r
3048                 for(i=0;i<split_merge.size();++i){\r
3049                         ret_vec.push_back(split_merge[i]);\r
3050                 }\r
3051                 */\r
3052                 ret_vec.push_back(mrg_node);\r
3053                 ret_vec.push_back(stream_node);\r
3054                 hfta_returned = 1/*split_merge.size()*/ + 1;\r
3055 \r
3056         }else{\r
3057                 fta_node->table_name->set_machine(ifaces[0].first);\r
3058                 fta_node->table_name->set_interface(ifaces[0].second);\r
3059                 fta_node->table_name->set_ifq(false);\r
3060                 if(fta_node->resolve_if_params(ifdb, this->err_str)){\r
3061                         this->error_code = 3;\r
3062                         return ret_vec;\r
3063                 }\r
3064                 ret_vec.push_back(fta_node);\r
3065                 ret_vec.push_back(stream_node);\r
3066                 hfta_returned = 1;\r
3067         }\r
3068 \r
3069 // printf("FTA node is:\n%s\n\n",fta_node->to_query_string().c_str() );\r
3070 // printf("Stream node is:\n%s\n\n",stream_node->to_query_string().c_str() );\r
3071 \r
3072 \r
3073         return(ret_vec);\r
3074 }\r
3075 \r
3076 \r
3077 /*\r
3078         Splitting a aggregation+sampling operator.\r
3079     right now, return an error if any splitting is required.\r
3080 */\r
3081 \r
3082 vector<qp_node *> sgahcwcb_qpn::split_node_for_fta(ext_fcn_list *Ext_fcns, table_list *Schema, int &hfta_returned, ifq_t *ifdb, int n_virtual_ifaces, int hfta_parallelism, int hfta_idx){\r
3083 \r
3084         hfta_returned = 1;\r
3085 \r
3086         vector<qp_node *> ret_vec;\r
3087         int s, p, g, a, o, i;\r
3088         int si;\r
3089 \r
3090         vector<string> fta_flds, stream_flds;\r
3091 \r
3092 //                      If the node reads from a stream, don't split.\r
3093 //      int t = Schema->get_table_ref(table_name->get_schema_name());\r
3094         int t = table_name->get_schema_ref();\r
3095         if(Schema->get_schema_type(t) != PROTOCOL_SCHEMA){\r
3096                 ret_vec.push_back(this);\r
3097                 return(ret_vec);\r
3098         }\r
3099 \r
3100         fprintf(stderr,"ERROR : cannot split a sampling operator (not yet implemented).\n");\r
3101         exit(1);\r
3102 \r
3103         return ret_vec;\r
3104 \r
3105 \r
3106 }\r
3107 \r
3108 \r
3109 /*\r
3110         Splitting a running aggregation operator.\r
3111     The code is almost identical to that of the the sgah operator\r
3112     except that\r
3113        - there is no lfta-only option.\r
3114            - the stream node is rsagh_qpn (lfta is sgah or spx)\r
3115            - need to handle the closing when (similar to having)\r
3116 */\r
3117 \r
3118 vector<qp_node *> rsgah_qpn::split_node_for_fta(ext_fcn_list *Ext_fcns, table_list *Schema, int &hfta_returned, ifq_t *ifdb, int n_virtual_ifaces, int hfta_parallelism, int hfta_idx){\r
3119 \r
3120         hfta_returned = 1;\r
3121 \r
3122         vector<qp_node *> ret_vec;\r
3123         int s, p, g, a, o, i;\r
3124         int si;\r
3125 \r
3126         vector<string> fta_flds, stream_flds;\r
3127 \r
3128 //                      If the node reads from a stream, don't split.\r
3129 //      int t = Schema->get_table_ref(table_name->get_schema_name());\r
3130         int t = table_name->get_schema_ref();\r
3131         if(Schema->get_schema_type(t) != PROTOCOL_SCHEMA){\r
3132                 ret_vec.push_back(this);\r
3133                 return(ret_vec);\r
3134         }\r
3135 \r
3136 //                      Get the set of interfaces it accesses.\r
3137         int ierr;\r
3138         vector<string> sel_names;\r
3139         vector<pair<string,string> > ifaces = get_ifaces(table_name, ifdb, n_virtual_ifaces, hfta_parallelism, hfta_idx);\r
3140         if (ifaces.empty()) {\r
3141                 fprintf(stderr,"INTERNAL ERROR in rsgah_qpn::split_node_for_fta - empty interface set\n");\r
3142                 exit(1);\r
3143         }\r
3144 \r
3145 \r
3146 \r
3147 \r
3148 //////////////////////////////////////////////////////////////\r
3149 ///                     Split into lfta, hfta.\r
3150 \r
3151 //                      A rsgah node must always be split,\r
3152 //                      if for no other reason than to complete the\r
3153 //                      partial aggregation.\r
3154 \r
3155 //                      First, determine if the query can be spit into aggr/aggr,\r
3156 //                      or if it must be selection/aggr.\r
3157 //                      Splitting into selection/aggr is allowed only\r
3158 //                      if select_lfta is set.\r
3159 \r
3160 \r
3161         bool select_allowed = definitions.count("select_lfta")>0;\r
3162         bool select_rqd = false;\r
3163 \r
3164         set<int> unsafe_gbvars;         // for processing where clause\r
3165         for(g=0;g<gb_tbl.size();g++){\r
3166                 if(! check_fta_forbidden_se(gb_tbl.get_def(g), &aggr_tbl, Ext_fcns)){\r
3167                         if(!select_allowed){\r
3168                           sprintf(tmpstr,"ERROR in rsgah_qpn::split_node_for_fta : group by attribute (%s) has LFTA-unsafe definition but select_lfta is not enabled (%s).\n",\r
3169                                 gb_tbl.get_name(g).c_str(), se_to_query_string(gb_tbl.get_def(g), &aggr_tbl).c_str()\r
3170                           );\r
3171                           this->error_code = 1;\r
3172                           this->err_str = tmpstr;\r
3173                           return(ret_vec);\r
3174                         }else{\r
3175                           select_rqd = true;\r
3176                           unsafe_gbvars.insert(g);\r
3177                         }\r
3178                 }\r
3179         }\r
3180 \r
3181 //                      Verify that the SEs in the aggregate definitions are fta-safe\r
3182         for(a=0;a<aggr_tbl.size();++a){\r
3183                 scalarexp_t *ase = aggr_tbl.get_aggr_se(a);\r
3184                 if(ase != NULL){        // COUNT(*) does not have a SE.\r
3185                   if(!select_allowed){\r
3186                     if(! check_fta_forbidden_se(aggr_tbl.get_aggr_se(a), &aggr_tbl, Ext_fcns)){\r
3187                           sprintf(tmpstr,"ERROR in rsgah_qpn::split_node_for_fta : aggregate (%s) has FTA-unsafe scalar expression but select_lfta is not enabled (%s).\n",\r
3188                                 aggr_tbl.get_op(a).c_str(), se_to_query_string(aggr_tbl.get_aggr_se(a), &aggr_tbl).c_str()\r
3189                           );\r
3190                           this->error_code = 1;\r
3191                           this->err_str = tmpstr;\r
3192                           return(ret_vec);\r
3193                     }\r
3194                   }else{\r
3195                         select_rqd = true;\r
3196                   }\r
3197                 }\r
3198         }\r
3199 \r
3200 //                      Verify that all of the ref'd UDAFs can be split.\r
3201 \r
3202         for(a=0;a<aggr_tbl.size();++a){\r
3203                 if(! aggr_tbl.is_builtin(a)){\r
3204                         int afcn = aggr_tbl.get_fcn_id(a);\r
3205                         int super_id = Ext_fcns->get_superaggr_id(afcn);\r
3206                         int sub_id = Ext_fcns->get_subaggr_id(afcn);\r
3207                         if(super_id < 0 || sub_id < 0){\r
3208                           if(!select_allowed){\r
3209                                 this->err_str += "ERROR in rsgah_qpn::split_node_for_fta : UDAF "+aggr_tbl.get_op(a)+" doesn't have sub/super UDAFS so it can't be split, but select_lfta is not enabled.\n";\r
3210                                 this->error_code = 1;\r
3211                                 return(ret_vec);\r
3212                           }else{\r
3213                                 select_rqd = true;\r
3214                           }\r
3215                         }\r
3216                 }\r
3217     }\r
3218 \r
3219         for(p=0;p<where.size();p++){\r
3220                 if(! check_fta_forbidden_pr(where[p]->pr, &aggr_tbl, Ext_fcns) ){\r
3221                   if(!select_allowed){\r
3222                         sprintf(tmpstr,"ERROR in rsgah_qpn::split_node_for_fta : all of the WHERE predicate must be FTA-safe, but select_lfta is not enabled (%s).\n",\r
3223                                 pred_to_query_str(where[p]->pr,&aggr_tbl).c_str()\r
3224                         );\r
3225                         this->error_code = 1;\r
3226                         this->err_str = tmpstr;\r
3227                         return(ret_vec);\r
3228                   }else{\r
3229                         select_rqd = true;\r
3230                   }\r
3231                 }\r
3232         }\r
3233 \r
3234 \r
3235         if(! select_rqd){\r
3236 \r
3237 /////////////////////////////////////////////////////\r
3238 //                      Split into  aggr/aggr.\r
3239 \r
3240 \r
3241 \r
3242 \r
3243 \r
3244         sgah_qpn *fta_node = new sgah_qpn();\r
3245                 fta_node->table_name = table_name;\r
3246                 fta_node->set_node_name( "_fta_"+node_name );\r
3247                 fta_node->table_name->set_range_var(table_name->get_var_name());\r
3248 \r
3249 \r
3250         rsgah_qpn *stream_node = new rsgah_qpn();\r
3251                 stream_node->table_name = new tablevar_t(  ("_fta_"+node_name).c_str());\r
3252                 stream_node->set_node_name( node_name );\r
3253                 stream_node->table_name->set_range_var(table_name->get_var_name());\r
3254 \r
3255 //                      First, process the group-by variables.\r
3256 //                      The fta must supply the values of all the gbvars.\r
3257 //                      If a gb is computed, the computation must be\r
3258 //                      performed at the FTA, so the SE must be FTA-safe.\r
3259 //                      Nice side effect : the gbvar table contains\r
3260 //                      matching entries for the original query, the lfta query,\r
3261 //                      and the hfta query.  So gbrefs in the new queries are set\r
3262 //                      correctly just by inheriting the gbrefs from the old query.\r
3263 //                      If this property changed, I'll need translation tables.\r
3264 \r
3265 \r
3266         for(g=0;g<gb_tbl.size();g++){\r
3267 //                      Insert the gbvar into the lfta.\r
3268                 scalarexp_t *gbvar_def = dup_se(gb_tbl.get_def(g), &aggr_tbl);\r
3269                 fta_node->gb_tbl.add_gb_var(\r
3270                         gb_tbl.get_name(g), gb_tbl.get_tblvar_ref(g), gbvar_def, gb_tbl.get_reftype(g)\r
3271                 );\r
3272 \r
3273 //                      Insert a ref to the value of the gbvar into the lfta select list.\r
3274                 colref_t *new_cr = new colref_t(gb_tbl.get_name(g).c_str() );\r
3275                 scalarexp_t *gbvar_fta = new scalarexp_t(new_cr);\r
3276                 gbvar_fta->set_gb_ref(g);\r
3277                 gbvar_fta->set_data_type( gb_tbl.get_def(g)->get_data_type() );\r
3278                 scalarexp_t *gbvar_stream = make_fta_se_ref(fta_node->select_list, gbvar_fta,0);\r
3279 \r
3280 //                      Insert the corresponding gbvar ref (gbvar_stream) into the stream.\r
3281                 gbvar_stream->set_gb_ref(-1);   // used as GBvar def\r
3282                 stream_node->gb_tbl.add_gb_var(\r
3283                         gbvar_stream->get_colref()->get_field(), -1, gbvar_stream,  gb_tbl.get_reftype(g)\r
3284                 );\r
3285 \r
3286         }\r
3287 \r
3288 //                      SEs in the aggregate definitions.\r
3289 //                      They are all safe, so split them up for later processing.\r
3290         map<int, scalarexp_t *> hfta_aggr_se;\r
3291         for(a=0;a<aggr_tbl.size();++a){\r
3292                 split_fta_aggr( &(aggr_tbl), a,\r
3293                                                 &(stream_node->aggr_tbl), &(fta_node->aggr_tbl)  ,\r
3294                                                 fta_node->select_list,\r
3295                                                 hfta_aggr_se,\r
3296                                                 Ext_fcns\r
3297                                         );\r
3298         }\r
3299 \r
3300 \r
3301 //                      Next, the select list.\r
3302 \r
3303         for(s=0;s<select_list.size();s++){\r
3304                 bool fta_forbidden = false;\r
3305                 scalarexp_t *root_se = rehome_fta_se(select_list[s]->se, &hfta_aggr_se);\r
3306                 stream_node->select_list.push_back(\r
3307                         new select_element(root_se, select_list[s]->name));\r
3308         }\r
3309 \r
3310 \r
3311 \r
3312 //                      All the predicates in the where clause must execute\r
3313 //                      in the fta.\r
3314 \r
3315         for(p=0;p<where.size();p++){\r
3316                 predicate_t *new_pr = dup_pr(where[p]->pr, &aggr_tbl);\r
3317                 cnf_elem *new_cnf = new cnf_elem(new_pr);\r
3318                 analyze_cnf(new_cnf);\r
3319 \r
3320                 fta_node->where.push_back(new_cnf);\r
3321         }\r
3322 \r
3323 //                      All of the predicates in the having clause must\r
3324 //                      execute in the stream node.\r
3325 \r
3326         for(p=0;p<having.size();p++){\r
3327                 predicate_t *pr_root = rehome_fta_pr( having[p]->pr,  &hfta_aggr_se);\r
3328                 cnf_elem *cnf_root = new cnf_elem(pr_root);\r
3329                 analyze_cnf(cnf_root);\r
3330 \r
3331                 stream_node->having.push_back(cnf_root);\r
3332         }\r
3333 \r
3334 //                      All of the predicates in the closing when clause must\r
3335 //                      execute in the stream node.\r
3336 \r
3337         for(p=0;p<closing_when.size();p++){\r
3338                 predicate_t *pr_root=rehome_fta_pr(closing_when[p]->pr,&hfta_aggr_se);\r
3339                 cnf_elem *cnf_root = new cnf_elem(pr_root);\r
3340                 analyze_cnf(cnf_root);\r
3341 \r
3342                 stream_node->closing_when.push_back(cnf_root);\r
3343         }\r
3344 \r
3345 \r
3346 //                      Divide the parameters among the stream, FTA.\r
3347 //                      Currently : assume that the stream receives all parameters\r
3348 //                      and parameter updates, incorporates them, then passes\r
3349 //                      all of the parameters to the FTA.\r
3350 //                      This will need to change (tables, fta-unsafe types. etc.)\r
3351 \r
3352 //                      I will pass on the use_handle_access marking, even\r
3353 //                      though the fcn call that requires handle access might\r
3354 //                      exist in only one of the parts of the query.\r
3355 //                      Parameter manipulation and handle access determination will\r
3356 //                      need to be revisited anyway.\r
3357         vector<string> param_names = param_tbl->get_param_names();\r
3358         int pi;\r
3359         for(pi=0;pi<param_names.size();pi++){\r
3360                 data_type *dt = param_tbl->get_data_type(param_names[pi]);\r
3361                 fta_node->param_tbl->add_param(param_names[pi],dt->duplicate(),\r
3362                                                                         param_tbl->handle_access(param_names[pi]));\r
3363                 stream_node->param_tbl->add_param(param_names[pi],dt->duplicate(),\r
3364                                                                         param_tbl->handle_access(param_names[pi]));\r
3365         }\r
3366         fta_node->definitions = definitions; fta_node->definitions.erase("_referenced_ifaces");\r
3367         stream_node->definitions = definitions;\r
3368 \r
3369 //              Now split by interfaces XXXX\r
3370         if(ifaces.size() > 1){\r
3371                 for(si=0;si<ifaces.size();++si){\r
3372                         sgah_qpn *subq_node = new sgah_qpn();\r
3373 \r
3374 //                      Name the subquery\r
3375                         string new_name =  "_"+node_name+"_"+ifaces[si].first+"_"+ifaces[si].second;\r
3376                         untaboo(new_name);\r
3377                         subq_node->set_node_name( new_name) ;\r
3378                         sel_names.push_back(subq_node->get_node_name());\r
3379 \r
3380 //                      Assign the table\r
3381                         subq_node->table_name = fta_node->table_name->duplicate();\r
3382                         subq_node->table_name->set_machine(ifaces[si].first);\r
3383                         subq_node->table_name->set_interface(ifaces[si].second);\r
3384                         subq_node->table_name->set_ifq(false);\r
3385 \r
3386 //                      the GB vars.\r
3387                         for(g=0;g<fta_node->gb_tbl.size();g++){\r
3388 //                      Insert the gbvar into the lfta.\r
3389                                 scalarexp_t *gbvar_def = dup_se(fta_node->gb_tbl.get_def(g), NULL);\r
3390                                 subq_node->gb_tbl.add_gb_var(\r
3391                                         fta_node->gb_tbl.get_name(g), fta_node->gb_tbl.get_tblvar_ref(g), gbvar_def, fta_node->gb_tbl.get_reftype(g)\r
3392                                 );\r
3393                         }\r
3394 \r
3395 //                      Insert the aggregates\r
3396                         for(a=0;a<fta_node->aggr_tbl.size();++a){\r
3397                                 subq_node->aggr_tbl.add_aggr(fta_node->aggr_tbl.duplicate(a));\r
3398                         }\r
3399 \r
3400                         for(s=0;s<fta_node->select_list.size();s++){\r
3401                                 subq_node->select_list.push_back( dup_select(fta_node->select_list[s], NULL) );\r
3402                         }\r
3403                         for(p=0;p<fta_node->where.size();p++){\r
3404                                 predicate_t *new_pr = dup_pr(fta_node->where[p]->pr, NULL);\r
3405                                 cnf_elem *new_cnf = new cnf_elem(new_pr);\r
3406                                 analyze_cnf(new_cnf);\r
3407 \r
3408                                 subq_node->where.push_back(new_cnf);\r
3409                         }\r
3410                         for(p=0;p<fta_node->having.size();p++){\r
3411                                 predicate_t *new_pr = dup_pr(fta_node->having[p]->pr, NULL);\r
3412                                 cnf_elem *new_cnf = new cnf_elem(new_pr);\r
3413                                 analyze_cnf(new_cnf);\r
3414 \r
3415                                 subq_node->having.push_back(new_cnf);\r
3416                         }\r
3417 //                      Xfer all of the parameters.\r
3418 //                      Use existing handle annotations.\r
3419                         vector<string> param_names = param_tbl->get_param_names();\r
3420                         int pi;\r
3421                         for(pi=0;pi<param_names.size();pi++){\r
3422                                 data_type *dt = param_tbl->get_data_type(param_names[pi]);\r
3423                                 subq_node->param_tbl->add_param(param_names[pi],dt->duplicate(),\r
3424                                                                         param_tbl->handle_access(param_names[pi]));\r
3425                         }\r
3426                         subq_node->definitions = definitions; subq_node->definitions.erase("_referenced_ifaces");\r
3427                         if(subq_node->resolve_if_params(ifdb, this->err_str)){\r
3428                                 this->error_code = 3;\r
3429                                 return ret_vec;\r
3430                         }\r
3431 \r
3432                         ret_vec.push_back(subq_node);\r
3433                 }\r
3434 \r
3435                 mrg_qpn *mrg_node = new mrg_qpn((sgah_qpn *)(ret_vec[0]),\r
3436                          fta_node->node_name, sel_names, ifaces, ifdb);\r
3437 \r
3438                 /*\r
3439                 Do not split sources until we are done with optimizations\r
3440                 vector<mrg_qpn *> split_merge = mrg_node->split_sources();\r
3441                 for(i=0;i<split_merge.size();++i){\r
3442                         ret_vec.push_back(split_merge[i]);\r
3443                 }\r
3444                 */\r
3445                 ret_vec.push_back(mrg_node);\r
3446                 ret_vec.push_back(stream_node);\r
3447                 hfta_returned = 1/*split_merge.size()*/+1;\r
3448 \r
3449         }else{\r
3450                 fta_node->table_name->set_machine(ifaces[0].first);\r
3451                 fta_node->table_name->set_interface(ifaces[0].second);\r
3452                 fta_node->table_name->set_ifq(false);\r
3453                 if(fta_node->resolve_if_params(ifdb, this->err_str)){\r
3454                         this->error_code = 3;\r
3455                         return ret_vec;\r
3456                 }\r
3457                 ret_vec.push_back(fta_node);\r
3458                 ret_vec.push_back(stream_node);\r
3459                 hfta_returned = 1;\r
3460         }\r
3461 \r
3462 \r
3463 //      ret_vec.push_back(fta_node);\r
3464 //      ret_vec.push_back(stream_node);\r
3465 \r
3466 \r
3467         return(ret_vec);\r
3468 \r
3469         }\r
3470 \r
3471 /////////////////////////////////////////////////////////////////////\r
3472 ///             Split into selection LFTA, aggregation HFTA.\r
3473 \r
3474         spx_qpn *fta_node = new spx_qpn();\r
3475                 fta_node->table_name = table_name;\r
3476                 fta_node->set_node_name( "_fta_"+node_name );\r
3477                 fta_node->table_name->set_range_var(table_name->get_var_name());\r
3478 \r
3479 \r
3480         rsgah_qpn *stream_node = new rsgah_qpn();\r
3481                 stream_node->table_name = new tablevar_t( ("_fta_"+node_name).c_str());\r
3482                 stream_node->set_node_name( node_name );\r
3483                 stream_node->table_name->set_range_var(table_name->get_var_name());\r
3484 \r
3485 \r
3486         vector< vector<select_element *> *> select_vec;\r
3487         select_vec.push_back(&(fta_node->select_list)); // only one child\r
3488 \r
3489 //                      Process the gbvars.  Split their defining SEs.\r
3490         for(g=0;g<gb_tbl.size();g++){\r
3491                 bool fta_forbidden = false;\r
3492                 int se_src = SPLIT_FTAVEC_NOTBLVAR;\r
3493 \r
3494                 scalarexp_t *gbvar_se = split_ftavec_se( gb_tbl.get_def(g),\r
3495                                         fta_forbidden, se_src, select_vec, Ext_fcns\r
3496                 );\r
3497 //              if(fta_forbidden) (\r
3498                 if(fta_forbidden || se_src == SPLIT_FTAVEC_NOTBLVAR){\r
3499                         stream_node->gb_tbl.add_gb_var(\r
3500                           gb_tbl.get_name(g),gb_tbl.get_tblvar_ref(g),gbvar_se,gb_tbl.get_reftype(g)\r
3501                         );\r
3502                 }else{\r
3503                         scalarexp_t *new_se=make_fta_se_ref(fta_node->select_list,gbvar_se,0);\r
3504                         stream_node->gb_tbl.add_gb_var(\r
3505                           gb_tbl.get_name(g),gb_tbl.get_tblvar_ref(g),new_se,gb_tbl.get_reftype(g)\r
3506                         );\r
3507                 }\r
3508         }\r
3509 \r
3510 //              Process the aggregate table.\r
3511 //              Copy to stream, split the SEs.\r
3512         map<int, scalarexp_t *> hfta_aggr_se;   // for rehome\r
3513         for(a=0;a<aggr_tbl.size();++a){\r
3514                 scalarexp_t *hse;\r
3515                 if(aggr_tbl.is_builtin(a)){\r
3516                         if(aggr_tbl.is_star_aggr(a)){\r
3517                                 stream_node->aggr_tbl.add_aggr(aggr_tbl.get_op(a),NULL, false);\r
3518                                 hse=scalarexp_t::make_star_aggr(aggr_tbl.get_op(a).c_str());\r
3519                         }else{\r
3520                                 bool fta_forbidden = false;\r
3521                                 int se_src = SPLIT_FTAVEC_NOTBLVAR;\r
3522 \r
3523                                 scalarexp_t *agg_se = split_ftavec_se( aggr_tbl.get_aggr_se(a),\r
3524                                         fta_forbidden, se_src, select_vec, Ext_fcns\r
3525                                 );\r
3526 //                              if(fta_forbidden) (\r
3527                                 if(fta_forbidden || se_src == SPLIT_FTAVEC_NOTBLVAR){\r
3528                                         stream_node->aggr_tbl.add_aggr(aggr_tbl.get_op(a), agg_se,false);\r
3529                                         hse=scalarexp_t::make_se_aggr(aggr_tbl.get_op(a).c_str(),agg_se);\r
3530                                 }else{\r
3531                                         scalarexp_t *new_se=make_fta_se_ref(fta_node->select_list,agg_se,0);\r
3532                                         stream_node->aggr_tbl.add_aggr(aggr_tbl.get_op(a), new_se,false);\r
3533                                         hse=scalarexp_t::make_se_aggr(aggr_tbl.get_op(a).c_str(),new_se);\r
3534                                 }\r
3535                         }\r
3536                         hse->set_data_type(aggr_tbl.get_data_type(a));\r
3537                         hse->set_aggr_id(a);\r
3538                         hfta_aggr_se[a]=hse;\r
3539                 }else{\r
3540                         vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(a);\r
3541                         vector<scalarexp_t *> new_opl;\r
3542                         for(o=0;o<opl.size();++o){\r
3543                                 bool fta_forbidden = false;\r
3544                                 int se_src = SPLIT_FTAVEC_NOTBLVAR;\r
3545                                 scalarexp_t *agg_se = split_ftavec_se( opl[o],\r
3546                                         fta_forbidden, se_src, select_vec, Ext_fcns\r
3547                                 );\r
3548 //                              scalarexp_t *agg_se = split_ftavec_se( aggr_tbl.get_aggr_se(a),\r
3549 //                                      fta_forbidden, se_src, select_vec, Ext_fcns\r
3550 //                              );\r
3551 //                              if(fta_forbidden) (\r
3552                                 if(fta_forbidden || se_src == SPLIT_FTAVEC_NOTBLVAR){\r
3553                                         new_opl.push_back(agg_se);\r
3554                                 }else{\r
3555                                         scalarexp_t *new_se=make_fta_se_ref(fta_node->select_list,agg_se,0);\r
3556                                         new_opl.push_back(new_se);\r
3557                                 }\r
3558                         }\r
3559                         stream_node->aggr_tbl.add_aggr(aggr_tbl.get_op(a), aggr_tbl.get_fcn_id(a), new_opl, aggr_tbl.get_storage_type(a),false, false,aggr_tbl.has_bailout(a));\r
3560                         hse = new scalarexp_t(aggr_tbl.get_op(a).c_str(),new_opl);\r
3561                         hse->set_data_type(Ext_fcns->get_fcn_dt(aggr_tbl.get_fcn_id(a)));\r
3562                         hse->set_fcn_id(aggr_tbl.get_fcn_id(a));\r
3563                         hse->set_aggr_id(a);\r
3564                         hfta_aggr_se[a]=hse;\r
3565                 }\r
3566         }\r
3567 \r
3568 \r
3569 //              Process the WHERE clause.\r
3570 //              If it is fta-safe AND it refs only fta-safe gbvars,\r
3571 //              then expand the gbvars and put it into the lfta.\r
3572 //              Else, split it into an hfta predicate ref'ing\r
3573 //              se's computed partially in the lfta.\r
3574 \r
3575         predicate_t *pr_root;\r
3576         bool fta_forbidden;\r
3577         for(p=0;p<where.size();p++){\r
3578                 if(! check_fta_forbidden_pr(where[p]->pr, NULL, Ext_fcns) || contains_gb_pr(where[p]->pr, unsafe_gbvars) ){\r
3579                         pr_root = split_ftavec_pr(where[p]->pr,select_vec,Ext_fcns);\r
3580                         fta_forbidden = true;\r
3581                 }else{\r
3582                         pr_root = dup_pr(where[p]->pr, NULL);\r
3583                         expand_gbvars_pr(pr_root, gb_tbl);\r
3584                         fta_forbidden = false;\r
3585                 }\r
3586                 cnf_elem *cnf_root = new cnf_elem(pr_root);\r
3587                 analyze_cnf(cnf_root);\r
3588 \r
3589                 if(fta_forbidden){\r
3590                         stream_node->where.push_back(cnf_root);\r
3591                 }else{\r
3592                         fta_node->where.push_back(cnf_root);\r
3593                 }\r
3594         }\r
3595 \r
3596 \r
3597 //              Process the Select clause, rehome it on the\r
3598 //              new defs.\r
3599         for(s=0;s<select_list.size();s++){\r
3600                 bool fta_forbidden = false;\r
3601                 scalarexp_t *root_se = rehome_fta_se(select_list[s]->se, &hfta_aggr_se);\r
3602                 stream_node->select_list.push_back(\r
3603                         new select_element(root_se, select_list[s]->name));\r
3604         }\r
3605 \r
3606 \r
3607 // Process the Having clause\r
3608 \r
3609 //                      All of the predicates in the having clause must\r
3610 //                      execute in the stream node.\r
3611 \r
3612         for(p=0;p<having.size();p++){\r
3613                 predicate_t *pr_root = rehome_fta_pr( having[p]->pr,  &hfta_aggr_se);\r
3614                 cnf_elem *cnf_root = new cnf_elem(pr_root);\r
3615                 analyze_cnf(cnf_root);\r
3616 \r
3617                 stream_node->having.push_back(cnf_root);\r
3618         }\r
3619 //                      Same for closing when\r
3620         for(p=0;p<closing_when.size();p++){\r
3621                 predicate_t *pr_root=rehome_fta_pr(closing_when[p]->pr,&hfta_aggr_se);\r
3622                 cnf_elem *cnf_root = new cnf_elem(pr_root);\r
3623                 analyze_cnf(cnf_root);\r
3624 \r
3625                 stream_node->closing_when.push_back(cnf_root);\r
3626         }\r
3627 \r
3628 \r
3629 //              Handle parameters and a few last details.\r
3630         vector<string> param_names = param_tbl->get_param_names();\r
3631         int pi;\r
3632         for(pi=0;pi<param_names.size();pi++){\r
3633                 data_type *dt = param_tbl->get_data_type(param_names[pi]);\r
3634                 fta_node->param_tbl->add_param(param_names[pi],dt->duplicate(),\r
3635                                                                         param_tbl->handle_access(param_names[pi]));\r
3636                 stream_node->param_tbl->add_param(param_names[pi],dt->duplicate(),\r
3637                                                                         param_tbl->handle_access(param_names[pi]));\r
3638         }\r
3639 \r
3640         fta_node->definitions = definitions; fta_node->definitions.erase("_referenced_ifaces");\r
3641         stream_node->definitions = definitions;\r
3642 \r
3643 //              Now split by interfaces YYYY\r
3644         if(ifaces.size() > 1){\r
3645                 for(si=0;si<ifaces.size();++si){\r
3646                         spx_qpn *subq_node = new spx_qpn();\r
3647 \r
3648 //                      Name the subquery\r
3649                         string new_name =  "_"+node_name+"_"+ifaces[si].first+"_"+ifaces[si].second;\r
3650                         untaboo(new_name);\r
3651                         subq_node->set_node_name( new_name) ;\r
3652                         sel_names.push_back(subq_node->get_node_name());\r
3653 \r
3654 //                      Assign the table\r
3655                         subq_node->table_name = fta_node->table_name->duplicate();\r
3656                         subq_node->table_name->set_machine(ifaces[si].first);\r
3657                         subq_node->table_name->set_interface(ifaces[si].second);\r
3658                         subq_node->table_name->set_ifq(false);\r
3659 \r
3660                         for(s=0;s<fta_node->select_list.size();s++){\r
3661                                 subq_node->select_list.push_back( dup_select(fta_node->select_list[s], NULL) );\r
3662                         }\r
3663                         for(p=0;p<fta_node->where.size();p++){\r
3664                                 predicate_t *new_pr = dup_pr(fta_node->where[p]->pr, NULL);\r
3665                                 cnf_elem *new_cnf = new cnf_elem(new_pr);\r
3666                                 analyze_cnf(new_cnf);\r
3667 \r
3668                                 subq_node->where.push_back(new_cnf);\r
3669                         }\r
3670 //                      Xfer all of the parameters.\r
3671 //                      Use existing handle annotations.\r
3672                         vector<string> param_names = param_tbl->get_param_names();\r
3673                         int pi;\r
3674                         for(pi=0;pi<param_names.size();pi++){\r
3675                                 data_type *dt = param_tbl->get_data_type(param_names[pi]);\r
3676                                 subq_node->param_tbl->add_param(param_names[pi],dt->duplicate(),\r
3677                                                                         param_tbl->handle_access(param_names[pi]));\r
3678                         }\r
3679                         subq_node->definitions = definitions; subq_node->definitions.erase("_referenced_ifaces");\r
3680                         if(subq_node->resolve_if_params(ifdb, this->err_str)){\r
3681                                 this->error_code = 3;\r
3682                                 return ret_vec;\r
3683                         }\r
3684 \r
3685                         ret_vec.push_back(subq_node);\r
3686                 }\r
3687 \r
3688                 mrg_qpn *mrg_node = new mrg_qpn((spx_qpn *)(ret_vec[0]),\r
3689                          fta_node->node_name, sel_names, ifaces, ifdb);\r
3690                 /*\r
3691                 Do not split sources until we are done with optimizations\r
3692                 vector<mrg_qpn *> split_merge = mrg_node->split_sources();\r
3693                 for(i=0;i<split_merge.size();++i){\r
3694                         ret_vec.push_back(split_merge[i]);\r
3695                 }\r
3696                 */\r
3697                 ret_vec.push_back(mrg_node);\r
3698                 ret_vec.push_back(stream_node);\r
3699                 hfta_returned = 1/*split_merge.size()*/+1;\r
3700 \r
3701         }else{\r
3702                 fta_node->table_name->set_machine(ifaces[0].first);\r
3703                 fta_node->table_name->set_interface(ifaces[0].second);\r
3704                 fta_node->table_name->set_ifq(false);\r
3705                 if(fta_node->resolve_if_params(ifdb, this->err_str)){\r
3706                         this->error_code = 3;\r
3707                         return ret_vec;\r
3708                 }\r
3709                 ret_vec.push_back(fta_node);\r
3710                 ret_vec.push_back(stream_node);\r
3711                 hfta_returned = 1;\r
3712         }\r
3713 \r
3714         return(ret_vec);\r
3715 \r
3716 }\r
3717 \r
3718 \r
3719 /*\r
3720                 Splitting an aggregation operator\r
3721 \r
3722                 An aggregation operator can reference\r
3723                         literals, parameters, colrefs, group-by vars, aggregates,\r
3724                         operators, functions\r
3725 \r
3726                 an aggregation contains\r
3727                         A selection list of SEs\r
3728                         A where list of predicates\r
3729                         A list group-by variable definition\r
3730                         A list of aggregates to be computed\r
3731                         A HAVING list of predicates.\r
3732 \r
3733                 Aggregation involves two phases:\r
3734                         1) given an input tuple, determine if it satisfies all of\r
3735                                 the WHERE predicates.  If so, compute the group.\r
3736                                 Look up the group, update its aggregates.\r
3737                         2) given a closed group and its aggregates, determine\r
3738                                 if these values satisfy all of the HAVING predicates.\r
3739                                 If so, evaluate the SEs on the selection list from the\r
3740                                 group and its aggregates.\r
3741                 The two-phase nature of aggregation places restrictions on\r
3742                 what can be referenced by different components of the operator\r
3743                 (in addition to functions and operators).\r
3744                 - group-by variables : literals, parameters, colrefs\r
3745                 - WHERE predicates : group-by vars, literals, params, colrefs\r
3746                 - HAVING predicates : group-by vars, literals, params, aggregates\r
3747                 - Selection list SEs : group-by vars, literals, params, aggregates\r
3748 \r
3749                 Splitting an aggregation operator into an LFTA/HFTA part\r
3750                 involves performing partial aggregation at the LFTA and\r
3751                 completing the aggregation at the HFTA.\r
3752                 - given a tuple, the LFTA part evaluates the WHERE clause,\r
3753                   and if it is satisfied, computes the group.  lookup the group\r
3754                   and update the aggregates.  output the group and its partial\r
3755                   aggregates\r
3756                 - Given a partial aggregate from the LFTA, look up the group and\r
3757                   update its aggregates.  When the group is closed, evalute\r
3758                   the HAVING clause and the SEs on the selection list.\r
3759                 THEREFORE the selection list of the LFTA must consist of the\r
3760                 group-by variables and the set of (bare) subaggregate values\r
3761                 necessary to compute the super aggregates.\r
3762                 Unlike the case with the SPX operator, the SE splitting point\r
3763                 is at the GBvar and the aggregate value level.\r
3764 \r
3765                 ALGORITHM:\r
3766                 For each group-by variable\r
3767                         Put the GB variable definition in the LFTA GBVAR list.\r
3768                         Put the GBVAR in the LFTA selection list (as an SE).\r
3769                         Put a reference to that GBVAR in the HFTA GBVAR list.\r
3770                 For each aggregate\r
3771                         Split the aggregate into a superaggregate and a subaggregate.\r
3772                                 The SE of the superaggregate references the subaggregate value.\r
3773                                 (this will need modifications for MF aggregation)\r
3774                 For each SE in the selection list, HAVING predicate\r
3775                         Make GBVAR references point to the new GBVAR\r
3776                         make the aggregate value references point to the new aggregates.\r
3777 \r
3778                 SEs are not so much split as their ref's are changed.\r
3779 \r
3780                 TODO: insert tablevar names into the colrefs.\r
3781 */\r
3782 \r
3783 \r
3784 \r
3785 vector<qp_node *> sgah_qpn::split_node_for_fta(ext_fcn_list *Ext_fcns, table_list *Schema, int &hfta_returned, ifq_t *ifdb, int n_virtual_ifaces, int hfta_parallelism, int hfta_idx){\r
3786 \r
3787         hfta_returned = 1;\r
3788 \r
3789         vector<qp_node *> ret_vec;\r
3790         int s, p, g, a, o, i;\r
3791         int si;\r
3792 \r
3793         vector<string> fta_flds, stream_flds;\r
3794 \r
3795 //                      If the node reads from a stream, don't split.\r
3796 //      int t = Schema->get_table_ref(table_name->get_schema_name());\r
3797         int t = table_name->get_schema_ref();\r
3798         if(Schema->get_schema_type(t) != PROTOCOL_SCHEMA){\r
3799                 ret_vec.push_back(this);\r
3800                 return(ret_vec);\r
3801         }\r
3802 \r
3803 //                      Get the set of interfaces it accesses.\r
3804         int ierr;\r
3805         vector<string> sel_names;\r
3806         vector<pair<string,string> > ifaces = get_ifaces(table_name, ifdb, n_virtual_ifaces, hfta_parallelism, hfta_idx);\r
3807         if (ifaces.empty()) {\r
3808                 fprintf(stderr,"INTERNAL ERROR in sgah_qpn::split_node_for_fta - empty interface set\n");\r
3809                 exit(1);\r
3810         }\r
3811 \r
3812 \r
3813 \r
3814 //////////////////////////////////////////////\r
3815 //              Is this LFTA-only?\r
3816         if(definitions.count("lfta_aggregation")>0){\r
3817 //                      Yes.  Ensure that everything is lfta-safe.\r
3818 \r
3819 //                      Check only one interface is accessed.\r
3820                 if(ifaces.size()>1){\r
3821                         this->err_str = "ERROR, group-by query "+node_name+" is lfta-only, but it accesses more than one interface:\n";\r
3822                         for(si=0;si<ifaces.size();++si)\r
3823                                 this->err_str += "\t"+ifaces[si].first+"."+ifaces[si].second+"\n";\r
3824                         this->error_code = 2;\r
3825                         return(ret_vec);\r
3826                 }\r
3827 \r
3828 //                      Check the group-by attributes\r
3829                 for(g=0;g<gb_tbl.size();g++){\r
3830                         if(! check_fta_forbidden_se(gb_tbl.get_def(g), &aggr_tbl, Ext_fcns)){\r
3831                                 sprintf(tmpstr,"ERROR in sgah_qpn::split_node_for_fta : group by attribute (%s) has LFTA-unsafe definition and the query is lfta-only (%s).\n",\r
3832                                         gb_tbl.get_name(g).c_str(), se_to_query_string(gb_tbl.get_def(g), &aggr_tbl).c_str()\r
3833                                 );\r
3834                                 this->error_code = 1;\r
3835                                 this->err_str = tmpstr;\r
3836                                 return(ret_vec);\r
3837                         }\r
3838                 }\r
3839 \r
3840 //                      Verify that the SEs in the aggregate definitions are fta-safe\r
3841                 for(a=0;a<aggr_tbl.size();++a){\r
3842                         scalarexp_t *ase = aggr_tbl.get_aggr_se(a);\r
3843                         if(ase != NULL){        // COUNT(*) does not have a SE.\r
3844                                 if(! check_fta_forbidden_se(aggr_tbl.get_aggr_se(a), &aggr_tbl, Ext_fcns)){\r
3845                                         sprintf(tmpstr,"ERROR in sgah_qpn::split_node_for_fta : aggregate (%s) has LFTA-unsafe scalar expression and the query is lfta-only (%s).\n",\r
3846                                                 aggr_tbl.get_op(a).c_str(), se_to_query_string(aggr_tbl.get_aggr_se(a), &aggr_tbl).c_str()\r
3847                                         );\r
3848                                         this->error_code = 1;\r
3849                                         this->err_str = tmpstr;\r
3850                                         return(ret_vec);\r
3851                                 }\r
3852                         }\r
3853                         if(! aggr_tbl.fta_legal(a,Ext_fcns)){\r
3854                           if(! check_fta_forbidden_se(aggr_tbl.get_aggr_se(a), &aggr_tbl, Ext_fcns)){\r
3855                                 sprintf(tmpstr,"ERROR in sgah_qpn::split_node_for_fta : aggregate (%s) has LFTA-unsafe aggregate and the query is lfta-only (%s).\n",\r
3856                                         aggr_tbl.get_op(a).c_str(), se_to_query_string(aggr_tbl.get_aggr_se(a), &aggr_tbl).c_str()\r
3857                                 );\r
3858                                 this->error_code = 1;\r
3859                                 this->err_str = tmpstr;\r
3860                                 return(ret_vec);\r
3861                                 }\r
3862                         }\r
3863                 }\r
3864 \r
3865 //              Ensure that all the aggregates are fta-safe ....\r
3866 \r
3867 //              select list\r
3868 \r
3869                 for(s=0;s<select_list.size();s++){\r
3870                         if(! check_fta_forbidden_se(select_list[s]->se,NULL, Ext_fcns)){\r
3871                                 sprintf(tmpstr,"ERROR in sgah_qpn::split_node_for_fta : all of the WHERE predicate must be LFTA-safe and the query is lfta-only (%s).\n",\r
3872                                         pred_to_query_str(where[p]->pr,&aggr_tbl).c_str()\r
3873                                 );\r
3874                                 this->error_code = 1;\r
3875                                 this->err_str = tmpstr;\r
3876                                 return(ret_vec);\r
3877                         }\r
3878                 }\r
3879 \r
3880 //              where predicate\r
3881 \r
3882                 for(p=0;p<where.size();p++){\r
3883                         if(! check_fta_forbidden_pr(where[p]->pr, &aggr_tbl, Ext_fcns) ){\r
3884                                 sprintf(tmpstr,"ERROR in sgah_qpn::split_node_for_fta : all of the WHERE predicate must be LFTA-safe and the query is lfta-only (%s).\n",\r
3885                                         pred_to_query_str(where[p]->pr,&aggr_tbl).c_str()\r
3886                                 );\r
3887                                 this->error_code = 1;\r
3888                                 this->err_str = tmpstr;\r
3889                                 return(ret_vec);\r
3890                         }\r
3891                 }\r
3892 \r
3893 \r
3894 //              having predicate\r
3895                 if(having.size()>0){\r
3896                         sprintf(tmpstr,"ERROR in sgah_qpn::split_node_for_fta :  the query is lfta-only, so it can't have a HAVING clause.(%s).\n",\r
3897                                 pred_to_query_str(where[p]->pr,&aggr_tbl).c_str()\r
3898                         );\r
3899                         this->error_code = 1;\r
3900                         this->err_str = tmpstr;\r
3901                         return(ret_vec);\r
3902                 }\r
3903 //                      The query is lfta safe, return it.\r
3904 \r
3905                 hfta_returned = 0;\r
3906                 ret_vec.push_back(this);\r
3907                 return(ret_vec);\r
3908         }\r
3909 \r
3910 //////////////////////////////////////////////////////////////\r
3911 ///                     Split into lfta, hfta.\r
3912 \r
3913 //                      A sgah node must always be split,\r
3914 //                      if for no other reason than to complete the\r
3915 //                      partial aggregation.\r
3916 \r
3917 //                      First, determine if the query can be spit into aggr/aggr,\r
3918 //                      or if it must be selection/aggr.\r
3919 //                      Splitting into selection/aggr is allowed only\r
3920 //                      if select_lfta is set.\r
3921 \r
3922 \r
3923         bool select_allowed = definitions.count("select_lfta")>0;\r
3924         bool select_rqd = false;\r
3925 \r
3926         set<int> unsafe_gbvars;         // for processing where clause\r
3927         for(g=0;g<gb_tbl.size();g++){\r
3928                 if(! check_fta_forbidden_se(gb_tbl.get_def(g), &aggr_tbl, Ext_fcns)){\r
3929                         if(!select_allowed){\r
3930                           sprintf(tmpstr,"ERROR in sgah_qpn::split_node_for_fta : group by attribute (%s) has LFTA-unsafe definition but select_lfta is not enabled (%s).\n",\r
3931                                 gb_tbl.get_name(g).c_str(), se_to_query_string(gb_tbl.get_def(g), &aggr_tbl).c_str()\r
3932                           );\r
3933                           this->error_code = 1;\r
3934                           this->err_str = tmpstr;\r
3935                           return(ret_vec);\r
3936                         }else{\r
3937                           select_rqd = true;\r
3938                           unsafe_gbvars.insert(g);\r
3939                         }\r
3940                 }\r
3941         }\r
3942 \r
3943 //                      Verify that the SEs in the aggregate definitions are fta-safe\r
3944         for(a=0;a<aggr_tbl.size();++a){\r
3945                 scalarexp_t *ase = aggr_tbl.get_aggr_se(a);\r
3946                 if(ase != NULL){        // COUNT(*) does not have a SE.\r
3947                   if(!select_allowed){\r
3948                     if(! check_fta_forbidden_se(aggr_tbl.get_aggr_se(a), &aggr_tbl, Ext_fcns)){\r
3949                           sprintf(tmpstr,"ERROR in sgah_qpn::split_node_for_fta : aggregate (%s) has FTA-unsafe scalar expression but select_lfta is not enabled (%s).\n",\r
3950                                 aggr_tbl.get_op(a).c_str(), se_to_query_string(aggr_tbl.get_aggr_se(a), &aggr_tbl).c_str()\r
3951                           );\r
3952                           this->error_code = 1;\r
3953                           this->err_str = tmpstr;\r
3954                           return(ret_vec);\r
3955                     }\r
3956                   }else{\r
3957                         select_rqd = true;\r
3958                   }\r
3959                 }\r
3960         }\r
3961 \r
3962 //                      Verify that all of the ref'd UDAFs can be split.\r
3963 \r
3964         for(a=0;a<aggr_tbl.size();++a){\r
3965                 if(! aggr_tbl.is_builtin(a)){\r
3966                         int afcn = aggr_tbl.get_fcn_id(a);\r
3967                         int super_id = Ext_fcns->get_superaggr_id(afcn);\r
3968                         int sub_id = Ext_fcns->get_subaggr_id(afcn);\r
3969                         if(super_id < 0 || sub_id < 0){\r
3970                           if(!select_allowed){\r
3971                                 this->err_str += "ERROR in sgah_qpn::split_node_for_fta : UDAF "+aggr_tbl.get_op(a)+" doesn't have sub/super UDAFS so it can't be split, but select_lfta is not enabled.\n";\r
3972                                 this->error_code = 1;\r
3973                                 return(ret_vec);\r
3974                           }else{\r
3975                                 select_rqd = true;\r
3976                           }\r
3977                         }\r
3978                 }\r
3979     }\r
3980 \r
3981         for(p=0;p<where.size();p++){\r
3982                 if(! check_fta_forbidden_pr(where[p]->pr, &aggr_tbl, Ext_fcns) ){\r
3983                   if(!select_allowed){\r
3984                         sprintf(tmpstr,"ERROR in sgah_qpn::split_node_for_fta : all of the WHERE predicate must be FTA-safe, but select_lfta is not enabled (%s).\n",\r
3985                                 pred_to_query_str(where[p]->pr,&aggr_tbl).c_str()\r
3986                         );\r
3987                         this->error_code = 1;\r
3988                         this->err_str = tmpstr;\r
3989                         return(ret_vec);\r
3990                   }else{\r
3991                         select_rqd = true;\r
3992                   }\r
3993                 }\r
3994         }\r
3995 \r
3996 \r
3997         if(! select_rqd){\r
3998 \r
3999 /////////////////////////////////////////////////////\r
4000 //                      Split into  aggr/aggr.\r
4001 \r
4002 \r
4003 \r
4004 \r
4005 \r
4006         sgah_qpn *fta_node = new sgah_qpn();\r
4007                 fta_node->table_name = table_name;\r
4008                 fta_node->set_node_name( "_fta_"+node_name );\r
4009                 fta_node->table_name->set_range_var(table_name->get_var_name());\r
4010 \r
4011 \r
4012         sgah_qpn *stream_node = new sgah_qpn();\r
4013                 stream_node->table_name = new tablevar_t(  ("_fta_"+node_name).c_str());\r
4014                 stream_node->set_node_name( node_name );\r
4015                 stream_node->table_name->set_range_var(table_name->get_var_name());\r
4016 \r
4017 //                      allowed stream disorder.  Default is 2,\r
4018 //                      can override with max_lfta_disorder setting.\r
4019 //                      Also limit the hfta disorder, set to lfta disorder + 1.\r
4020 //                      can override with max_hfta_disorder.\r
4021 \r
4022         fta_node->lfta_disorder = 2;\r
4023         if(this->get_val_of_def("max_lfta_disorder") != ""){\r
4024                 int d = atoi(this->get_val_of_def("max_lfta_disorder").c_str() );\r
4025                 if(d<1){\r
4026                         fprintf(stderr,"Warning, max_lfta_disorder in node %s is %d, must be at least 1, ignoring.\n",node_name.c_str(), d);\r
4027                 }else{\r
4028                         fta_node->lfta_disorder = d;\r
4029 printf("node %s setting lfta_disorder = %d\n",node_name.c_str(),fta_node->lfta_disorder);\r
4030                 }\r
4031         }\r
4032         if(fta_node->lfta_disorder > 1)\r
4033                 stream_node->hfta_disorder = fta_node->lfta_disorder + 1;\r
4034         else\r
4035                 stream_node->hfta_disorder =  1;\r
4036 \r
4037         if(this->get_val_of_def("max_hfta_disorder") != ""){\r
4038                 int d = atoi(this->get_val_of_def("max_hfta_disorder").c_str() );\r
4039                 if(d<fta_node->lfta_disorder){\r
4040                         fprintf(stderr,"Warning, max_hfta_disorder in node %s is %d, must be at least the max lfta disorder %d, ignoring.\n",node_name.c_str(), d,fta_node->lfta_disorder);\r
4041                 }else{\r
4042                         fta_node->lfta_disorder = d;\r
4043                 }\r
4044                 if(fta_node->lfta_disorder < fta_node->hfta_disorder){\r
4045                         fta_node->hfta_disorder = fta_node->lfta_disorder + 1;\r
4046                 }\r
4047         }\r
4048 \r
4049 //                      First, process the group-by variables.\r
4050 //                      The fta must supply the values of all the gbvars.\r
4051 //                      If a gb is computed, the computation must be\r
4052 //                      performed at the FTA, so the SE must be FTA-safe.\r
4053 //                      Nice side effect : the gbvar table contains\r
4054 //                      matching entries for the original query, the lfta query,\r
4055 //                      and the hfta query.  So gbrefs in the new queries are set\r
4056 //                      correctly just by inheriting the gbrefs from the old query.\r
4057 //                      If this property changed, I'll need translation tables.\r
4058 \r
4059 \r
4060         for(g=0;g<gb_tbl.size();g++){\r
4061 //                      Insert the gbvar into the lfta.\r
4062                 scalarexp_t *gbvar_def = dup_se(gb_tbl.get_def(g), &aggr_tbl);\r
4063                 fta_node->gb_tbl.add_gb_var(\r
4064                         gb_tbl.get_name(g), gb_tbl.get_tblvar_ref(g), gbvar_def, gb_tbl.get_reftype(g)\r
4065                 );\r
4066 \r
4067 //                      Insert a ref to the value of the gbvar into the lfta select list.\r
4068                 colref_t *new_cr = new colref_t(gb_tbl.get_name(g).c_str() );\r
4069                 scalarexp_t *gbvar_fta = new scalarexp_t(new_cr);\r
4070                 gbvar_fta->set_gb_ref(g);\r
4071                 gbvar_fta->set_data_type( gb_tbl.get_def(g)->get_data_type() );\r
4072                 scalarexp_t *gbvar_stream = make_fta_se_ref(fta_node->select_list, gbvar_fta,0);\r
4073 \r
4074 //                      Insert the corresponding gbvar ref (gbvar_stream) into the stream.\r
4075                 gbvar_stream->set_gb_ref(-1);   // used as GBvar def\r
4076                 stream_node->gb_tbl.add_gb_var(\r
4077                         gbvar_stream->get_colref()->get_field(), -1, gbvar_stream,  gb_tbl.get_reftype(g)\r
4078                 );\r
4079         }\r
4080 //                      multiple aggregation patterns, if any, go with the hfta\r
4081         stream_node->gb_tbl.set_pattern_info( &gb_tbl);\r
4082 \r
4083 //                      SEs in the aggregate definitions.\r
4084 //                      They are all safe, so split them up for later processing.\r
4085         map<int, scalarexp_t *> hfta_aggr_se;\r
4086         for(a=0;a<aggr_tbl.size();++a){\r
4087                 split_fta_aggr( &(aggr_tbl), a,\r
4088                                                 &(stream_node->aggr_tbl), &(fta_node->aggr_tbl)  ,\r
4089                                                 fta_node->select_list,\r
4090                                                 hfta_aggr_se,\r
4091                                                 Ext_fcns\r
4092                                         );\r
4093 /*\r
4094 //              OLD TRACING CODE\r
4095 \r
4096 int ii;\r
4097 for(ii=0;ii<fta_flds.size() || ii < fta_node->select_list.size();++ii){\r
4098         if(ii<fta_flds.size())\r
4099                 printf("\t%s : ",fta_flds[ii].c_str());\r
4100         else\r
4101                 printf("\t. : ");\r
4102         if(ii<fta_node->select_list.size())\r
4103                 printf("%s\n",fta_node->select_list[ii]->to_string().c_str());\r
4104         else\r
4105                 printf(".\n");\r
4106 }\r
4107 printf("hfta aggregates are:");\r
4108 for(ii=0;ii<stream_node->aggr_tbl.size();++ii){\r
4109         printf(" %s",stream_node->aggr_tbl.get_op(ii).c_str());\r
4110 }\r
4111 printf("\nlfta aggregates are:");\r
4112 for(ii=0;ii<fta_node->aggr_tbl.size();++ii){\r
4113         printf(" %s",fta_node->aggr_tbl.get_op(ii).c_str());\r
4114 }\r
4115 printf("\n\n");\r
4116 */\r
4117 \r
4118         }\r
4119 \r
4120 \r
4121 //                      Next, the select list.\r
4122 \r
4123         for(s=0;s<select_list.size();s++){\r
4124                 bool fta_forbidden = false;\r
4125                 scalarexp_t *root_se = rehome_fta_se(select_list[s]->se, &hfta_aggr_se);\r
4126                 stream_node->select_list.push_back(\r
4127                         new select_element(root_se, select_list[s]->name));\r
4128         }\r
4129 \r
4130 \r
4131 \r
4132 //                      All the predicates in the where clause must execute\r
4133 //                      in the fta.\r
4134 \r
4135         for(p=0;p<where.size();p++){\r
4136                 predicate_t *new_pr = dup_pr(where[p]->pr, &aggr_tbl);\r
4137                 cnf_elem *new_cnf = new cnf_elem(new_pr);\r
4138                 analyze_cnf(new_cnf);\r
4139 \r
4140                 fta_node->where.push_back(new_cnf);\r
4141         }\r
4142 \r
4143 //                      All of the predicates in the having clause must\r
4144 //                      execute in the stream node.\r
4145 \r
4146         for(p=0;p<having.size();p++){\r
4147                 predicate_t *pr_root = rehome_fta_pr( having[p]->pr,  &hfta_aggr_se);\r
4148                 cnf_elem *cnf_root = new cnf_elem(pr_root);\r
4149                 analyze_cnf(cnf_root);\r
4150 \r
4151                 stream_node->having.push_back(cnf_root);\r
4152         }\r
4153 \r
4154 \r
4155 //                      Divide the parameters among the stream, FTA.\r
4156 //                      Currently : assume that the stream receives all parameters\r
4157 //                      and parameter updates, incorporates them, then passes\r
4158 //                      all of the parameters to the FTA.\r
4159 //                      This will need to change (tables, fta-unsafe types. etc.)\r
4160 \r
4161 //                      I will pass on the use_handle_access marking, even\r
4162 //                      though the fcn call that requires handle access might\r
4163 //                      exist in only one of the parts of the query.\r
4164 //                      Parameter manipulation and handle access determination will\r
4165 //                      need to be revisited anyway.\r
4166         vector<string> param_names = param_tbl->get_param_names();\r
4167         int pi;\r
4168         for(pi=0;pi<param_names.size();pi++){\r
4169                 data_type *dt = param_tbl->get_data_type(param_names[pi]);\r
4170                 fta_node->param_tbl->add_param(param_names[pi],dt->duplicate(),\r
4171                                                                         param_tbl->handle_access(param_names[pi]));\r
4172                 stream_node->param_tbl->add_param(param_names[pi],dt->duplicate(),\r
4173                                                                         param_tbl->handle_access(param_names[pi]));\r
4174         }\r
4175         fta_node->definitions = definitions; fta_node->definitions.erase("_referenced_ifaces");\r
4176         stream_node->definitions = definitions;\r
4177 \r
4178 //              Now split by interfaces XXXX\r
4179         if(ifaces.size() > 1){\r
4180                 for(si=0;si<ifaces.size();++si){\r
4181                         sgah_qpn *subq_node = new sgah_qpn();\r
4182 \r
4183 //                      Name the subquery\r
4184                         string new_name =  "_"+node_name+"_"+ifaces[si].first+"_"+ifaces[si].second;\r
4185                         untaboo(new_name);\r
4186                         subq_node->set_node_name( new_name) ;\r
4187                         sel_names.push_back(subq_node->get_node_name());\r
4188 \r
4189 //                      Assign the table\r
4190                         subq_node->table_name = fta_node->table_name->duplicate();\r
4191                         subq_node->table_name->set_machine(ifaces[si].first);\r
4192                         subq_node->table_name->set_interface(ifaces[si].second);\r
4193                         subq_node->table_name->set_ifq(false);\r
4194 \r
4195 //                      the GB vars.\r
4196                         for(g=0;g<fta_node->gb_tbl.size();g++){\r
4197 //                      Insert the gbvar into the lfta.\r
4198                                 scalarexp_t *gbvar_def = dup_se(fta_node->gb_tbl.get_def(g), NULL);\r
4199                                 subq_node->gb_tbl.add_gb_var(\r
4200                                         fta_node->gb_tbl.get_name(g), fta_node->gb_tbl.get_tblvar_ref(g), gbvar_def, fta_node->gb_tbl.get_reftype(g)\r
4201                                 );\r
4202                         }\r
4203 \r
4204 //                      Insert the aggregates\r
4205                         for(a=0;a<fta_node->aggr_tbl.size();++a){\r
4206                                 subq_node->aggr_tbl.add_aggr(fta_node->aggr_tbl.duplicate(a));\r
4207                         }\r
4208 \r
4209                         for(s=0;s<fta_node->select_list.size();s++){\r
4210                                 subq_node->select_list.push_back( dup_select(fta_node->select_list[s], NULL) );\r
4211                         }\r
4212                         for(p=0;p<fta_node->where.size();p++){\r
4213                                 predicate_t *new_pr = dup_pr(fta_node->where[p]->pr, NULL);\r
4214                                 cnf_elem *new_cnf = new cnf_elem(new_pr);\r
4215                                 analyze_cnf(new_cnf);\r
4216 \r
4217                                 subq_node->where.push_back(new_cnf);\r
4218                         }\r
4219                         for(p=0;p<fta_node->having.size();p++){\r
4220                                 predicate_t *new_pr = dup_pr(fta_node->having[p]->pr, NULL);\r
4221                                 cnf_elem *new_cnf = new cnf_elem(new_pr);\r
4222                                 analyze_cnf(new_cnf);\r
4223 \r
4224                                 subq_node->having.push_back(new_cnf);\r
4225                         }\r
4226 //                      Xfer all of the parameters.\r
4227 //                      Use existing handle annotations.\r
4228                         vector<string> param_names = param_tbl->get_param_names();\r
4229                         int pi;\r
4230                         for(pi=0;pi<param_names.size();pi++){\r
4231                                 data_type *dt = param_tbl->get_data_type(param_names[pi]);\r
4232                                 subq_node->param_tbl->add_param(param_names[pi],dt->duplicate(),\r
4233                                                                         param_tbl->handle_access(param_names[pi]));\r
4234                         }\r
4235                         subq_node->definitions = definitions; subq_node->definitions.erase("_referenced_ifaces");\r
4236                         if(subq_node->resolve_if_params(ifdb, this->err_str)){\r
4237                                 this->error_code = 3;\r
4238                                 return ret_vec;\r
4239                         }\r
4240 \r
4241 //                      THe disorder\r
4242                         subq_node->lfta_disorder = fta_node->lfta_disorder;\r
4243 \r
4244                         ret_vec.push_back(subq_node);\r
4245                 }\r
4246 \r
4247                 mrg_qpn *mrg_node = new mrg_qpn((sgah_qpn *)(ret_vec[0]),\r
4248                          fta_node->node_name, sel_names, ifaces, ifdb);\r
4249                 mrg_node->set_disorder(fta_node->lfta_disorder);\r
4250 \r
4251                 /*\r
4252                 Do not split sources until we are done with optimizations\r
4253                 vector<mrg_qpn *> split_merge = mrg_node->split_sources();\r
4254                 for(i=0;i<split_merge.size();++i){\r
4255                         ret_vec.push_back(split_merge[i]);\r
4256                 }\r
4257                 */\r
4258                 ret_vec.push_back(mrg_node);\r
4259                 ret_vec.push_back(stream_node);\r
4260                 hfta_returned = 1/*split_merge.size()*/+1;\r
4261 \r
4262         }else{\r
4263                 fta_node->table_name->set_machine(ifaces[0].first);\r
4264                 fta_node->table_name->set_interface(ifaces[0].second);\r
4265                 fta_node->table_name->set_ifq(false);\r
4266                 if(fta_node->resolve_if_params(ifdb, this->err_str)){\r
4267                         this->error_code = 3;\r
4268                         return ret_vec;\r
4269                 }\r
4270                 ret_vec.push_back(fta_node);\r
4271                 ret_vec.push_back(stream_node);\r
4272                 hfta_returned = 1;\r
4273         }\r
4274 \r
4275 \r
4276 //      ret_vec.push_back(fta_node);\r
4277 //      ret_vec.push_back(stream_node);\r
4278 \r
4279 \r
4280         return(ret_vec);\r
4281 \r
4282         }\r
4283 \r
4284 /////////////////////////////////////////////////////////////////////\r
4285 ///             Split into selection LFTA, aggregation HFTA.\r
4286 \r
4287         spx_qpn *fta_node = new spx_qpn();\r
4288                 fta_node->table_name = table_name;\r
4289                 fta_node->set_node_name( "_fta_"+node_name );\r
4290                 fta_node->table_name->set_range_var(table_name->get_var_name());\r
4291 \r
4292 \r
4293         sgah_qpn *stream_node = new sgah_qpn();\r
4294                 stream_node->table_name = new tablevar_t( ("_fta_"+node_name).c_str());\r
4295                 stream_node->set_node_name( node_name );\r
4296                 stream_node->table_name->set_range_var(table_name->get_var_name());\r
4297 \r
4298 \r
4299         vector< vector<select_element *> *> select_vec;\r
4300         select_vec.push_back(&(fta_node->select_list)); // only one child\r
4301 \r
4302 //                      Process the gbvars.  Split their defining SEs.\r
4303         for(g=0;g<gb_tbl.size();g++){\r
4304                 bool fta_forbidden = false;\r
4305                 int se_src = SPLIT_FTAVEC_NOTBLVAR;\r
4306 \r
4307                 scalarexp_t *gbvar_se = split_ftavec_se( gb_tbl.get_def(g),\r
4308                                         fta_forbidden, se_src, select_vec, Ext_fcns\r
4309                 );\r
4310 //              if(fta_forbidden) (\r
4311                 if(fta_forbidden || se_src == SPLIT_FTAVEC_NOTBLVAR){\r
4312                         stream_node->gb_tbl.add_gb_var(\r
4313                           gb_tbl.get_name(g),gb_tbl.get_tblvar_ref(g),gbvar_se,gb_tbl.get_reftype(g)\r
4314                         );\r
4315                 }else{\r
4316                         scalarexp_t *new_se=make_fta_se_ref(fta_node->select_list,gbvar_se,0);\r
4317                         stream_node->gb_tbl.add_gb_var(\r
4318                           gb_tbl.get_name(g),gb_tbl.get_tblvar_ref(g),new_se,gb_tbl.get_reftype(g)\r
4319                         );\r
4320                 }\r
4321         }\r
4322         stream_node->gb_tbl.set_pattern_info( &gb_tbl);\r
4323 \r
4324 //              Process the aggregate table.\r
4325 //              Copy to stream, split the SEs.\r
4326         map<int, scalarexp_t *> hfta_aggr_se;   // for rehome\r
4327         for(a=0;a<aggr_tbl.size();++a){\r
4328                 scalarexp_t *hse;\r
4329                 if(aggr_tbl.is_builtin(a)){\r
4330                         if(aggr_tbl.is_star_aggr(a)){\r
4331                                 stream_node->aggr_tbl.add_aggr(aggr_tbl.get_op(a),NULL, false);\r
4332                                 hse=scalarexp_t::make_star_aggr(aggr_tbl.get_op(a).c_str());\r
4333                         }else{\r
4334                                 bool fta_forbidden = false;\r
4335                                 int se_src = SPLIT_FTAVEC_NOTBLVAR;\r
4336 \r
4337                                 scalarexp_t *agg_se = split_ftavec_se( aggr_tbl.get_aggr_se(a),\r
4338                                         fta_forbidden, se_src, select_vec, Ext_fcns\r
4339                                 );\r
4340 //                              if(fta_forbidden) (\r
4341                                 if(fta_forbidden || se_src == SPLIT_FTAVEC_NOTBLVAR){\r
4342                                         stream_node->aggr_tbl.add_aggr(aggr_tbl.get_op(a), agg_se,false);\r
4343                                         hse=scalarexp_t::make_se_aggr(aggr_tbl.get_op(a).c_str(),agg_se);\r
4344                                 }else{\r
4345                                         scalarexp_t *new_se=make_fta_se_ref(fta_node->select_list,agg_se,0);\r
4346                                         stream_node->aggr_tbl.add_aggr(aggr_tbl.get_op(a), new_se,false);\r
4347                                         hse=scalarexp_t::make_se_aggr(aggr_tbl.get_op(a).c_str(),new_se);\r
4348                                 }\r
4349                         }\r
4350                         hse->set_data_type(aggr_tbl.get_data_type(a));\r
4351                         hse->set_aggr_id(a);\r
4352                         hfta_aggr_se[a]=hse;\r
4353                 }else{\r
4354                         vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(a);\r
4355                         vector<scalarexp_t *> new_opl;\r
4356                         for(o=0;o<opl.size();++o){\r
4357                                 bool fta_forbidden = false;\r
4358                                 int se_src = SPLIT_FTAVEC_NOTBLVAR;\r
4359                                 scalarexp_t *agg_se = split_ftavec_se( opl[o],\r
4360                                         fta_forbidden, se_src, select_vec, Ext_fcns\r
4361                                 );\r
4362 //                              scalarexp_t *agg_se = split_ftavec_se( aggr_tbl.get_aggr_se(a),\r
4363 //                                      fta_forbidden, se_src, select_vec, Ext_fcns\r
4364 //                              );\r
4365 //                              if(fta_forbidden) (\r
4366                                 if(fta_forbidden || se_src == SPLIT_FTAVEC_NOTBLVAR){\r
4367                                         new_opl.push_back(agg_se);\r
4368                                 }else{\r
4369                                         scalarexp_t *new_se=make_fta_se_ref(fta_node->select_list,agg_se,0);\r
4370                                         new_opl.push_back(new_se);\r
4371                                 }\r
4372                         }\r
4373                         stream_node->aggr_tbl.add_aggr(aggr_tbl.get_op(a), aggr_tbl.get_fcn_id(a), new_opl, aggr_tbl.get_storage_type(a),false, false,aggr_tbl.has_bailout(a));\r
4374                         hse = new scalarexp_t(aggr_tbl.get_op(a).c_str(),new_opl);\r
4375                         hse->set_data_type(Ext_fcns->get_fcn_dt(aggr_tbl.get_fcn_id(a)));\r
4376                         hse->set_fcn_id(aggr_tbl.get_fcn_id(a));\r
4377                         hse->set_aggr_id(a);\r
4378                         hfta_aggr_se[a]=hse;\r
4379                 }\r
4380         }\r
4381 \r
4382 \r
4383 //              Process the WHERE clause.\r
4384 //              If it is fta-safe AND it refs only fta-safe gbvars,\r
4385 //              then expand the gbvars and put it into the lfta.\r
4386 //              Else, split it into an hfta predicate ref'ing\r
4387 //              se's computed partially in the lfta.\r
4388 \r
4389         predicate_t *pr_root;\r
4390         bool fta_forbidden;\r
4391         for(p=0;p<where.size();p++){\r
4392                 if(! check_fta_forbidden_pr(where[p]->pr, NULL, Ext_fcns) || contains_gb_pr(where[p]->pr, unsafe_gbvars) ){\r
4393                         pr_root = split_ftavec_pr(where[p]->pr,select_vec,Ext_fcns);\r
4394                         fta_forbidden = true;\r
4395                 }else{\r
4396                         pr_root = dup_pr(where[p]->pr, NULL);\r
4397                         expand_gbvars_pr(pr_root, gb_tbl);\r
4398                         fta_forbidden = false;\r
4399                 }\r
4400                 cnf_elem *cnf_root = new cnf_elem(pr_root);\r
4401                 analyze_cnf(cnf_root);\r
4402 \r
4403                 if(fta_forbidden){\r
4404                         stream_node->where.push_back(cnf_root);\r
4405                 }else{\r
4406                         fta_node->where.push_back(cnf_root);\r
4407                 }\r
4408         }\r
4409 \r
4410 \r
4411 //              Process the Select clause, rehome it on the\r
4412 //              new defs.\r
4413         for(s=0;s<select_list.size();s++){\r
4414                 bool fta_forbidden = false;\r
4415                 scalarexp_t *root_se = rehome_fta_se(select_list[s]->se, &hfta_aggr_se);\r
4416                 stream_node->select_list.push_back(\r
4417                         new select_element(root_se, select_list[s]->name));\r
4418         }\r
4419 \r
4420 \r
4421 // Process the Having clause\r
4422 \r
4423 //                      All of the predicates in the having clause must\r
4424 //                      execute in the stream node.\r
4425 \r
4426         for(p=0;p<having.size();p++){\r
4427                 predicate_t *pr_root = rehome_fta_pr( having[p]->pr,  &hfta_aggr_se);\r
4428                 cnf_elem *cnf_root = new cnf_elem(pr_root);\r
4429                 analyze_cnf(cnf_root);\r
4430 \r
4431                 stream_node->having.push_back(cnf_root);\r
4432         }\r
4433 \r
4434 //              Handle parameters and a few last details.\r
4435         vector<string> param_names = param_tbl->get_param_names();\r
4436         int pi;\r
4437         for(pi=0;pi<param_names.size();pi++){\r
4438                 data_type *dt = param_tbl->get_data_type(param_names[pi]);\r
4439                 fta_node->param_tbl->add_param(param_names[pi],dt->duplicate(),\r
4440                                                                         param_tbl->handle_access(param_names[pi]));\r
4441                 stream_node->param_tbl->add_param(param_names[pi],dt->duplicate(),\r
4442                                                                         param_tbl->handle_access(param_names[pi]));\r
4443         }\r
4444 \r
4445         fta_node->definitions = definitions; fta_node->definitions.erase("_referenced_ifaces");\r
4446         stream_node->definitions = definitions;\r
4447 \r
4448 //              Now split by interfaces YYYY\r
4449         if(ifaces.size() > 1){\r
4450                 for(si=0;si<ifaces.size();++si){\r
4451                         spx_qpn *subq_node = new spx_qpn();\r
4452 \r
4453 //                      Name the subquery\r
4454                         string new_name =  "_"+node_name+"_"+ifaces[si].first+"_"+ifaces[si].second;\r
4455                         untaboo(new_name);\r
4456                         subq_node->set_node_name( new_name) ;\r
4457                         sel_names.push_back(subq_node->get_node_name());\r
4458 \r
4459 //                      Assign the table\r
4460                         subq_node->table_name = fta_node->table_name->duplicate();\r
4461                         subq_node->table_name->set_machine(ifaces[si].first);\r
4462                         subq_node->table_name->set_interface(ifaces[si].second);\r
4463                         subq_node->table_name->set_ifq(false);\r
4464 \r
4465                         for(s=0;s<fta_node->select_list.size();s++){\r
4466                                 subq_node->select_list.push_back( dup_select(fta_node->select_list[s], NULL) );\r
4467                         }\r
4468                         for(p=0;p<fta_node->where.size();p++){\r
4469                                 predicate_t *new_pr = dup_pr(fta_node->where[p]->pr, NULL);\r
4470                                 cnf_elem *new_cnf = new cnf_elem(new_pr);\r
4471                                 analyze_cnf(new_cnf);\r
4472 \r
4473                                 subq_node->where.push_back(new_cnf);\r
4474                         }\r
4475 //                      Xfer all of the parameters.\r
4476 //                      Use existing handle annotations.\r
4477                         vector<string> param_names = param_tbl->get_param_names();\r
4478                         int pi;\r
4479                         for(pi=0;pi<param_names.size();pi++){\r
4480                                 data_type *dt = param_tbl->get_data_type(param_names[pi]);\r
4481                                 subq_node->param_tbl->add_param(param_names[pi],dt->duplicate(),\r
4482                                                                         param_tbl->handle_access(param_names[pi]));\r
4483                         }\r
4484                         subq_node->definitions = definitions; subq_node->definitions.erase("_referenced_ifaces");\r
4485                         if(subq_node->resolve_if_params(ifdb, this->err_str)){\r
4486                                 this->error_code = 3;\r
4487                                 return ret_vec;\r
4488                         }\r
4489 \r
4490                         ret_vec.push_back(subq_node);\r
4491                 }\r
4492 \r
4493                 mrg_qpn *mrg_node = new mrg_qpn((spx_qpn *)(ret_vec[0]),\r
4494                          fta_node->node_name, sel_names, ifaces, ifdb);\r
4495                 /*\r
4496                 Do not split sources until we are done with optimizations\r
4497                 vector<mrg_qpn *> split_merge = mrg_node->split_sources();\r
4498                 for(i=0;i<split_merge.size();++i){\r
4499                         ret_vec.push_back(split_merge[i]);\r
4500                 }\r
4501                 */\r
4502                 ret_vec.push_back(mrg_node);\r
4503                 ret_vec.push_back(stream_node);\r
4504                 hfta_returned = 1/*split_merge.size()*/+1;\r
4505 \r
4506         }else{\r
4507                 fta_node->table_name->set_machine(ifaces[0].first);\r
4508                 fta_node->table_name->set_interface(ifaces[0].second);\r
4509                 fta_node->table_name->set_ifq(false);\r
4510                 if(fta_node->resolve_if_params(ifdb, this->err_str)){\r
4511                         this->error_code = 3;\r
4512                         return ret_vec;\r
4513                 }\r
4514                 ret_vec.push_back(fta_node);\r
4515                 ret_vec.push_back(stream_node);\r
4516                 hfta_returned = 1;\r
4517         }\r
4518 \r
4519 \r
4520 //      ret_vec.push_back(fta_node);\r
4521 //      ret_vec.push_back(stream_node);\r
4522 \r
4523 \r
4524         return(ret_vec);\r
4525 \r
4526 }\r
4527 \r
4528 \r
4529 /*\r
4530         SPLITTING A EQ-TEMPORAL, HASH JOIN OPERATOR\r
4531 \r
4532         An JOIN_EQ_HASH_QPN node may reference:\r
4533                 literals, parameters, colrefs, functions, operators\r
4534         An JOIN_EQ_HASH_QPN node may not reference:\r
4535                 group-by variables, aggregates\r
4536 \r
4537         An JOIN_EQ_HASH_QPN node contains\r
4538                 selection list of SEs\r
4539                 where list of CNF predicates, broken into:\r
4540                         prefilter[2]\r
4541                         temporal_eq\r
4542                         hash_eq\r
4543                         postfilter\r
4544 \r
4545         Algorithm:\r
4546                 For each tablevar whose source is a PROTOCOL\r
4547                         Create a LFTA for that tablevar\r
4548                         Push as many prefilter[..] predicates to that tablevar as is\r
4549                                 possible.\r
4550                         Split the SEs in the select list, and the predicates not\r
4551                                 pushed to the LFTA.\r
4552 \r
4553 */\r
4554 \r
4555 vector<qp_node *> join_eq_hash_qpn::split_node_for_fta(ext_fcn_list *Ext_fcns, table_list *Schema, int &hfta_returned, ifq_t *ifdb, int n_virtual_ifaces, int hfta_parallelism, int hfta_idx){\r
4556 \r
4557         vector<qp_node *> ret_vec;\r
4558         int f,p,s;\r
4559 \r
4560 //                      If the node reads from streams only, don't split.\r
4561         bool stream_only = true;\r
4562         for(f=0;f<from.size();++f){\r
4563 //              int t = Schema->get_table_ref(from[f]->get_schema_name());\r
4564                 int t = from[f]->get_schema_ref();\r
4565                 if(Schema->get_schema_type(t) == PROTOCOL_SCHEMA) stream_only = false;\r
4566         }\r
4567         if(stream_only){\r
4568                 hfta_returned = 1;\r
4569                 ret_vec.push_back(this);\r
4570                 return(ret_vec);\r
4571         }\r
4572 \r
4573 \r
4574 //                      The HFTA node, it is always returned.\r
4575 \r
4576         join_eq_hash_qpn *stream_node = new join_eq_hash_qpn();\r
4577         for(f=0;f<from.size();++f){\r
4578 //              tablevar_t *tmp_tblvar = new tablevar_t( from[f]->get_interface().c_str(), from[f]->get_schema_name().c_str());\r
4579                 tablevar_t *tmp_tblvar =  from[f]->duplicate();\r
4580 //              tmp_tblvar->set_range_var(from[f]->get_var_name());\r
4581 \r
4582                 stream_node->from.push_back(tmp_tblvar);\r
4583         }\r
4584         stream_node->set_node_name(node_name);\r
4585 \r
4586 //                      Create spx (selection) children for each PROTOCOL source.\r
4587         vector<spx_qpn *> child_vec;\r
4588         vector< vector<select_element *> *> select_vec;\r
4589         for(f=0;f<from.size();++f){\r
4590 //              int t = Schema->get_table_ref(from[f]->get_schema_name());\r
4591                 int t = from[f]->get_schema_ref();\r
4592                 if(Schema->get_schema_type(t) == PROTOCOL_SCHEMA){\r
4593                         spx_qpn *child_qpn = new spx_qpn();\r
4594                         sprintf(tmpstr,"_fta_%d_%s",f,node_name.c_str());\r
4595                         child_qpn->set_node_name(string(tmpstr));\r
4596                         child_qpn->table_name = new tablevar_t(\r
4597                            from[f]->get_interface().c_str(), from[f]->get_schema_name().c_str(), from[f]->get_ifq());\r
4598                         child_qpn->table_name->set_range_var(from[f]->get_var_name());\r
4599 \r
4600                         child_vec.push_back(child_qpn);\r
4601                         select_vec.push_back(&(child_qpn->select_list));\r
4602 \r
4603 //                      Update the stream's FROM clause to read from this child\r
4604                         stream_node->from[f]->set_interface("");\r
4605                         stream_node->from[f]->set_schema(tmpstr);\r
4606                 }else{\r
4607                         child_vec.push_back(NULL);\r
4608                         select_vec.push_back(NULL);\r
4609                 }\r
4610         }\r
4611 \r
4612 //              Push lfta-safe prefilter to the lfta\r
4613 //              TODO: I'm not copying the preds, I dont *think* it will be a problem.\r
4614         predicate_t *pr_root;\r
4615 \r
4616         for(f=0;f<from.size();++f){\r
4617           vector<cnf_elem *> pred_vec = prefilter[f];\r
4618           if(child_vec[f] != NULL){\r
4619                 for(p=0;p<pred_vec.size();++p){\r
4620                         if(check_fta_forbidden_pr(pred_vec[p]->pr,NULL, Ext_fcns)){\r
4621                                 child_vec[f]->where.push_back(pred_vec[p]);\r
4622                         }else{\r
4623                                 pr_root = split_ftavec_pr(pred_vec[p]->pr,select_vec,Ext_fcns);\r
4624                                 cnf_elem *cnf_root = new cnf_elem(pr_root);\r
4625                                 analyze_cnf(cnf_root);\r
4626                                 stream_node->prefilter[f].push_back(cnf_root);\r
4627                         }\r
4628                 }\r
4629           }else{\r
4630                 for(p=0;p<pred_vec.size();++p){\r
4631                         stream_node->prefilter[f].push_back(pred_vec[p]);\r
4632                 }\r
4633           }\r
4634 \r
4635         }\r
4636 \r
4637 //              Process the other predicates\r
4638         for(p=0;p<temporal_eq.size();++p){\r
4639                 pr_root = split_ftavec_pr(temporal_eq[p]->pr,select_vec,Ext_fcns);\r
4640                 cnf_elem *cnf_root = new cnf_elem(pr_root);\r
4641                 analyze_cnf(cnf_root);\r
4642                 stream_node->temporal_eq.push_back(cnf_root);\r
4643         }\r
4644         for(p=0;p<hash_eq.size();++p){\r
4645                 pr_root = split_ftavec_pr(hash_eq[p]->pr,select_vec,Ext_fcns);\r
4646                 cnf_elem *cnf_root = new cnf_elem(pr_root);\r
4647                 analyze_cnf(cnf_root);\r
4648                 stream_node->hash_eq.push_back(cnf_root);\r
4649         }\r
4650         for(p=0;p<postfilter.size();++p){\r
4651                 pr_root = split_ftavec_pr(postfilter[p]->pr,select_vec,Ext_fcns);\r
4652                 cnf_elem *cnf_root = new cnf_elem(pr_root);\r
4653                 analyze_cnf(cnf_root);\r
4654                 stream_node->postfilter.push_back(cnf_root);\r
4655         }\r
4656 \r
4657 //              Process the SEs\r
4658         for(s=0;s<select_list.size();s++){\r
4659                 bool fta_forbidden = false;\r
4660                 int se_src = SPLIT_FTAVEC_NOTBLVAR;\r
4661                 scalarexp_t *root_se = split_ftavec_se( select_list[s]->se,\r
4662                                         fta_forbidden, se_src, select_vec, Ext_fcns\r
4663                 );\r
4664                 if(fta_forbidden || !is_PROTOCOL_source(se_src, select_vec)){\r
4665                         stream_node->select_list.push_back(\r
4666                                 new select_element(root_se, select_list[s]->name) );\r
4667                 }else{\r
4668                         scalarexp_t *new_se=make_fta_se_ref(select_vec,root_se,se_src);\r
4669                         stream_node->select_list.push_back(\r
4670                                 new select_element(new_se, select_list[s]->name)\r
4671                         );\r
4672                 }\r
4673         }\r
4674 \r
4675 \r
4676 //              I need to "rehome" the colrefs -- make the annotations in the colrefs\r
4677 //              agree with their tablevars.\r
4678         for(f=0;f<child_vec.size();++f){\r
4679           if(child_vec[f]!=NULL){\r
4680                 vector<tablevar_t *> fm; fm.push_back(child_vec[f]->table_name);\r
4681 \r
4682                 for(s=0;s<child_vec[f]->select_list.size();++s)\r
4683                         bind_colref_se(child_vec[f]->select_list[s]->se, fm,0,0);\r
4684                 for(p=0;p<child_vec[f]->where.size();++p)\r
4685 //                      bind_colref_pr(child_vec[f]->where[p]->pr, fm,f,0);\r
4686                         bind_colref_pr(child_vec[f]->where[p]->pr, fm,0,0);\r
4687           }\r
4688         }\r
4689 \r
4690 //              rehome the colrefs in the hfta node.\r
4691         for(f=0;f<stream_node->from.size();++f){\r
4692           stream_node->where.clear();\r
4693           for(s=0;s<stream_node->from.size();++s){\r
4694                 for(p=0;p<stream_node->prefilter[s].size();++p){\r
4695                   bind_colref_pr((stream_node->prefilter[s])[p]->pr,stream_node->from,f,f);\r
4696                 }\r
4697           }\r
4698           for(p=0;p<stream_node->temporal_eq.size();++p){\r
4699                 bind_colref_pr(stream_node->temporal_eq[p]->pr,stream_node->from,f,f);\r
4700           }\r
4701           for(p=0;p<stream_node->hash_eq.size();++p){\r
4702                 bind_colref_pr(stream_node->hash_eq[p]->pr,stream_node->from,f,f);\r
4703           }\r
4704           for(p=0;p<stream_node->postfilter.size();++p){\r
4705                 bind_colref_pr(stream_node->postfilter[p]->pr,stream_node->from,f,f);\r
4706           }\r
4707           for(s=0;s<stream_node->select_list.size();++s){\r
4708                 bind_colref_se(stream_node->select_list[s]->se,stream_node->from,f,f);\r
4709           }\r
4710         }\r
4711 \r
4712 //                      Rebuild the WHERE clause\r
4713         stream_node->where.clear();\r
4714         for(s=0;s<stream_node->from.size();++s){\r
4715                 for(p=0;p<stream_node->prefilter[s].size();++p){\r
4716                   stream_node->where.push_back((stream_node->prefilter[s])[p]);\r
4717                 }\r
4718         }\r
4719         for(p=0;p<stream_node->temporal_eq.size();++p){\r
4720                 stream_node->where.push_back(stream_node->temporal_eq[p]);\r
4721         }\r
4722         for(p=0;p<stream_node->hash_eq.size();++p){\r
4723                 stream_node->where.push_back(stream_node->hash_eq[p]);\r
4724         }\r
4725         for(p=0;p<stream_node->postfilter.size();++p){\r
4726                 stream_node->where.push_back(stream_node->postfilter[p]);\r
4727         }\r
4728 \r
4729 \r
4730 //              Build the return list\r
4731         vector<qp_node *> hfta_nodes;\r
4732         hfta_returned = 1;\r
4733         for(f=0;f<from.size();++f){\r
4734                 if(child_vec[f] != NULL){\r
4735                         spx_qpn *c_node = child_vec[f];\r
4736                         vector<pair<string, string> > ifaces = get_ifaces(c_node->table_name, ifdb, n_virtual_ifaces, hfta_parallelism, hfta_idx);\r
4737                         if (ifaces.empty()) {\r
4738                                 fprintf(stderr,"INTERNAL ERROR in join_eq_hash_qpn::split_node_for_fta - empty interface set\n");\r
4739                                 exit(1);\r
4740                         }\r
4741 \r
4742                         if(ifaces.size() == 1){\r
4743                                 c_node->table_name->set_machine(ifaces[0].first);\r
4744                                 c_node->table_name->set_interface(ifaces[0].second);\r
4745                                 c_node->table_name->set_ifq(false);\r
4746                                 if(c_node->resolve_if_params(ifdb, this->err_str)){\r
4747                                         this->error_code = 3;\r
4748                                         return ret_vec;\r
4749                                 }\r
4750                                 ret_vec.push_back(c_node);\r
4751                         }else{\r
4752                                 vector<string> sel_names;\r
4753                                 int si;\r
4754                                 for(si=0;si<ifaces.size();++si){\r
4755                                         spx_qpn *subq_node = new spx_qpn();\r
4756 \r
4757 //                      Name the subquery\r
4758                                         string new_name =  "_"+c_node->node_name+"_"+ifaces[si].first+"_"+ifaces[si].second;\r
4759                                         untaboo(new_name);\r
4760                                         subq_node->set_node_name( new_name) ;\r
4761                                         sel_names.push_back(subq_node->get_node_name());\r
4762 \r
4763 //                      Assign the table\r
4764                                         subq_node->table_name = c_node->table_name->duplicate();\r
4765                                         subq_node->table_name->set_machine(ifaces[si].first);\r
4766                                         subq_node->table_name->set_interface(ifaces[si].second);\r
4767                                         subq_node->table_name->set_ifq(false);\r
4768 \r
4769                                         for(s=0;s<c_node->select_list.size();s++){\r
4770                                           subq_node->select_list.push_back(dup_select(c_node->select_list[s], NULL));\r
4771                                         }\r
4772                                         for(p=0;p<c_node->where.size();p++){\r
4773                                           predicate_t *new_pr = dup_pr(c_node->where[p]->pr, NULL);\r
4774                                           cnf_elem *new_cnf = new cnf_elem(new_pr);\r
4775                                           analyze_cnf(new_cnf);\r
4776 \r
4777 printf("table name is %s\n",subq_node->table_name->to_string().c_str());\r
4778                                           subq_node->where.push_back(new_cnf);\r
4779                                         }\r
4780 //                      Xfer all of the parameters.\r
4781 //                      Use existing handle annotations.\r
4782 //                                      vector<string> param_names = param_tbl->get_param_names();\r
4783 //                                      int pi;\r
4784 //                                      for(pi=0;pi<param_names.size();pi++){\r
4785 //                                              data_type *dt = param_tbl->get_data_type(param_names[pi]);\r
4786 //                                              subq_node->param_tbl->add_param(param_names[pi],dt->duplicate(),\r
4787 //                                                                      param_tbl->handle_access(param_names[pi]));\r
4788 //                                      }\r
4789 //                                      subq_node->definitions = definitions;\r
4790 \r
4791                                 if(subq_node->resolve_if_params(ifdb, this->err_str)){\r
4792                                         this->error_code = 3;\r
4793                                         return ret_vec;\r
4794                                 }\r
4795 \r
4796                                         ret_vec.push_back(subq_node);\r
4797                                 }\r
4798                                 int lpos = ret_vec.size()-1     ;\r
4799                                 mrg_qpn *mrg_node = new mrg_qpn((spx_qpn *)(ret_vec[lpos]),c_node->node_name,sel_names, ifaces, ifdb);\r
4800                                 /*\r
4801                                 Do not split sources until we are done with optimizations\r
4802                                 vector<mrg_qpn *> split_merge = mrg_node->split_sources();\r
4803                                 int i;\r
4804                                 for(i=0;i<split_merge.size();++i){\r
4805                                         hfta_nodes.push_back(split_merge[i]);\r
4806                                 }\r
4807                                 */\r
4808                                 hfta_nodes.push_back(mrg_node);\r
4809                         }\r
4810                 }\r
4811         }\r
4812         int i;\r
4813         for(i=0;i<hfta_nodes.size();++i) ret_vec.push_back(hfta_nodes[i]);\r
4814         ret_vec.push_back(stream_node);\r
4815         hfta_returned = hfta_nodes.size()+1;\r
4816 \r
4817 //                      Currently : assume that the stream receives all parameters\r
4818 //                      and parameter updates, incorporates them, then passes\r
4819 //                      all of the parameters to the FTA.\r
4820 //                      This will need to change (tables, fta-unsafe types. etc.)\r
4821 \r
4822 //                      I will pass on the use_handle_access marking, even\r
4823 //                      though the fcn call that requires handle access might\r
4824 //                      exist in only one of the parts of the query.\r
4825 //                      Parameter manipulation and handle access determination will\r
4826 //                      need to be revisited anyway.\r
4827         vector<string> param_names = param_tbl->get_param_names();\r
4828         int pi;\r
4829         for(pi=0;pi<param_names.size();pi++){\r
4830                 int ri;\r
4831                 data_type *dt = param_tbl->get_data_type(param_names[pi]);\r
4832                 for(ri=0;ri<ret_vec.size();++ri){\r
4833                         ret_vec[ri]->param_tbl->add_param(param_names[pi],dt->duplicate(),\r
4834                                                                         param_tbl->handle_access(param_names[pi]));\r
4835                         ret_vec[ri]->definitions = definitions; ret_vec[ri]->definitions.erase("_referenced_ifaces");\r
4836                 }\r
4837         }\r
4838 \r
4839 \r
4840 \r
4841         return(ret_vec);\r
4842 \r
4843 }\r
4844 \r
4845 \r
4846 /////////////////////////////////////////////////////////////\r
4847 ////                    extract_opview\r
4848 \r
4849 //              Common processing\r
4850 int process_opview(tablevar_t *fmtbl, int pos, string node_name,\r
4851                                  table_list *Schema,\r
4852                                 vector<query_node *> &qnodes,\r
4853                                 opview_set &opviews,\r
4854                                 vector<table_exp_t *> &ret, string rootnm, string silo_nm){\r
4855 \r
4856         int s,f,q,m;\r
4857 \r
4858         int schref = fmtbl->get_schema_ref();\r
4859         if(schref <= 0)\r
4860                 return 0;\r
4861 \r
4862         if(Schema->get_schema_type(schref) == OPERATOR_VIEW_SCHEMA){\r
4863                 opview_entry *opv = new opview_entry();\r
4864                 opv->parent_qname = node_name;\r
4865                 opv->root_name = rootnm;\r
4866                 opv->view_name = fmtbl->get_schema_name();\r
4867                 opv->pos = pos;\r
4868                 sprintf(tmpstr,"%s_UDOP%d_%s",node_name.c_str(),pos,opv->view_name.c_str());\r
4869                 opv->udop_alias = tmpstr;\r
4870                 fmtbl->set_udop_alias(opv->udop_alias);\r
4871 \r
4872                 opv->exec_fl = Schema->get_op_prop(schref, string("file"));\r
4873                 opv->liveness_timeout = atoi(Schema->get_op_prop(schref, string("liveness_timeout")).c_str());\r
4874 \r
4875                 vector<subquery_spec *> subq = Schema->get_subqueryspecs(schref);\r
4876                 for(s=0;s<subq.size();++s){\r
4877 //                              Validate that the fields match.\r
4878                         subquery_spec *sqs = subq[s];\r
4879                         vector<field_entry *> flds = Schema->get_fields(sqs->name+silo_nm);\r
4880                         if(flds.size() == 0){\r
4881                                 fprintf(stderr,"INTERNAL ERROR: subquery %s of view %s not found in Schema.\n",sqs->name.c_str(), opv->view_name.c_str());\r
4882                                 return(1);\r
4883                         }\r
4884                         if(flds.size() < sqs->types.size()){\r
4885                                 fprintf(stderr,"ERROR: subquery %s of view %s does not have enough fields (%lu found, %lu expected).\n",sqs->name.c_str(), opv->view_name.c_str(),flds.size(), sqs->types.size());\r
4886                                 return(1);\r
4887                         }\r
4888                         bool failed = false;\r
4889                         for(f=0;f<sqs->types.size();++f){\r
4890                                 data_type dte(sqs->types[f],sqs->modifiers[f]);\r
4891                                 data_type dtf(flds[f]->get_type(),flds[f]->get_modifier_list());\r
4892                                 if(! dte.subsumes_type(&dtf) ){\r
4893                                         fprintf(stderr,"ERROR: subquery %s of view %s does not have the correct type for field %d (%s found, %s expected).\n",sqs->name.c_str(), opv->view_name.c_str(),f,dtf.to_string().c_str(), dte.to_string().c_str());\r
4894                                         failed = true;\r
4895                                 }\r
4896 /*\r
4897                                 if(dte.is_temporal() && (dte.get_temporal() != dtf.get_temporal()) ){\r
4898                                         string pstr = dte.get_temporal_string();\r
4899                                         fprintf(stderr,"ERROR: subquery %s of view %s does not have the expected temporal value %s of field %d.\n",sqs->name.c_str(), opv->view_name.c_str(),pstr.c_str(),f);\r
4900                                         failed = true;\r
4901                                 }\r
4902 */\r
4903                         }\r
4904                         if(failed)\r
4905                                 return(1);\r
4906 ///                             Validation done, find the subquery, make a copy of the\r
4907 ///                             parse tree, and add it to the return list.\r
4908                         for(q=0;q<qnodes.size();++q)\r
4909                                 if(qnodes[q]->name == sqs->name)\r
4910                                         break;\r
4911                         if(q==qnodes.size()){\r
4912                                 fprintf(stderr,"INTERNAL ERROR: subquery %s of view %s not found in list of query names.\n",sqs->name.c_str(), opv->view_name.c_str());\r
4913                                 return(1);\r
4914                         }\r
4915 \r
4916                         table_exp_t *newq = dup_table_exp(qnodes[q]->parse_tree);\r
4917                         sprintf(tmpstr,"%s_OP%d_%s_SUBQ%d",node_name.c_str(),pos,opv->view_name.c_str(),s);\r
4918                         string newq_name = tmpstr;\r
4919                         newq->nmap["query_name"] = newq_name;\r
4920                         ret.push_back(newq);\r
4921                         opv->subq_names.push_back(newq_name);\r
4922                 }\r
4923                 fmtbl->set_opview_idx(opviews.append(opv));\r
4924         }\r
4925 \r
4926         return 0;\r
4927 }\r
4928 \r
4929 vector<table_exp_t *> spx_qpn::extract_opview(table_list *Schema, vector<query_node *> &qnodes, opview_set &opviews, string rootnm, string silo_name){\r
4930         vector<table_exp_t *> ret;\r
4931 \r
4932         int retval = process_opview(table_name,0,node_name,\r
4933                                                                 Schema,qnodes,opviews,ret, rootnm, silo_name);\r
4934         if(retval) exit(1);\r
4935     return(ret);\r
4936 }\r
4937 \r
4938 \r
4939 vector<table_exp_t *> sgah_qpn::extract_opview(table_list *Schema,  vector<query_node *> &qnodes, opview_set &opviews, string rootnm, string silo_name){\r
4940         vector<table_exp_t *> ret;\r
4941 \r
4942         int retval = process_opview(table_name,0,node_name,\r
4943                                                                 Schema,qnodes,opviews,ret, rootnm, silo_name);\r
4944         if(retval) exit(1);\r
4945     return(ret);\r
4946 }\r
4947 \r
4948 vector<table_exp_t *> rsgah_qpn::extract_opview(table_list *Schema,  vector<query_node *> &qnodes, opview_set &opviews, string rootnm, string silo_name){\r
4949         vector<table_exp_t *> ret;\r
4950 \r
4951         int retval = process_opview(table_name,0,node_name,\r
4952                                                                 Schema,qnodes,opviews,ret, rootnm, silo_name);\r
4953         if(retval) exit(1);\r
4954     return(ret);\r
4955 }\r
4956 \r
4957 \r
4958 vector<table_exp_t *> sgahcwcb_qpn::extract_opview(table_list *Schema,  vector<query_node *> &qnodes, opview_set &opviews, string rootnm, string silo_name){\r
4959         vector<table_exp_t *> ret;\r
4960 \r
4961         int retval = process_opview(table_name,0,node_name,\r
4962                                                                 Schema,qnodes,opviews,ret, rootnm, silo_name);\r
4963         if(retval) exit(1);\r
4964     return(ret);\r
4965 }\r
4966 \r
4967 \r
4968 \r
4969 vector<table_exp_t *> mrg_qpn::extract_opview(table_list *Schema,  vector<query_node *> &qnodes, opview_set &opviews, string rootnm, string silo_name){\r
4970         vector<table_exp_t *> ret;\r
4971         int f;\r
4972         for(f=0;f<fm.size();++f){\r
4973                 int retval = process_opview(fm[f],f,node_name,\r
4974                                                                 Schema,qnodes,opviews,ret, rootnm, silo_name);\r
4975                 if(retval) exit(1);\r
4976         }\r
4977     return(ret);\r
4978 }\r
4979 \r
4980 \r
4981 \r
4982 \r
4983 vector<table_exp_t *> join_eq_hash_qpn::extract_opview(table_list *Schema,  vector<query_node *> &qnodes, opview_set &opviews, string rootnm, string silo_name){\r
4984         vector<table_exp_t *> ret;\r
4985         int f;\r
4986         for(f=0;f<from.size();++f){\r
4987                 int retval = process_opview(from[f],f,node_name,\r
4988                                                                 Schema,qnodes,opviews,ret, rootnm, silo_name);\r
4989                 if(retval) exit(1);\r
4990         }\r
4991     return(ret);\r
4992 }\r
4993 \r
4994 vector<table_exp_t *> filter_join_qpn::extract_opview(table_list *Schema,  vector<query_node *> &qnodes, opview_set &opviews, string rootnm, string silo_name){\r
4995         vector<table_exp_t *> ret;\r
4996         int f;\r
4997         for(f=0;f<from.size();++f){\r
4998                 int retval = process_opview(from[f],f,node_name,\r
4999                                                                 Schema,qnodes,opviews,ret, rootnm, silo_name);\r
5000                 if(retval) exit(1);\r
5001         }\r
5002     return(ret);\r
5003 }\r
5004 \r
5005 \r
5006 \r
5007 //////////////////////////////////////////////////////////////////\r
5008 //////////////////////////////////////////////////////////////////\r
5009 ///////                 Additional methods\r
5010 \r
5011 \r
5012 \r
5013 //////////////////////////////////////////////////////////////////\r
5014 //              Get schema of operator output\r
5015 \r
5016 table_def *mrg_qpn::get_fields(){\r
5017         return(table_layout);\r
5018 }\r
5019 \r
5020 \r
5021 table_def *spx_qpn::get_fields(){\r
5022         return(create_attributes(node_name, select_list));\r
5023 }\r
5024 \r
5025 table_def *sgah_qpn::get_fields(){\r
5026         return(create_attributes(node_name, select_list));\r
5027 }\r
5028 \r
5029 table_def *rsgah_qpn::get_fields(){\r
5030         return(create_attributes(node_name, select_list));\r
5031 }\r
5032 \r
5033 table_def *sgahcwcb_qpn::get_fields(){\r
5034         return(create_attributes(node_name, select_list));\r
5035 }\r
5036 \r
5037 table_def *filter_join_qpn::get_fields(){\r
5038         return(create_attributes(node_name, select_list));\r
5039 }\r
5040 \r
5041 \r
5042 table_def *join_eq_hash_qpn::get_fields(){\r
5043         int i, h, s, t;\r
5044 \r
5045 //                      First, gather temporal colrefs and SEs.\r
5046         map<col_id, temporal_type> temporal_cids;\r
5047         vector<scalarexp_t *> temporal_se;\r
5048         for(h=0;h<temporal_eq.size();++h){\r
5049                 scalarexp_t *sel = temporal_eq[h]->pr->get_left_se();\r
5050                 scalarexp_t *ser = temporal_eq[h]->pr->get_right_se();\r
5051 \r
5052                 if(sel->get_operator_type() == SE_COLREF){\r
5053                         col_id tcol(sel->get_colref());\r
5054                         if(temporal_cids.count(tcol) == 0){\r
5055                                 temporal_cids[tcol] = sel->get_data_type()->get_temporal();\r
5056                         }\r
5057                 }else{\r
5058                         temporal_se.push_back(sel);\r
5059                 }\r
5060 \r
5061                 if(ser->get_operator_type() == SE_COLREF){\r
5062                         col_id tcol(ser->get_colref());\r
5063                         if(temporal_cids.count(tcol) == 0){\r
5064                                 temporal_cids[tcol] = ser->get_data_type()->get_temporal();\r
5065                         }\r
5066                 }else{\r
5067                         temporal_se.push_back(ser);\r
5068                 }\r
5069         }\r
5070 \r
5071 //              Mark select elements as nontemporal, then deduce which\r
5072 //              ones are temporal.\r
5073         for(s=0;s<select_list.size();++s){\r
5074                 select_list[s]->se->get_data_type()->set_temporal(\r
5075                         compute_se_temporal(select_list[s]->se, temporal_cids)\r
5076                 );\r
5077 //                              Second chance if it is an exact match to an SE.\r
5078 //      for(s=0;s<select_list.size();++s){\r
5079                 if(! select_list[s]->se->get_data_type()->is_temporal() ){\r
5080                         for(t=0;t<temporal_se.size();++t){\r
5081                                 if(is_equivalent_se(temporal_se[t], select_list[s]->se)){\r
5082                                         select_list[s]->se->get_data_type()->set_temporal(\r
5083                                                 temporal_se[t]->get_data_type()->get_temporal()\r
5084                                         );\r
5085                                 }\r
5086                         }\r
5087                 }\r
5088 //      }\r
5089         }\r
5090 \r
5091 //                      If there is an outer join, verify that\r
5092 //                      the temporal attributes are actually temporal.\r
5093 //                      NOTE: this code must be synchronized with the\r
5094 //                      equivalence finding in join_eq_hash_qpn::generate_functor\r
5095 //                      (and also, the join_eq_hash_qpn constructor)\r
5096   if(from[0]->get_property() || from[1]->get_property()){\r
5097         set<string> l_equiv, r_equiv;\r
5098         for(i=0;i<temporal_eq.size();i++){\r
5099                 scalarexp_t *lse =      temporal_eq[i]->pr->get_left_se();\r
5100                 scalarexp_t *rse =      temporal_eq[i]->pr->get_right_se();\r
5101                 if(lse->get_operator_type()==SE_COLREF){\r
5102                         l_equiv.insert(lse->get_colref()->get_field());\r
5103                 }\r
5104                 if(rse->get_operator_type()==SE_COLREF){\r
5105                         r_equiv.insert(rse->get_colref()->get_field());\r
5106                 }\r
5107         }\r
5108 \r
5109         for(s=0;s<select_list.size();++s){\r
5110                 if(select_list[s]->se->get_data_type()->is_temporal()){\r
5111                         col_id_set cid_set;\r
5112                         col_id_set::iterator ci;\r
5113                         bool failed = false;\r
5114                         gather_se_col_ids(select_list[s]->se,cid_set, NULL);\r
5115                         for(ci=cid_set.begin();ci!=cid_set.end();++ci){\r
5116                                 if((*ci).tblvar_ref == 0){\r
5117                                          if(from[0]->get_property()){\r
5118                                                 if(l_equiv.count((*ci).field) == 0){\r
5119                                                         failed = true;\r
5120                                                 }\r
5121                                         }\r
5122                                 }else{\r
5123                                          if(from[1]->get_property()){\r
5124                                                 if(r_equiv.count((*ci).field) == 0){\r
5125                                                         failed = true;\r
5126                                                 }\r
5127                                         }\r
5128                                 }\r
5129                         }\r
5130                         if(failed){\r
5131                                 select_list[s]->se->get_data_type()->reset_temporal();\r
5132                         }\r
5133                 }\r
5134         }\r
5135   }\r
5136 \r
5137 \r
5138         return create_attributes(node_name, select_list);\r
5139 }\r
5140 \r
5141 \r
5142 \r
5143 //-----------------------------------------------------------------\r
5144 //                      get output tables\r
5145 \r
5146 \r
5147 //                      Get tablevar_t names of input and output tables\r
5148 \r
5149 //      output_file_qpn::output_file_qpn(){source_op_name = ""; }\r
5150         vector<tablevar_t *> output_file_qpn::get_input_tbls(){\r
5151                 return(fm);\r
5152         }\r
5153 \r
5154         vector<tablevar_t *> mrg_qpn::get_input_tbls(){\r
5155                 return(fm);\r
5156         }\r
5157 \r
5158         vector<tablevar_t *> spx_qpn::get_input_tbls(){\r
5159                 vector<tablevar_t *> retval(1,table_name);\r
5160                 return(retval);\r
5161         }\r
5162 \r
5163         vector<tablevar_t *> sgah_qpn::get_input_tbls(){\r
5164                 vector<tablevar_t *> retval(1,table_name);\r
5165                 return(retval);\r
5166         }\r
5167 \r
5168         vector<tablevar_t *> rsgah_qpn::get_input_tbls(){\r
5169                 vector<tablevar_t *> retval(1,table_name);\r
5170                 return(retval);\r
5171         }\r
5172 \r
5173         vector<tablevar_t *> sgahcwcb_qpn::get_input_tbls(){\r
5174                 vector<tablevar_t *> retval(1,table_name);\r
5175                 return(retval);\r
5176         }\r
5177 \r
5178         vector<tablevar_t *> join_eq_hash_qpn::get_input_tbls(){\r
5179                 return(from);\r
5180         }\r
5181 \r
5182         vector<tablevar_t *> filter_join_qpn::get_input_tbls(){\r
5183                 return(from);\r
5184         }\r
5185 \r
5186 //-----------------------------------------------------------------\r
5187 //                      get output tables\r
5188 \r
5189 \r
5190 //              This does not make sense, this fcn returns the output table *name*,\r
5191 //              not its schema, and then there is another fcn to rturn the schema.\r
5192         vector<tablevar_t *> output_file_qpn::get_output_tbls(){\r
5193                 vector<tablevar_t *> retval(1,new tablevar_t(node_name.c_str()));\r
5194                 return(retval);\r
5195         }\r
5196 \r
5197         vector<tablevar_t *> mrg_qpn::get_output_tbls(){\r
5198                 vector<tablevar_t *> retval(1,new tablevar_t(node_name.c_str()));\r
5199                 return(retval);\r
5200         }\r
5201 \r
5202         vector<tablevar_t *> spx_qpn::get_output_tbls(){\r
5203                 vector<tablevar_t *> retval(1,new tablevar_t(node_name.c_str()));\r
5204                 return(retval);\r
5205         }\r
5206 \r
5207         vector<tablevar_t *> sgah_qpn::get_output_tbls(){\r
5208                 vector<tablevar_t *> retval(1,new tablevar_t(node_name.c_str()));\r
5209                 return(retval);\r
5210         }\r
5211 \r
5212         vector<tablevar_t *> rsgah_qpn::get_output_tbls(){\r
5213                 vector<tablevar_t *> retval(1,new tablevar_t(node_name.c_str()));\r
5214                 return(retval);\r
5215         }\r
5216 \r
5217         vector<tablevar_t *> sgahcwcb_qpn::get_output_tbls(){\r
5218                 vector<tablevar_t *> retval(1,new tablevar_t(node_name.c_str()));\r
5219                 return(retval);\r
5220         }\r
5221 \r
5222         vector<tablevar_t *> join_eq_hash_qpn::get_output_tbls(){\r
5223                 vector<tablevar_t *> retval(1,new tablevar_t(node_name.c_str()));\r
5224                 return(retval);\r
5225         }\r
5226 \r
5227         vector<tablevar_t *> filter_join_qpn::get_output_tbls(){\r
5228                 vector<tablevar_t *> retval(1,new tablevar_t(node_name.c_str()));\r
5229                 return(retval);\r
5230         }\r
5231 \r
5232 \r
5233 \r
5234 //-----------------------------------------------------------------\r
5235 //                      Bind to schema\r
5236 \r
5237 //              Associate colrefs with this schema.\r
5238 //              Also, use this opportunity to create table_layout (the output schema).\r
5239 //              If the output schema is ever needed before\r
5240 void mrg_qpn::bind_to_schema(table_list *Schema){\r
5241         int t;\r
5242         for(t=0;t<fm.size();++t){\r
5243                 int tblref = Schema->get_table_ref(fm[t]->get_schema_name());\r
5244                 if(tblref>=0)\r
5245                 fm[t]->set_schema_ref(tblref );\r
5246         }\r
5247 \r
5248 //              Here I assume that the colrefs have been reorderd\r
5249 //              during analysis so that mvars line up with fm.\r
5250         mvars[0]->set_schema_ref(fm[0]->get_schema_ref());\r
5251         mvars[1]->set_schema_ref(fm[1]->get_schema_ref());\r
5252 \r
5253 \r
5254 }\r
5255 \r
5256 \r
5257 \r
5258 //              Associate colrefs in SEs with this schema.\r
5259 void spx_qpn::bind_to_schema(table_list *Schema){\r
5260 //                      Bind the tablevars in the From clause to the Schema\r
5261 //                      (it might have changed from analysis time)\r
5262         int t = Schema->get_table_ref(table_name->get_schema_name() );\r
5263         if(t>=0)\r
5264         table_name->set_schema_ref(t );\r
5265 \r
5266 //                      Get the "from" clause\r
5267         tablevar_list_t fm(table_name);\r
5268 \r
5269 //                      Bind all SEs to this schema\r
5270         int p;\r
5271         for(p=0;p<where.size();++p){\r
5272                 bind_to_schema_pr(where[p]->pr, &fm, Schema);\r
5273         }\r
5274         int s;\r
5275         for(s=0;s<select_list.size();++s){\r
5276                 bind_to_schema_se(select_list[s]->se, &fm, Schema);\r
5277         }\r
5278 \r
5279 //              Collect set of tuples referenced in this HFTA\r
5280 //              input, internal, or output.\r
5281 \r
5282 }\r
5283 \r
5284 col_id_set spx_qpn::get_colrefs(bool ext_fcns_only,table_list *Schema){\r
5285         col_id_set retval, tmp_cset;\r
5286         int p;\r
5287         for(p=0;p<where.size();++p){\r
5288                 gather_pr_col_ids(where[p]->pr, tmp_cset, NULL);\r
5289         }\r
5290         int s;\r
5291         for(s=0;s<select_list.size();++s){\r
5292                 gather_se_col_ids(select_list[s]->se, tmp_cset, NULL);\r
5293         }\r
5294         col_id_set::iterator  cisi;\r
5295         if(ext_fcns_only){\r
5296                 for(cisi=tmp_cset.begin();cisi!=tmp_cset.end();++cisi){\r
5297                         field_entry *fe = Schema->get_field((*cisi).schema_ref, (*cisi).field);\r
5298                         if(fe->get_unpack_fcns().size()>0)\r
5299                                 retval.insert((*cisi));\r
5300                 }\r
5301                 return retval;\r
5302         }\r
5303 \r
5304         return tmp_cset;\r
5305 }\r
5306 \r
5307 col_id_set filter_join_qpn::get_colrefs(bool ext_fcns_only,table_list *Schema){\r
5308         col_id_set retval, tmp_cset;\r
5309         int p;\r
5310         for(p=0;p<where.size();++p){\r
5311                 gather_pr_col_ids(where[p]->pr, tmp_cset, NULL);\r
5312         }\r
5313         int s;\r
5314         for(s=0;s<select_list.size();++s){\r
5315                 gather_se_col_ids(select_list[s]->se, tmp_cset, NULL);\r
5316         }\r
5317         col_id_set::iterator  cisi;\r
5318         if(ext_fcns_only){\r
5319                 for(cisi=tmp_cset.begin();cisi!=tmp_cset.end();++cisi){\r
5320                         field_entry *fe = Schema->get_field((*cisi).schema_ref, (*cisi).field);\r
5321                         if(fe->get_unpack_fcns().size()>0)\r
5322                                 retval.insert((*cisi));\r
5323                 }\r
5324                 return retval;\r
5325         }\r
5326 \r
5327         return tmp_cset;\r
5328 }\r
5329 \r
5330 \r
5331 \r
5332 //              Associate colrefs in SEs with this schema.\r
5333 void join_eq_hash_qpn::bind_to_schema(table_list *Schema){\r
5334 //                      Bind the tablevars in the From clause to the Schema\r
5335 //                      (it might have changed from analysis time)\r
5336         int f;\r
5337         for(f=0;f<from.size();++f){\r
5338                 string snm = from[f]->get_schema_name();\r
5339                 int tbl_ref = Schema->get_table_ref(snm);\r
5340                 if(tbl_ref >= 0)\r
5341                 from[f]->set_schema_ref(tbl_ref);\r
5342         }\r
5343 \r
5344 //                      Bind all SEs to this schema\r
5345         tablevar_list_t fm(from);\r
5346 \r
5347         int p;\r
5348         for(p=0;p<where.size();++p){\r
5349                 bind_to_schema_pr(where[p]->pr, &fm, Schema);\r
5350         }\r
5351         int s;\r
5352         for(s=0;s<select_list.size();++s){\r
5353                 bind_to_schema_se(select_list[s]->se, &fm, Schema);\r
5354         }\r
5355 \r
5356 //              Collect set of tuples referenced in this HFTA\r
5357 //              input, internal, or output.\r
5358 \r
5359 }\r
5360 \r
5361 void filter_join_qpn::bind_to_schema(table_list *Schema){\r
5362 //                      Bind the tablevars in the From clause to the Schema\r
5363 //                      (it might have changed from analysis time)\r
5364         int f;\r
5365         for(f=0;f<from.size();++f){\r
5366                 string snm = from[f]->get_schema_name();\r
5367                 int tbl_ref = Schema->get_table_ref(snm);\r
5368                 if(tbl_ref >= 0)\r
5369                 from[f]->set_schema_ref(tbl_ref);\r
5370         }\r
5371 \r
5372 //                      Bind all SEs to this schema\r
5373         tablevar_list_t fm(from);\r
5374 \r
5375         int p;\r
5376         for(p=0;p<where.size();++p){\r
5377                 bind_to_schema_pr(where[p]->pr, &fm, Schema);\r
5378         }\r
5379         int s;\r
5380         for(s=0;s<select_list.size();++s){\r
5381                 bind_to_schema_se(select_list[s]->se, &fm, Schema);\r
5382         }\r
5383 \r
5384 //              Collect set of tuples referenced in this HFTA\r
5385 //              input, internal, or output.\r
5386 \r
5387 }\r
5388 \r
5389 \r
5390 \r
5391 \r
5392 void sgah_qpn::bind_to_schema(table_list *Schema){\r
5393 //                      Bind the tablevars in the From clause to the Schema\r
5394 //                      (it might have changed from analysis time)\r
5395 \r
5396 \r
5397         int t = Schema->get_table_ref(table_name->get_schema_name() );\r
5398         if(t>=0)\r
5399         table_name->set_schema_ref(t );\r
5400 \r
5401 //                      Get the "from" clause\r
5402         tablevar_list_t fm(table_name);\r
5403 \r
5404 \r
5405 \r
5406 //                      Bind all SEs to this schema\r
5407         int p;\r
5408         for(p=0;p<where.size();++p){\r
5409                 bind_to_schema_pr(where[p]->pr, &fm, Schema);\r
5410         }\r
5411         for(p=0;p<having.size();++p){\r
5412                 bind_to_schema_pr(having[p]->pr, &fm, Schema);\r
5413         }\r
5414         int s;\r
5415         for(s=0;s<select_list.size();++s){\r
5416                 bind_to_schema_se(select_list[s]->se, &fm, Schema);\r
5417         }\r
5418         int g;\r
5419         for(g=0;g<gb_tbl.size();++g){\r
5420                 bind_to_schema_se(gb_tbl.get_def(g), &fm, Schema);\r
5421         }\r
5422         int a;\r
5423         for(a=0;a<aggr_tbl.size();++a){\r
5424                 if(aggr_tbl.is_builtin(a)){\r
5425                         bind_to_schema_se(aggr_tbl.get_aggr_se(a), &fm, Schema);\r
5426                 }else{\r
5427                         vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(a);\r
5428                         int o;\r
5429                         for(o=0;o<opl.size();++o){\r
5430                                 bind_to_schema_se(opl[o],&fm,Schema);\r
5431                         }\r
5432                 }\r
5433         }\r
5434 }\r
5435 \r
5436 col_id_set sgah_qpn::get_colrefs(bool ext_fcns_only,table_list *Schema){\r
5437         col_id_set retval, tmp_cset;\r
5438         int p;\r
5439         for(p=0;p<where.size();++p){\r
5440                 gather_pr_col_ids(where[p]->pr, tmp_cset, &gb_tbl);\r
5441         }\r
5442         int g;\r
5443         for(g=0;g<gb_tbl.size();++g){\r
5444                 gather_se_col_ids(gb_tbl.get_def(g), tmp_cset, &gb_tbl);\r
5445         }\r
5446         int a;\r
5447         for(a=0;a<aggr_tbl.size();++a){\r
5448                 if(aggr_tbl.is_builtin(a)){\r
5449                         gather_se_col_ids(aggr_tbl.get_aggr_se(a), tmp_cset, &gb_tbl);\r
5450                 }else{\r
5451                         vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(a);\r
5452                         int o;\r
5453                         for(o=0;o<opl.size();++o){\r
5454                                 gather_se_col_ids(opl[o], tmp_cset, &gb_tbl);\r
5455                         }\r
5456                 }\r
5457         }\r
5458 \r
5459         col_id_set::iterator  cisi;\r
5460         if(ext_fcns_only){\r
5461                 for(cisi=tmp_cset.begin();cisi!=tmp_cset.end();++cisi){\r
5462                         field_entry *fe = Schema->get_field((*cisi).schema_ref, (*cisi).field);\r
5463                         if(fe->get_unpack_fcns().size()>0)\r
5464                                 retval.insert((*cisi));\r
5465                 }\r
5466                 return retval;\r
5467         }\r
5468 \r
5469         return tmp_cset;\r
5470 }\r
5471 \r
5472 \r
5473 void rsgah_qpn::bind_to_schema(table_list *Schema){\r
5474 //                      Bind the tablevars in the From clause to the Schema\r
5475 //                      (it might have changed from analysis time)\r
5476         int t = Schema->get_table_ref(table_name->get_schema_name() );\r
5477         if(t>=0)\r
5478         table_name->set_schema_ref(t );\r
5479 \r
5480 //                      Get the "from" clause\r
5481         tablevar_list_t fm(table_name);\r
5482 \r
5483 //                      Bind all SEs to this schema\r
5484         int p;\r
5485         for(p=0;p<where.size();++p){\r
5486                 bind_to_schema_pr(where[p]->pr, &fm, Schema);\r
5487         }\r
5488         for(p=0;p<having.size();++p){\r
5489                 bind_to_schema_pr(having[p]->pr, &fm, Schema);\r
5490         }\r
5491         for(p=0;p<closing_when.size();++p){\r
5492                 bind_to_schema_pr(closing_when[p]->pr, &fm, Schema);\r
5493         }\r
5494         int s;\r
5495         for(s=0;s<select_list.size();++s){\r
5496                 bind_to_schema_se(select_list[s]->se, &fm, Schema);\r
5497         }\r
5498         int g;\r
5499         for(g=0;g<gb_tbl.size();++g){\r
5500                 bind_to_schema_se(gb_tbl.get_def(g), &fm, Schema);\r
5501         }\r
5502         int a;\r
5503         for(a=0;a<aggr_tbl.size();++a){\r
5504                 if(aggr_tbl.is_builtin(a)){\r
5505                         bind_to_schema_se(aggr_tbl.get_aggr_se(a), &fm, Schema);\r
5506                 }else{\r
5507                         vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(a);\r
5508                         int o;\r
5509                         for(o=0;o<opl.size();++o){\r
5510                                 bind_to_schema_se(opl[o],&fm,Schema);\r
5511                         }\r
5512                 }\r
5513         }\r
5514 }\r
5515 \r
5516 \r
5517 void sgahcwcb_qpn::bind_to_schema(table_list *Schema){\r
5518 //                      Bind the tablevars in the From clause to the Schema\r
5519 //                      (it might have changed from analysis time)\r
5520         int t = Schema->get_table_ref(table_name->get_schema_name() );\r
5521         if(t>=0)\r
5522         table_name->set_schema_ref(t );\r
5523 \r
5524 //                      Get the "from" clause\r
5525         tablevar_list_t fm(table_name);\r
5526 \r
5527 //                      Bind all SEs to this schema\r
5528         int p;\r
5529         for(p=0;p<where.size();++p){\r
5530                 bind_to_schema_pr(where[p]->pr, &fm, Schema);\r
5531         }\r
5532         for(p=0;p<having.size();++p){\r
5533                 bind_to_schema_pr(having[p]->pr, &fm, Schema);\r
5534         }\r
5535         for(p=0;p<having.size();++p){\r
5536                 bind_to_schema_pr(cleanby[p]->pr, &fm, Schema);\r
5537         }\r
5538         for(p=0;p<having.size();++p){\r
5539                 bind_to_schema_pr(cleanwhen[p]->pr, &fm, Schema);\r
5540         }\r
5541         int s;\r
5542         for(s=0;s<select_list.size();++s){\r
5543                 bind_to_schema_se(select_list[s]->se, &fm, Schema);\r
5544         }\r
5545         int g;\r
5546         for(g=0;g<gb_tbl.size();++g){\r
5547                 bind_to_schema_se(gb_tbl.get_def(g), &fm, Schema);\r
5548         }\r
5549         int a;\r
5550         for(a=0;a<aggr_tbl.size();++a){\r
5551                 if(aggr_tbl.is_builtin(a)){\r
5552                         bind_to_schema_se(aggr_tbl.get_aggr_se(a), &fm, Schema);\r
5553                 }else{\r
5554                         vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(a);\r
5555                         int o;\r
5556                         for(o=0;o<opl.size();++o){\r
5557                                 bind_to_schema_se(opl[o],&fm,Schema);\r
5558                         }\r
5559                 }\r
5560         }\r
5561 }\r
5562 \r
5563 \r
5564 \r
5565 \r
5566 \r
5567 \r
5568 ///////////////////////////////////////////////////////////////\r
5569 ///////////////////////////////////////////////////////////////\r
5570 ///             Functions for code generation.\r
5571 \r
5572 \r
5573 //-----------------------------------------------------------------\r
5574 //              get_cplx_lit_tbl\r
5575 \r
5576 cplx_lit_table *mrg_qpn::get_cplx_lit_tbl(ext_fcn_list *Ext_fcns){\r
5577         return(new cplx_lit_table());\r
5578 }\r
5579 \r
5580 cplx_lit_table *spx_qpn::get_cplx_lit_tbl(ext_fcn_list *Ext_fcns){\r
5581         int i;\r
5582         cplx_lit_table *complex_literals = new cplx_lit_table();\r
5583 \r
5584         for(i=0;i<select_list.size();i++){\r
5585                 find_complex_literal_se(select_list[i]->se, Ext_fcns, complex_literals);\r
5586         }\r
5587         for(i=0;i<where.size();++i){\r
5588                 find_complex_literal_pr(where[i]->pr,Ext_fcns, complex_literals);\r
5589         }\r
5590 \r
5591         return(complex_literals);\r
5592 }\r
5593 \r
5594 cplx_lit_table *sgah_qpn::get_cplx_lit_tbl(ext_fcn_list *Ext_fcns){\r
5595         int i,j;\r
5596         cplx_lit_table *complex_literals = new cplx_lit_table();\r
5597 \r
5598         for(i=0;i<aggr_tbl.size();++i){\r
5599                 if(aggr_tbl.is_builtin(i) && !aggr_tbl.is_star_aggr(i)){\r
5600                         find_complex_literal_se(aggr_tbl.get_aggr_se(i), Ext_fcns, complex_literals);\r
5601                 }else{\r
5602                         vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(i);\r
5603                         for(j=0;j<opl.size();++j)\r
5604                                 find_complex_literal_se(opl[j], Ext_fcns, complex_literals);\r
5605                 }\r
5606         }\r
5607 \r
5608         for(i=0;i<select_list.size();i++){\r
5609                 find_complex_literal_se(select_list[i]->se, Ext_fcns, complex_literals);\r
5610         }\r
5611     for(i=0;i<gb_tbl.size();i++){\r
5612         find_complex_literal_se(gb_tbl.get_def(i), Ext_fcns, complex_literals);\r
5613     }\r
5614         for(i=0;i<where.size();++i){\r
5615                 find_complex_literal_pr(where[i]->pr,Ext_fcns, complex_literals);\r
5616         }\r
5617         for(i=0;i<having.size();++i){\r
5618                         find_complex_literal_pr(having[i]->pr,Ext_fcns, complex_literals);\r
5619         }\r
5620 \r
5621         return(complex_literals);\r
5622 }\r
5623 \r
5624 \r
5625 cplx_lit_table *rsgah_qpn::get_cplx_lit_tbl(ext_fcn_list *Ext_fcns){\r
5626         int i,j;\r
5627         cplx_lit_table *complex_literals = new cplx_lit_table();\r
5628 \r
5629         for(i=0;i<aggr_tbl.size();++i){\r
5630                 if(aggr_tbl.is_builtin(i) && !aggr_tbl.is_star_aggr(i)){\r
5631                         find_complex_literal_se(aggr_tbl.get_aggr_se(i), Ext_fcns, complex_literals);\r
5632                 }else{\r
5633                         vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(i);\r
5634                         for(j=0;j<opl.size();++j)\r
5635                                 find_complex_literal_se(opl[j], Ext_fcns, complex_literals);\r
5636                 }\r
5637         }\r
5638 \r
5639         for(i=0;i<select_list.size();i++){\r
5640                 find_complex_literal_se(select_list[i]->se, Ext_fcns, complex_literals);\r
5641         }\r
5642     for(i=0;i<gb_tbl.size();i++){\r
5643         find_complex_literal_se(gb_tbl.get_def(i), Ext_fcns, complex_literals);\r
5644     }\r
5645         for(i=0;i<where.size();++i){\r
5646                 find_complex_literal_pr(where[i]->pr,Ext_fcns, complex_literals);\r
5647         }\r
5648         for(i=0;i<having.size();++i){\r
5649                         find_complex_literal_pr(having[i]->pr,Ext_fcns, complex_literals);\r
5650         }\r
5651         for(i=0;i<closing_when.size();++i){\r
5652                         find_complex_literal_pr(closing_when[i]->pr,Ext_fcns, complex_literals);\r
5653         }\r
5654 \r
5655         return(complex_literals);\r
5656 }\r
5657 \r
5658 \r
5659 cplx_lit_table *sgahcwcb_qpn::get_cplx_lit_tbl(ext_fcn_list *Ext_fcns){\r
5660         int i,j;\r
5661         cplx_lit_table *complex_literals = new cplx_lit_table();\r
5662 \r
5663         for(i=0;i<aggr_tbl.size();++i){\r
5664                 if(aggr_tbl.is_builtin(i) && !aggr_tbl.is_star_aggr(i)){\r
5665                         find_complex_literal_se(aggr_tbl.get_aggr_se(i), Ext_fcns, complex_literals);\r
5666                 }else{\r
5667                         vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(i);\r
5668                         for(j=0;j<opl.size();++j)\r
5669                                 find_complex_literal_se(opl[j], Ext_fcns, complex_literals);\r
5670                 }\r
5671         }\r
5672 \r
5673         for(i=0;i<select_list.size();i++){\r
5674                 find_complex_literal_se(select_list[i]->se, Ext_fcns, complex_literals);\r
5675         }\r
5676     for(i=0;i<gb_tbl.size();i++){\r
5677         find_complex_literal_se(gb_tbl.get_def(i), Ext_fcns, complex_literals);\r
5678     }\r
5679         for(i=0;i<where.size();++i){\r
5680                 find_complex_literal_pr(where[i]->pr,Ext_fcns, complex_literals);\r
5681         }\r
5682         for(i=0;i<having.size();++i){\r
5683                         find_complex_literal_pr(having[i]->pr,Ext_fcns, complex_literals);\r
5684         }\r
5685         for(i=0;i<cleanwhen.size();++i){\r
5686                         find_complex_literal_pr(cleanwhen[i]->pr,Ext_fcns, complex_literals);\r
5687         }\r
5688         for(i=0;i<cleanby.size();++i){\r
5689                         find_complex_literal_pr(cleanby[i]->pr,Ext_fcns, complex_literals);\r
5690         }\r
5691 \r
5692         return(complex_literals);\r
5693 }\r
5694 \r
5695 cplx_lit_table *join_eq_hash_qpn::get_cplx_lit_tbl(ext_fcn_list *Ext_fcns){\r
5696         int i;\r
5697         cplx_lit_table *complex_literals = new cplx_lit_table();\r
5698 \r
5699         for(i=0;i<select_list.size();i++){\r
5700                 find_complex_literal_se(select_list[i]->se, Ext_fcns, complex_literals);\r
5701         }\r
5702         for(i=0;i<where.size();++i){\r
5703                 find_complex_literal_pr(where[i]->pr,Ext_fcns, complex_literals);\r
5704         }\r
5705 \r
5706         return(complex_literals);\r
5707 }\r
5708 \r
5709 cplx_lit_table *filter_join_qpn::get_cplx_lit_tbl(ext_fcn_list *Ext_fcns){\r
5710         int i;\r
5711         cplx_lit_table *complex_literals = new cplx_lit_table();\r
5712 \r
5713         for(i=0;i<select_list.size();i++){\r
5714                 find_complex_literal_se(select_list[i]->se, Ext_fcns, complex_literals);\r
5715         }\r
5716         for(i=0;i<where.size();++i){\r
5717                 find_complex_literal_pr(where[i]->pr,Ext_fcns, complex_literals);\r
5718         }\r
5719 \r
5720         return(complex_literals);\r
5721 }\r
5722 \r
5723 \r
5724 \r
5725 \r
5726 //-----------------------------------------------------------------\r
5727 //              get_handle_param_tbl\r
5728 \r
5729 vector<handle_param_tbl_entry *> mrg_qpn::get_handle_param_tbl(ext_fcn_list *Ext_fcns){\r
5730     vector<handle_param_tbl_entry *> retval;\r
5731         return(retval);\r
5732 }\r
5733 \r
5734 \r
5735 vector<handle_param_tbl_entry *> spx_qpn::get_handle_param_tbl(ext_fcn_list *Ext_fcns){\r
5736         int i;\r
5737     vector<handle_param_tbl_entry *> retval;\r
5738 \r
5739         for(i=0;i<select_list.size();i++){\r
5740                 find_param_handles_se(select_list[i]->se, Ext_fcns, retval);\r
5741         }\r
5742         for(i=0;i<where.size();++i){\r
5743                 find_param_handles_pr(where[i]->pr,Ext_fcns, retval);\r
5744         }\r
5745 \r
5746         return(retval);\r
5747 }\r
5748 \r
5749 \r
5750 vector<handle_param_tbl_entry *> sgah_qpn::get_handle_param_tbl(ext_fcn_list *Ext_fcns){\r
5751         int i,j;\r
5752     vector<handle_param_tbl_entry *> retval;\r
5753 \r
5754 \r
5755         for(i=0;i<aggr_tbl.size();++i){\r
5756                 if(aggr_tbl.is_builtin(i) && !aggr_tbl.is_star_aggr(i)){\r
5757                         find_param_handles_se(aggr_tbl.get_aggr_se(i), Ext_fcns, retval);\r
5758                 }else{\r
5759                         vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(i);\r
5760                         for(j=0;j<opl.size();++j)\r
5761                                 find_param_handles_se(opl[j], Ext_fcns, retval);\r
5762                 }\r
5763         }\r
5764         for(i=0;i<select_list.size();i++){\r
5765                 find_param_handles_se(select_list[i]->se, Ext_fcns, retval);\r
5766         }\r
5767     for(i=0;i<gb_tbl.size();i++){\r
5768         find_param_handles_se(gb_tbl.get_def(i), Ext_fcns, retval);\r
5769     }\r
5770         for(i=0;i<where.size();++i){\r
5771                 find_param_handles_pr(where[i]->pr,Ext_fcns, retval);\r
5772         }\r
5773         for(i=0;i<having.size();++i){\r
5774                         find_param_handles_pr(having[i]->pr,Ext_fcns, retval);\r
5775         }\r
5776 \r
5777         return(retval);\r
5778 }\r
5779 \r
5780 \r
5781 vector<handle_param_tbl_entry *> rsgah_qpn::get_handle_param_tbl(ext_fcn_list *Ext_fcns){\r
5782         int i,j;\r
5783     vector<handle_param_tbl_entry *> retval;\r
5784 \r
5785 \r
5786         for(i=0;i<aggr_tbl.size();++i){\r
5787                 if(aggr_tbl.is_builtin(i) && !aggr_tbl.is_star_aggr(i)){\r
5788                         find_param_handles_se(aggr_tbl.get_aggr_se(i), Ext_fcns, retval);\r
5789                 }else{\r
5790                         vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(i);\r
5791                         for(j=0;j<opl.size();++j)\r
5792                                 find_param_handles_se(opl[j], Ext_fcns, retval);\r
5793                 }\r
5794         }\r
5795         for(i=0;i<select_list.size();i++){\r
5796                 find_param_handles_se(select_list[i]->se, Ext_fcns, retval);\r
5797         }\r
5798     for(i=0;i<gb_tbl.size();i++){\r
5799         find_param_handles_se(gb_tbl.get_def(i), Ext_fcns, retval);\r
5800     }\r
5801         for(i=0;i<where.size();++i){\r
5802                 find_param_handles_pr(where[i]->pr,Ext_fcns, retval);\r
5803         }\r
5804         for(i=0;i<having.size();++i){\r
5805                         find_param_handles_pr(having[i]->pr,Ext_fcns, retval);\r
5806         }\r
5807         for(i=0;i<closing_when.size();++i){\r
5808                         find_param_handles_pr(closing_when[i]->pr,Ext_fcns, retval);\r
5809         }\r
5810 \r
5811         return(retval);\r
5812 }\r
5813 \r
5814 \r
5815 vector<handle_param_tbl_entry *> sgahcwcb_qpn::get_handle_param_tbl(ext_fcn_list *Ext_fcns){\r
5816         int i,j;\r
5817     vector<handle_param_tbl_entry *> retval;\r
5818 \r
5819 \r
5820         for(i=0;i<aggr_tbl.size();++i){\r
5821                 if(aggr_tbl.is_builtin(i) && !aggr_tbl.is_star_aggr(i)){\r
5822                         find_param_handles_se(aggr_tbl.get_aggr_se(i), Ext_fcns, retval);\r
5823                 }else{\r
5824                         vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(i);\r
5825                         for(j=0;j<opl.size();++j)\r
5826                                 find_param_handles_se(opl[j], Ext_fcns, retval);\r
5827                 }\r
5828         }\r
5829         for(i=0;i<select_list.size();i++){\r
5830                 find_param_handles_se(select_list[i]->se, Ext_fcns, retval);\r
5831         }\r
5832     for(i=0;i<gb_tbl.size();i++){\r
5833         find_param_handles_se(gb_tbl.get_def(i), Ext_fcns, retval);\r
5834     }\r
5835         for(i=0;i<where.size();++i){\r
5836                 find_param_handles_pr(where[i]->pr,Ext_fcns, retval);\r
5837         }\r
5838         for(i=0;i<having.size();++i){\r
5839                         find_param_handles_pr(having[i]->pr,Ext_fcns, retval);\r
5840         }\r
5841         for(i=0;i<cleanwhen.size();++i){\r
5842                         find_param_handles_pr(cleanwhen[i]->pr,Ext_fcns, retval);\r
5843         }\r
5844         for(i=0;i<cleanby.size();++i){\r
5845                         find_param_handles_pr(cleanby[i]->pr,Ext_fcns, retval);\r
5846         }\r
5847 \r
5848         return(retval);\r
5849 }\r
5850 \r
5851 vector<handle_param_tbl_entry *> join_eq_hash_qpn::get_handle_param_tbl(ext_fcn_list *Ext_fcns){\r
5852         int i;\r
5853     vector<handle_param_tbl_entry *> retval;\r
5854 \r
5855         for(i=0;i<select_list.size();i++){\r
5856                 find_param_handles_se(select_list[i]->se, Ext_fcns, retval);\r
5857         }\r
5858         for(i=0;i<where.size();++i){\r
5859                 find_param_handles_pr(where[i]->pr,Ext_fcns, retval);\r
5860         }\r
5861 \r
5862         return(retval);\r
5863 }\r
5864 \r
5865 \r
5866 vector<handle_param_tbl_entry *> filter_join_qpn::get_handle_param_tbl(ext_fcn_list *Ext_fcns){\r
5867         int i;\r
5868     vector<handle_param_tbl_entry *> retval;\r
5869 \r
5870         for(i=0;i<select_list.size();i++){\r
5871                 find_param_handles_se(select_list[i]->se, Ext_fcns, retval);\r
5872         }\r
5873         for(i=0;i<where.size();++i){\r
5874                 find_param_handles_pr(where[i]->pr,Ext_fcns, retval);\r
5875         }\r
5876 \r
5877         return(retval);\r
5878 }\r
5879 \r
5880 ///////////////////////////////////////////////////////////////\r
5881 ///////////////////////////////////////////////////////////////\r
5882 ///             Functions for operator output rates estimations\r
5883 \r
5884 \r
5885 //-----------------------------------------------------------------\r
5886 //              get_rate_estimate\r
5887 \r
5888 double spx_qpn::get_rate_estimate() {\r
5889 \r
5890         // dummy method for now\r
5891         return SPX_SELECTIVITY * DEFAULT_INTERFACE_RATE;\r
5892 }\r
5893 \r
5894 double sgah_qpn::get_rate_estimate() {\r
5895 \r
5896         // dummy method for now\r
5897         return SGAH_SELECTIVITY * DEFAULT_INTERFACE_RATE;\r
5898 }\r
5899 \r
5900 double rsgah_qpn::get_rate_estimate() {\r
5901 \r
5902         // dummy method for now\r
5903         return RSGAH_SELECTIVITY * DEFAULT_INTERFACE_RATE;\r
5904 }\r
5905 \r
5906 double sgahcwcb_qpn::get_rate_estimate() {\r
5907 \r
5908         // dummy method for now\r
5909         return SGAHCWCB_SELECTIVITY * DEFAULT_INTERFACE_RATE;\r
5910 }\r
5911 \r
5912 double mrg_qpn::get_rate_estimate() {\r
5913 \r
5914         // dummy method for now\r
5915         return MRG_SELECTIVITY * DEFAULT_INTERFACE_RATE;\r
5916 }\r
5917 \r
5918 double join_eq_hash_qpn::get_rate_estimate() {\r
5919 \r
5920         // dummy method for now\r
5921         return JOIN_EQ_HASH_SELECTIVITY * DEFAULT_INTERFACE_RATE;\r
5922 }\r
5923 \r
5924 \r
5925 //////////////////////////////////////////////////////////////////////////////\r
5926 //////////////////////////////////////////////////////////////////////////////\r
5927 /////           Generate functors\r
5928 \r
5929 \r
5930 \r
5931 \r
5932 //-------------------------------------------------------------------------\r
5933 //                      Code generation utilities.\r
5934 //-------------------------------------------------------------------------\r
5935 \r
5936 //              Globals referenced by generate utilities\r
5937 \r
5938 static gb_table *segen_gb_tbl;            // Table of all group-by attributes.\r
5939 \r
5940 \r
5941 \r
5942 //                      Generate code that makes reference\r
5943 //                      to the tuple, and not to any aggregates.\r
5944 //                              NEW : it might reference a stateful function.\r
5945 static string generate_se_code(scalarexp_t *se,table_list *schema){\r
5946         string ret;\r
5947     data_type *ldt, *rdt;\r
5948         int o;\r
5949         vector<scalarexp_t *> operands;\r
5950 \r
5951 \r
5952         switch(se->get_operator_type()){\r
5953         case SE_LITERAL:\r
5954                 if(se->is_handle_ref()){\r
5955                         sprintf(tmpstr,"handle_param_%d",se->get_handle_ref() );\r
5956                         ret = tmpstr;\r
5957                         return(ret);\r
5958                 }\r
5959                 if(se->get_literal()->is_cpx_lit()){\r
5960                         sprintf(tmpstr,"complex_literal_%d",se->get_literal()->get_cpx_lit_ref() );\r
5961                         ret = tmpstr;\r
5962                         return(ret);\r
5963                 }\r
5964                 return(se->get_literal()->to_hfta_C_code("")); // not complex no constr.\r
5965         case SE_PARAM:\r
5966                 if(se->is_handle_ref()){\r
5967                         sprintf(tmpstr,"handle_param_%d",se->get_handle_ref() );\r
5968                         ret = tmpstr;\r
5969                         return(ret);\r
5970                 }\r
5971                 ret.append("param_");\r
5972                 ret.append(se->get_param_name());\r
5973                 return(ret);\r
5974         case SE_UNARY_OP:\r
5975         ldt = se->get_left_se()->get_data_type();\r
5976         if(ldt->complex_operator(se->get_op()) ){\r
5977                         ret.append( ldt->get_complex_operator(se->get_op()) );\r
5978                         ret.append("(");\r
5979                         ret.append(generate_se_code(se->get_left_se(),schema));\r
5980             ret.append(")");\r
5981                 }else{\r
5982                         ret.append("(");\r
5983                         ret.append(se->get_op());\r
5984                         ret.append(generate_se_code(se->get_left_se(),schema));\r
5985                         ret.append(")");\r
5986                 }\r
5987                 return(ret);\r
5988         case SE_BINARY_OP:\r
5989         ldt = se->get_left_se()->get_data_type();\r
5990         rdt = se->get_right_se()->get_data_type();\r
5991 \r
5992         if(ldt->complex_operator(rdt, se->get_op()) ){\r
5993                         ret.append( ldt->get_complex_operator(rdt, se->get_op()) );\r
5994                         ret.append("(");\r
5995                         ret.append(generate_se_code(se->get_left_se(),schema));\r
5996                         ret.append(", ");\r
5997                         ret.append(generate_se_code(se->get_right_se(),schema));\r
5998                         ret.append(")");\r
5999                 }else{\r
6000                         ret.append("(");\r
6001                         ret.append(generate_se_code(se->get_left_se(),schema));\r
6002                         ret.append(se->get_op());\r
6003                         ret.append(generate_se_code(se->get_right_se(),schema));\r
6004                         ret.append(")");\r
6005                 }\r
6006                 return(ret);\r
6007         case SE_COLREF:\r
6008                 if(se->is_gb()){                // OK to ref gb attrs, but they're not yet unpacked ...\r
6009                                                         // so return the defining code.\r
6010                         int gref = se->get_gb_ref();\r
6011                         scalarexp_t *gdef_se = segen_gb_tbl->get_def(gref);\r
6012                         ret = generate_se_code(gdef_se, schema );\r
6013 \r
6014                 }else{\r
6015                 sprintf(tmpstr,"unpack_var_%s_%d",\r
6016                   se->get_colref()->get_field().c_str(), se->get_colref()->get_tablevar_ref() );\r
6017                 ret = tmpstr;\r
6018                 }\r
6019                 return(ret);\r
6020         case SE_FUNC:\r
6021                 if(se->is_partial()){\r
6022                         sprintf(tmpstr,"partial_fcn_result_%d",se->get_partial_ref());\r
6023                         ret = tmpstr;\r
6024                 }else{\r
6025                         ret += se->op + "(";\r
6026                         operands = se->get_operands();\r
6027                         bool first_elem = true;\r
6028                         if(se->get_storage_state() != ""){\r
6029                                 ret += "&(stval->state_var_"+se->get_storage_state()+"),cd";\r
6030                                 first_elem = false;\r
6031                         }\r
6032                         for(o=0;o<operands.size();o++){\r
6033                                 if(first_elem) first_elem=false; else ret += ", ";\r
6034                                 if(operands[o]->get_data_type()->is_buffer_type() &&\r
6035                                         (! (operands[o]->is_handle_ref()) ) )\r
6036                                         ret.append("&");\r
6037                                 ret += generate_se_code(operands[o], schema);\r
6038                         }\r
6039                         ret += ")";\r
6040                 }\r
6041                 return(ret);\r
6042         default:\r
6043                 fprintf(stderr,"INTERNAL ERROR in generate_se_code (hfta), line %d, character %d: unknown operator type %d\n",\r
6044                                 se->get_lineno(), se->get_charno(),se->get_operator_type());\r
6045                 return("ERROR in generate_se_code");\r
6046         }\r
6047 }\r
6048 \r
6049 //              generate code that refers only to aggregate data and constants.\r
6050 //                      NEW : modified to handle superaggregates and stateful fcn refs.\r
6051 //                      Assume that the state is in *stval\r
6052 static string generate_se_code_fm_aggr(scalarexp_t *se, string gbvar, string aggvar, table_list *schema){\r
6053 \r
6054         string ret;\r
6055     data_type *ldt, *rdt;\r
6056         int o;\r
6057         vector<scalarexp_t *> operands;\r
6058 \r
6059 \r
6060         switch(se->get_operator_type()){\r
6061         case SE_LITERAL:\r
6062                 if(se->is_handle_ref()){\r
6063                         sprintf(tmpstr,"handle_param_%d",se->get_handle_ref() );\r
6064                         ret = tmpstr;\r
6065                         return(ret);\r
6066                 }\r
6067                 if(se->get_literal()->is_cpx_lit()){\r
6068                         sprintf(tmpstr,"complex_literal_%d",se->get_literal()->get_cpx_lit_ref() );\r
6069                         ret = tmpstr;\r
6070                         return(ret);\r
6071                 }\r
6072                 return(se->get_literal()->to_hfta_C_code("")); // not complex no constr.\r
6073         case SE_PARAM:\r
6074                 if(se->is_handle_ref()){\r
6075                         sprintf(tmpstr,"handle_param_%d",se->get_handle_ref() );\r
6076                         ret = tmpstr;\r
6077                         return(ret);\r
6078                 }\r
6079                 ret.append("param_");\r
6080                 ret.append(se->get_param_name());\r
6081                 return(ret);\r
6082         case SE_UNARY_OP:\r
6083         ldt = se->get_left_se()->get_data_type();\r
6084         if(ldt->complex_operator(se->get_op()) ){\r
6085                         ret.append( ldt->get_complex_operator(se->get_op()) );\r
6086                         ret.append("(");\r
6087                         ret.append(generate_se_code_fm_aggr(se->get_left_se(),gbvar,aggvar,schema));\r
6088             ret.append(")");\r
6089                 }else{\r
6090                         ret.append("(");\r
6091                         ret.append(se->get_op());\r
6092                         ret.append(generate_se_code_fm_aggr(se->get_left_se(),gbvar,aggvar,schema));\r
6093                         ret.append(")");\r
6094                 }\r
6095                 return(ret);\r
6096         case SE_BINARY_OP:\r
6097         ldt = se->get_left_se()->get_data_type();\r
6098         rdt = se->get_right_se()->get_data_type();\r
6099 \r
6100         if(ldt->complex_operator(rdt, se->get_op()) ){\r
6101                         ret.append( ldt->get_complex_operator(rdt, se->get_op()) );\r
6102                         ret.append("(");\r
6103                         ret.append(generate_se_code_fm_aggr(se->get_left_se(),gbvar,aggvar,schema));\r
6104                         ret.append(", ");\r
6105                         ret.append(generate_se_code_fm_aggr(se->get_right_se(),gbvar,aggvar,schema));\r
6106                         ret.append(")");\r
6107                 }else{\r
6108                         ret.append("(");\r
6109                         ret.append(generate_se_code_fm_aggr(se->get_left_se(),gbvar,aggvar,schema));\r
6110                         ret.append(se->get_op());\r
6111                         ret.append(generate_se_code_fm_aggr(se->get_right_se(),gbvar,aggvar,schema));\r
6112                         ret.append(")");\r
6113                 }\r
6114                 return(ret);\r
6115         case SE_COLREF:\r
6116                 if(se->is_gb()){                // OK to ref gb attrs, but they're not yet unpacked ...\r
6117                                                         // so return the defining code.\r
6118                         sprintf(tmpstr,"%s%d",gbvar.c_str(),se->get_gb_ref());\r
6119                         ret = tmpstr;\r
6120 \r
6121                 }else{\r
6122                 fprintf(stderr,"ERROR reference to non-GB column ref not permitted here,"\r
6123                                 "error in query_plan.cc:generate_se_code_fm_aggr, line %d, character %d.\n",\r
6124                                 se->get_lineno(), se->get_charno());\r
6125                 ret = tmpstr;\r
6126                 }\r
6127                 return(ret);\r
6128         case SE_AGGR_STAR:\r
6129         case SE_AGGR_SE:\r
6130                 if(se->is_superaggr()){\r
6131                         sprintf(tmpstr,"stval->aggr_var%d",se->get_aggr_ref());\r
6132                 }else{\r
6133                         sprintf(tmpstr,"%saggr_var%d",aggvar.c_str(),se->get_aggr_ref());\r
6134                 }\r
6135                 ret = tmpstr;\r
6136                 return(ret);\r
6137         case SE_FUNC:\r
6138 //                              Is it a UDAF?\r
6139                 if(se->get_aggr_ref() >= 0){\r
6140                         sprintf(tmpstr,"udaf_ret_%d",se->get_aggr_ref());\r
6141                         ret = tmpstr;\r
6142                         return(ret);\r
6143                 }\r
6144 \r
6145                 if(se->is_partial()){\r
6146                         sprintf(tmpstr,"partial_fcn_result_%d",se->get_partial_ref());\r
6147                         ret = tmpstr;\r
6148                 }else{\r
6149                         ret += se->op + "(";\r
6150                         bool first_elem = true;\r
6151                         if(se->get_storage_state() != ""){\r
6152                                 ret += "&(stval->state_var_"+se->get_storage_state()+"),cd";\r
6153                                 first_elem = false;\r
6154                         }\r
6155                         operands = se->get_operands();\r
6156                         for(o=0;o<operands.size();o++){\r
6157                                 if(first_elem) first_elem=false; else ret += ", ";\r
6158                                 if(operands[o]->get_data_type()->is_buffer_type() &&\r
6159                                         (! (operands[o]->is_handle_ref()) ) )\r
6160                                         ret.append("&");\r
6161                                 ret += generate_se_code_fm_aggr(operands[o], gbvar,aggvar, schema);\r
6162                         }\r
6163                         ret += ")";\r
6164                 }\r
6165                 return(ret);\r
6166         default:\r
6167                 fprintf(stderr,"INTERNAL ERROR in query_plan.cc::generate_se_code_fm_aggr, line %d, character %d: unknown operator type %d\n",\r
6168                                 se->get_lineno(), se->get_charno(),se->get_operator_type());\r
6169                 return("ERROR in generate_se_code_fm_aggr");\r
6170         }\r
6171 \r
6172 }\r
6173 \r
6174 \r
6175 static string unpack_partial_fcn_fm_aggr(scalarexp_t *se, int pfn_id, string gbvar, string aggvar, table_list *schema){\r
6176         string ret;\r
6177         int o;\r
6178         vector<scalarexp_t *> operands;\r
6179 \r
6180 \r
6181         if(se->get_operator_type() != SE_FUNC){\r
6182                 fprintf(stderr,"INTERNAL ERROR, non-function SE passed to unpack_partial_fcn_fm_aggr. line %d, character %d\n",\r
6183                                 se->get_lineno(), se->get_charno());\r
6184                 return("ERROR in unpack_partial_fcn_fm_aggr");\r
6185         }\r
6186 \r
6187         ret = "\tretval = " + se->get_op() + "( ",\r
6188         sprintf(tmpstr, "&partial_fcn_result_%d",pfn_id);\r
6189         ret += tmpstr;\r
6190 \r
6191         if(se->get_storage_state() != ""){\r
6192                 ret += ",&(stval->state_var_"+se->get_storage_state()+"),cd";\r
6193         }\r
6194 \r
6195         operands = se->get_operands();\r
6196         for(o=0;o<operands.size();o++){\r
6197                 ret += ", ";\r
6198                 if(operands[o]->get_data_type()->is_buffer_type() &&\r
6199                                         (! (operands[o]->is_handle_ref()) ) )\r
6200                         ret.append("&");\r
6201                 ret += generate_se_code_fm_aggr(operands[o], gbvar,aggvar, schema);\r
6202         }\r
6203         ret += ");\n";\r
6204 \r
6205         return(ret);\r
6206 }\r
6207 \r
6208 \r
6209 static string unpack_partial_fcn(scalarexp_t *se, int pfn_id, table_list *schema){\r
6210         string ret;\r
6211         int o;\r
6212         vector<scalarexp_t *> operands;\r
6213 \r
6214         if(se->get_operator_type() != SE_FUNC){\r
6215                 fprintf(stderr,"INTERNAL ERROR, non-function SE passed to unpack_partial_fcn. line %d, character %d\n",\r
6216                                 se->get_lineno(), se->get_charno());\r
6217                 return("ERROR in unpack_partial_fcn");\r
6218         }\r
6219 \r
6220         ret = "\tretval = " + se->get_op() + "( ",\r
6221         sprintf(tmpstr, "&partial_fcn_result_%d",pfn_id);\r
6222         ret += tmpstr;\r
6223 \r
6224         if(se->get_storage_state() != ""){\r
6225                 ret += ",&(stval->state_var_"+se->get_storage_state()+"),cd";\r
6226         }\r
6227 \r
6228         operands = se->get_operands();\r
6229         for(o=0;o<operands.size();o++){\r
6230                 ret += ", ";\r
6231                 if(operands[o]->get_data_type()->is_buffer_type() &&\r
6232                                         (! (operands[o]->is_handle_ref()) ) )\r
6233                         ret.append("&");\r
6234                 ret += generate_se_code(operands[o], schema);\r
6235         }\r
6236         ret += ");\n";\r
6237 \r
6238         return(ret);\r
6239 }\r
6240 \r
6241 static string generate_cached_fcn(scalarexp_t *se, int pfn_id, table_list *schema){\r
6242         string ret;\r
6243         int o;\r
6244         vector<scalarexp_t *> operands;\r
6245 \r
6246         if(se->get_operator_type() != SE_FUNC){\r
6247                 fprintf(stderr,"INTERNAL ERROR, non-function SE passed to generate_cached_fcn. line %d, character %d\n",\r
6248                                 se->get_lineno(), se->get_charno());\r
6249                 return("ERROR in generate_cached_fcn");\r
6250         }\r
6251 \r
6252         ret = se->get_op()+"(";\r
6253 \r
6254         if(se->get_storage_state() != ""){\r
6255                 ret += "&(stval->state_var_"+se->get_storage_state()+"),cd,";\r
6256         }\r
6257 \r
6258         operands = se->get_operands();\r
6259         for(o=0;o<operands.size();o++){\r
6260                 if(o) ret += ", ";\r
6261                 if(operands[o]->get_data_type()->is_buffer_type() &&\r
6262                                         (! (operands[o]->is_handle_ref()) ) )\r
6263                         ret.append("&");\r
6264                 ret += generate_se_code(operands[o], schema);\r
6265         }\r
6266         ret += ");\n";\r
6267 \r
6268         return(ret);\r
6269 }\r
6270 \r
6271 \r
6272 \r
6273 \r
6274 \r
6275 static string generate_C_comparison_op(string op){\r
6276   if(op == "=") return("==");\r
6277   if(op == "<>") return("!=");\r
6278   return(op);\r
6279 }\r
6280 \r
6281 static string generate_C_boolean_op(string op){\r
6282         if( (op == "AND") || (op == "And") || (op == "and") ){\r
6283                 return("&&");\r
6284         }\r
6285         if( (op == "OR") || (op == "Or") || (op == "or") ){\r
6286                 return("||");\r
6287         }\r
6288         if( (op == "NOT") || (op == "Not") || (op == "not") ){\r
6289                 return("!");\r
6290         }\r
6291 \r
6292         return("ERROR UNKNOWN BOOLEAN OPERATOR");\r
6293 }\r
6294 \r
6295 \r
6296 static string generate_predicate_code(predicate_t *pr,table_list *schema){\r
6297         string ret;\r
6298         vector<literal_t *>  litv;\r
6299         int i;\r
6300     data_type *ldt, *rdt;\r
6301         vector<scalarexp_t *> op_list;\r
6302         int o;\r
6303 \r
6304         switch(pr->get_operator_type()){\r
6305         case PRED_IN:\r
6306         ldt = pr->get_left_se()->get_data_type();\r
6307 \r
6308                 ret.append("( ");\r
6309                 litv = pr->get_lit_vec();\r
6310                 for(i=0;i<litv.size();i++){\r
6311                         if(i>0) ret.append(" || ");\r
6312                         ret.append("( ");\r
6313 \r
6314                 if(ldt->complex_comparison(ldt) ){\r
6315                                 ret.append( ldt->get_hfta_comparison_fcn(ldt) );\r
6316                                 ret.append("( ");\r
6317                                 if(ldt->is_buffer_type() )\r
6318                                         ret.append("&");\r
6319                                 ret.append(generate_se_code(pr->get_left_se(), schema));\r
6320                                 ret.append(", ");\r
6321                                 if(ldt->is_buffer_type() )\r
6322                                         ret.append("&");\r
6323                                 if(litv[i]->is_cpx_lit()){\r
6324                                         sprintf(tmpstr,"complex_literal_%d",litv[i]->get_cpx_lit_ref() );\r
6325                                         ret += tmpstr;\r
6326                                 }else{\r
6327                                         ret.append(litv[i]->to_C_code(""));\r
6328                                 }\r
6329                                 ret.append(") == 0");\r
6330                         }else{\r
6331                                 ret.append(generate_se_code(pr->get_left_se(), schema));\r
6332                                 ret.append(" == ");\r
6333                                 ret.append(litv[i]->to_hfta_C_code(""));\r
6334                         }\r
6335 \r
6336                         ret.append(" )");\r
6337                 }\r
6338                 ret.append(" )");\r
6339                 return(ret);\r
6340 \r
6341         case PRED_COMPARE:\r
6342         ldt = pr->get_left_se()->get_data_type();\r
6343         rdt = pr->get_right_se()->get_data_type();\r
6344 \r
6345                 ret.append("( ");\r
6346         if(ldt->complex_comparison(rdt) ){\r
6347                         ret.append(ldt->get_hfta_comparison_fcn(rdt));\r
6348                         ret.append("(");\r
6349                         if(ldt->is_buffer_type() )\r
6350                                 ret.append("&");\r
6351                         ret.append(generate_se_code(pr->get_left_se(),schema) );\r
6352                         ret.append(", ");\r
6353                         if(rdt->is_buffer_type() )\r
6354                                 ret.append("&");\r
6355                         ret.append(generate_se_code(pr->get_right_se(),schema) );\r
6356                         ret.append(") ");\r
6357                         ret.append( generate_C_comparison_op(pr->get_op()));\r
6358                         ret.append("0");\r
6359                 }else{\r
6360                         ret.append(generate_se_code(pr->get_left_se(),schema) );\r
6361                         ret.append( generate_C_comparison_op(pr->get_op()));\r
6362                         ret.append(generate_se_code(pr->get_right_se(),schema) );\r
6363                 }\r
6364                 ret.append(" )");\r
6365                 return(ret);\r
6366         case PRED_UNARY_OP:\r
6367                 ret.append("( ");\r
6368                 ret.append( generate_C_boolean_op(pr->get_op()) );\r
6369                 ret.append(generate_predicate_code(pr->get_left_pr(),schema) );\r
6370                 ret.append(" )");\r
6371                 return(ret);\r
6372         case PRED_BINARY_OP:\r
6373                 ret.append("( ");\r
6374                 ret.append(generate_predicate_code(pr->get_left_pr(),schema) );\r
6375                 ret.append( generate_C_boolean_op(pr->get_op()) );\r
6376                 ret.append(generate_predicate_code(pr->get_right_pr(),schema) );\r
6377                 ret.append(" )");\r
6378                 return(ret);\r
6379         case PRED_FUNC:\r
6380                 ret += pr->get_op() + "( ";\r
6381                 op_list = pr->get_op_list();\r
6382                 for(o=0;o<op_list.size();++o){\r
6383                         if(o>0) ret += ", ";\r
6384                         if(op_list[o]->get_data_type()->is_buffer_type() && (! (op_list[o]->is_handle_ref()) ) )\r
6385                                         ret.append("&");\r
6386                         ret += generate_se_code(op_list[o], schema);\r
6387                 }\r
6388                 ret += " )";\r
6389                 return(ret);\r
6390         default:\r
6391                 fprintf(stderr,"INTERNAL ERROR in generate_predicate_code, line %d, character %d, unknown predicate operator type %d\n",\r
6392                         pr->get_lineno(), pr->get_charno(), pr->get_operator_type() );\r
6393                 return("ERROR in generate_predicate_code");\r
6394         }\r
6395 }\r
6396 \r
6397 static string generate_predicate_code_fm_aggr(predicate_t *pr, string gbvar, string aggvar,table_list *schema){\r
6398         string ret;\r
6399         vector<literal_t *>  litv;\r
6400         int i;\r
6401     data_type *ldt, *rdt;\r
6402         vector<scalarexp_t *> op_list;\r
6403         int o;\r
6404 \r
6405         switch(pr->get_operator_type()){\r
6406         case PRED_IN:\r
6407         ldt = pr->get_left_se()->get_data_type();\r
6408 \r
6409                 ret.append("( ");\r
6410                 litv = pr->get_lit_vec();\r
6411                 for(i=0;i<litv.size();i++){\r
6412                         if(i>0) ret.append(" || ");\r
6413                         ret.append("( ");\r
6414 \r
6415                 if(ldt->complex_comparison(ldt) ){\r
6416                                 ret.append( ldt->get_hfta_comparison_fcn(ldt) );\r
6417                                 ret.append("( ");\r
6418                                 if(ldt->is_buffer_type() )\r
6419                                         ret.append("&");\r
6420                                 ret.append(generate_se_code_fm_aggr(pr->get_left_se(), gbvar, aggvar, schema));\r
6421                                 ret.append(", ");\r
6422                                 if(ldt->is_buffer_type() )\r
6423                                         ret.append("&");\r
6424                                 if(litv[i]->is_cpx_lit()){\r
6425                                         sprintf(tmpstr,"complex_literal_%d",litv[i]->get_cpx_lit_ref() );\r
6426                                         ret += tmpstr;\r
6427                                 }else{\r
6428                                         ret.append(litv[i]->to_C_code(""));\r
6429                                 }\r
6430                                 ret.append(") == 0");\r
6431                         }else{\r
6432                                 ret.append(generate_se_code_fm_aggr(pr->get_left_se(), gbvar, aggvar, schema));\r
6433                                 ret.append(" == ");\r
6434                                 ret.append(litv[i]->to_hfta_C_code(""));\r
6435                         }\r
6436 \r
6437                         ret.append(" )");\r
6438                 }\r
6439                 ret.append(" )");\r
6440                 return(ret);\r
6441 \r
6442         case PRED_COMPARE:\r
6443         ldt = pr->get_left_se()->get_data_type();\r
6444         rdt = pr->get_right_se()->get_data_type();\r
6445 \r
6446                 ret.append("( ");\r
6447         if(ldt->complex_comparison(rdt) ){\r
6448                         ret.append(ldt->get_hfta_comparison_fcn(rdt));\r
6449                         ret.append("(");\r
6450                         if(ldt->is_buffer_type() )\r
6451                                 ret.append("&");\r
6452                         ret.append(generate_se_code_fm_aggr(pr->get_left_se(), gbvar, aggvar,schema) );\r
6453                         ret.append(", ");\r
6454                         if(rdt->is_buffer_type() )\r
6455                                 ret.append("&");\r
6456                         ret.append(generate_se_code_fm_aggr(pr->get_right_se(), gbvar, aggvar,schema) );\r
6457                         ret.append(") ");\r
6458                         ret.append( generate_C_comparison_op(pr->get_op()));\r
6459                         ret.append("0");\r
6460                 }else{\r
6461                         ret.append(generate_se_code_fm_aggr(pr->get_left_se(), gbvar, aggvar,schema) );\r
6462                         ret.append( generate_C_comparison_op(pr->get_op()));\r
6463                         ret.append(generate_se_code_fm_aggr(pr->get_right_se(), gbvar, aggvar,schema) );\r
6464                 }\r
6465                 ret.append(" )");\r
6466                 return(ret);\r
6467         case PRED_UNARY_OP:\r
6468                 ret.append("( ");\r
6469                 ret.append( generate_C_boolean_op(pr->get_op()) );\r
6470                 ret.append(generate_predicate_code_fm_aggr(pr->get_left_pr(), gbvar, aggvar,schema) );\r
6471                 ret.append(" )");\r
6472                 return(ret);\r
6473         case PRED_BINARY_OP:\r
6474                 ret.append("( ");\r
6475                 ret.append(generate_predicate_code_fm_aggr(pr->get_left_pr(), gbvar, aggvar,schema) );\r
6476                 ret.append( generate_C_boolean_op(pr->get_op()) );\r
6477                 ret.append(generate_predicate_code_fm_aggr(pr->get_right_pr(), gbvar, aggvar,schema) );\r
6478                 ret.append(" )");\r
6479                 return(ret);\r
6480         case PRED_FUNC:\r
6481                 ret += pr->get_op() + "( ";\r
6482                 op_list = pr->get_op_list();\r
6483                 for(o=0;o<op_list.size();++o){\r
6484                         if(o>0) ret += ", ";\r
6485                         if(op_list[o]->get_data_type()->is_buffer_type() && (! (op_list[o]->is_handle_ref()) ) )\r
6486                                         ret.append("&");\r
6487                         ret += generate_se_code_fm_aggr(op_list[o], gbvar, aggvar, schema);\r
6488                 }\r
6489                 ret += " )";\r
6490                 return(ret);\r
6491         default:\r
6492                 fprintf(stderr,"INTERNAL ERROR in generate_predicate_code, line %d, character %d, unknown predicate operator type %d\n",\r
6493                         pr->get_lineno(), pr->get_charno(), pr->get_operator_type() );\r
6494                 return("ERROR in generate_predicate_code");\r
6495         }\r
6496 }\r
6497 \r
6498 \r
6499 //                              Aggregation code\r
6500 \r
6501 \r
6502 static string generate_equality_test(string &lhs_op, string &rhs_op, data_type *dt){\r
6503         string ret;\r
6504 \r
6505     if(dt->complex_comparison(dt) ){\r
6506                 ret.append(dt->get_hfta_comparison_fcn(dt));\r
6507                 ret.append("(");\r
6508                         if(dt->is_buffer_type() )\r
6509                                 ret.append("&");\r
6510                 ret.append(lhs_op);\r
6511                 ret.append(", ");\r
6512                         if(dt->is_buffer_type() )\r
6513                                 ret.append("&");\r
6514                 ret.append(rhs_op );\r
6515                 ret.append(") == 0");\r
6516         }else{\r
6517                 ret.append(lhs_op );\r
6518                 ret.append(" == ");\r
6519                 ret.append(rhs_op );\r
6520         }\r
6521 \r
6522         return(ret);\r
6523 }\r
6524 \r
6525 static string generate_comparison(string &lhs_op, string &rhs_op, data_type *dt){\r
6526         string ret;\r
6527 \r
6528     if(dt->complex_comparison(dt) ){\r
6529                 ret.append(dt->get_hfta_comparison_fcn(dt));\r
6530                 ret.append("(");\r
6531                         if(dt->is_buffer_type() )\r
6532                                 ret.append("&");\r
6533                 ret.append(lhs_op);\r
6534                 ret.append(", ");\r
6535                         if(dt->is_buffer_type() )\r
6536                                 ret.append("&");\r
6537                 ret.append(rhs_op );\r
6538                 ret.append(") == 0");\r
6539         }else{\r
6540                 ret.append(lhs_op );\r
6541                 ret.append(" == ");\r
6542                 ret.append(rhs_op );\r
6543         }\r
6544 \r
6545         return(ret);\r
6546 }\r
6547 \r
6548 \r
6549 //              Here I assume that only MIN and MAX aggregates can be computed\r
6550 //              over BUFFER data types.\r
6551 \r
6552 static string generate_aggr_update(string var, aggregate_table *atbl,int aidx, table_list *schema){\r
6553         string retval = "\t\t";\r
6554         string op = atbl->get_op(aidx);\r
6555 \r
6556 //              Is it a UDAF\r
6557         if(! atbl->is_builtin(aidx)) {\r
6558                 int o;\r
6559                 retval += op+"_HFTA_AGGR_UPDATE_(";\r
6560                 if(atbl->get_storage_type(aidx)->get_type() != fstring_t) retval+="&";\r
6561                 retval+="("+var+")";\r
6562                 vector<scalarexp_t *> opl = atbl->get_operand_list(aidx);\r
6563                 for(o=0;o<opl.size();++o){{\r
6564                         retval += ",";\r
6565                         if(opl[o]->get_data_type()->is_buffer_type() && (! (opl[o]->is_handle_ref()) ) )\r
6566                                         retval.append("&");\r
6567                                 retval += generate_se_code(opl[o], schema);\r
6568                         }\r
6569                 }\r
6570                 retval += ");\n";\r
6571 \r
6572                 return retval;\r
6573         }\r
6574 \r
6575 \r
6576 //                      builtin processing\r
6577         data_type *dt = atbl->get_data_type(aidx);\r
6578 \r
6579         if(op == "COUNT"){\r
6580                 retval.append(var);\r
6581                 retval.append("++;\n");\r
6582                 return(retval);\r
6583         }\r
6584         if(op == "SUM"){\r
6585                 retval.append(var);\r
6586                 retval.append(" += ");\r
6587                 retval.append(generate_se_code(atbl->get_aggr_se(aidx), schema) );\r
6588                 retval.append(";\n");\r
6589                 return(retval);\r
6590         }\r
6591         if(op == "MIN"){\r
6592                 sprintf(tmpstr,"aggr_tmp_%d",aidx);\r
6593                 retval += dt->make_host_cvar(tmpstr);\r
6594                 retval += " = ";\r
6595                 retval += generate_se_code(atbl->get_aggr_se(aidx), schema )+";\n";\r
6596                 if(dt->complex_comparison(dt)){\r
6597                         if(dt->is_buffer_type())\r
6598                           sprintf(tmpstr,"\t\tif(%s(&aggr_tmp_%d,&(%s)) < 0)\n",dt->get_hfta_comparison_fcn(dt).c_str(), aidx, var.c_str());\r
6599                         else\r
6600                           sprintf(tmpstr,"\t\tif(%s(aggr_tmp_%d,%s) < 0)\n",dt->get_hfta_comparison_fcn(dt).c_str(), aidx, var.c_str());\r
6601                 }else{\r
6602                         sprintf(tmpstr,"\t\tif(aggr_tmp_%d < %s)\n",aidx,var.c_str());\r
6603                 }\r
6604                 retval.append(tmpstr);\r
6605                 if(dt->is_buffer_type()){\r
6606                         sprintf(tmpstr,"\t\t\t%s(&(%s),&aggr_tmp_%d);\n",dt->get_hfta_buffer_replace().c_str(),var.c_str(),aidx);\r
6607                 }else{\r
6608                         sprintf(tmpstr,"\t\t\t%s = aggr_tmp_%d;\n",var.c_str(),aidx);\r
6609                 }\r
6610                 retval.append(tmpstr);\r
6611 \r
6612                 return(retval);\r
6613         }\r
6614         if(op == "MAX"){\r
6615                 sprintf(tmpstr,"aggr_tmp_%d",aidx);\r
6616                 retval+=dt->make_host_cvar(tmpstr);\r
6617                 retval+=" = ";\r
6618                 retval+=generate_se_code(atbl->get_aggr_se(aidx), schema )+";\n";\r
6619                 if(dt->complex_comparison(dt)){\r
6620                         if(dt->is_buffer_type())\r
6621                          sprintf(tmpstr,"\t\tif(%s(&aggr_tmp_%d,&(%s)) > 0)\n",dt->get_hfta_comparison_fcn(dt).c_str(), aidx, var.c_str());\r
6622                         else\r
6623                          sprintf(tmpstr,"\t\tif(%s(aggr_tmp_%d,%s) > 0)\n",dt->get_hfta_comparison_fcn(dt).c_str(), aidx, var.c_str());\r
6624                 }else{\r
6625                         sprintf(tmpstr,"\t\tif(aggr_tmp_%d > %s)\n",aidx,var.c_str());\r
6626                 }\r
6627                 retval.append(tmpstr);\r
6628                 if(dt->is_buffer_type()){\r
6629                         sprintf(tmpstr,"\t\t\t%s(&(%s),&aggr_tmp_%d);\n",dt->get_hfta_buffer_replace().c_str(),var.c_str(),aidx);\r
6630                 }else{\r
6631                         sprintf(tmpstr,"\t\t\t%s = aggr_tmp_%d;\n",var.c_str(),aidx);\r
6632                 }\r
6633                 retval.append(tmpstr);\r
6634 \r
6635                 return(retval);\r
6636 \r
6637         }\r
6638         if(op == "AND_AGGR"){\r
6639                 retval.append(var);\r
6640                 retval.append(" &= ");\r
6641                 retval.append(generate_se_code(atbl->get_aggr_se(aidx), schema) );\r
6642                 retval.append(";\n");\r
6643                 return(retval);\r
6644         }\r
6645         if(op == "OR_AGGR"){\r
6646                 retval.append(var);\r
6647                 retval.append(" |= ");\r
6648                 retval.append(generate_se_code(atbl->get_aggr_se(aidx), schema) );\r
6649                 retval.append(";\n");\r
6650                 return(retval);\r
6651         }\r
6652         if(op == "XOR_AGGR"){\r
6653                 retval.append(var);\r
6654                 retval.append(" ^= ");\r
6655                 retval.append(generate_se_code(atbl->get_aggr_se(aidx), schema) );\r
6656                 retval.append(";\n");\r
6657                 return(retval);\r
6658         }\r
6659         if(op=="AVG"){\r
6660                 retval += var+"_sum += "+generate_se_code(atbl->get_aggr_se(aidx), schema)+";\n";\r
6661                 retval += "\t\t"+var+"_cnt += 1;\n";\r
6662                 retval += "\t\t"+var+" = "+var+"_sum / "+var+"_cnt;\n";\r
6663                 return retval;\r
6664         }\r
6665 \r
6666         fprintf(stderr,"INTERNAL ERROR : aggregate %s not recognized in query_plan::generate_aggr_update.\n",op.c_str());\r
6667         exit(1);\r
6668         return(retval);\r
6669 \r
6670 }\r
6671 \r
6672 \r
6673 //              superaggr minus.\r
6674 \r
6675 static string generate_superaggr_minus(string var, string supervar, aggregate_table *atbl,int aidx, table_list *schema){\r
6676         string retval = "\t\t";\r
6677         string op = atbl->get_op(aidx);\r
6678 \r
6679 //              Is it a UDAF\r
6680         if(! atbl->is_builtin(aidx)) {\r
6681                 int o;\r
6682                 retval += op+"_HFTA_AGGR_MINUS_(";\r
6683                 if(atbl->get_storage_type(aidx)->get_type() != fstring_t) retval+="&";\r
6684                 retval+="("+supervar+"),";\r
6685                 if(atbl->get_storage_type(aidx)->get_type() != fstring_t) retval+="&";\r
6686                 retval+="("+var+");\n";\r
6687 \r
6688                 return retval;\r
6689         }\r
6690 \r
6691 \r
6692         if(op == "COUNT" || op == "SUM"){\r
6693                 retval += supervar + "-=" +var + ";\n";\r
6694                 return(retval);\r
6695         }\r
6696 \r
6697         if(op == "XOR_AGGR"){\r
6698                 retval += supervar + "^=" +var + ";\n";\r
6699                 return(retval);\r
6700         }\r
6701 \r
6702         if(op=="MIN" || op == "MAX")\r
6703                 return "";\r
6704 \r
6705         fprintf(stderr,"INTERNAL ERROR : aggregate %s not recognized in generate_superaggr_minus.\n",op.c_str());\r
6706         exit(1);\r
6707         return(retval);\r
6708 \r
6709 }\r
6710 \r
6711 \r
6712 \r
6713 \r
6714 static string generate_aggr_init(string var, aggregate_table *atbl,int aidx, table_list *schema){\r
6715         string retval;\r
6716         string op = atbl->get_op(aidx);\r
6717 \r
6718 //                      UDAF processing\r
6719         if(! atbl->is_builtin(aidx)){\r
6720 //                      initialize\r
6721                 retval += "\t"+atbl->get_op(aidx)+"_HFTA_AGGR_INIT_(";\r
6722                 if(atbl->get_storage_type(aidx)->get_type() != fstring_t) retval+="&";\r
6723                 retval+="("+var+"));\n";\r
6724 //                      Add 1st tupl\r
6725                 retval += "\t"+atbl->get_op(aidx)+"_HFTA_AGGR_UPDATE_(";\r
6726                 if(atbl->get_storage_type(aidx)->get_type() != fstring_t) retval+="&";\r
6727                 retval+="("+var+")";\r
6728                 vector<scalarexp_t *> opl = atbl->get_operand_list(aidx);\r
6729                 int o;\r
6730                 for(o=0;o<opl.size();++o){\r
6731                         retval += ",";\r
6732                         if(opl[o]->get_data_type()->is_buffer_type() && (! (opl[o]->is_handle_ref()) ) )\r
6733                                         retval.append("&");\r
6734                                 retval += generate_se_code(opl[o],schema);\r
6735                         }\r
6736                 retval += ");\n";\r
6737                 return(retval);\r
6738         }\r
6739 \r
6740 //                      builtin aggregate processing\r
6741         data_type *dt = atbl->get_data_type(aidx);\r
6742 \r
6743         if(op == "COUNT"){\r
6744                 retval = var;\r
6745                 retval.append(" = 1;\n");\r
6746                 return(retval);\r
6747         }\r
6748 \r
6749         if(op == "SUM" || op == "MIN" || op == "MAX" || op == "AND_AGGR" ||\r
6750                                         op=="AVG" || op == "OR_AGGR" || op == "XOR_AGGR"){\r
6751                 if(dt->is_buffer_type()){\r
6752                         sprintf(tmpstr,"\t\taggr_tmp_%d = %s;\n",aidx,generate_se_code(atbl->get_aggr_se(aidx), schema ).c_str() );\r
6753                         retval.append(tmpstr);\r
6754                         sprintf(tmpstr,"\t\t%s(&(%s),&aggr_tmp_%d);\n",dt->get_hfta_buffer_assign_copy().c_str(),var.c_str(),aidx);\r
6755                         retval.append(tmpstr);\r
6756                 }else{\r
6757                         if(op=="AVG"){\r
6758                                 retval += var+"_sum = "+generate_se_code(atbl->get_aggr_se(aidx), schema)+";\n";\r
6759                                 retval += "\t"+var+"_cnt = 1;\n";\r
6760                                 retval += "\t"+var+" = "+var+"_sum;\n";\r
6761                         }else{\r
6762                                 retval = var;\r
6763                                 retval += " = ";\r
6764                                 retval.append(generate_se_code(atbl->get_aggr_se(aidx), schema));\r
6765                                 retval.append(";\n");\r
6766                         }\r
6767                 }\r
6768                 return(retval);\r
6769         }\r
6770 \r
6771         fprintf(stderr,"INTERNAL ERROR : aggregate %s not recognized in query_plan::generate_aggr_init.\n",op.c_str());\r
6772         exit(1);\r
6773         return(retval);\r
6774 \r
6775 }\r
6776 \r
6777 \r
6778 \r
6779 static string generate_aggr_reinitialize(string var, aggregate_table *atbl,int aidx, table_list *schema){\r
6780         string retval;\r
6781         string op = atbl->get_op(aidx);\r
6782 \r
6783 //                      UDAF processing\r
6784         if(! atbl->is_builtin(aidx)){\r
6785 //                      initialize\r
6786                 retval +=  "\t"+atbl->get_op(aidx);\r
6787                 if(atbl->is_running_aggr(aidx)){\r
6788                         retval += "_HFTA_AGGR_REINIT_(";\r
6789                 }else{\r
6790                         retval += "_HFTA_AGGR_INIT_(";\r
6791                 }\r
6792                 if(atbl->get_storage_type(aidx)->get_type() != fstring_t) retval+="&";\r
6793                 retval+="("+var+"));\n";\r
6794                 return(retval);\r
6795         }\r
6796 \r
6797 //                      builtin aggregate processing\r
6798         data_type *dt = atbl->get_data_type(aidx);\r
6799 \r
6800         if(op == "COUNT"){\r
6801                 retval = var;\r
6802                 retval.append(" = 0;\n");\r
6803                 return(retval);\r
6804         }\r
6805 \r
6806         if(op == "SUM" ||  op == "AND_AGGR" ||\r
6807                                                                         op == "OR_AGGR" || op == "XOR_AGGR"){\r
6808                 if(dt->is_buffer_type()){\r
6809                         return("ERROR, cannot yet handle reinitialization of builtin aggregates over strings.");\r
6810                 }else{\r
6811                         retval = var;\r
6812                         retval += " = ";\r
6813                         literal_t l(dt->type_indicator());\r
6814                         retval.append(l.to_string());\r
6815                         retval.append(";\n");\r
6816                 }\r
6817                 return(retval);\r
6818         }\r
6819 \r
6820         if(op == "MIN"){\r
6821                 if(dt->is_buffer_type()){\r
6822                         return("ERROR, cannot yet handle reinitialization of builtin aggregates over strings.");\r
6823                 }else{\r
6824                         retval = var;\r
6825                         retval += " = ";\r
6826                         retval.append(dt->get_max_literal());\r
6827                         retval.append(";\n");\r
6828                 }\r
6829                 return(retval);\r
6830         }\r
6831 \r
6832         if(op == "MAX"){\r
6833                 if(dt->is_buffer_type()){\r
6834                         return("ERROR, cannot yet handle reinitialization of builtin aggregates over strings.");\r
6835                 }else{\r
6836                         retval = var;\r
6837                         retval += " = ";\r
6838                         retval.append(dt->get_min_literal());\r
6839                         retval.append(";\n");\r
6840                 }\r
6841                 return(retval);\r
6842         }\r
6843 \r
6844         fprintf(stderr,"INTERNAL ERROR : aggregate %s not recognized in generate_aggr_reinitialize.\n",op.c_str());\r
6845         exit(1);\r
6846         return(retval);\r
6847 \r
6848 }\r
6849 \r
6850 \r
6851 //                      Generate parameter holding vars from a param table.\r
6852 static string generate_param_vars(param_table *param_tbl){\r
6853         string ret;\r
6854         int p;\r
6855         vector<string> param_vec = param_tbl->get_param_names();\r
6856         for(p=0;p<param_vec.size();p++){\r
6857                 data_type *dt = param_tbl->get_data_type(param_vec[p]);\r
6858                 sprintf(tmpstr,"param_%s;\n", param_vec[p].c_str());\r
6859                 ret += "\t"+dt->make_host_cvar(tmpstr)+";\n";\r
6860                 if(param_tbl->handle_access(param_vec[p])){\r
6861                         ret += "\tstruct search_handle *param_handle_"+param_vec[p]+";\n";\r
6862                 }\r
6863         }\r
6864         return(ret);\r
6865 }\r
6866 \r
6867 //                      Parameter manipulation routines\r
6868 static string generate_load_param_block(string functor_name,\r
6869                                                         param_table *param_tbl,\r
6870                                                         vector<handle_param_tbl_entry *> param_handle_table\r
6871                                                         ){\r
6872         int p;\r
6873         vector<string> param_names = param_tbl->get_param_names();\r
6874 \r
6875         string ret = "int load_params_"+functor_name+"(gs_int32_t sz, void *value){\n";\r
6876     ret.append("\tint pos=0;\n");\r
6877     ret.append("\tint data_pos;\n");\r
6878 \r
6879         for(p=0;p<param_names.size();p++){\r
6880                 data_type *dt = param_tbl->get_data_type(param_names[p]);\r
6881                 if(dt->is_buffer_type()){\r
6882                         sprintf(tmpstr,"tmp_var_%s;\n", param_names[p].c_str());\r
6883                         ret += "\t"+dt->make_host_cvar(tmpstr)+";\n";\r
6884                 }\r
6885         }\r
6886 \r
6887 \r
6888 //              Verify that the block is of minimum size\r
6889         if(param_names.size() > 0){\r
6890                 ret += "//\tVerify that the value block is large enough */\n";\r
6891                 ret.append("\n\tdata_pos = ");\r
6892                 for(p=0;p<param_names.size();p++){\r
6893                         if(p>0) ret.append(" + ");\r
6894                         data_type *dt = param_tbl->get_data_type(param_names[p]);\r
6895                         ret.append("sizeof( ");\r
6896                         ret.append( dt->get_host_cvar_type() );\r
6897                         ret.append(" )");\r
6898                 }\r
6899                 ret.append(";\n");\r
6900                 ret.append("\tif(data_pos > sz) return 1;\n\n");\r
6901         }\r
6902 \r
6903 ///////////////////////\r
6904 ///             Verify that all strings can be unpacked.\r
6905 \r
6906         ret += "//\tVerify that the strings can be unpacked */\n";\r
6907         for(p=0;p<param_names.size();p++){\r
6908                 data_type *dt = param_tbl->get_data_type(param_names[p]);\r
6909                 if(dt->is_buffer_type()){\r
6910                         sprintf(tmpstr,"\ttmp_var_%s =  *( (%s *)((gs_sp_t )value+pos) );\n",param_names[p].c_str(), dt->get_host_cvar_type().c_str() );\r
6911                         ret.append(tmpstr);\r
6912                         switch( dt->get_type() ){\r
6913                         case v_str_t:\r
6914 //                              ret += "\ttmp_var_"+param_names[p]+".offset = ntohl( tmp_var_"+param_names[p]+".offset );\n";           // ntoh conversion\r
6915 //                              ret += "\ttmp_var_"+param_names[p]+".length = ntohl( tmp_var_"+param_names[p]+".length );\n";   // ntoh conversion\r
6916                                 sprintf(tmpstr,"\tif( (int)(tmp_var_%s.offset) + tmp_var_%s.length > sz) return 1;\n",param_names[p].c_str(), param_names[p].c_str() );\r
6917                                 ret.append(tmpstr);\r
6918                                 sprintf(tmpstr,"\ttmp_var_%s.offset = (gs_p_t)( (gs_sp_t )value + (gs_p_t)(tmp_var_%s.offset) );\n",param_names[p].c_str(), param_names[p].c_str() );\r
6919                                 ret.append(tmpstr);\r
6920                         break;\r
6921                         default:\r
6922                                 fprintf(stderr,"ERROR: parameter %s is of type %s, a buffered type, but I don't know how to unpack it as a parameter.\n",param_names[p].c_str(), dt->to_string().c_str() );\r
6923                                 exit(1);\r
6924                         break;\r
6925                         }\r
6926                 }\r
6927                 ret += "\tpos += sizeof( "+dt->get_host_cvar_type()+" );\n";\r
6928         }\r
6929 \r
6930 \r
6931 /////////////////////////\r
6932 \r
6933         ret += "/*\tThe block is OK, do the unpacking.  */\n";\r
6934         ret += "\tpos = 0;\n";\r
6935 \r
6936         for(p=0;p<param_names.size();p++){\r
6937                 data_type *dt = param_tbl->get_data_type(param_names[p]);\r
6938                 if(dt->is_buffer_type()){\r
6939             sprintf(tmpstr,"\t%s(&param_%s, &tmp_var_%s);\n", dt->get_hfta_buffer_assign_copy().c_str(),param_names[p].c_str(),param_names[p].c_str() );\r
6940             ret.append(tmpstr);\r
6941                 }else{\r
6942 //                      if(dt->needs_hn_translation()){\r
6943 //                              sprintf(tmpstr,"\tparam_%s =  %s( *( (%s *)( (gs_sp_t )value+pos) ) );\n",\r
6944 //                                param_names[p].c_str(), dt->ntoh_translation().c_str(), dt->get_host_cvar_type().c_str() );\r
6945 //                      }else{\r
6946                                 sprintf(tmpstr,"\tparam_%s =  *( (%s *)( (gs_sp_t )value+pos) );\n",\r
6947                                   param_names[p].c_str(), dt->get_host_cvar_type().c_str() );\r
6948 //                      }\r
6949                         ret.append(tmpstr);\r
6950                 }\r
6951                 ret += "\tpos += sizeof( "+dt->get_host_cvar_type()+" );\n";\r
6952         }\r
6953 \r
6954 //                      TODO: I think this method of handle registration is obsolete\r
6955 //                      and should be deleted.\r
6956 //                         some examination reveals that handle_access is always false.\r
6957         for(p=0;p<param_names.size();p++){\r
6958                 if(param_tbl->handle_access(param_names[p]) ){\r
6959                         data_type *pdt = param_tbl->get_data_type(param_names[p]);\r
6960 //                                      create the new.\r
6961                         ret += "\tt->param_handle_"+param_names[p]+" = " +\r
6962                                 pdt->handle_registration_name() +\r
6963                                 "((struct FTA *)t, &(t->param_"+param_names[p]+"));\n";\r
6964                 }\r
6965         }\r
6966 //                      Register the pass-by-handle parameters\r
6967 \r
6968         ret += "/* register the pass-by-handle parameters */\n";\r
6969 \r
6970     int ph;\r
6971     for(ph=0;ph<param_handle_table.size();++ph){\r
6972                 data_type pdt(param_handle_table[ph]->type_name);\r
6973                 switch(param_handle_table[ph]->val_type){\r
6974                 case cplx_lit_e:\r
6975                         break;\r
6976                 case litval_e:\r
6977                         break;\r
6978                 case param_e:\r
6979                         sprintf(tmpstr,"\thandle_param_%d = %s(",ph,param_handle_table[ph]->lfta_registration_fcn().c_str());\r
6980                         ret += tmpstr;\r
6981                         if(pdt.is_buffer_type()) ret += "&(";\r
6982                         ret += "param_"+param_handle_table[ph]->param_name;\r
6983                         if(pdt.is_buffer_type()) ret += ")";\r
6984                     ret += ");\n";\r
6985                         break;\r
6986                 default:\r
6987                         fprintf(stderr, "INTERNAL ERROR unknown case found when processing pass-by-handle parameter table.\n");\r
6988                         exit(1);\r
6989                 }\r
6990         }\r
6991 \r
6992 \r
6993         ret += "\treturn(0);\n";\r
6994         ret.append("}\n\n");\r
6995 \r
6996         return(ret);\r
6997 \r
6998 }\r
6999 \r
7000 static string generate_delete_param_block(string functor_name,\r
7001                                                 param_table *param_tbl,\r
7002                                                 vector<handle_param_tbl_entry *> param_handle_table\r
7003                                 ){\r
7004 \r
7005         int p;\r
7006         vector<string> param_names = param_tbl->get_param_names();\r
7007 \r
7008         string ret = "void destroy_params_"+functor_name+"(){\n";\r
7009 \r
7010         for(p=0;p<param_names.size();p++){\r
7011                 data_type *dt = param_tbl->get_data_type(param_names[p]);\r
7012                 if(dt->is_buffer_type()){\r
7013                         sprintf(tmpstr,"\t\t%s(&param_%s);\n",dt->get_hfta_buffer_destroy().c_str(),param_names[p].c_str());\r
7014                         ret.append(tmpstr);\r
7015                 }\r
7016                 if(param_tbl->handle_access(param_names[p]) ){\r
7017                         ret += "\t\t" + dt->get_handle_destructor() +\r
7018                                 "(t->param_handle_" + param_names[p] + ");\n";\r
7019                 }\r
7020         }\r
7021 \r
7022         ret += "//\t\tDeregister handles.\n";\r
7023     int ph;\r
7024     for(ph=0;ph<param_handle_table.size();++ph){\r
7025                 if(param_handle_table[ph]->val_type == param_e){\r
7026                   sprintf(tmpstr, "\t\t%s(handle_param_%d);\n",\r
7027                         param_handle_table[ph]->lfta_deregistration_fcn().c_str(),ph);\r
7028                   ret += tmpstr;\r
7029                 }\r
7030         }\r
7031 \r
7032         ret += "}\n\n";\r
7033         return ret;\r
7034 }\r
7035 \r
7036 // ---------------------------------------------------------------------\r
7037 //              functions for creating functor variables.\r
7038 \r
7039 static string generate_access_vars(col_id_set &cid_set, table_list *schema){\r
7040         string ret;\r
7041         col_id_set::iterator csi;\r
7042 \r
7043         for(csi=cid_set.begin(); csi!=cid_set.end();++csi){\r
7044         int schref = (*csi).schema_ref;\r
7045                 int tblref = (*csi).tblvar_ref;\r
7046                 string field = (*csi).field;\r
7047                 data_type dt(schema->get_type_name(schref,field));\r
7048                 sprintf(tmpstr,"unpack_var_%s_%d", field.c_str(), tblref);\r
7049                 ret+="\t"+dt.make_host_cvar(tmpstr)+";\n";\r
7050                 sprintf(tmpstr,"\tgs_int32_t unpack_offset_%s_%d;\n", field.c_str(), tblref);\r
7051                 ret.append(tmpstr);\r
7052         }\r
7053         return(ret);\r
7054 }\r
7055 \r
7056 static string generate_partial_fcn_vars(vector<scalarexp_t *> &partial_fcns,\r
7057         vector<int> &ref_cnt, vector<bool> &is_partial, bool gen_fcn_cache){\r
7058         string ret;\r
7059         int p;\r
7060 \r
7061 \r
7062         for(p=0;p<partial_fcns.size();++p){\r
7063                 if(!gen_fcn_cache || is_partial[p] ||  ref_cnt[p]>1){\r
7064                         sprintf(tmpstr,"partial_fcn_result_%d", p);\r
7065                         ret+="\t"+partial_fcns[p]->get_data_type()->make_host_cvar(tmpstr)+";\n";\r
7066                         if(gen_fcn_cache && ref_cnt[p]>1){\r
7067                                 ret+="\tint fcn_ref_cnt_"+int_to_string(p)+";\n";\r
7068                         }\r
7069                 }\r
7070         }\r
7071         return(ret);\r
7072 }\r
7073 \r
7074 \r
7075 static string generate_complex_lit_vars(cplx_lit_table *complex_literals){\r
7076         string ret;\r
7077     int cl;\r
7078     for(cl=0;cl<complex_literals->size();cl++){\r
7079         literal_t *l = complex_literals->get_literal(cl);\r
7080         data_type *dtl = new data_type( l->get_type() );\r
7081         sprintf(tmpstr,"complex_literal_%d",cl);\r
7082                 ret += "\t"+dtl->make_host_cvar(tmpstr)+";\n";\r
7083         if(complex_literals->is_handle_ref(cl)){\r
7084             sprintf(tmpstr,"\tstruct search_handle *lit_handle_%d;\n",cl);\r
7085             ret.append(tmpstr);\r
7086         }\r
7087     }\r
7088         return(ret);\r
7089 }\r
7090 \r
7091 \r
7092 static string generate_pass_by_handle_vars(\r
7093                                 vector<handle_param_tbl_entry *> &param_handle_table){\r
7094         string ret;\r
7095         int p;\r
7096 \r
7097         for(p=0;p<param_handle_table.size();++p){\r
7098                 sprintf(tmpstr,"\tgs_param_handle_t handle_param_%d;\n",p);\r
7099                 ret += tmpstr;\r
7100         }\r
7101 \r
7102         return(ret);\r
7103 }\r
7104 \r
7105 \r
7106 // ------------------------------------------------------------\r
7107 //              functions for generating initialization code.\r
7108 \r
7109 static string gen_access_var_init(col_id_set &cid_set){\r
7110         string ret;\r
7111         col_id_set::iterator csi;\r
7112 \r
7113     for(csi=cid_set.begin(); csi!=cid_set.end();++csi){\r
7114         int tblref = (*csi).tblvar_ref;\r
7115         string field = (*csi).field;\r
7116         sprintf(tmpstr,"\tunpack_offset_%s_%d = ftaschema_get_field_offset_by_name(schema_handle%d, \"%s\");\n", field.c_str(),tblref,tblref,field.c_str());\r
7117         ret.append(tmpstr);\r
7118     }\r
7119         return ret;\r
7120 }\r
7121 \r
7122 \r
7123 static string gen_complex_lit_init(cplx_lit_table *complex_literals){\r
7124         string ret;\r
7125 \r
7126         int cl;\r
7127     for(cl=0;cl<complex_literals->size();cl++){\r
7128         literal_t *l = complex_literals->get_literal(cl);\r
7129 //        sprintf(tmpstr,"\tcomplex_literal_%d = ",cl);\r
7130 //        ret += tmpstr + l->to_hfta_C_code() + ";\n";\r
7131         sprintf(tmpstr,"&(complex_literal_%d)",cl);\r
7132         ret += "\t" + l->to_hfta_C_code(tmpstr) + ";\n";\r
7133 //                      I think that the code below is obsolete\r
7134 //                      TODO: it is obsolete.  add_cpx_lit is always\r
7135 //                      called with the handle indicator being false.\r
7136 //                      This entire structure should be cleansed.\r
7137         if(complex_literals->is_handle_ref(cl)){\r
7138             data_type *dt = new data_type( l->get_type() );\r
7139             sprintf(tmpstr,"\tlit_handle_%d = %s(&(f->complex_literal_%d));\n",\r
7140                 cl, dt->hfta_handle_registration_name().c_str(), cl);\r
7141             ret += tmpstr;\r
7142             delete dt;\r
7143        }\r
7144     }\r
7145         return(ret);\r
7146 }\r
7147 \r
7148 \r
7149 static string gen_partial_fcn_init(vector<scalarexp_t *> &partial_fcns){\r
7150         string ret;\r
7151 \r
7152         int p;\r
7153         for(p=0;p<partial_fcns.size();++p){\r
7154                 data_type *pdt =partial_fcns[p]->get_data_type();\r
7155                 literal_t empty_lit(pdt->type_indicator());\r
7156                 if(pdt->is_buffer_type()){\r
7157 //                      sprintf(tmpstr,"\tpartial_fcn_result_%d = %s;\n",\r
7158 //                               p, empty_lit.to_hfta_C_code().c_str());\r
7159                         sprintf(tmpstr,"&(partial_fcn_result_%d)",p);\r
7160                         ret += "\t"+empty_lit.to_hfta_C_code(tmpstr)+";\n";\r
7161                 }\r
7162         }\r
7163         return(ret);\r
7164 }\r
7165 \r
7166 static string gen_pass_by_handle_init(\r
7167                                 vector<handle_param_tbl_entry *> &param_handle_table){\r
7168         string ret;\r
7169 \r
7170     int ph;\r
7171     for(ph=0;ph<param_handle_table.size();++ph){\r
7172                 data_type pdt(param_handle_table[ph]->type_name);\r
7173                 sprintf(tmpstr,"\thandle_param_%d = %s(",ph,param_handle_table[ph]->lfta_registration_fcn().c_str());\r
7174                 switch(param_handle_table[ph]->val_type){\r
7175                 case cplx_lit_e:\r
7176                         ret += tmpstr;\r
7177                         if(pdt.is_buffer_type()) ret += "&(";\r
7178                         sprintf(tmpstr,"complex_literal_%d",param_handle_table[ph]->complex_literal_idx);\r
7179                         ret += tmpstr;\r
7180                         if(pdt.is_buffer_type()) ret += ")";\r
7181                         ret += ");\n";\r
7182                         break;\r
7183                 case litval_e:\r
7184                         ret += tmpstr;\r
7185                         ret += param_handle_table[ph]->litval->to_hfta_C_code("") + ");\n";\r
7186 //                      ret += ");\n";\r
7187                         break;\r
7188                 case param_e:\r
7189 //                              query parameter handles are regstered/deregistered in the\r
7190 //                              load_params function.\r
7191 //                      ret += "t->param_"+param_handle_table[ph]->param_name;\r
7192                         break;\r
7193                 default:\r
7194                         fprintf(stderr, "INTERNAL ERROR unknown case found when processing pass-by-handle parameter table.\n");\r
7195                         exit(1);\r
7196                 }\r
7197         }\r
7198         return(ret);\r
7199 }\r
7200 \r
7201 //------------------------------------------------------------\r
7202 //                      functions for destructor and deregistration code\r
7203 \r
7204 static string gen_complex_lit_dtr(cplx_lit_table *complex_literals){\r
7205         string ret;\r
7206 \r
7207         int cl;\r
7208     for(cl=0;cl<complex_literals->size();cl++){\r
7209         literal_t *l = complex_literals->get_literal(cl);\r
7210                 data_type ldt(  l->get_type() );\r
7211         if(ldt.is_buffer_type()){\r
7212                         sprintf(tmpstr,"\t\t%s(&complex_literal_%d);\n",\r
7213                           ldt.get_hfta_buffer_destroy().c_str(), cl );\r
7214             ret += tmpstr;\r
7215         }\r
7216     }\r
7217         return(ret);\r
7218 }\r
7219 \r
7220 \r
7221 static string gen_pass_by_handle_dtr(\r
7222                                 vector<handle_param_tbl_entry *> &param_handle_table){\r
7223         string ret;\r
7224 \r
7225         int ph;\r
7226     for(ph=0;ph<param_handle_table.size();++ph){\r
7227                 sprintf(tmpstr, "\t\t%s(handle_param_%d);\n",\r
7228                         param_handle_table[ph]->lfta_deregistration_fcn().c_str(),ph);\r
7229                 ret += tmpstr;\r
7230         }\r
7231         return(ret);\r
7232 }\r
7233 \r
7234 //                      Destroy all previous results\r
7235 static string gen_partial_fcn_dtr(vector<scalarexp_t *> &partial_fcns){\r
7236         string ret;\r
7237 \r
7238         int p;\r
7239         for(p=0;p<partial_fcns.size();++p){\r
7240                 data_type *pdt =partial_fcns[p]->get_data_type();\r
7241                 if(pdt->is_buffer_type()){\r
7242                         sprintf(tmpstr,"\t\t%s(&partial_fcn_result_%d);\n",\r
7243                           pdt->get_hfta_buffer_destroy().c_str(), p );\r
7244                         ret += tmpstr;\r
7245                 }\r
7246         }\r
7247         return(ret);\r
7248 }\r
7249 \r
7250 //              Destroy previsou results of fcns in pfcn_set\r
7251 static string gen_partial_fcn_dtr(vector<scalarexp_t *> &partial_fcns, set<int> &pfcn_set){\r
7252         string ret;\r
7253         set<int>::iterator si;\r
7254 \r
7255         for(si=pfcn_set.begin(); si!=pfcn_set.end(); ++si){\r
7256                 data_type *pdt =partial_fcns[(*si)]->get_data_type();\r
7257                 if(pdt->is_buffer_type()){\r
7258                         sprintf(tmpstr,"\t\t%s(&partial_fcn_result_%d);\n",\r
7259                           pdt->get_hfta_buffer_destroy().c_str(), (*si) );\r
7260                         ret += tmpstr;\r
7261                 }\r
7262         }\r
7263         return(ret);\r
7264 }\r
7265 \r
7266 \r
7267 //-------------------------------------------------------------------------\r
7268 //                      Functions related to se generation bookkeeping.\r
7269 \r
7270 static void get_new_pred_cids(predicate_t *pr, col_id_set &found_cids,\r
7271                                                                 col_id_set &new_cids, gb_table *gtbl){\r
7272         col_id_set this_pred_cids;\r
7273         col_id_set::iterator csi;\r
7274 \r
7275 //                              get colrefs in predicate not already found.\r
7276         gather_pr_col_ids(pr,this_pred_cids,gtbl);\r
7277         set_difference(this_pred_cids.begin(), this_pred_cids.end(),\r
7278                                            found_cids.begin(), found_cids.end(),\r
7279                                                 inserter(new_cids,new_cids.begin()) );\r
7280 \r
7281 //                              We've found these cids, so update found_cids\r
7282         for(csi=new_cids.begin(); csi!=new_cids.end(); ++csi)\r
7283                 found_cids.insert((*csi));\r
7284 \r
7285 }\r
7286 \r
7287 //              after the call, new_cids will have the colrefs in se but not found_cids.\r
7288 //              update found_cids with the new cids.\r
7289 static void get_new_se_cids(scalarexp_t *se, col_id_set &found_cids,\r
7290                                                                 col_id_set &new_cids, gb_table *gtbl){\r
7291         col_id_set this_se_cids;\r
7292         col_id_set::iterator csi;\r
7293 \r
7294 //                              get colrefs in se not already found.\r
7295         gather_se_col_ids(se,this_se_cids,gtbl);\r
7296         set_difference(this_se_cids.begin(), this_se_cids.end(),\r
7297                                            found_cids.begin(), found_cids.end(),\r
7298                                                 inserter(new_cids,new_cids.begin()) );\r
7299 \r
7300 //                              We've found these cids, so update found_cids\r
7301         for(csi=new_cids.begin(); csi!=new_cids.end(); ++csi)\r
7302                 found_cids.insert((*csi));\r
7303 \r
7304 }\r
7305 \r
7306 static string gen_unpack_cids(table_list *schema, col_id_set &new_cids, string on_problem, vector<bool> &needs_xform){\r
7307         string ret;\r
7308         col_id_set::iterator csi;\r
7309 \r
7310         for(csi=new_cids.begin(); csi!=new_cids.end(); ++csi){\r
7311         int schref = (*csi).schema_ref;\r
7312             int tblref = (*csi).tblvar_ref;\r
7313         string field = (*csi).field;\r
7314                 data_type dt(schema->get_type_name(schref,field));\r
7315                 string unpack_fcn;\r
7316                 if(needs_xform[tblref]){\r
7317                         unpack_fcn = dt.get_hfta_unpack_fcn();\r
7318                 }else{\r
7319                         unpack_fcn = dt.get_hfta_unpack_fcn_noxf();\r
7320                 }\r
7321                 if(dt.is_buffer_type()){\r
7322                         sprintf(tmpstr,"\t unpack_var_%s_%d = %s(tup%d.data, tup%d.tuple_size, unpack_offset_%s_%d, &problem);\n",field.c_str(), tblref, unpack_fcn.c_str(), tblref, tblref, field.c_str(), tblref);\r
7323                 }else{\r
7324                         sprintf(tmpstr,"\t unpack_var_%s_%d = %s_nocheck(tup%d.data,  unpack_offset_%s_%d);\n",field.c_str(), tblref, unpack_fcn.c_str(), tblref,  field.c_str(), tblref);\r
7325                 }\r
7326                 ret += tmpstr;\r
7327                 if(dt.is_buffer_type()){\r
7328                         ret += "\tif(problem) return "+on_problem+" ;\n";\r
7329                 }\r
7330         }\r
7331         return(ret);\r
7332 }\r
7333 \r
7334 // generates the declaration of all the variables related to\r
7335 // temp tuples generation\r
7336 static string gen_decl_temp_vars(){\r
7337         string ret;\r
7338 \r
7339         ret += "\t// variables related to temp tuple generation\n";\r
7340         ret += "\tbool temp_tuple_received;\n";\r
7341 \r
7342         return(ret);\r
7343 }\r
7344 \r
7345 // generates initialization code for variables related to temp tuple processing\r
7346 static string gen_init_temp_vars(table_list *schema, vector<select_element *>& select_list, gb_table *gtbl){\r
7347         string ret;\r
7348         col_id_set::iterator csi;\r
7349         int s;\r
7350 \r
7351 //              Initialize internal state\r
7352         ret += "\ttemp_tuple_received = false;\n";\r
7353 \r
7354         col_id_set temp_cids;   // colrefs unpacked thus far.\r
7355 \r
7356         for(s=0;s<select_list.size();s++){\r
7357                 if (select_list[s]->se->get_data_type()->is_temporal()) {\r
7358 //                      Find the set of attributes accessed in this SE\r
7359                         col_id_set new_cids;\r
7360                         get_new_se_cids(select_list[s]->se,temp_cids, new_cids, gtbl);\r
7361 \r
7362                         // init these vars\r
7363                         for(csi=new_cids.begin(); csi!=new_cids.end(); ++csi){\r
7364                                 int schref = (*csi).schema_ref;\r
7365                                 int tblref = (*csi).tblvar_ref;\r
7366                                 string field = (*csi).field;\r
7367                                 data_type dt(schema->get_type_name(schref,field), schema->get_modifier_list(schref,field));\r
7368 \r
7369                                 sprintf(tmpstr,"\t unpack_var_%s_%d = %s;\n", field.c_str(), tblref,\r
7370                                         dt.is_increasing() ? dt.get_min_literal().c_str() : dt.get_max_literal().c_str());\r
7371                                 ret += tmpstr;\r
7372                         }\r
7373                 }\r
7374         }\r
7375         return(ret);\r
7376 }\r
7377 \r
7378 \r
7379 \r
7380 // generates a check if tuple is temporal\r
7381 static string gen_temp_tuple_check(string node_name, int channel) {\r
7382         string ret;\r
7383 \r
7384         char tmpstr[256];\r
7385         sprintf(tmpstr, "tup%d", channel);\r
7386         string tup_name = tmpstr;\r
7387         sprintf(tmpstr, "schema_handle%d", channel);\r
7388         string schema_handle_name = tmpstr;\r
7389         string tuple_offset_name = "tuple_metadata_offset"+int_to_string(channel);\r
7390 \r
7391 //                      check if it is a temporary status tuple\r
7392         ret += "\t// check if tuple is temp status tuple\n";\r
7393 //              ret += "\tif (ftaschema_is_temporal_tuple(" + schema_handle_name + ", " + tup_name + ".data)) {\n";\r
7394         ret += "\tif (ftaschema_is_temporal_tuple_offset(" + tuple_offset_name + ", " + tup_name + ".data)) {\n";\r
7395         ret += "\t\ttemp_tuple_received = true;\n";\r
7396         ret += "\t}\n";\r
7397         ret += "\telse\n\t\ttemp_tuple_received = false;\n\n";\r
7398 \r
7399         return(ret);\r
7400 }\r
7401 \r
7402 // generates unpacking code for all temporal attributes referenced in select\r
7403 static string gen_unpack_temp_vars(table_list *schema, col_id_set& found_cids, vector<select_element *>& select_list, gb_table *gtbl, vector<bool> &needs_xform) {\r
7404         string ret;\r
7405         int s;\r
7406 \r
7407 //              Unpack all the temporal attributes references in select list\r
7408 //              we need it to be able to generate temp status tuples\r
7409         for(s=0;s<select_list.size();s++){\r
7410                 if (select_list[s]->se->get_data_type()->is_temporal()) {\r
7411 //                      Find the set of attributes accessed in this SE\r
7412                         col_id_set new_cids;\r
7413                         get_new_se_cids(select_list[s]->se,found_cids, new_cids, gtbl);\r
7414 //                      Unpack these values.\r
7415                         ret += gen_unpack_cids(schema, new_cids, "false", needs_xform);\r
7416                 }\r
7417         }\r
7418 \r
7419         return(ret);\r
7420 }\r
7421 \r
7422 \r
7423 //              Generates temporal tuple generation code (except attribute packing)\r
7424 static string gen_init_temp_status_tuple(string node_name) {\r
7425         string ret;\r
7426 \r
7427         ret += "\t// create temp status tuple\n";\r
7428         ret += "\tresult.tuple_size = sizeof("+generate_tuple_name( node_name)+") + sizeof(gs_uint8_t);\n";\r
7429         ret += "\tresult.data = (gs_sp_t )malloc(result.tuple_size);\n";\r
7430         ret += "\tresult.heap_resident = true;\n";\r
7431         ret += "\t//            Mark tuple as temporal\n";\r
7432         ret += "\t*((gs_sp_t )result.data + sizeof("+generate_tuple_name( node_name)+")) = TEMPORAL_TUPLE;\n";\r
7433 \r
7434         ret += "\t"+generate_tuple_name( node_name)+" *tuple = ("+\r
7435                 generate_tuple_name( node_name) +" *)(result.data);\n";\r
7436 \r
7437         return(ret);\r
7438 }\r
7439 \r
7440 \r
7441 //              Assume that all colrefs unpacked already ...\r
7442 static string gen_unpack_partial_fcn(table_list *schema,\r
7443                                         vector<scalarexp_t *> &partial_fcns,set<int> &pfcn_refs,\r
7444                                         string on_problem){\r
7445         string ret;\r
7446         set<int>::iterator si;\r
7447 \r
7448 //                      Since set<..> is a "Sorted Associative Container",\r
7449 //                      we can walk through it in sorted order by walking from\r
7450 //                      begin() to end().  (and the partial fcns must be\r
7451 //                      evaluated in this order).\r
7452         for(si=pfcn_refs.begin();si!=pfcn_refs.end();++si){\r
7453                 ret += unpack_partial_fcn(partial_fcns[(*si)], (*si), schema);\r
7454                 ret += "\tif(retval) return "+on_problem+" ;\n";\r
7455         }\r
7456         return(ret);\r
7457 }\r
7458 \r
7459 //              Assume that all colrefs unpacked already ...\r
7460 //              this time with cached functions.\r
7461 static string gen_unpack_partial_fcn(table_list *schema,\r
7462                                         vector<scalarexp_t *> &partial_fcns,set<int> &pfcn_refs,\r
7463                                         vector<int> &fcn_ref_cnt, vector<bool> &is_partial_fcn,\r
7464                                         string on_problem){\r
7465         string ret;\r
7466         set<int>::iterator si;\r
7467 \r
7468 //                      Since set<..> is a "Sorted Associative Container",\r
7469 //                      we can walk through it in sorted order by walking from\r
7470 //                      begin() to end().  (and the partial fcns must be\r
7471 //                      evaluated in this order).\r
7472         for(si=pfcn_refs.begin();si!=pfcn_refs.end();++si){\r
7473                 if(fcn_ref_cnt[(*si)] > 1){\r
7474                         ret += "\tif(fcn_ref_cnt_"+int_to_string((*si))+"==0){\n";\r
7475                 }\r
7476                 if(is_partial_fcn[(*si)]){\r
7477                         ret += unpack_partial_fcn(partial_fcns[(*si)], (*si), schema);\r
7478                         ret += "\tif(retval) return "+on_problem+" ;\n";\r
7479                 }\r
7480                 if(fcn_ref_cnt[(*si)] > 1){\r
7481                         if(!is_partial_fcn[(*si)]){\r
7482                                 ret += "\t\tpartial_fcn_result_"+int_to_string((*si))+"="+generate_cached_fcn(partial_fcns[(*si)],(*si),schema)+";\n";\r
7483                         }\r
7484                         ret += "\t\tfcn_ref_cnt_"+int_to_string((*si))+"=1;\n";\r
7485                         ret += "\t}\n";\r
7486                 }\r
7487         }\r
7488 \r
7489         return(ret);\r
7490 }\r
7491 \r
7492 \r
7493 //              This version finds and unpacks new colrefs.\r
7494 //              found_cids gets updated with the newly unpacked cids.\r
7495 static string gen_full_unpack_partial_fcn(table_list *schema,\r
7496                                         vector<scalarexp_t *> &partial_fcns,set<int> &pfcn_refs,\r
7497                                         col_id_set &found_cids, gb_table *gtbl, string on_problem,\r
7498                                         vector<bool> &needs_xform){\r
7499         string ret;\r
7500         set<int>::iterator slsi;\r
7501 \r
7502         for(slsi=pfcn_refs.begin(); slsi!=pfcn_refs.end(); ++slsi){\r
7503 //                      find all new fields ref'd by this partial fcn.\r
7504                 col_id_set new_cids;\r
7505                 get_new_se_cids(partial_fcns[(*slsi)], found_cids, new_cids, gtbl);\r
7506 //                      Unpack these values.\r
7507                 ret += gen_unpack_cids(schema, new_cids, on_problem, needs_xform);\r
7508 \r
7509 //                      Now evaluate the partial fcn.\r
7510                 ret += unpack_partial_fcn(partial_fcns[(*slsi)], (*slsi), schema);\r
7511                 ret += "\tif(retval) return "+on_problem+" ;\n";\r
7512         }\r
7513         return(ret);\r
7514 }\r
7515 \r
7516 //              This version finds and unpacks new colrefs.\r
7517 //              found_cids gets updated with the newly unpacked cids.\r
7518 //                      BUT : only for the partial functions.\r
7519 static string gen_full_unpack_partial_fcn(table_list *schema,\r
7520                                         vector<scalarexp_t *> &partial_fcns,set<int> &pfcn_refs,\r
7521                                         vector<int> &fcn_ref_cnt, vector<bool> &is_partial_fcn,\r
7522                                         col_id_set &found_cids, gb_table *gtbl, string on_problem,\r
7523                                         vector<bool> &needs_xform){\r
7524         string ret;\r
7525         set<int>::iterator slsi;\r
7526 \r
7527         for(slsi=pfcn_refs.begin(); slsi!=pfcn_refs.end(); ++slsi){\r
7528           if(is_partial_fcn[(*slsi)]){\r
7529 //                      find all new fields ref'd by this partial fcn.\r
7530                 col_id_set new_cids;\r
7531                 get_new_se_cids(partial_fcns[(*slsi)], found_cids, new_cids, gtbl);\r
7532 //                      Unpack these values.\r
7533                 ret += gen_unpack_cids(schema, new_cids, on_problem, needs_xform);\r
7534 \r
7535 //                      Now evaluate the partial fcn.\r
7536                 if(fcn_ref_cnt[(*slsi)] > 1){\r
7537                         ret += "\tif(fcn_ref_cnt_"+int_to_string((*slsi))+"==0){\n";\r
7538                 }\r
7539                 if(is_partial_fcn[(*slsi)]){\r
7540                         ret += unpack_partial_fcn(partial_fcns[(*slsi)], (*slsi), schema);\r
7541                         ret += "\tif(retval) return "+on_problem+" ;\n";\r
7542                 }\r
7543                 if(fcn_ref_cnt[(*slsi)] > 1){\r
7544                         ret += "\t\tfcn_ref_cnt_"+int_to_string((*slsi))+"=1;\n";\r
7545                         ret += "\t}\n";\r
7546                 }\r
7547 \r
7548           }\r
7549         }\r
7550         return(ret);\r
7551 }\r
7552 \r
7553 static string gen_remaining_cached_fcns(table_list *schema,\r
7554                                         vector<scalarexp_t *> &partial_fcns,set<int> &pfcn_refs,\r
7555                                         vector<int> &fcn_ref_cnt, vector<bool> &is_partial_fcn){\r
7556         string ret;\r
7557         set<int>::iterator slsi;\r
7558 \r
7559         for(slsi=pfcn_refs.begin(); slsi!=pfcn_refs.end(); ++slsi){\r
7560           if(!is_partial_fcn[(*slsi)] && fcn_ref_cnt[(*slsi)] > 1){\r
7561 \r
7562                 if(fcn_ref_cnt[(*slsi)] > 1){\r
7563                         ret += "\tif(fcn_ref_cnt_"+int_to_string((*slsi))+"==0){\n";\r
7564                         ret += "\t\tpartial_fcn_result_"+int_to_string((*slsi))+"="+generate_cached_fcn(partial_fcns[(*slsi)],(*slsi),schema)+";\n";\r
7565                         ret += "\t\tfcn_ref_cnt_"+int_to_string((*slsi))+"=1;\n";\r
7566                         ret += "\t}\n";\r
7567                 }\r
7568           }\r
7569         }\r
7570         return(ret);\r
7571 }\r
7572 \r
7573 \r
7574 //              unpack the colrefs in cid_set not in found_cids\r
7575 static string gen_remaining_colrefs(table_list *schema,\r
7576                         col_id_set &cid_set, col_id_set &found_cids, string on_problem,\r
7577                         vector<bool> &needs_xform){\r
7578         string ret;\r
7579         col_id_set::iterator csi;\r
7580 \r
7581         for(csi=cid_set.begin(); csi!=cid_set.end();csi++){\r
7582                 if(found_cids.count( (*csi) ) == 0){\r
7583                 int schref = (*csi).schema_ref;\r
7584                     int tblref = (*csi).tblvar_ref;\r
7585                 string field = (*csi).field;\r
7586                         data_type dt(schema->get_type_name(schref,field));\r
7587                         string unpack_fcn;\r
7588                         if(needs_xform[tblref]){\r
7589                                 unpack_fcn = dt.get_hfta_unpack_fcn();\r
7590                         }else{\r
7591                                 unpack_fcn = dt.get_hfta_unpack_fcn_noxf();\r
7592                         }\r
7593                         if(dt.is_buffer_type()){\r
7594                                 sprintf(tmpstr,"\t unpack_var_%s_%d = %s(tup%d.data, tup%d.tuple_size, unpack_offset_%s_%d, &problem);\n",field.c_str(), tblref, unpack_fcn.c_str(), tblref, tblref, field.c_str(), tblref);\r
7595                         }else{\r
7596                                 sprintf(tmpstr,"\t unpack_var_%s_%d = %s_nocheck(tup%d.data, unpack_offset_%s_%d);\n",field.c_str(), tblref, unpack_fcn.c_str(), tblref, field.c_str(), tblref);\r
7597                         }\r
7598                         ret += tmpstr;\r
7599                         if(dt.is_buffer_type()){\r
7600                                 ret.append("\tif(problem) return "+on_problem+" ;\n");\r
7601                         }\r
7602                 }\r
7603         }\r
7604         return(ret);\r
7605 }\r
7606 \r
7607 static string gen_buffer_selvars(table_list *schema,\r
7608                                                                 vector<select_element *> &select_list){\r
7609         string ret;\r
7610         int s;\r
7611 \r
7612     for(s=0;s<select_list.size();s++){\r
7613                 scalarexp_t *se = select_list[s]->se;\r
7614         data_type *sdt = se->get_data_type();\r
7615         if(sdt->is_buffer_type() &&\r
7616                         !( (se->get_operator_type() == SE_COLREF) ||\r
7617                            (se->get_operator_type() == SE_FUNC && se->is_partial()) ||\r
7618                            (se->get_operator_type() == SE_FUNC && se->get_aggr_ref() >= 0))\r
7619                 ){\r
7620             sprintf(tmpstr,"selvar_%d",s);\r
7621                         ret+="\t"+sdt->make_host_cvar(tmpstr)+" = ";\r
7622                         ret += generate_se_code(se,schema) +";\n";\r
7623         }\r
7624     }\r
7625         return(ret);\r
7626 }\r
7627 \r
7628 static string gen_buffer_selvars_size(vector<select_element *> &select_list,table_list *schema){\r
7629         string ret;\r
7630         int s;\r
7631 \r
7632     for(s=0;s<select_list.size();s++){\r
7633                 scalarexp_t *se = select_list[s]->se;\r
7634         data_type *sdt = se->get_data_type();\r
7635         if(sdt->is_buffer_type()){\r
7636                   if( !( (se->get_operator_type() == SE_COLREF) ||\r
7637                            (se->get_operator_type() == SE_FUNC && se->is_partial()) ||\r
7638                            (se->get_operator_type() == SE_FUNC && se->get_aggr_ref() >= 0))\r
7639                   ){\r
7640             sprintf(tmpstr," + %s(&selvar_%d)", sdt->get_hfta_buffer_size().c_str(),s);\r
7641             ret.append(tmpstr);\r
7642                   }else{\r
7643             sprintf(tmpstr," + %s(&%s)", sdt->get_hfta_buffer_size().c_str(),\r
7644                                 generate_se_code(se,schema).c_str());\r
7645             ret.append(tmpstr);\r
7646                   }\r
7647         }\r
7648     }\r
7649         return(ret);\r
7650 }\r
7651 \r
7652 static string gen_buffer_selvars_dtr(vector<select_element *> &select_list){\r
7653         string ret;\r
7654         int s;\r
7655 \r
7656     for(s=0;s<select_list.size();s++){\r
7657                 scalarexp_t *se = select_list[s]->se;\r
7658         data_type *sdt = se->get_data_type();\r
7659         if(sdt->is_buffer_type() &&\r
7660                         !( (se->get_operator_type() == SE_COLREF) ||\r
7661                                 (se->get_operator_type() == SE_AGGR_STAR) ||\r
7662                                 (se->get_operator_type() == SE_AGGR_SE) ||\r
7663                            (se->get_operator_type() == SE_FUNC && se->is_partial()) ||\r
7664                            (se->get_operator_type() == SE_FUNC && se->get_aggr_ref() >= 0))\r
7665                         ){\r
7666                                 sprintf(tmpstr,"\t\t%s(&selvar_%d);\n",\r
7667                                   sdt->get_hfta_buffer_destroy().c_str(), s );\r
7668                 ret += tmpstr;\r
7669         }\r
7670     }\r
7671         return(ret);\r
7672 }\r
7673 \r
7674 \r
7675 static string gen_pack_tuple(table_list *schema, vector<select_element *> &select_list, string node_name, bool temporal_only){\r
7676         string ret;\r
7677         int s;\r
7678 \r
7679         ret += "\tint tuple_pos = sizeof("+generate_tuple_name(node_name)+") + sizeof(gs_uint8_t);\n";\r
7680     for(s=0;s<select_list.size();s++){\r
7681                 scalarexp_t *se  = select_list[s]->se;\r
7682         data_type *sdt = se->get_data_type();\r
7683 \r
7684         if(!temporal_only && sdt->is_buffer_type()){\r
7685                   if( !( (se->get_operator_type() == SE_COLREF) ||\r
7686                            (se->get_operator_type() == SE_FUNC && se->is_partial()))\r
7687                         ){\r
7688                 sprintf(tmpstr,"\t%s(&(tuple->tuple_var%d), &selvar_%d, ((gs_sp_t )tuple)+tuple_pos, tuple_pos);\n", sdt->get_hfta_buffer_tuple_copy().c_str(),s, s);\r
7689                 ret.append(tmpstr);\r
7690                 sprintf(tmpstr,"\ttuple_pos += %s(&selvar_%d);\n", sdt->get_hfta_buffer_size().c_str(), s);\r
7691                 ret.append(tmpstr);\r
7692                         }else{\r
7693                 sprintf(tmpstr,"\t%s(&(tuple->tuple_var%d), &%s, ((gs_sp_t )tuple)+tuple_pos, tuple_pos);\n", sdt->get_hfta_buffer_tuple_copy().c_str(),s, generate_se_code(se,schema).c_str());\r
7694                 ret.append(tmpstr);\r
7695                 sprintf(tmpstr,"\ttuple_pos += %s(&%s);\n", sdt->get_hfta_buffer_size().c_str(), generate_se_code(se,schema).c_str());\r
7696                 ret.append(tmpstr);\r
7697                         }\r
7698         }else if (!temporal_only || sdt->is_temporal()) {\r
7699             sprintf(tmpstr,"\ttuple->tuple_var%d = ",s);\r
7700             ret.append(tmpstr);\r
7701             ret.append(generate_se_code(se,schema) );\r
7702             ret.append(";\n");\r
7703         }\r
7704     }\r
7705         return(ret);\r
7706 }\r
7707 \r
7708 \r
7709 //-------------------------------------------------------------------------\r
7710 //                      functor generation methods\r
7711 //-------------------------------------------------------------------------\r
7712 \r
7713 /////////////////////////////////////////////////////////\r
7714 ////                    File Output Operator\r
7715 string output_file_qpn::generate_functor_name(){\r
7716         return("output_file_functor_" + normalize_name(get_node_name()));\r
7717 }\r
7718 \r
7719 \r
7720 string output_file_qpn::generate_functor(table_list *schema, ext_fcn_list *Ext_fcns, vector<bool> &needs_xform){\r
7721         string ret = "class " + this->generate_functor_name() + "{\n";\r
7722 \r
7723 //              Find the temporal field\r
7724         int temporal_field_idx;\r
7725         data_type *tdt = NULL;\r
7726         for(temporal_field_idx=0;temporal_field_idx<fields.size();temporal_field_idx++){\r
7727                 tdt = new data_type(fields[temporal_field_idx]->get_type(), fields[temporal_field_idx]->get_modifier_list());\r
7728                 if(tdt->is_temporal()){\r
7729                         break;\r
7730                 }else{\r
7731                         delete tdt;\r
7732                 }\r
7733         }\r
7734 \r
7735         if(temporal_field_idx == fields.size()){\r
7736                 fprintf(stderr,"ERROR, no temporal field for file output operator %s\n",node_name.c_str());\r
7737                 exit(1);\r
7738         }\r
7739 \r
7740         ret += "private:\n";\r
7741 \r
7742         // var to save the schema handle\r
7743         ret += "\tint schema_handle0;\n";\r
7744 //                      tuple metadata offset\r
7745         ret += "\tint tuple_metadata_offset0;\n";\r
7746         sprintf(tmpstr,"\tgs_int32_t unpack_offset_%s_0;\n",  fields[temporal_field_idx]->get_name().c_str());\r
7747         ret.append(tmpstr);\r
7748 \r
7749 //              For unpacking the hashing fields, if any\r
7750         int h;\r
7751         for(h=0;h<hash_flds.size();++h){\r
7752                 sprintf(tmpstr,"unpack_var_%s", fields[hash_flds[h]]->get_name().c_str());\r
7753                 data_type *hdt = new data_type(fields[hash_flds[h]]->get_type(), fields[hash_flds[h]]->get_modifier_list());\r
7754                 ret+="\t"+hdt->make_host_cvar(tmpstr)+";\n";\r
7755                 if(hash_flds[h]!=temporal_field_idx){\r
7756                         sprintf(tmpstr,"\tgs_int32_t unpack_offset_%s_0;\n",  fields[hash_flds[h]]->get_name().c_str());\r
7757                         ret.append(tmpstr);\r
7758                 }\r
7759         }\r
7760 //              Specail case for output file hashing\r
7761         if(n_streams>1 && hash_flds.size()==0){\r
7762                 ret+="\tgs_uint32_t outfl_cnt;\n";\r
7763         }\r
7764 \r
7765         ret += "//\t\tRemember the last posted timestamp.\n";\r
7766         ret+="\t"+tdt->make_host_cvar("timestamp")+";\n";\r
7767         ret+="\t"+tdt->make_host_cvar("last_bucket")+";\n";\r
7768         ret+="\t"+tdt->make_host_cvar("slack")+";\n";\r
7769         ret += "\tbool first_execution;\n";\r
7770         ret += "\tbool temp_tuple_received;\n";\r
7771         ret += "\tbool is_eof;\n";\r
7772 \r
7773         ret += "\tgs_int32_t bucketwidth;\n";\r
7774 \r
7775         ret += "public:\n";\r
7776 //-------------------\r
7777 //                      The functor constructor\r
7778 //                      pass in a schema handle (e.g. for the 1st input stream),\r
7779 //                      use it to determine how to unpack the merge variable.\r
7780 //                      ASSUME that both streams have the same layout,\r
7781 //                      just duplicate it.\r
7782 \r
7783 //              unpack vars\r
7784         ret += "//\t\tFunctor constructor.\n";\r
7785         ret +=  this->generate_functor_name()+"(int schema_hndl){\n";\r
7786 \r
7787         ret += "\tschema_handle0 = schema_hndl;\n";\r
7788 //              tuple metadata offset\r
7789         ret += "\ttuple_metadata_offset0 = ftaschema_get_tuple_metadata_offset(schema_handle0);\n";\r
7790 \r
7791         if(output_spec->bucketwidth == 0)\r
7792                 ret += "\tbucketwidth = 60;\n";\r
7793         else\r
7794                 ret += "\tbucketwidth = "+int_to_string(output_spec->bucketwidth)+";\n";\r
7795         ret += "//\t\tGet offsets for unpacking fields from input tuple.\n";\r
7796 \r
7797    sprintf(tmpstr,"\tunpack_offset_%s_0 = ftaschema_get_field_offset_by_name(schema_handle0, \"%s\");\n", fields[temporal_field_idx]->get_name().c_str(), fields[temporal_field_idx]->get_name().c_str());\r
7798    ret.append(tmpstr);\r
7799 //              Hashing field unpacking, if any\r
7800         for(h=0;h<hash_flds.size();++h){\r
7801                 if(hash_flds[h]!=temporal_field_idx){\r
7802                         sprintf(tmpstr,"\tunpack_offset_%s_0 = ftaschema_get_field_offset_by_name(schema_handle0, \"%s\");\n",  fields[hash_flds[h]]->get_name().c_str(),fields[hash_flds[h]]->get_name().c_str());\r
7803                         ret.append(tmpstr);\r
7804                 }\r
7805         }\r
7806 \r
7807         ret+="\tfirst_execution = true;\n";\r
7808 \r
7809 //              Initialize internal state\r
7810         ret += "\ttemp_tuple_received = false;\n";\r
7811 \r
7812         //              Init last timestamp values to minimum value for their type\r
7813         if (tdt->is_increasing()){\r
7814                 ret+="\ttimestamp = " + tdt->get_min_literal() + ";\n";\r
7815                 ret+="\tlast_bucket = " + tdt->get_min_literal() + ";\n";\r
7816         }else{\r
7817                 ret+="\ttimestamp = " + tdt->get_max_literal() + ";\n";\r
7818                 ret+="\tlast_bucket = " + tdt->get_max_literal() + ";\n";\r
7819         }\r
7820 \r
7821 \r
7822         ret += "};\n\n";\r
7823 \r
7824         ret += "//\t\tFunctor destructor.\n";\r
7825         ret +=  "~"+this->generate_functor_name()+"(){\n";\r
7826         ret+="};\n\n";\r
7827 \r
7828 \r
7829         ret += "int load_params_"+this->generate_functor_name()+"(gs_int32_t sz, void *value){return 0;}\n";\r
7830         ret += "void destroy_params_"+this->generate_functor_name()+"(){}\n";\r
7831 \r
7832 //                      Register new parameter block\r
7833         ret += "int set_param_block(gs_int32_t sz, void* value){\n";\r
7834           ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";\r
7835           ret += "\treturn this->load_params_"+this->generate_functor_name()+\r
7836                                 "(sz, value);\n";\r
7837         ret += "};\n\n";\r
7838 \r
7839         ret+="\nbool temp_status_received(const host_tuple& tup0)/* const*/   {\n";\r
7840         ret+="\tgs_int32_t problem;\n";\r
7841 \r
7842         ret += "\tvoid *tup_ptr = (void *)(&tup0);\n";\r
7843         ret += "\tis_eof = ftaschema_is_eof_tuple(schema_handle0,tup_ptr);\n";\r
7844 \r
7845         ret += gen_temp_tuple_check(this->node_name, 0);\r
7846 \r
7847         sprintf(tmpstr,"\ttimestamp = %s_nocheck(tup0.data, unpack_offset_%s_%d);\n",  tdt->get_hfta_unpack_fcn_noxf().c_str(), fields[temporal_field_idx]->get_name().c_str(), 0);\r
7848         ret += tmpstr;\r
7849 \r
7850         for(h=0;h<hash_flds.size();++h){\r
7851                 data_type *hdt = new data_type(fields[hash_flds[h]]->get_type(), fields[hash_flds[h]]->get_modifier_list());\r
7852                 sprintf(tmpstr,"\tunpack_var_%s = %s_nocheck(tup0.data, unpack_offset_%s_%d);\n", fields[hash_flds[h]]->get_name().c_str(), hdt->get_hfta_unpack_fcn_noxf().c_str(), fields[hash_flds[h]]->get_name().c_str(), 0);\r
7853         ret += tmpstr;\r
7854         }\r
7855         ret +=\r
7856 "       return temp_tuple_received;\n"\r
7857 "}\n"\r
7858 "\n"\r
7859 ;\r
7860 \r
7861         ret +=\r
7862 "bool new_epoch(){\n"\r
7863 "       if(first_execution || (last_bucket + 1) * bucketwidth <= timestamp){\n"\r
7864 "               last_bucket = timestamp / bucketwidth;\n"\r
7865 "               first_execution = false;\n"\r
7866 "               return true;\n"\r
7867 "       }\n"\r
7868 "       return false;\n"\r
7869 "}\n"\r
7870 "\n"\r
7871 ;\r
7872 \r
7873         if(n_streams <= 1){\r
7874                 ret+=\r
7875 "inline gs_uint32_t output_hash(){return 0;}\n\n";\r
7876         }else{\r
7877                 if(hash_flds.size()==0){\r
7878                         ret +=\r
7879 "gs_uint32_t output_hash(){\n"\r
7880 "       outfl_cnt++;\n"\r
7881 "       if(outfl_cnt >= "+int_to_string(n_streams)+")\n"\r
7882 "               outfl_cnt = 0;\n"\r
7883 "       return outfl_cnt;\n"\r
7884 "}\n"\r
7885 "\n"\r
7886 ;\r
7887                 }else{\r
7888                         ret +=\r
7889 "gs_uint32_t output_hash(){\n"\r
7890 "       gs_uint32_t ret = "\r
7891 ;\r
7892                         for(h=0;h<hash_flds.size();++h){\r
7893                                 if(h>0) ret += "^";\r
7894                                 data_type *hdt = new data_type(fields[hash_flds[h]]->get_type(), fields[hash_flds[h]]->get_modifier_list());\r
7895                                 if(hdt->use_hashfunc()){\r
7896                                         sprintf(tmpstr,"%s(&(unpack_var_%s))",hdt->get_hfta_hashfunc().c_str(),fields[hash_flds[h]]->get_name().c_str());\r
7897                                 }else{\r
7898                                         sprintf(tmpstr,"unpack_var_%s",fields[hash_flds[h]]->get_name().c_str());\r
7899                                 }\r
7900                                 ret += tmpstr;\r
7901                         }\r
7902                         ret +=\r
7903 ";\n"\r
7904 "       return  ret % "+int_to_string(hash_flds.size())+";\n"\r
7905 "}\n\n"\r
7906 ;\r
7907                 }\r
7908         }\r
7909 \r
7910 ret +=\r
7911 "gs_uint32_t num_file_streams(){\n"\r
7912 "       return("+int_to_string(n_streams)+");\n"\r
7913 "}\n\n"\r
7914 ;\r
7915 \r
7916         ret +=\r
7917 "string get_filename_base(){\n"\r
7918 "       char tmp_fname[500];\n";\r
7919 \r
7920         string output_filename_base = hfta_query_name+filestream_id;\r
7921 /*\r
7922         if(n_hfta_clones > 1){\r
7923                 output_filename_base += "_"+int_to_string(parallel_idx);\r
7924         }\r
7925 */\r
7926 \r
7927 \r
7928 \r
7929         if(output_spec->output_directory == "")\r
7930                 ret +=\r
7931 "       sprintf(tmp_fname,\""+output_filename_base+"_%lld\",(gs_int64_t)(last_bucket*bucketwidth));\n";\r
7932                 else ret +=\r
7933 "       sprintf(tmp_fname,\""+output_spec->output_directory+"/"+output_filename_base+"_%lld\",(gs_int64_t)(last_bucket*bucketwidth));\n";\r
7934 ret +=\r
7935 "       return (string)(tmp_fname);\n"\r
7936 "}\n"\r
7937 "\n";\r
7938 \r
7939 \r
7940 ret+=\r
7941 "bool do_compression(){\n";\r
7942         if(do_gzip)\r
7943                 ret += "        return true;\n";\r
7944         else\r
7945                 ret += "        return false;\n";\r
7946 ret+=\r
7947 "}\n"\r
7948 "\n"\r
7949 "bool is_eof_tuple(){\n"\r
7950 "       return is_eof;\n"\r
7951 "}\n"\r
7952 "\n"\r
7953 "bool propagate_tuple(){\n"\r
7954 ;\r
7955 if(eat_input)\r
7956         ret+="\treturn false;\n";\r
7957 else\r
7958         ret+="\treturn true;\n";\r
7959 ret+="}\n\n";\r
7960 //              create a temp status tuple\r
7961         ret += "int create_temp_status_tuple(host_tuple& result) {\n\n";\r
7962 \r
7963         ret += gen_init_temp_status_tuple(this->hfta_query_name);\r
7964 \r
7965         sprintf(tmpstr,"\ttuple->tuple_var%d = timestamp;\n",temporal_field_idx);\r
7966 \r
7967 \r
7968         ret += tmpstr;\r
7969 \r
7970         ret += "\treturn 0;\n";\r
7971         ret += "}\n\n";\r
7972         ret += "};\n\n";\r
7973 \r
7974         return ret;\r
7975 }\r
7976 \r
7977 \r
7978 string output_file_qpn::generate_operator(int i, string params){\r
7979         string optype = "file_output_operator";\r
7980         switch(compression_type){\r
7981         case regular:\r
7982                 optype = "file_output_operator";\r
7983         break;\r
7984         case gzip:\r
7985                 optype = "zfile_output_operator";\r
7986         break;\r
7987         case bzip:\r
7988                 optype = "bfile_output_operator";\r
7989         break;\r
7990         }\r
7991 \r
7992                 return("        "+optype+"<" +\r
7993                 generate_functor_name() +\r
7994                 "> *op"+int_to_string(i)+" = new "+optype+"<"+\r
7995                 generate_functor_name() +">("+params+", \"" + hfta_query_name + "\""\r
7996                 + "," + hfta_query_name + "_schema_definition);\n");\r
7997 }\r
7998 \r
7999 /////////////////////////////////////////////////////////\r
8000 //////                  SPX functor\r
8001 \r
8002 \r
8003 string spx_qpn::generate_functor_name(){\r
8004         return("spx_functor_" + normalize_name(normalize_name(this->get_node_name())));\r
8005 }\r
8006 \r
8007 string spx_qpn::generate_functor(table_list *schema, ext_fcn_list *Ext_fcns, vector<bool> &needs_xform){\r
8008 //                      Initialize generate utility globals\r
8009         segen_gb_tbl = NULL;\r
8010 \r
8011         string ret = "class " + this->generate_functor_name() + "{\n";\r
8012 \r
8013 //                      Find variables referenced in this query node.\r
8014 \r
8015   col_id_set cid_set;\r
8016   col_id_set::iterator csi;\r
8017 \r
8018         int w, s, p;\r
8019     for(w=0;w<where.size();++w)\r
8020         gather_pr_col_ids(where[w]->pr,cid_set,NULL);\r
8021     for(s=0;s<select_list.size();s++){\r
8022         gather_se_col_ids(select_list[s]->se,cid_set,NULL);\r
8023     }\r
8024 \r
8025 \r
8026 //                      Private variables : store the state of the functor.\r
8027 //                      1) variables for unpacked attributes\r
8028 //                      2) offsets of the upacked attributes\r
8029 //                      3) storage of partial functions\r
8030 //                      4) storage of complex literals (i.e., require a constructor)\r
8031 \r
8032         ret += "private:\n";\r
8033         ret += "\tbool first_execution;\t// internal processing state \n";\r
8034         ret += "\tint schema_handle0;\n";\r
8035 \r
8036         // generate the declaration of all the variables related to\r
8037         // temp tuples generation\r
8038         ret += gen_decl_temp_vars();\r
8039 \r
8040 \r
8041 //                      unpacked attribute storage, offsets\r
8042         ret += "//\t\tstorage and offsets of accessed fields.\n";\r
8043         ret += generate_access_vars(cid_set,schema);\r
8044 //                      tuple metadata management\r
8045         ret += "\tint tuple_metadata_offset0;\n";\r
8046 \r
8047 //                      Variables to store results of partial functions.\r
8048 //                      WARNING find_partial_functions modifies the SE\r
8049 //                      (it marks the partial function id).\r
8050         ret += "//\t\tParital function result storage\n";\r
8051         vector<scalarexp_t *> partial_fcns;\r
8052         vector<int> fcn_ref_cnt;\r
8053         vector<bool> is_partial_fcn;\r
8054         for(s=0;s<select_list.size();s++){\r
8055                 find_partial_fcns(select_list[s]->se, &partial_fcns,&fcn_ref_cnt,&is_partial_fcn, Ext_fcns);\r
8056         }\r
8057         for(w=0;w<where.size();w++){\r
8058                 find_partial_fcns_pr(where[w]->pr, &partial_fcns, &fcn_ref_cnt,&is_partial_fcn,Ext_fcns);\r
8059         }\r
8060 //              Unmark non-partial expensive functions referenced only once.\r
8061         for(p=0; p<partial_fcns.size();p++){\r
8062                 if(!is_partial_fcn[p] && fcn_ref_cnt[p] <= 1){\r
8063                         partial_fcns[p]->set_partial_ref(-1);\r
8064                 }\r
8065         }\r
8066         if(partial_fcns.size()>0){\r
8067           ret += generate_partial_fcn_vars(partial_fcns,fcn_ref_cnt,is_partial_fcn,true);\r
8068         }\r
8069 \r
8070 //                      Complex literals (i.e., they need constructors)\r
8071         ret += "//\t\tComplex literal storage.\n";\r
8072         cplx_lit_table *complex_literals = this->get_cplx_lit_tbl(Ext_fcns);\r
8073         ret += generate_complex_lit_vars(complex_literals);\r
8074 \r
8075 //                      Pass-by-handle parameters\r
8076         ret += "//\t\tPass-by-handle storage.\n";\r
8077         vector<handle_param_tbl_entry *> param_handle_table = this->get_handle_param_tbl(Ext_fcns);\r
8078         ret += generate_pass_by_handle_vars(param_handle_table);\r
8079 \r
8080 //                      Variables to hold parameters\r
8081         ret += "//\tfor query parameters\n";\r
8082         ret += generate_param_vars(param_tbl);\r
8083 \r
8084 \r
8085 //                      The publicly exposed functions\r
8086 \r
8087         ret += "\npublic:\n";\r
8088 \r
8089 \r
8090 //-------------------\r
8091 //                      The functor constructor\r
8092 //                      pass in the schema handle.\r
8093 //                      1) make assignments to the unpack offset variables\r
8094 //                      2) initialize the complex literals\r
8095 //                      3) Set the initial values of the temporal attributes\r
8096 //                              referenced in select clause (in case we need to emit\r
8097 //                              temporal tuple before receiving first tuple )\r
8098 \r
8099         ret += "//\t\tFunctor constructor.\n";\r
8100         ret +=  this->generate_functor_name()+"(int schema_handle0){\n";\r
8101 \r
8102 //              save schema handle\r
8103         ret += "this->schema_handle0 = schema_handle0;\n";\r
8104 \r
8105 //              unpack vars\r
8106         ret += "//\t\tGet offsets for unpacking fields from input tuple.\n";\r
8107         ret += gen_access_var_init(cid_set);\r
8108 //              tuple metadata\r
8109         ret += "\ttuple_metadata_offset0 = ftaschema_get_tuple_metadata_offset(schema_handle0);\n";\r
8110 \r
8111 //              complex literals\r
8112         ret += "//\t\tInitialize complex literals.\n";\r
8113         ret += gen_complex_lit_init(complex_literals);\r
8114 \r
8115 //              Initialize partial function results so they can be safely GC'd\r
8116         ret += gen_partial_fcn_init(partial_fcns);\r
8117 \r
8118 //              Initialize non-query-parameter parameter handles\r
8119         ret += gen_pass_by_handle_init(param_handle_table);\r
8120 \r
8121 //              Init temporal attributes referenced in select list\r
8122         ret += gen_init_temp_vars(schema, select_list, NULL);\r
8123 \r
8124         ret += "};\n\n";\r
8125 \r
8126 \r
8127 //-------------------\r
8128 //                      Functor destructor\r
8129         ret += "//\t\tFunctor destructor.\n";\r
8130         ret +=  "~"+this->generate_functor_name()+"(){\n";\r
8131 \r
8132 //              clean up buffer-type complex literals.\r
8133         ret += gen_complex_lit_dtr(complex_literals);\r
8134 \r
8135 //                      Deregister the pass-by-handle parameters\r
8136         ret += "/* register and de-register the pass-by-handle parameters */\n";\r
8137         ret += gen_pass_by_handle_dtr(param_handle_table);\r
8138 \r
8139 //                      Reclaim buffer space for partial fucntion results\r
8140         ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";\r
8141         ret += gen_partial_fcn_dtr(partial_fcns);\r
8142 \r
8143 \r
8144 //                      Destroy the parameters, if any need to be destroyed\r
8145         ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";\r
8146 \r
8147         ret += "};\n\n";\r
8148 \r
8149 \r
8150 //-------------------\r
8151 //                      Parameter manipulation routines\r
8152         ret += generate_load_param_block(this->generate_functor_name(),\r
8153                                                                         this->param_tbl,param_handle_table );\r
8154         ret += generate_delete_param_block(this->generate_functor_name(),\r
8155                                                                         this->param_tbl,param_handle_table);\r
8156 \r
8157 \r
8158 //-------------------\r
8159 //                      Register new parameter block\r
8160         ret += "int set_param_block(gs_int32_t sz, void* value){\n";\r
8161           ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";\r
8162           ret += "\treturn this->load_params_"+this->generate_functor_name()+\r
8163                                 "(sz, value);\n";\r
8164         ret += "};\n\n";\r
8165 \r
8166 \r
8167 //-------------------\r
8168 //                      The selection predicate.\r
8169 //                      Unpack variables for 1 cnf element\r
8170 //                      at a time, return false immediately if the\r
8171 //                      predicate fails.\r
8172 //                      optimization : evaluate the cheap cnf elements\r
8173 //                      first, the expensive ones last.\r
8174 \r
8175         ret += "bool predicate(host_tuple &tup0){\n";\r
8176         //              Variables for execution of the function.\r
8177         ret += "\tgs_int32_t problem = 0;\n";   // return unpack failure\r
8178 //              Initialize cached function indicators.\r
8179         for(p=0;p<partial_fcns.size();++p){\r
8180                 if(fcn_ref_cnt[p]>1){\r
8181                         ret+="\tfcn_ref_cnt_"+int_to_string(p)+"=0;\n";\r
8182                 }\r
8183         }\r
8184 \r
8185 \r
8186         ret += gen_temp_tuple_check(this->node_name, 0);\r
8187 \r
8188         if(partial_fcns.size()>0){              // partial fcn access failure\r
8189           ret += "\tgs_retval_t retval = 0;\n";\r
8190           ret += "\n";\r
8191         }\r
8192 \r
8193 //                      Reclaim buffer space for partial fucntion results\r
8194         ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";\r
8195         ret += gen_partial_fcn_dtr(partial_fcns);\r
8196 \r
8197         col_id_set found_cids;  // colrefs unpacked thus far.\r
8198         ret += gen_unpack_temp_vars(schema, found_cids, select_list, NULL, needs_xform);\r
8199 \r
8200 //              For temporal status tuple we don't need to do anything else\r
8201         ret += "\tif (temp_tuple_received) return false;\n\n";\r
8202 \r
8203 \r
8204         for(w=0;w<where.size();++w){\r
8205                 sprintf(tmpstr,"//\t\tPredicate clause %d.\n",w);\r
8206                 ret += tmpstr;\r
8207 //                      Find the set of variables accessed in this CNF elem,\r
8208 //                      but in no previous element.\r
8209                 col_id_set new_cids;\r
8210                 get_new_pred_cids(where[w]->pr,found_cids, new_cids, NULL);\r
8211 //                      Unpack these values.\r
8212                 ret += gen_unpack_cids(schema, new_cids, "false", needs_xform);\r
8213 //                      Find partial fcns ref'd in this cnf element\r
8214                 set<int> pfcn_refs;\r
8215                 collect_partial_fcns_pr(where[w]->pr, pfcn_refs);\r
8216                 ret += gen_unpack_partial_fcn(schema,partial_fcns,pfcn_refs,fcn_ref_cnt, is_partial_fcn, "false");\r
8217 \r
8218                 ret += "\tif( !("+generate_predicate_code(where[w]->pr,schema)+\r
8219                                 +") ) return(false);\n";\r
8220         }\r
8221 \r
8222 //              The partial functions ref'd in the select list\r
8223 //              must also be evaluated.  If one returns false,\r
8224 //              then implicitly the predicate is false.\r
8225         set<int> sl_pfcns;\r
8226         for(s=0;s<select_list.size();s++){\r
8227                 collect_partial_fcns(select_list[s]->se, sl_pfcns);\r
8228         }\r
8229         if(sl_pfcns.size() > 0)\r
8230                 ret += "//\t\tUnpack remaining partial fcns.\n";\r
8231         ret += gen_full_unpack_partial_fcn(schema, partial_fcns, sl_pfcns,\r
8232                                         fcn_ref_cnt, is_partial_fcn,\r
8233                                         found_cids, NULL, "false", needs_xform);\r
8234 \r
8235 //                      Unpack remaining fields\r
8236         ret += "//\t\tunpack any remaining fields from the input tuple.\n";\r
8237         ret += gen_remaining_colrefs(schema, cid_set, found_cids, "false", needs_xform);\r
8238 \r
8239 \r
8240         ret += "\treturn(true);\n";\r
8241         ret += "};\n\n";\r
8242 \r
8243 \r
8244 //-------------------\r
8245 //                      The output tuple function.\r
8246 //                      Unpack the remaining attributes into\r
8247 //                      the placeholder variables, unpack the\r
8248 //                      partial fcn refs, then pack up the tuple.\r
8249 \r
8250         ret += "host_tuple create_output_tuple() {\n";\r
8251         ret += "\thost_tuple tup;\n";\r
8252         ret += "\tgs_retval_t retval = 0;\n";\r
8253 \r
8254 //                      Unpack any remaining cached functions.\r
8255         ret += gen_remaining_cached_fcns(schema, partial_fcns, sl_pfcns,\r
8256                                         fcn_ref_cnt, is_partial_fcn);\r
8257 \r
8258 \r
8259 //          Now, compute the size of the tuple.\r
8260 \r
8261 //          Unpack any BUFFER type selections into temporaries\r
8262 //          so that I can compute their size and not have\r
8263 //          to recompute their value during tuple packing.\r
8264 //          I can use regular assignment here because\r
8265 //          these temporaries are non-persistent.\r
8266 \r
8267         ret += "//\t\tCompute the size of the tuple.\n";\r
8268         ret += "//\t\t\tNote: buffer storage packed at the end of the tuple.\n";\r
8269 \r
8270 //                      Unpack all buffer type selections, to be able to compute their size\r
8271         ret += gen_buffer_selvars(schema, select_list);\r
8272 \r
8273 //      The size of the tuple is the size of the tuple struct plus the\r
8274 //      size of the buffers to be copied in.\r
8275 \r
8276 \r
8277       ret+="\ttup.tuple_size = sizeof(" + generate_tuple_name( this->get_node_name()) +") + sizeof(gs_uint8_t)";\r
8278         ret += gen_buffer_selvars_size(select_list,schema);\r
8279         ret.append(";\n");\r
8280 \r
8281 //              Allocate tuple data block.\r
8282         ret += "//\t\tCreate the tuple block.\n";\r
8283           ret += "\ttup.data = malloc(tup.tuple_size);\n";\r
8284           ret += "\ttup.heap_resident = true;\n";\r
8285 //              Mark tuple as regular\r
8286           ret += "\t*((gs_sp_t )tup.data + sizeof(" + generate_tuple_name( this->get_node_name()) +")) = REGULAR_TUPLE;\n";\r
8287 \r
8288 //        ret += "\ttup.channel = 0;\n";\r
8289           ret += "\t"+generate_tuple_name( this->get_node_name())+" *tuple = ("+\r
8290                                 generate_tuple_name( this->get_node_name())+" *)(tup.data);\n";\r
8291 \r
8292 //              Start packing.\r
8293 //                      (Here, offsets are hard-wired.  is this a problem?)\r
8294 \r
8295         ret += "//\t\tPack the fields into the tuple.\n";\r
8296         ret += gen_pack_tuple(schema,select_list,this->get_node_name(), false );\r
8297 \r
8298 //                      Delete string temporaries\r
8299         ret += gen_buffer_selvars_dtr(select_list);\r
8300 \r
8301         ret += "\treturn tup;\n";\r
8302         ret += "};\n";\r
8303 \r
8304 //-------------------------------------------------------------------\r
8305 //              Temporal update functions\r
8306 \r
8307         ret += "bool temp_status_received(){return temp_tuple_received;};\n\n";\r
8308 \r
8309 \r
8310 //              create a temp status tuple\r
8311         ret += "int create_temp_status_tuple(host_tuple& result) {\n\n";\r
8312 \r
8313         ret += gen_init_temp_status_tuple(this->get_node_name());\r
8314 \r
8315 //              Start packing.\r
8316 //                      (Here, offsets are hard-wired.  is this a problem?)\r
8317 \r
8318         ret += "//\t\tPack the fields into the tuple.\n";\r
8319         ret += gen_pack_tuple(schema,select_list,this->get_node_name(), true );\r
8320 \r
8321         ret += "\treturn 0;\n";\r
8322         ret += "};};\n\n";\r
8323 \r
8324         return(ret);\r
8325 }\r
8326 \r
8327 \r
8328 string spx_qpn::generate_operator(int i, string params){\r
8329 \r
8330                 return("        select_project_operator<" +\r
8331                 generate_functor_name() +\r
8332                 "> *op"+int_to_string(i)+" = new select_project_operator<"+\r
8333                 generate_functor_name() +">("+params+", \"" + get_node_name() + "\");\n");\r
8334 }\r
8335 \r
8336 \r
8337 ////////////////////////////////////////////////////////////////\r
8338 ////    SGAH functor\r
8339 \r
8340 \r
8341 \r
8342 string sgah_qpn::generate_functor_name(){\r
8343         return("sgah_functor_" + normalize_name(this->get_node_name()));\r
8344 }\r
8345 \r
8346 \r
8347 string sgah_qpn::generate_functor(table_list *schema, ext_fcn_list *Ext_fcns, vector<bool> &needs_xform){\r
8348         int a,g,w,s;\r
8349 \r
8350 \r
8351 //                      Initialize generate utility globals\r
8352         segen_gb_tbl = &(gb_tbl);\r
8353 \r
8354 //              Might need to generate empty values for cube processing.\r
8355         map<int, string> structured_types;\r
8356         for(g=0;g<gb_tbl.size();++g){\r
8357                 if(gb_tbl.get_data_type(g)->is_structured_type()){\r
8358                         structured_types[gb_tbl.get_data_type(g)->type_indicator()] = gb_tbl.get_data_type(g)->get_type_str();\r
8359                 }\r
8360         }\r
8361 \r
8362 //--------------------------------\r
8363 //                      group definition class\r
8364         string ret = "class " + generate_functor_name() + "_groupdef{\n";\r
8365         ret += "public:\n";\r
8366         for(g=0;g<this->gb_tbl.size();g++){\r
8367                 sprintf(tmpstr,"gb_var%d",g);\r
8368                 ret+="\t"+this->gb_tbl.get_data_type(g)->make_host_cvar(tmpstr)+";\n";\r
8369         }\r
8370 //              empty strucutred literals\r
8371         map<int, string>::iterator sii;\r
8372         for(sii=structured_types.begin();sii!=structured_types.end();++sii){\r
8373                 data_type dt(sii->second);\r
8374                 literal_t empty_lit(sii->first);\r
8375                 ret += "\t"+dt.make_host_cvar(empty_lit.hfta_empty_literal_name())+";\n";\r
8376         }\r
8377 //              Constructors\r
8378         if(structured_types.size()==0){\r
8379                 ret += "\t"+generate_functor_name() + "_groupdef(){};\n";\r
8380         }else{\r
8381                 ret += "\t"+generate_functor_name() + "_groupdef(){}\n";\r
8382         }\r
8383 \r
8384 \r
8385         ret += "\t"+generate_functor_name() + "_groupdef("+\r
8386                 this->generate_functor_name() + "_groupdef *gd){\n";\r
8387         for(g=0;g<gb_tbl.size();g++){\r
8388                 data_type *gdt = gb_tbl.get_data_type(g);\r
8389                 if(gdt->is_buffer_type()){\r
8390                         sprintf(tmpstr,"\t\t%s(&gb_var%d, &(gd->gb_var%d));\n",\r
8391                           gdt->get_hfta_buffer_assign_copy().c_str(),g,g );\r
8392                         ret += tmpstr;\r
8393                 }else{\r
8394                         sprintf(tmpstr,"\t\tgb_var%d = gd->gb_var%d;\n",g,g);\r
8395                         ret += tmpstr;\r
8396                 }\r
8397         }\r
8398         ret += "\t}\n";\r
8399         ret += "\t"+generate_functor_name() + "_groupdef("+\r
8400                 this->generate_functor_name() + "_groupdef *gd, bool *pattern){\n";\r
8401         for(sii=structured_types.begin();sii!=structured_types.end();++sii){\r
8402                 literal_t empty_lit(sii->first);\r
8403                 ret += "\t\t"+empty_lit.to_hfta_C_code("&"+empty_lit.hfta_empty_literal_name())+";\n";\r
8404         }\r
8405         for(g=0;g<gb_tbl.size();g++){\r
8406                 data_type *gdt = gb_tbl.get_data_type(g);\r
8407                 ret += "\t\tif(pattern["+int_to_string(g)+"]){\n";\r
8408                 if(gdt->is_buffer_type()){\r
8409                         sprintf(tmpstr,"\t\t\t%s(&gb_var%d, &(gd->gb_var%d));\n",\r
8410                           gdt->get_hfta_buffer_assign_copy().c_str(),g,g );\r
8411                         ret += tmpstr;\r
8412                 }else{\r
8413                         sprintf(tmpstr,"\t\t\tgb_var%d = gd->gb_var%d;\n",g,g);\r
8414                         ret += tmpstr;\r
8415                 }\r
8416                 ret += "\t\t}else{\n";\r
8417                 literal_t empty_lit(gdt->type_indicator());\r
8418                 if(empty_lit.is_cpx_lit()){\r
8419                         ret +="\t\t\tgb_var"+int_to_string(g)+"= "+empty_lit.hfta_empty_literal_name()+";\n";\r
8420                 }else{\r
8421                         ret +="\t\t\tgb_var"+int_to_string(g)+"="+empty_lit.to_hfta_C_code("")+";\n";\r
8422                 }\r
8423                 ret += "\t\t}\n";\r
8424         }\r
8425         ret += "\t};\n";\r
8426 //              destructor\r
8427         ret += "\t~"+ generate_functor_name() + "_groupdef(){\n";\r
8428         for(g=0;g<gb_tbl.size();g++){\r
8429                 data_type *gdt = gb_tbl.get_data_type(g);\r
8430                 if(gdt->is_buffer_type()){\r
8431                         sprintf(tmpstr,"\t\t%s(&gb_var%d);\n",\r
8432                           gdt->get_hfta_buffer_destroy().c_str(), g );\r
8433                         ret += tmpstr;\r
8434                 }\r
8435         }\r
8436         ret += "\t};\n";\r
8437 \r
8438         data_type *tgdt;\r
8439         for(g=0;g<gb_tbl.size();g++){\r
8440                 data_type *gdt = gb_tbl.get_data_type(g);\r
8441                 if(gdt->is_temporal()){\r
8442                         tgdt = gdt;\r
8443                         break;\r
8444                 }\r
8445         }\r
8446         ret += tgdt->get_host_cvar_type()+" get_curr_gb(){\n";\r
8447         ret+="\treturn gb_var"+int_to_string(g)+";\n";\r
8448         ret+="}\n";\r
8449 \r
8450         ret +="};\n\n";\r
8451 \r
8452 //--------------------------------\r
8453 //                      aggr definition class\r
8454         ret += "class " + this->generate_functor_name() + "_aggrdef{\n";\r
8455         ret += "public:\n";\r
8456         for(a=0;a<aggr_tbl.size();a++){\r
8457                 aggr_table_entry *ate = aggr_tbl.agr_tbl[a];\r
8458                 sprintf(tmpstr,"aggr_var%d",a);\r
8459                 if(aggr_tbl.is_builtin(a)){\r
8460                   ret+="\t"+ aggr_tbl.get_data_type(a)->make_host_cvar(tmpstr)+";\n";\r
8461                   if(aggr_tbl.get_op(a) == "AVG"){      // HACK!\r
8462                         data_type cnt_type = data_type("ullong");\r
8463                         ret+="\t"+cnt_type.make_host_cvar(string(tmpstr)+"_cnt")+";\n";\r
8464                         ret+="\t"+ aggr_tbl.get_data_type(a)->make_host_cvar(string(tmpstr)+"_sum")+";\n";\r
8465                   }\r
8466                 }else{\r
8467                   ret+="\t"+ aggr_tbl.get_storage_type(a)->make_host_cvar(tmpstr)+";\n";\r
8468                 }\r
8469         }\r
8470 //              Constructors\r
8471         ret += "\t"+this->generate_functor_name() + "_aggrdef(){};\n";\r
8472 //              destructor\r
8473         ret += "\t~"+this->generate_functor_name() + "_aggrdef(){\n";\r
8474         for(a=0;a<aggr_tbl.size();a++){\r
8475                 if(aggr_tbl.is_builtin(a)){\r
8476                         data_type *adt = aggr_tbl.get_data_type(a);\r
8477                         if(adt->is_buffer_type()){\r
8478                                 sprintf(tmpstr,"\t\t%s(&aggr_var%d);\n",\r
8479                                 adt->get_hfta_buffer_destroy().c_str(), a );\r
8480                                 ret += tmpstr;\r
8481                         }\r
8482                 }else{\r
8483                         ret+="\t\t"+aggr_tbl.get_op(a)+"_HFTA_AGGR_DESTROY_(";\r
8484                         if(aggr_tbl.get_storage_type(a)->get_type() != fstring_t) ret+="&";\r
8485                         ret+="(aggr_var"+int_to_string(a)+"));\n";\r
8486                 }\r
8487         }\r
8488         ret += "\t};\n";\r
8489         ret +="};\n\n";\r
8490 \r
8491 //-------------------------------------------\r
8492 //              group-by patterns for the functor,\r
8493 //              initialization within the class is cumbersome.\r
8494         int n_patterns = gb_tbl.gb_patterns.size();\r
8495         int i,j;\r
8496         ret += "bool "+this->generate_functor_name()+"_gb_patterns["+int_to_string(n_patterns)+\r
8497                         "]["+int_to_string(gb_tbl.size())+"] = {\n";\r
8498         if(n_patterns == 0){\r
8499                 for(i=0;i<gb_tbl.size();++i){\r
8500                         if(i>0) ret += ",";\r
8501                         ret += "true";\r
8502                 }\r
8503         }else{\r
8504                 for(i=0;i<n_patterns;++i){\r
8505                         if(i>0) ret += ",\n";\r
8506                         ret += "\t{";\r
8507                         for(j=0;j<gb_tbl.size();j++){\r
8508                                 if(j>0) ret += ", ";\r
8509                                 if(gb_tbl.gb_patterns[i][j]){\r
8510                                         ret += "true";\r
8511                                 }else{\r
8512                                         ret += "false";\r
8513                                 }\r
8514                         }\r
8515                         ret += "}";\r
8516                 }\r
8517                 ret += "\n";\r
8518         }\r
8519         ret += "};\n";\r
8520 \r
8521 \r
8522 //--------------------------------\r
8523 //                      gb functor class\r
8524         ret += "class " + this->generate_functor_name() + "{\n";\r
8525 \r
8526 //                      Find variables referenced in this query node.\r
8527 \r
8528   col_id_set cid_set;\r
8529   col_id_set::iterator csi;\r
8530 \r
8531     for(w=0;w<where.size();++w)\r
8532         gather_pr_col_ids(where[w]->pr,cid_set,segen_gb_tbl);\r
8533     for(w=0;w<having.size();++w)\r
8534         gather_pr_col_ids(having[w]->pr,cid_set,segen_gb_tbl);\r
8535         for(g=0;g<gb_tbl.size();g++)\r
8536                 gather_se_col_ids(gb_tbl.get_def(g),cid_set,segen_gb_tbl);\r
8537 \r
8538     for(s=0;s<select_list.size();s++){\r
8539         gather_se_col_ids(select_list[s]->se,cid_set,segen_gb_tbl);     // descends into aggregates\r
8540     }\r
8541 \r
8542 \r
8543 //                      Private variables : store the state of the functor.\r
8544 //                      1) variables for unpacked attributes\r
8545 //                      2) offsets of the upacked attributes\r
8546 //                      3) storage of partial functions\r
8547 //                      4) storage of complex literals (i.e., require a constructor)\r
8548 \r
8549         ret += "private:\n";\r
8550 \r
8551         // var to save the schema handle\r
8552         ret += "\tint schema_handle0;\n";\r
8553         // metadata from schema handle\r
8554         ret += "\tint tuple_metadata_offset0;\n";\r
8555 \r
8556         // generate the declaration of all the variables related to\r
8557         // temp tuples generation\r
8558         ret += gen_decl_temp_vars();\r
8559 \r
8560 //                      unpacked attribute storage, offsets\r
8561         ret += "//\t\tstorage and offsets of accessed fields.\n";\r
8562         ret += generate_access_vars(cid_set, schema);\r
8563 \r
8564 //                      Variables to store results of partial functions.\r
8565 //                      WARNING find_partial_functions modifies the SE\r
8566 //                      (it marks the partial function id).\r
8567         ret += "//\t\tParital function result storage\n";\r
8568         vector<scalarexp_t *> partial_fcns;\r
8569         vector<int> fcn_ref_cnt;\r
8570         vector<bool> is_partial_fcn;\r
8571         for(s=0;s<select_list.size();s++){\r
8572                 find_partial_fcns(select_list[s]->se, &partial_fcns,NULL,NULL,  Ext_fcns);\r
8573         }\r
8574         for(w=0;w<where.size();w++){\r
8575                 find_partial_fcns_pr(where[w]->pr, &partial_fcns,NULL,NULL,  Ext_fcns);\r
8576         }\r
8577         for(w=0;w<having.size();w++){\r
8578                 find_partial_fcns_pr(having[w]->pr, &partial_fcns,NULL,NULL,  Ext_fcns);\r
8579         }\r
8580         for(g=0;g<gb_tbl.size();g++){\r
8581                 find_partial_fcns(gb_tbl.get_def(g), &partial_fcns,NULL,NULL,  Ext_fcns);\r
8582         }\r
8583         for(a=0;a<aggr_tbl.size();a++){\r
8584                 find_partial_fcns(aggr_tbl.get_aggr_se(a), &partial_fcns,NULL,NULL,  Ext_fcns);\r
8585         }\r
8586         if(partial_fcns.size()>0){\r
8587           ret += "/*\t\tVariables for storing results of partial functions. \t*/\n";\r
8588           ret += generate_partial_fcn_vars(partial_fcns,fcn_ref_cnt,is_partial_fcn,false);\r
8589         }\r
8590 \r
8591 //                      Complex literals (i.e., they need constructors)\r
8592         ret += "//\t\tComplex literal storage.\n";\r
8593         cplx_lit_table *complex_literals = this->get_cplx_lit_tbl(Ext_fcns);\r
8594         ret += generate_complex_lit_vars(complex_literals);\r
8595 \r
8596 //                      Pass-by-handle parameters\r
8597         ret += "//\t\tPass-by-handle storage.\n";\r
8598         vector<handle_param_tbl_entry *> param_handle_table = this->get_handle_param_tbl(Ext_fcns);\r
8599         ret += generate_pass_by_handle_vars(param_handle_table);\r
8600 \r
8601 \r
8602 //                      variables to hold parameters.\r
8603         ret += "//\tfor query parameters\n";\r
8604         ret += generate_param_vars(param_tbl);\r
8605 \r
8606 //              Is there a temporal flush?  If so create flush temporaries,\r
8607 //              create flush indicator.\r
8608         bool uses_temporal_flush = false;\r
8609         for(g=0;g<gb_tbl.size();g++){\r
8610                 data_type *gdt = gb_tbl.get_data_type(g);\r
8611                 if(gdt->is_temporal())\r
8612                         uses_temporal_flush = true;\r
8613         }\r
8614 \r
8615         if(uses_temporal_flush){\r
8616                 ret += "//\t\tFor temporal flush\n";\r
8617                 for(g=0;g<gb_tbl.size();g++){\r
8618                         data_type *gdt = gb_tbl.get_data_type(g);\r
8619                         if(gdt->is_temporal()){\r
8620                           sprintf(tmpstr,"last_gb%d",g);\r
8621                           ret+="\t"+gb_tbl.get_data_type(g)->make_host_cvar(tmpstr)+";\n";\r
8622                           sprintf(tmpstr,"last_flushed_gb%d",g);\r
8623                           ret+="\t"+gb_tbl.get_data_type(g)->make_host_cvar(tmpstr)+";\n";\r
8624                         }\r
8625                 }\r
8626                 ret += "\tbool needs_temporal_flush;\n";\r
8627         }\r
8628 \r
8629 \r
8630 //                      The publicly exposed functions\r
8631 \r
8632         ret += "\npublic:\n";\r
8633 \r
8634 \r
8635 //-------------------\r
8636 //                      The functor constructor\r
8637 //                      pass in the schema handle.\r
8638 //                      1) make assignments to the unpack offset variables\r
8639 //                      2) initialize the complex literals\r
8640 \r
8641         ret += "//\t\tFunctor constructor.\n";\r
8642         ret +=  this->generate_functor_name()+"(int schema_handle0){\n";\r
8643 \r
8644         // save the schema handle\r
8645         ret += "\t\tthis->schema_handle0 = schema_handle0;\n";\r
8646 \r
8647 //              unpack vars\r
8648         ret += "//\t\tGet offsets for unpacking fields from input tuple.\n";\r
8649         ret += gen_access_var_init(cid_set);\r
8650 //              tuple metadata\r
8651         ret += "tuple_metadata_offset0 = ftaschema_get_tuple_metadata_offset(schema_handle0);\n";\r
8652 \r
8653 //              complex literals\r
8654         ret += "//\t\tInitialize complex literals.\n";\r
8655         ret += gen_complex_lit_init(complex_literals);\r
8656 \r
8657 //              Initialize partial function results so they can be safely GC'd\r
8658         ret += gen_partial_fcn_init(partial_fcns);\r
8659 \r
8660 //              Initialize non-query-parameter parameter handles\r
8661         ret += gen_pass_by_handle_init(param_handle_table);\r
8662 \r
8663 //              temporal flush variables\r
8664 //              ASSUME that structured values won't be temporal.\r
8665         if(uses_temporal_flush){\r
8666                 ret += "//\t\tInitialize temporal flush variables.\n";\r
8667                 for(g=0;g<gb_tbl.size();g++){\r
8668                         data_type *gdt = gb_tbl.get_data_type(g);\r
8669                         if(gdt->is_temporal()){\r
8670                                 literal_t gl(gdt->type_indicator());\r
8671                                 sprintf(tmpstr,"\tlast_gb%d = %s;\n",g, gl.to_hfta_C_code("").c_str());\r
8672                                 ret.append(tmpstr);\r
8673                                 sprintf(tmpstr,"\tlast_flushed_gb%d = %s;\n",g, gl.to_hfta_C_code("").c_str());\r
8674                                 ret.append(tmpstr);\r
8675                         }\r
8676                 }\r
8677                 ret += "\tneeds_temporal_flush = false;\n";\r
8678         }\r
8679 \r
8680         //              Init temporal attributes referenced in select list\r
8681         ret += gen_init_temp_vars(schema, select_list, segen_gb_tbl);\r
8682 \r
8683         ret += "}\n\n";\r
8684 \r
8685 //-------------------\r
8686 //                      Functor destructor\r
8687         ret += "//\t\tFunctor destructor.\n";\r
8688         ret +=  "~"+this->generate_functor_name()+"(){\n";\r
8689 \r
8690 //                      clean up buffer type complex literals\r
8691         ret += gen_complex_lit_dtr(complex_literals);\r
8692 \r
8693 //                      Deregister the pass-by-handle parameters\r
8694         ret += "/* register and de-register the pass-by-handle parameters */\n";\r
8695         ret += gen_pass_by_handle_dtr(param_handle_table);\r
8696 \r
8697 //                      clean up partial function results.\r
8698         ret += "/* clean up partial function storage    */\n";\r
8699         ret += gen_partial_fcn_dtr(partial_fcns);\r
8700 \r
8701 //                      Destroy the parameters, if any need to be destroyed\r
8702         ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";\r
8703 \r
8704         ret += "};\n\n";\r
8705 \r
8706 \r
8707 //-------------------\r
8708 //                      Parameter manipulation routines\r
8709         ret += generate_load_param_block(this->generate_functor_name(),\r
8710                                                                         this->param_tbl,param_handle_table);\r
8711         ret += generate_delete_param_block(this->generate_functor_name(),\r
8712                                                                         this->param_tbl,param_handle_table);\r
8713 \r
8714 //-------------------\r
8715 //                      Register new parameter block\r
8716 \r
8717         ret += "int set_param_block(gs_int32_t sz, void* value){\n";\r
8718           ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";\r
8719           ret += "\treturn this->load_params_"+this->generate_functor_name()+\r
8720                                 "(sz, value);\n";\r
8721         ret += "};\n\n";\r
8722 \r
8723 // -----------------------------------\r
8724 //                      group-by pattern support\r
8725 \r
8726         ret +=\r
8727 "int n_groupby_patterns(){\n"\r
8728 "       return "+int_to_string(gb_tbl.gb_patterns.size())+";\n"\r
8729 "}\n"\r
8730 "bool *get_pattern(int p){\n"\r
8731 "       return "+this->generate_functor_name()+"_gb_patterns[p];\n"\r
8732 "}\n\n"\r
8733 ;\r
8734 \r
8735 \r
8736 \r
8737 \r
8738 //-------------------\r
8739 //              the create_group method.\r
8740 //              This method creates a group in a buffer passed in\r
8741 //              (to allow for creation on the stack).\r
8742 //              There are also a couple of side effects:\r
8743 //              1) evaluate the WHERE clause (and therefore, unpack all partial fcns)\r
8744 //              2) determine if a temporal flush is required.\r
8745 \r
8746         ret += this->generate_functor_name()+"_groupdef *create_group(host_tuple &tup0, gs_sp_t buffer){\n";\r
8747         //              Variables for execution of the function.\r
8748         ret += "\tgs_int32_t problem = 0;\n";   // return unpack failure\r
8749 \r
8750         if(partial_fcns.size()>0){              // partial fcn access failure\r
8751           ret += "\tgs_retval_t retval = 0;\n";\r
8752           ret += "\n";\r
8753         }\r
8754 //              return value\r
8755         ret += "\t"+generate_functor_name()+"_groupdef *gbval = ("+generate_functor_name()+\r
8756                         "_groupdef *) buffer;\n";\r
8757 \r
8758 //              Start by cleaning up partial function results\r
8759         ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";\r
8760         set<int> w_pfcns;       // partial fcns in where clause\r
8761         for(w=0;w<where.size();++w)\r
8762                 collect_partial_fcns_pr(where[w]->pr, w_pfcns);\r
8763 \r
8764         set<int> ag_gb_pfcns;   // partial fcns in gbdefs, aggr se's\r
8765         for(g=0;g<gb_tbl.size();g++){\r
8766                 collect_partial_fcns(gb_tbl.get_def(g), ag_gb_pfcns);\r
8767         }\r
8768         for(a=0;a<aggr_tbl.size();a++){\r
8769                 collect_partial_fcns(aggr_tbl.get_aggr_se(a), ag_gb_pfcns);\r
8770         }\r
8771         ret += gen_partial_fcn_dtr(partial_fcns,w_pfcns);\r
8772         ret += gen_partial_fcn_dtr(partial_fcns,ag_gb_pfcns);\r
8773 //      ret += gen_partial_fcn_dtr(partial_fcns);\r
8774 \r
8775 \r
8776         ret += gen_temp_tuple_check(this->node_name, 0);\r
8777         col_id_set found_cids;  // colrefs unpacked thus far.\r
8778         ret += gen_unpack_temp_vars(schema, found_cids, select_list, segen_gb_tbl, needs_xform);\r
8779 \r
8780 \r
8781 //                      Save temporal group-by variables\r
8782 \r
8783 \r
8784         ret.append("\n\t//\t\tCompute temporal groupby attributes\n\n");\r
8785 \r
8786           for(g=0;g<gb_tbl.size();g++){\r
8787 \r
8788                         data_type *gdt = gb_tbl.get_data_type(g);\r
8789 \r
8790                         if(gdt->is_temporal()){\r
8791                                 sprintf(tmpstr,"\tgbval->gb_var%d = %s;\n",\r
8792                                         g, generate_se_code(gb_tbl.get_def(g),schema).c_str() );\r
8793                                 ret.append(tmpstr);\r
8794                         }\r
8795                 }\r
8796                 ret.append("\n");\r
8797 \r
8798 \r
8799 \r
8800 //                      Compare the temporal GB vars with the stored ones,\r
8801 //                      set flush indicator and update stored GB vars if there is any change.\r
8802 \r
8803 ret += "// hfta_disorder = "+int_to_string(hfta_disorder)+"\n";\r
8804         if(hfta_disorder < 2){\r
8805                 if(uses_temporal_flush){\r
8806                         ret+= "\tif( !( (";\r
8807                         bool first_one = true;\r
8808                         for(g=0;g<gb_tbl.size();g++){\r
8809                                 data_type *gdt = gb_tbl.get_data_type(g);\r
8810 \r
8811                                 if(gdt->is_temporal()){\r
8812                                 sprintf(tmpstr,"last_gb%d",g);   string lhs_op = tmpstr;\r
8813                                 sprintf(tmpstr,"gbval->gb_var%d",g);   string rhs_op = tmpstr;\r
8814                                 if(first_one){first_one = false;} else {ret += ") && (";}\r
8815                                 ret += generate_equality_test(lhs_op, rhs_op, gdt);\r
8816                                 }\r
8817                         }\r
8818                         ret += ") ) ){\n";\r
8819                         for(g=0;g<gb_tbl.size();g++){\r
8820                         data_type *gdt = gb_tbl.get_data_type(g);\r
8821                         if(gdt->is_temporal()){\r
8822                                 if(gdt->is_buffer_type()){\r
8823                                         sprintf(tmpstr,"\t\t%s(&(gbval->gb_var%d),&last_gb%d);\n",gdt->get_hfta_buffer_replace().c_str(),g,g);\r
8824                                 }else{\r
8825                                         sprintf(tmpstr,"\t\tlast_flushed_gb%d = last_gb%d;\n",g,g);\r
8826                                         ret += tmpstr;\r
8827                                         sprintf(tmpstr,"\t\tlast_gb%d = gbval->gb_var%d;\n",g,g);\r
8828                                 }\r
8829                                 ret += tmpstr;\r
8830                                 }\r
8831                         }\r
8832                         ret += "\t\tneeds_temporal_flush=true;\n";\r
8833                         ret += "\t\t}else{\n"\r
8834                                 "\t\t\tneeds_temporal_flush=false;\n"\r
8835                                 "\t\t}\n";\r
8836                 }\r
8837         }else{\r
8838                 ret+= "\tif(temp_tuple_received && !( (";\r
8839                 bool first_one = true;\r
8840                 for(g=0;g<gb_tbl.size();g++){\r
8841                         data_type *gdt = gb_tbl.get_data_type(g);\r
8842 \r
8843                         if(gdt->is_temporal()){\r
8844                                 sprintf(tmpstr,"last_gb%d",g);   string lhs_op = tmpstr;\r
8845                                 sprintf(tmpstr,"gbval->gb_var%d",g);   string rhs_op = tmpstr;\r
8846                                 if(first_one){first_one = false;} else {ret += ") && (";}\r
8847                                 ret += generate_equality_test(lhs_op, rhs_op, gdt);\r
8848                                 break;\r
8849                         }\r
8850                 }\r
8851                 ret += ") ) ){\n";\r
8852                 int temporal_g = 0;\r
8853                 for(g=0;g<gb_tbl.size();g++){\r
8854                         data_type *gdt = gb_tbl.get_data_type(g);\r
8855                         if(gdt->is_temporal()){\r
8856                                 temporal_g = g;\r
8857                                 if(gdt->is_buffer_type()){\r
8858                                         sprintf(tmpstr,"\t\t%s(&(gbval->gb_var%d),&last_gb%d);\n",gdt->get_hfta_buffer_replace().c_str(),g,g);\r
8859                                 }else{\r
8860                                         sprintf(tmpstr,"\t\tlast_flushed_gb%d = last_gb%d;\n",g,g);\r
8861                                         ret += tmpstr;\r
8862                                         sprintf(tmpstr,"\t\tlast_gb%d = gbval->gb_var%d;\n",g,g);\r
8863                                 }\r
8864                                 ret += tmpstr;\r
8865                                 break;\r
8866                         }\r
8867                 }\r
8868                 data_type *tgdt = gb_tbl.get_data_type(temporal_g);\r
8869                 literal_t gl(tgdt->type_indicator());\r
8870                 ret += "\t\tif(last_flushed_gb"+int_to_string(temporal_g)+">"+gl.to_hfta_C_code("")+")\n";\r
8871                 ret += "\t\t\tneeds_temporal_flush=true;\n";\r
8872                 ret += "\t\t}else{\n"\r
8873                         "\t\t\tneeds_temporal_flush=false;\n"\r
8874                         "\t\t}\n";\r
8875         }\r
8876 \r
8877 \r
8878 //              For temporal status tuple we don't need to do anything else\r
8879         ret += "\tif (temp_tuple_received) return NULL;\n\n";\r
8880 \r
8881         for(w=0;w<where.size();++w){\r
8882                 sprintf(tmpstr,"//\t\tPredicate clause %d.\n",w);\r
8883                 ret += tmpstr;\r
8884 //                      Find the set of variables accessed in this CNF elem,\r
8885 //                      but in no previous element.\r
8886                 col_id_set new_cids;\r
8887                 get_new_pred_cids(where[w]->pr, found_cids, new_cids, segen_gb_tbl);\r
8888 \r
8889 //                      Unpack these values.\r
8890                 ret += gen_unpack_cids(schema, new_cids, "NULL", needs_xform);\r
8891 //                      Find partial fcns ref'd in this cnf element\r
8892                 set<int> pfcn_refs;\r
8893                 collect_partial_fcns_pr(where[w]->pr, pfcn_refs);\r
8894                 ret += gen_unpack_partial_fcn(schema, partial_fcns, pfcn_refs,"NULL");\r
8895 \r
8896                 ret += "\tif( !("+generate_predicate_code(where[w]->pr,schema)+\r
8897                                 +") ) return(NULL);\n";\r
8898         }\r
8899 \r
8900 //              The partial functions ref'd in the group-by var and aggregate\r
8901 //              definitions must also be evaluated.  If one returns false,\r
8902 //              then implicitly the predicate is false.\r
8903         set<int>::iterator pfsi;\r
8904 \r
8905         if(ag_gb_pfcns.size() > 0)\r
8906                 ret += "//\t\tUnpack remaining partial fcns.\n";\r
8907         ret += gen_full_unpack_partial_fcn(schema, partial_fcns, ag_gb_pfcns,\r
8908                                                                                 found_cids, segen_gb_tbl, "NULL", needs_xform);\r
8909 \r
8910 //                      Unpack the group-by variables\r
8911 \r
8912           for(g=0;g<gb_tbl.size();g++){\r
8913                 data_type *gdt = gb_tbl.get_data_type(g);\r
8914 \r
8915                 if(!gdt->is_temporal()){\r
8916 //                      Find the new fields ref'd by this GBvar def.\r
8917                         col_id_set new_cids;\r
8918                         get_new_se_cids(gb_tbl.get_def(g), found_cids, new_cids, segen_gb_tbl);\r
8919 //                      Unpack these values.\r
8920                         ret += gen_unpack_cids(schema, new_cids, "NULL", needs_xform);\r
8921 \r
8922                         sprintf(tmpstr,"\tgbval->gb_var%d = %s;\n",\r
8923                                 g, generate_se_code(gb_tbl.get_def(g),schema).c_str() );\r
8924 /*\r
8925 //                              There seems to be no difference between the two\r
8926 //                              branches of the IF statement.\r
8927                 data_type *gdt = gb_tbl.get_data_type(g);\r
8928                   if(gdt->is_buffer_type()){\r
8929 //                              Create temporary copy.\r
8930                         sprintf(tmpstr,"\tgbval->gb_var%d = %s;\n",\r
8931                                 g, generate_se_code(gb_tbl.get_def(g),schema).c_str() );\r
8932                   }else{\r
8933                         scalarexp_t *gse = gb_tbl.get_def(g);\r
8934                         sprintf(tmpstr,"\tgbval->gb_var%d = %s;\n",\r
8935                                         g,generate_se_code(gse,schema).c_str());\r
8936                   }\r
8937 */\r
8938 \r
8939                         ret.append(tmpstr);\r
8940                 }\r
8941           }\r
8942           ret.append("\n");\r
8943 \r
8944         ret+= "\treturn gbval;\n";\r
8945         ret += "};\n\n\n";\r
8946 \r
8947 //--------------------------------------------------------\r
8948 //                      Create and initialize an aggregate object\r
8949 \r
8950         ret += this->generate_functor_name()+"_aggrdef *create_aggregate(host_tuple &tup0, gs_sp_t buffer){\n";\r
8951         //              Variables for execution of the function.\r
8952         ret += "\tgs_int32_t problem = 0;\n";   // return unpack failure\r
8953 \r
8954 //              return value\r
8955         ret += "\t"+generate_functor_name()+"_aggrdef *aggval = ("+generate_functor_name()+\r
8956                         "_aggrdef *)buffer;\n";\r
8957 \r
8958         for(a=0;a<aggr_tbl.size();a++){\r
8959                 if(aggr_tbl.is_builtin(a)){\r
8960 //                      Create temporaries for buffer return values\r
8961                   data_type *adt = aggr_tbl.get_data_type(a);\r
8962                   if(adt->is_buffer_type()){\r
8963                         sprintf(tmpstr,"aggr_tmp_%d", a);\r
8964                         ret+=adt->make_host_cvar(tmpstr)+";\n";\r
8965                   }\r
8966                 }\r
8967         }\r
8968 \r
8969 //              Unpack all remaining attributes\r
8970         ret += gen_remaining_colrefs(schema, cid_set, found_cids, "NULL", needs_xform);\r
8971         for(a=0;a<aggr_tbl.size();a++){\r
8972           sprintf(tmpstr,"aggval->aggr_var%d",a);\r
8973           string assignto_var = tmpstr;\r
8974           ret += "\t"+generate_aggr_init(assignto_var,&aggr_tbl,a, schema);\r
8975         }\r
8976 \r
8977         ret += "\treturn aggval;\n";\r
8978         ret += "};\n\n";\r
8979 \r
8980 //--------------------------------------------------------\r
8981 //                      update an aggregate object\r
8982 \r
8983         ret += "void update_aggregate(host_tuple &tup0, "\r
8984                 +generate_functor_name()+"_groupdef *gbval, "+\r
8985                 generate_functor_name()+"_aggrdef *aggval){\n";\r
8986         //              Variables for execution of the function.\r
8987         ret += "\tgs_int32_t problem = 0;\n";   // return unpack failure\r
8988 \r
8989 //                      use of temporaries depends on the aggregate,\r
8990 //                      generate them in generate_aggr_update\r
8991 \r
8992 \r
8993 //              Unpack all remaining attributes\r
8994         ret += gen_remaining_colrefs(schema, cid_set, found_cids, "", needs_xform);\r
8995         for(a=0;a<aggr_tbl.size();a++){\r
8996           sprintf(tmpstr,"aggval->aggr_var%d",a);\r
8997           string varname = tmpstr;\r
8998           ret.append(generate_aggr_update(varname,&aggr_tbl,a, schema));\r
8999         }\r
9000 \r
9001         ret += "\treturn;\n";\r
9002         ret += "};\n";\r
9003 \r
9004 //---------------------------------------------------\r
9005 //                      Flush test\r
9006 \r
9007         ret += "\tbool flush_needed(){\n";\r
9008         if(uses_temporal_flush){\r
9009                 ret += "\t\treturn needs_temporal_flush;\n";\r
9010         }else{\r
9011                 ret += "\t\treturn false;\n";\r
9012         }\r
9013         ret += "\t};\n";\r
9014 \r
9015 //---------------------------------------------------\r
9016 //                      create output tuple\r
9017 //                      Unpack the partial functions ref'd in the where clause,\r
9018 //                      select clause.  Evaluate the where clause.\r
9019 //                      Finally, pack the tuple.\r
9020 \r
9021 //                      I need to use special code generation here,\r
9022 //                      so I'll leave it in longhand.\r
9023 \r
9024         ret += "host_tuple create_output_tuple("\r
9025                 +generate_functor_name()+"_groupdef *gbval, "+\r
9026                 generate_functor_name()+"_aggrdef *aggval, bool &failed){\n";\r
9027 \r
9028         ret += "\thost_tuple tup;\n";\r
9029         ret += "\tfailed = false;\n";\r
9030         ret += "\tgs_retval_t retval = 0;\n";\r
9031 \r
9032         string gbvar = "gbval->gb_var";\r
9033         string aggvar = "aggval->";\r
9034 \r
9035 //                      Create cached temporaries for UDAF return values.\r
9036         for(a=0;a<aggr_tbl.size();a++){\r
9037                 if(! aggr_tbl.is_builtin(a)){\r
9038                         int afcn_id = aggr_tbl.get_fcn_id(a);\r
9039                         data_type *adt = Ext_fcns->get_fcn_dt(afcn_id);\r
9040                         sprintf(tmpstr,"udaf_ret_%d", a);\r
9041                         ret+="\t"+adt->make_host_cvar(tmpstr)+";\n";\r
9042                 }\r
9043         }\r
9044 \r
9045 \r
9046 //                      First, get the return values from the UDAFS\r
9047         for(a=0;a<aggr_tbl.size();a++){\r
9048                 if(! aggr_tbl.is_builtin(a)){\r
9049                         ret += "\t"+aggr_tbl.get_op(a)+"_HFTA_AGGR_OUTPUT_(&(udaf_ret_"+int_to_string(a)+"),";\r
9050                         if(aggr_tbl.get_storage_type(a)->get_type() != fstring_t) ret+="&";\r
9051                         ret+="("+aggvar+"aggr_var"+int_to_string(a)+"));\n";\r
9052                 }\r
9053         }\r
9054 \r
9055         set<int> hv_sl_pfcns;\r
9056         for(w=0;w<having.size();w++){\r
9057                 collect_partial_fcns_pr(having[w]->pr, hv_sl_pfcns);\r
9058         }\r
9059         for(s=0;s<select_list.size();s++){\r
9060                 collect_partial_fcns(select_list[s]->se, hv_sl_pfcns);\r
9061         }\r
9062 \r
9063 //              clean up the partial fcn results from any previous execution\r
9064         ret += gen_partial_fcn_dtr(partial_fcns,hv_sl_pfcns);\r
9065 \r
9066 //              Unpack them now\r
9067         for(pfsi=hv_sl_pfcns.begin();pfsi!=hv_sl_pfcns.end();++pfsi){\r
9068                 ret += unpack_partial_fcn_fm_aggr(partial_fcns[(*pfsi)], (*pfsi), gbvar, aggvar, schema);\r
9069                 ret += "\tif(retval){ failed = true; return(tup);}\n";\r
9070         }\r
9071 \r
9072 //              Evalaute the HAVING clause\r
9073 //              TODO: this seems to have a ++ operator rather than a + operator.\r
9074         for(w=0;w<having.size();++w){\r
9075                 ret += "\tif( !("+generate_predicate_code_fm_aggr(having[w]->pr,gbvar, aggvar, schema) +") ) { failed = true; return(tup);}\n";\r
9076         }\r
9077 \r
9078 //          Now, compute the size of the tuple.\r
9079 \r
9080 //          Unpack any BUFFER type selections into temporaries\r
9081 //          so that I can compute their size and not have\r
9082 //          to recompute their value during tuple packing.\r
9083 //          I can use regular assignment here because\r
9084 //          these temporaries are non-persistent.\r
9085 //                      TODO: should I be using the selvar generation routine?\r
9086 \r
9087         ret += "//\t\tCompute the size of the tuple.\n";\r
9088         ret += "//\t\t\tNote: buffer storage packed at the end of the tuple.\n";\r
9089       for(s=0;s<select_list.size();s++){\r
9090                 scalarexp_t *se = select_list[s]->se;\r
9091         data_type *sdt = se->get_data_type();\r
9092         if(sdt->is_buffer_type() &&\r
9093                          !( (se->get_operator_type() == SE_COLREF) ||\r
9094                                 (se->get_operator_type() == SE_AGGR_STAR) ||\r
9095                                 (se->get_operator_type() == SE_AGGR_SE) ||\r
9096                            (se->get_operator_type() == SE_FUNC && se->is_partial()) ||\r
9097                            (se->get_operator_type() == SE_FUNC && se->get_aggr_ref() >= 0))\r
9098                 ){\r
9099             sprintf(tmpstr,"selvar_%d",s);\r
9100                         ret+="\t"+sdt->make_host_cvar(tmpstr)+" = ";\r
9101                         ret += generate_se_code_fm_aggr(se,gbvar, aggvar, schema) +";\n";\r
9102         }\r
9103       }\r
9104 \r
9105 //      The size of the tuple is the size of the tuple struct plus the\r
9106 //      size of the buffers to be copied in.\r
9107 \r
9108       ret+="\ttup.tuple_size = sizeof(" + generate_tuple_name( this->get_node_name()) +") + sizeof(gs_uint8_t)";\r
9109       for(s=0;s<select_list.size();s++){\r
9110 //              if(s>0) ret += "+";\r
9111                 scalarexp_t *se = select_list[s]->se;\r
9112         data_type *sdt = select_list[s]->se->get_data_type();\r
9113         if(sdt->is_buffer_type()){\r
9114                   if(!( (se->get_operator_type() == SE_COLREF) ||\r
9115                                 (se->get_operator_type() == SE_AGGR_STAR) ||\r
9116                                 (se->get_operator_type() == SE_AGGR_SE) ||\r
9117                            (se->get_operator_type() == SE_FUNC && se->is_partial()) ||\r
9118                            (se->get_operator_type() == SE_FUNC && se->get_aggr_ref() >= 0))\r
9119                   ){\r
9120             sprintf(tmpstr," + %s(&selvar_%d)", sdt->get_hfta_buffer_size().c_str(),s);\r
9121             ret.append(tmpstr);\r
9122                   }else{\r
9123             sprintf(tmpstr," + %s(&%s)", sdt->get_hfta_buffer_size().c_str(),generate_se_code_fm_aggr(se,gbvar, aggvar, schema).c_str());\r
9124             ret.append(tmpstr);\r
9125                   }\r
9126         }\r
9127       }\r
9128       ret.append(";\n");\r
9129 \r
9130 //              Allocate tuple data block.\r
9131         ret += "//\t\tCreate the tuple block.\n";\r
9132           ret += "\ttup.data = malloc(tup.tuple_size);\n";\r
9133           ret += "\ttup.heap_resident = true;\n";\r
9134 \r
9135 //              Mark tuple as regular\r
9136           ret += "\t*((gs_sp_t )tup.data + sizeof(" + generate_tuple_name( this->get_node_name()) +")) = REGULAR_TUPLE;\n";\r
9137 \r
9138 //        ret += "\ttup.channel = 0;\n";\r
9139           ret += "\t"+generate_tuple_name( this->get_node_name())+" *tuple = ("+\r
9140                                 generate_tuple_name( this->get_node_name())+" *)(tup.data);\n";\r
9141 \r
9142 //              Start packing.\r
9143 //                      (Here, offsets are hard-wired.  is this a problem?)\r
9144 \r
9145         ret += "//\t\tPack the fields into the tuple.\n";\r
9146           ret += "\tint tuple_pos = sizeof("+generate_tuple_name( this->get_node_name()) +") + sizeof(gs_uint8_t);\n";\r
9147       for(s=0;s<select_list.size();s++){\r
9148                 scalarexp_t *se = select_list[s]->se;\r
9149         data_type *sdt = se->get_data_type();\r
9150         if(sdt->is_buffer_type()){\r
9151                   if(!( (se->get_operator_type() == SE_COLREF) ||\r
9152                                 (se->get_operator_type() == SE_AGGR_STAR) ||\r
9153                                 (se->get_operator_type() == SE_AGGR_SE) ||\r
9154                            (se->get_operator_type() == SE_FUNC && se->is_partial()) ||\r
9155                            (se->get_operator_type() == SE_FUNC && se->get_aggr_ref() >= 0))\r
9156                   ){\r
9157             sprintf(tmpstr,"\t%s(&(tuple->tuple_var%d), &selvar_%d,  ((gs_sp_t)tuple)+tuple_pos, tuple_pos);\n", sdt->get_hfta_buffer_tuple_copy().c_str(),s, s);\r
9158             ret.append(tmpstr);\r
9159             sprintf(tmpstr,"\ttuple_pos += %s(&selvar_%d);\n", sdt->get_hfta_buffer_size().c_str(), s);\r
9160             ret.append(tmpstr);\r
9161                   }else{\r
9162             sprintf(tmpstr,"\t%s(&(tuple->tuple_var%d), &%s,  ((gs_sp_t)tuple)+tuple_pos, tuple_pos);\n", sdt->get_hfta_buffer_tuple_copy().c_str(),s, generate_se_code_fm_aggr(se,gbvar, aggvar, schema).c_str());\r
9163             ret.append(tmpstr);\r
9164             sprintf(tmpstr,"\ttuple_pos += %s(&%s);\n", sdt->get_hfta_buffer_size().c_str(), generate_se_code_fm_aggr(se,gbvar, aggvar, schema).c_str());\r
9165             ret.append(tmpstr);\r
9166                   }\r
9167         }else{\r
9168             sprintf(tmpstr,"\ttuple->tuple_var%d = ",s);\r
9169             ret.append(tmpstr);\r
9170             ret.append(generate_se_code_fm_aggr(se,gbvar, aggvar, schema) );\r
9171             ret.append(";\n");\r
9172         }\r
9173       }\r
9174 \r
9175 //                      Destroy string temporaries\r
9176           ret += gen_buffer_selvars_dtr(select_list);\r
9177 //                      Destroy string return vals of UDAFs\r
9178         for(a=0;a<aggr_tbl.size();a++){\r
9179                 if(! aggr_tbl.is_builtin(a)){\r
9180                         int afcn_id = aggr_tbl.get_fcn_id(a);\r
9181                         data_type *adt = Ext_fcns->get_fcn_dt(afcn_id);\r
9182                         if(adt->is_buffer_type()){\r
9183                                 sprintf(tmpstr,"\t%s(&udaf_ret_%d);\n",\r
9184                                 adt->get_hfta_buffer_destroy().c_str(), a );\r
9185                                 ret += tmpstr;\r
9186                         }\r
9187                 }\r
9188         }\r
9189 \r
9190 \r
9191           ret += "\treturn tup;\n";\r
9192           ret += "};\n";\r
9193 \r
9194 \r
9195 //-------------------------------------------------------------------\r
9196 //              Temporal update functions\r
9197 \r
9198         ret+="bool temp_status_received(){return temp_tuple_received;};\n\n";\r
9199 \r
9200         for(g=0;g<gb_tbl.size();g++){\r
9201                 data_type *gdt = gb_tbl.get_data_type(g);\r
9202                 if(gdt->is_temporal()){\r
9203                         tgdt = gdt;\r
9204                         break;\r
9205                 }\r
9206         }\r
9207         ret += tgdt->get_host_cvar_type()+" get_last_flushed_gb(){\n";\r
9208         ret+="\treturn last_flushed_gb"+int_to_string(g)+";\n";\r
9209         ret+="}\n";\r
9210         ret += tgdt->get_host_cvar_type()+" get_last_gb(){\n";\r
9211         ret+="\treturn last_gb"+int_to_string(g)+";\n";\r
9212         ret+="}\n";\r
9213 \r
9214 \r
9215 \r
9216 \r
9217 //              create a temp status tuple\r
9218         ret += "int create_temp_status_tuple(host_tuple& result, bool flush_finished) {\n\n";\r
9219 \r
9220         ret += gen_init_temp_status_tuple(this->get_node_name());\r
9221 \r
9222 //              Start packing.\r
9223 //                      (Here, offsets are hard-wired.  is this a problem?)\r
9224 \r
9225         ret += "//\t\tPack the fields into the tuple.\n";\r
9226         for(s=0;s<select_list.size();s++){\r
9227                 data_type *sdt = select_list[s]->se->get_data_type();\r
9228                 if(sdt->is_temporal()){\r
9229                         sprintf(tmpstr,"\ttuple->tuple_var%d = ",s);\r
9230                         ret += tmpstr;\r
9231 \r
9232                         sprintf(tmpstr,"(flush_finished) ? %s : %s ", generate_se_code(select_list[s]->se,schema).c_str(), generate_se_code_fm_aggr(select_list[s]->se,"last_flushed_gb", "", schema).c_str());\r
9233                         ret += tmpstr;\r
9234                         ret += ";\n";\r
9235                 }\r
9236         }\r
9237 \r
9238 \r
9239         ret += "\treturn 0;\n";\r
9240         ret += "};};\n\n\n";\r
9241 \r
9242 \r
9243 //----------------------------------------------------------\r
9244 //                      The hash function\r
9245 \r
9246         ret += "struct "+generate_functor_name()+"_hash_func{\n";\r
9247         ret += "\tgs_uint32_t operator()(const "+generate_functor_name()+\r
9248                                 "_groupdef *grp) const{\n";\r
9249         ret += "\t\treturn( (";\r
9250         for(g=0;g<gb_tbl.size();g++){\r
9251                 if(g>0) ret += "^";\r
9252                 data_type *gdt = gb_tbl.get_data_type(g);\r
9253                 if(gdt->use_hashfunc()){\r
9254                         if(gdt->is_buffer_type())\r
9255                                 sprintf(tmpstr,"(%s*%s(&(grp->gb_var%d)))",hash_nums[g%NRANDS].c_str(),gdt->get_hfta_hashfunc().c_str(),g);\r
9256                         else\r
9257                                 sprintf(tmpstr,"(%s*%s(grp->gb_var%d))",hash_nums[g%NRANDS].c_str(),gdt->get_hfta_hashfunc().c_str(),g);\r
9258                 }else{\r
9259                         sprintf(tmpstr,"(%s*grp->gb_var%d)",hash_nums[g%NRANDS].c_str(),g);\r
9260                 }\r
9261                 ret += tmpstr;\r
9262         }\r
9263         ret += ") >> 32);\n";\r
9264         ret += "\t}\n";\r
9265         ret += "};\n\n";\r
9266 \r
9267 //----------------------------------------------------------\r
9268 //                      The comparison function\r
9269 \r
9270         ret += "struct "+generate_functor_name()+"_equal_func{\n";\r
9271         ret += "\tbool operator()(const "+generate_functor_name()+"_groupdef *grp1, "+\r
9272                         generate_functor_name()+"_groupdef *grp2) const{\n";\r
9273         ret += "\t\treturn( (";\r
9274 \r
9275         for(g=0;g<gb_tbl.size();g++){\r
9276                 if(g>0) ret += ") && (";\r
9277                 data_type *gdt = gb_tbl.get_data_type(g);\r
9278                 if(gdt->complex_comparison(gdt)){\r
9279                 if(gdt->is_buffer_type())\r
9280                         sprintf(tmpstr,"(%s(&(grp1->gb_var%d), &(grp2->gb_var%d))==0)",\r
9281                                 gdt->get_hfta_comparison_fcn(gdt).c_str(),g,g);\r
9282                 else\r
9283                         sprintf(tmpstr,"(%s((grp1->gb_var%d), (grp2->gb_var%d))==0)",\r
9284                                 gdt->get_hfta_comparison_fcn(gdt).c_str(),g,g);\r
9285                 }else{\r
9286                         sprintf(tmpstr,"grp1->gb_var%d == grp2->gb_var%d",g,g);\r
9287                 }\r
9288                 ret += tmpstr;\r
9289         }\r
9290         ret += ") );\n";\r
9291         ret += "\t}\n";\r
9292         ret += "};\n\n";\r
9293 \r
9294 \r
9295         return(ret);\r
9296 }\r
9297 \r
9298 string sgah_qpn::generate_operator(int i, string params){\r
9299 \r
9300         if(hfta_disorder < 2){\r
9301                 return(\r
9302                         "       groupby_operator<" +\r
9303                         generate_functor_name()+","+\r
9304                         generate_functor_name() + "_groupdef, " +\r
9305                         generate_functor_name() + "_aggrdef, " +\r
9306                         generate_functor_name()+"_hash_func, "+\r
9307                         generate_functor_name()+"_equal_func "\r
9308                         "> *op"+int_to_string(i)+" = new groupby_operator<"+\r
9309                         generate_functor_name()+","+\r
9310                         generate_functor_name() + "_groupdef, " +\r
9311                         generate_functor_name() + "_aggrdef, " +\r
9312                         generate_functor_name()+"_hash_func, "+\r
9313                         generate_functor_name()+"_equal_func "\r
9314                         ">("+params+", \"" + get_node_name() +\r
9315 "\");\n"\r
9316                 );\r
9317         }\r
9318         data_type *tgdt;\r
9319         for(int g=0;g<gb_tbl.size();g++){\r
9320                 data_type *gdt = gb_tbl.get_data_type(g);\r
9321                 if(gdt->is_temporal()){\r
9322                         tgdt = gdt;\r
9323                         break;\r
9324                 }\r
9325         }\r
9326 \r
9327         return(\r
9328                         "       groupby_operator_oop<" +\r
9329                         generate_functor_name()+","+\r
9330                         generate_functor_name() + "_groupdef, " +\r
9331                         generate_functor_name() + "_aggrdef, " +\r
9332                         generate_functor_name()+"_hash_func, "+\r
9333                         generate_functor_name()+"_equal_func, " +\r
9334             tgdt->get_host_cvar_type() +\r
9335                         "> *op"+int_to_string(i)+" = new groupby_operator_oop<"+\r
9336                         generate_functor_name()+","+\r
9337                         generate_functor_name() + "_groupdef, " +\r
9338                         generate_functor_name() + "_aggrdef, " +\r
9339                         generate_functor_name()+"_hash_func, "+\r
9340                         generate_functor_name()+"_equal_func, " +\r
9341             tgdt->get_host_cvar_type() +\r
9342                         ">("+params+", \"" + get_node_name() +\r
9343 "\");\n"\r
9344                 );\r
9345 }\r
9346 \r
9347 \r
9348 ////////////////////////////////////////////////\r
9349 ///             MERGE operator\r
9350 ///             MRG functor\r
9351 ////////////////////////////////////////////\r
9352 \r
9353 string mrg_qpn::generate_functor_name(){\r
9354         return("mrg_functor_" + normalize_name(this->get_node_name()));\r
9355 }\r
9356 \r
9357 string mrg_qpn::generate_functor(table_list *schema, ext_fcn_list *Ext_fcns, vector<bool> &needs_xform){\r
9358         int tblref;\r
9359 \r
9360 \r
9361 //              Sanity check\r
9362         if(fm.size() != mvars.size()){\r
9363                 fprintf(stderr,"INTERNAL ERROR in mrg_qpn::generate_functor fm.size=%lu, mvars.size=%lu\n",fm.size(),mvars.size());\r
9364                 exit(1);\r
9365         }\r
9366         if(fm.size() != 2){\r
9367                 fprintf(stderr,"INTERNAL ERROR in mrg_qpn::generate_functor fm.size=mvars.size=%lu\n",fm.size());\r
9368                 exit(1);\r
9369         }\r
9370 \r
9371 \r
9372 //                      Initialize generate utility globals\r
9373         segen_gb_tbl = NULL;\r
9374 \r
9375         string ret = "class " + this->generate_functor_name() + "{\n";\r
9376 \r
9377 //              Private variable:\r
9378 //              1) Vars for unpacked attrs.\r
9379 //              2) offsets ofthe unpakced attrs\r
9380 //              3) last_posted_timestamp\r
9381 \r
9382         data_type dta(\r
9383                 schema->get_type_name(mvars[0]->get_schema_ref(), mvars[0]->get_field()),\r
9384                 schema->get_modifier_list(mvars[0]->get_schema_ref(), mvars[0]->get_field())\r
9385         );\r
9386         data_type dtb(\r
9387                 schema->get_type_name(mvars[1]->get_schema_ref(), mvars[1]->get_field()),\r
9388                 schema->get_modifier_list(mvars[1]->get_schema_ref(), mvars[1]->get_field())\r
9389         );\r
9390 \r
9391         ret += "private:\n";\r
9392 \r
9393         // var to save the schema handle\r
9394         ret += "\tint schema_handle0;\n";\r
9395 \r
9396         // generate the declaration of all the variables related to\r
9397         // temp tuples generation\r
9398         ret += gen_decl_temp_vars();\r
9399 \r
9400 //                      unpacked attribute storage, offsets\r
9401         ret += "//\t\tstorage and offsets of accessed fields.\n";\r
9402         ret += "\tint tuple_metadata_offset0, tuple_metadata_offset1;\n";\r
9403         tblref = 0;\r
9404         sprintf(tmpstr,"unpack_var_%s_%d", mvars[0]->get_field().c_str(), tblref);\r
9405         ret+="\t"+dta.make_host_cvar(tmpstr)+";\n";\r
9406         sprintf(tmpstr,"\tgs_int32_t unpack_offset_%s_%d;\n", mvars[0]->get_field().c_str(), tblref);\r
9407         ret.append(tmpstr);\r
9408         tblref = 1;\r
9409         sprintf(tmpstr,"unpack_var_%s_%d", mvars[1]->get_field().c_str(), tblref);\r
9410         ret+="\t"+dtb.make_host_cvar(tmpstr)+";\n";\r
9411         sprintf(tmpstr,"\tgs_int32_t unpack_offset_%s_%d;\n", mvars[1]->get_field().c_str(), tblref);\r
9412         ret.append(tmpstr);\r
9413 \r
9414         ret += "//\t\tRemember the last posted timestamp.\n";\r
9415         ret+="\t"+dta.make_host_cvar("last_posted_timestamp_0")+";\n";\r
9416         ret+="\t"+dta.make_host_cvar("last_posted_timestamp_1")+";\n";\r
9417         ret+="\t"+dta.make_host_cvar("timestamp")+";\n";\r
9418         ret+="\t"+dta.make_host_cvar("slack")+";\n";\r
9419 //      ret += "\t bool first_execution_0, first_execution_1;\n";\r
9420 \r
9421 //                      variables to hold parameters.\r
9422         ret += "//\tfor query parameters\n";\r
9423         ret += generate_param_vars(param_tbl);\r
9424 \r
9425         ret += "public:\n";\r
9426 //-------------------\r
9427 //                      The functor constructor\r
9428 //                      pass in a schema handle (e.g. for the 1st input stream),\r
9429 //                      use it to determine how to unpack the merge variable.\r
9430 //                      ASSUME that both streams have the same layout,\r
9431 //                      just duplicate it.\r
9432 \r
9433 //              unpack vars\r
9434         ret += "//\t\tFunctor constructor.\n";\r
9435         ret +=  this->generate_functor_name()+"(int schema_handle0){\n";\r
9436 \r
9437         // var to save the schema handle\r
9438         ret += "\tthis->schema_handle0 = schema_handle0;\n";\r
9439         ret += "\ttuple_metadata_offset0=ftaschema_get_tuple_metadata_offset(schema_handle0);\n";\r
9440         ret += "\ttuple_metadata_offset1=ftaschema_get_tuple_metadata_offset(schema_handle0);\n";\r
9441 \r
9442         ret += "//\t\tGet offsets for unpacking fields from input tuple.\n";\r
9443 \r
9444    sprintf(tmpstr,"\tunpack_offset_%s_%d = ftaschema_get_field_offset_by_name(schema_handle0, \"%s\");\n", mvars[0]->get_field().c_str(), 0,mvars[0]->get_field().c_str());\r
9445    ret.append(tmpstr);\r
9446         sprintf(tmpstr,"\tunpack_offset_%s_%d = unpack_offset_%s_%d;\n",mvars[1]->get_field().c_str(), 1,mvars[0]->get_field().c_str(), 0);\r
9447         ret.append(tmpstr);\r
9448 //      ret+="\tfirst_execution_0 = first_execution_1 = true;\n";\r
9449         if(slack)\r
9450                 ret+="\tslack = "+generate_se_code(slack,schema)+";\n";\r
9451         else\r
9452                 ret+="\tslack = 0;\n";\r
9453 \r
9454 //              Initialize internal state\r
9455         ret += "\ttemp_tuple_received = false;\n";\r
9456 \r
9457         //              Init last timestamp values to minimum value for their type\r
9458         if (dta.is_increasing())\r
9459                 ret+="\tlast_posted_timestamp_0 = last_posted_timestamp_1 = " + dta.get_min_literal() + ";\n";\r
9460         else\r
9461                 ret+="\tlast_posted_timestamp_0 = last_posted_timestamp_1 = " + dta.get_max_literal() + ";\n";\r
9462 \r
9463 \r
9464         ret += "};\n\n";\r
9465 \r
9466         ret += "//\t\tFunctor destructor.\n";\r
9467         ret +=  "~"+this->generate_functor_name()+"(){\n";\r
9468 \r
9469 //                      Destroy the parameters, if any need to be destroyed\r
9470         ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";\r
9471 \r
9472         ret+="};\n\n";\r
9473 \r
9474 \r
9475 //                      no pass-by-handle params.\r
9476         vector<handle_param_tbl_entry *> param_handle_table;\r
9477 \r
9478 //                      Parameter manipulation routines\r
9479         ret += generate_load_param_block(this->generate_functor_name(),\r
9480                                                                         this->param_tbl,param_handle_table);\r
9481         ret += generate_delete_param_block(this->generate_functor_name(),\r
9482                                                                         this->param_tbl,param_handle_table);\r
9483 \r
9484 //                      Register new parameter block\r
9485 \r
9486         ret += "int set_param_block(gs_int32_t sz, void* value){\n";\r
9487           ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";\r
9488           ret += "\treturn this->load_params_"+this->generate_functor_name()+\r
9489                                 "(sz, value);\n";\r
9490         ret += "};\n\n";\r
9491 \r
9492 \r
9493 //      -----------------------------------\r
9494 //                      Compare method\r
9495 \r
9496         string unpack_fcna;\r
9497         if(needs_xform[0]) unpack_fcna = dta.get_hfta_unpack_fcn();\r
9498         else unpack_fcna = dta.get_hfta_unpack_fcn_noxf();\r
9499         string unpack_fcnb;\r
9500         if(needs_xform[1]) unpack_fcnb = dtb.get_hfta_unpack_fcn();\r
9501         else unpack_fcnb = dtb.get_hfta_unpack_fcn_noxf();\r
9502 \r
9503 /*\r
9504         ret+="\tint compare(const host_tuple& tup1, const host_tuple& tup2) const{ \n";\r
9505         ret+="\t"+dta.make_host_cvar("timestamp1")+";\n";\r
9506         ret+="\t"+dta.make_host_cvar("timestamp2")+";\n";\r
9507         ret+="\tgs_int32_t problem;\n";\r
9508         ret+="\tif (tup1.channel == 0)  {\n";\r
9509         sprintf(tmpstr,"\t\ttimestamp1 = %s(tup1.data, tup1.tuple_size, unpack_offset_%s_%d, &problem);\n",  unpack_fcna.c_str(), mvars[0]->get_field().c_str(), 0);\r
9510         ret += tmpstr;\r
9511         sprintf(tmpstr,"\t\ttimestamp2 = %s(tup2.data, tup2.tuple_size, unpack_offset_%s_%d, &problem);\n",  unpack_fcnb.c_str(), mvars[1]->get_field().c_str(), 1);\r
9512         ret += tmpstr;\r
9513         ret+="\t}else{\n";\r
9514         sprintf(tmpstr,"\t\ttimestamp1 = %s(tup1.data, tup1.tuple_size, unpack_offset_%s_%d, &problem);\n",  unpack_fcna.c_str(), mvars[0]->get_field().c_str(), 1);\r
9515         ret += tmpstr;\r
9516         sprintf(tmpstr,"\t\ttimestamp2 = %s(tup2.data, tup2.tuple_size, unpack_offset_%s_%d, &problem);\n",  unpack_fcnb.c_str(), mvars[1]->get_field().c_str(), 0);\r
9517         ret += tmpstr;\r
9518         ret+="\t}\n";\r
9519         ret+=\r
9520 "        if (timestamp1 > timestamp2+slack)\n"\r
9521 "            return 1;\n"\r
9522 "        else if (timestamp1 < timestamp2)\n"\r
9523 "            return -1;\n"\r
9524 "        else\n"\r
9525 "            return 0;\n"\r
9526 "\n"\r
9527 "    }\n\n";\r
9528 */\r
9529 \r
9530 ret +=\r
9531 "       void get_timestamp(const host_tuple& tup0){\n"\r
9532 "               gs_int32_t problem;\n"\r
9533 ;\r
9534         sprintf(tmpstr,"\t\ttimestamp = %s_nocheck(tup0.data, unpack_offset_%s_%d);\n",  unpack_fcna.c_str(), mvars[0]->get_field().c_str(), 0);\r
9535         ret += tmpstr;\r
9536 ret +=\r
9537 "       }\n"\r
9538 "\n"\r
9539 ;\r
9540 \r
9541 \r
9542 \r
9543 //                      Compare to temp status.\r
9544         ret+=\r
9545 "       int compare_with_temp_status(int channel)   {\n"\r
9546 "       // check if tuple is temp status tuple\n"\r
9547 "\n"\r
9548 "       if (channel == 0)  {\n"\r
9549 //"     if(first_execution_0) return 1;\n"\r
9550 "        if (timestamp == last_posted_timestamp_0)\n"\r
9551 "            return 0;\n"\r
9552 "        else if (timestamp < last_posted_timestamp_0)\n"\r
9553 "            return -1;\n"\r
9554 "        else\n"\r
9555 "            return 1;\n"\r
9556 "       }\n"\r
9557 //"     if(first_execution_1) return 1;\n"\r
9558 "        if (timestamp == last_posted_timestamp_1)\n"\r
9559 "            return 0;\n"\r
9560 "        else if (timestamp < last_posted_timestamp_1)\n"\r
9561 "            return -1;\n"\r
9562 "        else\n"\r
9563 "            return 1;\n"\r
9564 "\n"\r
9565 "    }\n"\r
9566 ;\r
9567 \r
9568         ret +=\r
9569 "       int compare_stored_with_temp_status(const host_tuple& tup0, int channel)/* const*/   {\n"\r
9570 ;\r
9571         ret+="\t"+dta.make_host_cvar("l_timestamp")+";\n";\r
9572         ret+="\tgs_int32_t problem;\n";\r
9573 \r
9574         sprintf(tmpstr,"\t\tl_timestamp = %s_nocheck(tup0.data, unpack_offset_%s_%d);\n",  unpack_fcna.c_str(), mvars[0]->get_field().c_str(), 0);\r
9575         ret += tmpstr;\r
9576         ret+="\tif (channel == 0)  {\n";\r
9577 //              ret+="\tif(first_execution_0) return 1;\n";\r
9578         ret+=\r
9579 "        if (l_timestamp == last_posted_timestamp_0)\n"\r
9580 "            return 0;\n"\r
9581 "        else if (l_timestamp < last_posted_timestamp_0)\n"\r
9582 "            return -1;\n"\r
9583 "        else\n"\r
9584 "            return 1;\n"\r
9585 "       }\n";\r
9586 //              ret+="\tif(first_execution_1) return 1;\n";\r
9587         ret+=\r
9588 "        if (l_timestamp == last_posted_timestamp_1)\n"\r
9589 "            return 0;\n"\r
9590 "        else if (l_timestamp < last_posted_timestamp_1)\n"\r
9591 "            return -1;\n"\r
9592 "        else\n"\r
9593 "            return 1;\n"\r
9594 "\n"\r
9595 "    }\n\n";\r
9596 \r
9597 \r
9598 //                      update temp status.\r
9599         ret+=\r
9600 "       int update_temp_status(const host_tuple& tup) {\n"\r
9601 "               if (tup.channel == 0)  {\n"\r
9602 "                       last_posted_timestamp_0=timestamp;\n"\r
9603 //"                     first_execution_0 = false;\n"\r
9604 "               }else{\n"\r
9605 "                       last_posted_timestamp_1=timestamp;\n"\r
9606 //"                     first_execution_1 = false;\n"\r
9607 "               }\n"\r
9608 "               return 0;\n"\r
9609 "   }\n"\r
9610 ;\r
9611         ret+=\r
9612 "       int update_stored_temp_status(const host_tuple& tup, int channel) {\n"\r
9613 ;\r
9614         ret+="\t"+dta.make_host_cvar("l_timestamp")+";\n";\r
9615         ret+="\tgs_int32_t problem;\n";\r
9616         sprintf(tmpstr,"\t\tl_timestamp = %s_nocheck(tup.data, unpack_offset_%s_%d);\n",  unpack_fcna.c_str(), mvars[0]->get_field().c_str(), 0);\r
9617         ret += tmpstr;\r
9618 ret+=\r
9619 "               if (tup.channel == 0)  {\n"\r
9620 "                       last_posted_timestamp_0=l_timestamp;\n"\r
9621 //"                     first_execution_0 = false;\n"\r
9622 "               }else{\n"\r
9623 "                       last_posted_timestamp_1=l_timestamp;\n"\r
9624 //"                     first_execution_1 = false;\n"\r
9625 "               }\n"\r
9626 "               return 0;\n"\r
9627 "   }\n"\r
9628 ;\r
9629 /*\r
9630         ret+="\t"+dta.make_host_cvar("timestamp")+";\n";\r
9631         ret+="\tgs_int32_t problem;\n";\r
9632         ret+="\tif (tup.channel == 0)  {\n";\r
9633         sprintf(tmpstr,"\t\ttimestamp = %s(tup.data, tup.tuple_size, unpack_offset_%s_%d, &problem);\n",  unpack_fcna.c_str(), mvars[0]->get_field().c_str(), 0);\r
9634         ret += tmpstr;\r
9635         ret+="\t}else{\n";\r
9636         sprintf(tmpstr,"\t\ttimestamp = %s(tup.data, tup.tuple_size, unpack_offset_%s_%d, &problem);\n",  unpack_fcnb.c_str(), mvars[1]->get_field().c_str(), 1);\r
9637         ret += tmpstr;\r
9638         ret+="\t}\n";\r
9639         ret+="\tif (tup.channel == 0)  {\n";\r
9640         ret+="\tlast_posted_timestamp_0=timestamp;\n";\r
9641         ret +="\tfirst_execution_0 = false;\n";\r
9642         ret+="\t}else{\n";\r
9643         ret+="\tlast_posted_timestamp_1=timestamp;\n";\r
9644         ret +="\tfirst_execution_1 = false;\n";\r
9645         ret+="\t}\n";\r
9646         ret+=\r
9647 "    }\n\n";\r
9648 */\r
9649 \r
9650 \r
9651 //                      update temp status modulo slack.\r
9652         ret+="\tint update_temp_status_by_slack(const host_tuple& tup, int channel) {\n";\r
9653     if(slack){\r
9654         ret+="\t"+dta.make_host_cvar("timestamp")+";\n";\r
9655         ret+="\tgs_int32_t problem;\n";\r
9656         ret+="\tif (tup.channel == 0)  {\n";\r
9657         sprintf(tmpstr,"\t\ttimestamp = %s_nocheck(tup.data, unpack_offset_%s_%d);\n",  unpack_fcna.c_str(), mvars[0]->get_field().c_str(), 0);\r
9658         ret += tmpstr;\r
9659         ret+="\t}else{\n";\r
9660         sprintf(tmpstr,"\t\ttimestamp = %s_nocheck(tup.data, unpack_offset_%s_%d);\n",  unpack_fcnb.c_str(), mvars[1]->get_field().c_str(), 1);\r
9661         ret += tmpstr;\r
9662         ret+="\t}\n";\r
9663 ret +=\r
9664 "       if (channel == 0)  {\n"\r
9665 "               if(first_execution_0){\n"\r
9666 "                       last_posted_timestamp_0=timestamp - slack;\n"\r
9667 "                       first_execution_0 = false;\n"\r
9668 "               }else{\n"\r
9669 "                       if(last_posted_timestamp_0 < timestamp-slack)\n"\r
9670 "                               last_posted_timestamp_0 = timestamp-slack;\n"\r
9671 "               }\n"\r
9672 "       }else{\n"\r
9673 "               if(first_execution_1){\n"\r
9674 "                       last_posted_timestamp_1=timestamp - slack;\n"\r
9675 "                       first_execution_1 = false;\n"\r
9676 "               }else{\n"\r
9677 "                       if(last_posted_timestamp_1 < timestamp-slack)\n"\r
9678 "                               last_posted_timestamp_1 = timestamp-slack;\n"\r
9679 "               }\n"\r
9680 "       }\n"\r
9681 "       return 0;\n"\r
9682 "    }\n\n";\r
9683         }else{\r
9684         ret +=\r
9685 "       return 0;\n"\r
9686 "       }\n\n";\r
9687         }\r
9688 \r
9689 \r
9690 //\r
9691         ret+=\r
9692 "bool temp_status_received(const host_tuple& tup0){\n"\r
9693 "       return ftaschema_is_temporal_tuple_offset(tuple_metadata_offset0, tup0.data);\n"\r
9694 "};\n"\r
9695 ;\r
9696 //"bool temp_status_received(){return temp_tuple_received;};\n\n";\r
9697 \r
9698 \r
9699 //              create a temp status tuple\r
9700         ret += "int create_temp_status_tuple(host_tuple& result) {\n\n";\r
9701 \r
9702         ret += gen_init_temp_status_tuple(this->get_node_name());\r
9703 \r
9704 //              Start packing.\r
9705         ret += "//\t\tPack the fields into the tuple.\n";\r
9706 \r
9707         string fld_name = mvars[0]->get_field();\r
9708         int idx = table_layout->get_field_idx(fld_name);\r
9709         field_entry* fld = table_layout->get_field(idx);\r
9710         data_type dt(fld->get_type());\r
9711 \r
9712 //      if (needs_xform[0] && needs_xform[1] && dt.needs_hn_translation())\r
9713 //              sprintf(tmpstr,"\ttuple->tuple_var%d = %s((last_posted_timestamp_0 < last_posted_timestamp_1) ? last_posted_timestamp_0 : last_posted_timestamp_1);\n",idx, dt.hton_translation().c_str());\r
9714 //      else\r
9715                 sprintf(tmpstr,"\ttuple->tuple_var%d = (last_posted_timestamp_0 < last_posted_timestamp_1 ? last_posted_timestamp_0 : last_posted_timestamp_1);\n",idx);\r
9716 \r
9717         ret += tmpstr;\r
9718 \r
9719         ret += "\treturn 0;\n";\r
9720         ret += "}\n\n";\r
9721 \r
9722 //                      Transform tuple (before output)\r
9723 \r
9724 \r
9725  ret += "void xform_tuple(host_tuple &tup){\n";\r
9726  if((needs_xform[0] && !needs_xform[1]) || (needs_xform[1] && !needs_xform[0])){\r
9727   ret += "\tstruct "+generate_tuple_name(this->get_node_name())+" *tuple = ("+\r
9728                 generate_tuple_name(this->get_node_name())+" *)(tup.data);\n";\r
9729 \r
9730   vector<field_entry *> flds = table_layout->get_fields();\r
9731 \r
9732   ret+="\tif(tup.channel == 0){\n";\r
9733   if(needs_xform[0] && !needs_xform[1]){\r
9734         int f;\r
9735         for(f=0;f<flds.size();f++){\r
9736                 ret.append("\t");\r
9737                 data_type dt(flds[f]->get_type());\r
9738                 if(dt.get_type() == v_str_t){\r
9739 //                      sprintf(tmpstr,"\ttuple->tuple_var%d.offset = htonl(tuple->tuple_var%d.offset);\n",f,f);\r
9740 //                      ret += tmpstr;\r
9741 //                      sprintf(tmpstr,"\ttuple->tuple_var%d.length = htonl(tuple->tuple_var%d.length);\n",f,f);\r
9742 //                      ret += tmpstr;\r
9743 //                      sprintf(tmpstr,"\ttuple->tuple_var%d.reserved = htonl(tuple->tuple_var%d.reserved);\n",f,f);\r
9744 //                      ret += tmpstr;\r
9745                 }else{\r
9746                         if(dt.needs_hn_translation()){\r
9747 //                              sprintf(tmpstr,"\ttuple->tuple_var%d = %s(tuple->tuple_var%d);\n",\r
9748 //                                      f, dt.hton_translation().c_str(), f);\r
9749 //                              ret += tmpstr;\r
9750                         }\r
9751                 }\r
9752         }\r
9753   }else{\r
9754         ret += "\t\treturn;\n";\r
9755   }\r
9756   ret.append("\t}\n");\r
9757 \r
9758 \r
9759   ret+="\tif(tup.channel == 1){\n";\r
9760   if(needs_xform[1] && !needs_xform[0]){\r
9761         int f;\r
9762         for(f=0;f<flds.size();f++){\r
9763                 ret.append("\t");\r
9764                 data_type dt(flds[f]->get_type());\r
9765                 if(dt.get_type() == v_str_t){\r
9766 //                      sprintf(tmpstr,"\ttuple->tuple_var%d.offset = htonl(tuple->tuple_var%d.offset);\n",f,f);\r
9767 //                      ret += tmpstr;\r
9768 //                      sprintf(tmpstr,"\ttuple->tuple_var%d.length = htonl(tuple->tuple_var%d.length);\n",f,f);\r
9769 //                      ret += tmpstr;\r
9770 //                      sprintf(tmpstr,"\ttuple->tuple_var%d.reserved = htonl(tuple->tuple_var%d.reserved);\n",f,f);\r
9771 //                      ret += tmpstr;\r
9772                 }else{\r
9773                         if(dt.needs_hn_translation()){\r
9774 //                              sprintf(tmpstr,"\ttuple->tuple_var%d = %s(tuple->tuple_var%d);\n",\r
9775 //                                      f, dt.hton_translation().c_str(), f);\r
9776 //                              ret += tmpstr;\r
9777                         }\r
9778                 }\r
9779         }\r
9780   }else{\r
9781         ret += "\t\treturn;\n";\r
9782   }\r
9783   ret.append("\t}\n");\r
9784  }\r
9785 \r
9786   ret.append("};\n\n");\r
9787 \r
9788 //              print_warnings() : tell the functor if the user wants to print warnings.\r
9789   ret += "bool print_warnings(){\n";\r
9790   if(definitions.count("print_warnings") && (\r
9791                 definitions["print_warnings"] == "yes" ||\r
9792                 definitions["print_warnings"] == "Yes" ||\r
9793                 definitions["print_warnings"] == "YES" )) {\r
9794         ret += "return true;\n";\r
9795   }else{\r
9796         ret += "return false;\n";\r
9797   }\r
9798   ret.append("};\n\n");\r
9799 \r
9800 \r
9801 //              Done with methods.\r
9802         ret+="\n};\n\n";\r
9803 \r
9804 \r
9805         return(ret);\r
9806 }\r
9807 \r
9808 string mrg_qpn::generate_operator(int i, string params){\r
9809 \r
9810         if(disorder < 2){\r
9811                 return(\r
9812                         "       merge_operator<" +\r
9813                         generate_functor_name()+\r
9814                         "> *op"+int_to_string(i)+" = new merge_operator<"+\r
9815                         generate_functor_name()+\r
9816                         ">("+params+",10000,\"" + get_node_name() + "\");\n"\r
9817                 );\r
9818         }\r
9819         return(\r
9820                         "       merge_operator_oop<" +\r
9821                         generate_functor_name()+\r
9822                         "> *op"+int_to_string(i)+" = new merge_operator_oop<"+\r
9823                         generate_functor_name()+\r
9824                         ">("+params+",10000,\"" + get_node_name() + "\");\n"\r
9825         );\r
9826 }\r
9827 \r
9828 \r
9829 /////////////////////////////////////////////////////////\r
9830 //////                  JOIN_EQ_HASH functor\r
9831 \r
9832 \r
9833 string join_eq_hash_qpn::generate_functor_name(){\r
9834         return("join_eq_hash_functor_" + normalize_name(this->get_node_name()));\r
9835 }\r
9836 \r
9837 string join_eq_hash_qpn::generate_functor(table_list *schema, ext_fcn_list *Ext_fcns, vector<bool> &needs_xform){\r
9838         int p,s;\r
9839         vector<data_type *> hashkey_dt;         // data types in the hash key\r
9840         vector<data_type *> temporal_dt;        // data types in the temporal key\r
9841         map<string,scalarexp_t *> l_equiv, r_equiv;     // field equivalences\r
9842         set<int> pfcn_refs;\r
9843         col_id_set new_cids, local_cids;\r
9844 \r
9845 //--------------------------------\r
9846 //              Global init\r
9847 \r
9848         string plus_op = "+";\r
9849 \r
9850 //--------------------------------\r
9851 //                      key definition class\r
9852         string ret = "class " + generate_functor_name() + "_keydef{\n";\r
9853         ret += "public:\n";\r
9854 //                      Collect attributes from hash join predicates.\r
9855 //                      ASSUME equality predicate.\r
9856 //                      Use the upwardly compatible data type\r
9857 //                      (infer from '+' operator if possible, else use left type)\r
9858         for(p=0;p<this->hash_eq.size();++p){\r
9859                 scalarexp_t *lse =      hash_eq[p]->pr->get_left_se();\r
9860                 scalarexp_t *rse =      hash_eq[p]->pr->get_right_se();\r
9861                 data_type *hdt = new data_type(\r
9862                         lse->get_data_type(), rse->get_data_type(), plus_op );\r
9863                 if(hdt->get_type() == undefined_t){\r
9864                         hashkey_dt.push_back(lse->get_data_type()->duplicate());\r
9865                         delete hdt;\r
9866                 }else{\r
9867                         hashkey_dt.push_back(hdt);\r
9868                 }\r
9869                 sprintf(tmpstr,"hashkey_var%d",p);\r
9870                 ret+="\t"+hashkey_dt[p]->make_host_cvar(tmpstr)+";\n";\r
9871 \r
9872 //                      find equivalences\r
9873 //                      NOTE: this code needs to be synched with the temporality\r
9874 //                      checking done at join_eq_hash_qpn::get_fields\r
9875                 if(lse->get_operator_type()==SE_COLREF){\r
9876                         l_equiv[lse->get_colref()->get_field()] = rse;\r
9877                 }\r
9878                 if(rse->get_operator_type()==SE_COLREF){\r
9879                         r_equiv[rse->get_colref()->get_field()] = lse;\r
9880                 }\r
9881         }\r
9882         ret += "\tbool touched;\n";\r
9883 \r
9884 //              Constructors\r
9885         ret += "\t"+generate_functor_name() + "_keydef(){touched=false;};\n";\r
9886 //              destructor\r
9887         ret += "\t~"+ generate_functor_name() + "_keydef(){\n";\r
9888         for(p=0;p<hashkey_dt.size();p++){\r
9889                 if(hashkey_dt[p]->is_buffer_type()){\r
9890                         sprintf(tmpstr,"\t\t%s(&hashkey_var%d);\n",\r
9891                           hashkey_dt[p]->get_hfta_buffer_destroy().c_str(), p );\r
9892                         ret += tmpstr;\r
9893                 }\r
9894         }\r
9895         ret += "\t};\n";\r
9896         ret+="\tvoid touch(){touched = true;};\n";\r
9897         ret+="\tbool is_touched(){return touched;};\n";\r
9898         ret +="};\n\n";\r
9899 \r
9900 \r
9901 //--------------------------------\r
9902 //              temporal equality definition class\r
9903         ret += "class " + generate_functor_name() + "_tempeqdef{\n";\r
9904         ret += "public:\n";\r
9905 //                      Collect attributes from hash join predicates.\r
9906 //                      ASSUME equality predicate.\r
9907 //                      Use the upwardly compatible date type\r
9908 //                      (infer from '+' operator if possible, else use left type)\r
9909         for(p=0;p<this->temporal_eq.size();++p){\r
9910                 scalarexp_t *lse =      temporal_eq[p]->pr->get_left_se();\r
9911                 scalarexp_t *rse =      temporal_eq[p]->pr->get_right_se();\r
9912                 data_type *hdt = new data_type(\r
9913                         lse->get_data_type(), rse->get_data_type(), plus_op );\r
9914                 if(hdt->get_type() == undefined_t){\r
9915                         temporal_dt.push_back(hash_eq[p]->pr->get_left_se()->get_data_type()->duplicate());\r
9916                         delete hdt;\r
9917                 }else{\r
9918                         temporal_dt.push_back(hdt);\r
9919                 }\r
9920                 sprintf(tmpstr,"tempeq_var%d",p);\r
9921                 ret+="\t"+temporal_dt[p]->make_host_cvar(tmpstr)+";\n";\r
9922 //                      find equivalences\r
9923                 if(lse->get_operator_type()==SE_COLREF){\r
9924                         l_equiv[lse->get_colref()->get_field()] = rse;\r
9925                 }\r
9926                 if(rse->get_operator_type()==SE_COLREF){\r
9927                         r_equiv[rse->get_colref()->get_field()] = lse;\r
9928                 }\r
9929         }\r
9930 \r
9931 //              Constructors\r
9932         ret += "\t"+generate_functor_name() + "_tempeqdef(){};\n";\r
9933 //              destructor\r
9934         ret += "\t~"+ generate_functor_name() + "_tempeqdef(){\n";\r
9935         for(p=0;p<temporal_dt.size();p++){\r
9936                 if(temporal_dt[p]->is_buffer_type()){\r
9937                         sprintf(tmpstr,"\t\t%s(&tempeq_var%d);\n",\r
9938                           temporal_dt[p]->get_hfta_buffer_destroy().c_str(), p );\r
9939                         ret += tmpstr;\r
9940                 }\r
9941         }\r
9942         ret += "\t};\n";\r
9943         ret +="};\n\n";\r
9944 \r
9945 \r
9946 //--------------------------------\r
9947 //                      temporal eq, hash join functor class\r
9948         ret += "class " + this->generate_functor_name() + "{\n";\r
9949 \r
9950 //                      Find variables referenced in this query node.\r
9951 \r
9952         col_id_set cid_set;\r
9953         col_id_set::iterator csi;\r
9954 \r
9955     for(p=0;p<where.size();++p)\r
9956         gather_pr_col_ids(where[p]->pr,cid_set,NULL);\r
9957     for(s=0;s<select_list.size();s++)\r
9958         gather_se_col_ids(select_list[s]->se,cid_set,NULL);\r
9959 \r
9960 //                      Private variables : store the state of the functor.\r
9961 //                      1) variables for unpacked attributes\r
9962 //                      2) offsets of the upacked attributes\r
9963 //                      3) storage of partial functions\r
9964 //                      4) storage of complex literals (i.e., require a constructor)\r
9965 \r
9966         ret += "private:\n";\r
9967 \r
9968         // var to save the schema handles\r
9969         ret += "\tint schema_handle0;\n";\r
9970         ret += "\tint schema_handle1;\n";\r
9971 \r
9972         // generate the declaration of all the variables related to\r
9973         // temp tuples generation\r
9974         ret += gen_decl_temp_vars();\r
9975         // tuple metadata offsets\r
9976         ret += "\tint tuple_metadata_offset0, tuple_metadata_offset1;\n";\r
9977 \r
9978 //                      unpacked attribute storage, offsets\r
9979         ret += "//\t\tstorage and offsets of accessed fields.\n";\r
9980         ret += generate_access_vars(cid_set, schema);\r
9981 \r
9982 \r
9983 //                      Variables to store results of partial functions.\r
9984 //                      WARNING find_partial_functions modifies the SE\r
9985 //                      (it marks the partial function id).\r
9986         ret += "//\t\tParital function result storage\n";\r
9987         vector<scalarexp_t *> partial_fcns;\r
9988         vector<int> fcn_ref_cnt;\r
9989         vector<bool> is_partial_fcn;\r
9990         for(s=0;s<select_list.size();s++){\r
9991                 find_partial_fcns(select_list[s]->se, &partial_fcns,NULL,NULL,  Ext_fcns);\r
9992         }\r
9993         for(p=0;p<where.size();p++){\r
9994                 find_partial_fcns_pr(where[p]->pr, &partial_fcns,NULL,NULL,  Ext_fcns);\r
9995         }\r
9996         if(partial_fcns.size()>0){\r
9997           ret += "/*\t\tVariables for storing results of partial functions. \t*/\n";\r
9998           ret += generate_partial_fcn_vars(partial_fcns,fcn_ref_cnt,is_partial_fcn,false);\r
9999         }\r
10000 \r
10001 //                      Complex literals (i.e., they need constructors)\r
10002         ret += "//\t\tComplex literal storage.\n";\r
10003         cplx_lit_table *complex_literals = this->get_cplx_lit_tbl(Ext_fcns);\r
10004         ret += generate_complex_lit_vars(complex_literals);\r
10005 //                      We need the following to handle strings in outer joins.\r
10006 //                              NEED AN EMPTY LITERAL FOR EAcH STRUCTURED LITERAL\r
10007         ret += "\tstruct vstring EmptyString;\n";\r
10008         ret += "\tstruct hfta_ipv6_str EmptyIp6;\n";\r
10009 \r
10010 //                      Pass-by-handle parameters\r
10011         ret += "//\t\tPass-by-handle storage.\n";\r
10012         vector<handle_param_tbl_entry *> param_handle_table = this->get_handle_param_tbl(Ext_fcns);\r
10013         ret += generate_pass_by_handle_vars(param_handle_table);\r
10014 \r
10015 \r
10016 //                      variables to hold parameters.\r
10017         ret += "//\tfor query parameters\n";\r
10018         ret += generate_param_vars(param_tbl);\r
10019 \r
10020 \r
10021         ret += "\npublic:\n";\r
10022 //-------------------\r
10023 //                      The functor constructor\r
10024 //                      pass in the schema handle.\r
10025 //                      1) make assignments to the unpack offset variables\r
10026 //                      2) initialize the complex literals\r
10027 \r
10028         ret += "//\t\tFunctor constructor.\n";\r
10029         ret +=  this->generate_functor_name()+"(int schema_handle0, int schema_handle1){\n";\r
10030 \r
10031         ret += "\t\tthis->schema_handle0 = schema_handle0;\n";\r
10032         ret += "\t\tthis->schema_handle1 = schema_handle1;\n";\r
10033 //              metadata offsets\r
10034         ret += "\ttuple_metadata_offset0 = ftaschema_get_tuple_metadata_offset(schema_handle0);\n";\r
10035         ret += "\ttuple_metadata_offset1 = ftaschema_get_tuple_metadata_offset(schema_handle1);\n";\r
10036 \r
10037 //              unpack vars\r
10038         ret += "//\t\tGet offsets for unpacking fields from input tuple.\n";\r
10039         ret += gen_access_var_init(cid_set);\r
10040 \r
10041 //              complex literals\r
10042         ret += "//\t\tInitialize complex literals.\n";\r
10043         ret += gen_complex_lit_init(complex_literals);\r
10044 //              Initialize EmptyString to the ... empty string\r
10045 //                              NEED AN EMPTY LITERAL FOR EAcH STRUCTURED LITERAL\r
10046         literal_t mtstr_lit("");\r
10047         ret += "\t" + mtstr_lit.to_hfta_C_code("&EmptyString")+";\n";\r
10048         literal_t mip6_lit("0:0:0:0:0:0:0:0",LITERAL_IPV6);\r
10049         ret += "\t" + mip6_lit.to_hfta_C_code("&EmptyIp6")+";\n";\r
10050 \r
10051 //              Initialize partial function results so they can be safely GC'd\r
10052         ret += gen_partial_fcn_init(partial_fcns);\r
10053 \r
10054 //              Initialize non-query-parameter parameter handles\r
10055         ret += gen_pass_by_handle_init(param_handle_table);\r
10056 \r
10057 //              Init temporal attributes referenced in select list\r
10058         ret += gen_init_temp_vars(schema, select_list, NULL);\r
10059 \r
10060 \r
10061         ret += "};\n";\r
10062 \r
10063 \r
10064 \r
10065 //-------------------\r
10066 //                      Functor destructor\r
10067         ret += "//\t\tFunctor destructor.\n";\r
10068         ret +=  "~"+this->generate_functor_name()+"(){\n";\r
10069 \r
10070 //                      clean up buffer type complex literals\r
10071         ret += gen_complex_lit_dtr(complex_literals);\r
10072 \r
10073 //                      Deregister the pass-by-handle parameters\r
10074         ret += "/* register and de-register the pass-by-handle parameters */\n";\r
10075         ret += gen_pass_by_handle_dtr(param_handle_table);\r
10076 \r
10077 //                      clean up partial function results.\r
10078         ret += "/* clean up partial function storage    */\n";\r
10079         ret += gen_partial_fcn_dtr(partial_fcns);\r
10080 \r
10081 //                      Destroy the parameters, if any need to be destroyed\r
10082         ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";\r
10083 \r
10084         ret += "};\n\n";\r
10085 \r
10086 \r
10087 //-------------------\r
10088 //                      Parameter manipulation routines\r
10089         ret += generate_load_param_block(this->generate_functor_name(),\r
10090                                                                         this->param_tbl,param_handle_table);\r
10091         ret += generate_delete_param_block(this->generate_functor_name(),\r
10092                                                                         this->param_tbl,param_handle_table);\r
10093 \r
10094 //-------------------\r
10095 //                      Register new parameter block\r
10096 \r
10097         ret += "int set_param_block(gs_int32_t sz, void* value){\n";\r
10098           ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";\r
10099           ret += "\treturn this->load_params_"+this->generate_functor_name()+\r
10100                                 "(sz, value);\n";\r
10101         ret += "};\n\n";\r
10102 \r
10103 \r
10104 //-------------------\r
10105 //                      The create_key method.\r
10106 //                      Perform heap allocation.\r
10107 //                      ASSUME : the LHS of the preds reference channel 0 attributes\r
10108 //                      NOTE : it may fail if a partial function fails.\r
10109 \r
10110         ret += this->generate_functor_name()+"_keydef *create_key(host_tuple &tup, bool &failed){\n";\r
10111 //              Variables for execution of the function.\r
10112         ret+="\t"+this->generate_functor_name()+"_keydef *retval = NULL;\n";\r
10113         ret+="\tgs_int32_t problem = 0;\n";\r
10114 \r
10115 //              Assume unsuccessful completion\r
10116         ret+= "\tfailed = true;\n";\r
10117 \r
10118 //              Switch the processing based on the channel\r
10119         ret+="\tif(tup.channel == 0){\n";\r
10120         ret+="// ------------ processing for channel 0\n";\r
10121         ret+="\t\thost_tuple &tup0 = tup;\n";\r
10122 //              Gather partial fcns and colids ref'd by this branch\r
10123         pfcn_refs.clear();\r
10124         new_cids.clear(); local_cids.clear();\r
10125         for(p=0;p<hash_eq.size();p++){\r
10126                 collect_partial_fcns(hash_eq[p]->pr->get_left_se(), pfcn_refs);\r
10127                 gather_se_col_ids(hash_eq[p]->pr->get_left_se(),local_cids,NULL);\r
10128         }\r
10129 \r
10130 //              Start by cleaning up partial function results\r
10131         ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";\r
10132         ret += gen_partial_fcn_dtr(partial_fcns,pfcn_refs);\r
10133 \r
10134 //                      Evaluate the partial functions\r
10135         ret += gen_full_unpack_partial_fcn(schema, partial_fcns, pfcn_refs,\r
10136                                 new_cids, NULL, "NULL", needs_xform);\r
10137 //                      test passed -- unpack remaining cids.\r
10138         ret += gen_remaining_colrefs(schema, local_cids, new_cids, "NULL", needs_xform);\r
10139 \r
10140 //                      Alloc and load a key object\r
10141         ret += "\t\tretval = new "+this->generate_functor_name()+"_keydef();\n";\r
10142         for(p=0;p<hash_eq.size();p++){\r
10143                 data_type *hdt = hash_eq[p]->pr->get_left_se()->get_data_type();\r
10144                 if(hdt->is_buffer_type()){\r
10145                         string vname = "tmp_keyvar"+int_to_string(p);\r
10146                         ret += "\t\t"+hdt->make_host_cvar(vname)+" = "+generate_se_code(hash_eq[p]->pr->get_left_se(),schema)+";\n";\r
10147                         ret += "\t\t"+hdt->get_hfta_buffer_assign_copy()+"(&(retval->hashkey_var"+int_to_string(p)+"),&"+vname+");\n";\r
10148                 }else{\r
10149                   sprintf(tmpstr,"\t\tretval->hashkey_var%d = %s;\n",\r
10150                         p,generate_se_code(hash_eq[p]->pr->get_left_se(),schema).c_str() );\r
10151                   ret += tmpstr;\r
10152                 }\r
10153         }\r
10154         ret += "\t}else{\n";\r
10155 \r
10156         ret+="// ------------ processing for channel 1\n";\r
10157         ret+="\t\thost_tuple &tup1 = tup;\n";\r
10158 //              Gather partial fcns and colids ref'd by this branch\r
10159         pfcn_refs.clear();\r
10160         new_cids.clear(); local_cids.clear();\r
10161         for(p=0;p<hash_eq.size();p++){\r
10162                 collect_partial_fcns(hash_eq[p]->pr->get_right_se(), pfcn_refs);\r
10163                 gather_se_col_ids(hash_eq[p]->pr->get_right_se(),local_cids,NULL);\r
10164         }\r
10165 \r
10166 //              Start by cleaning up partial function results\r
10167         ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";\r
10168         ret += gen_partial_fcn_dtr(partial_fcns,pfcn_refs);\r
10169 \r
10170 //                      Evaluate the partial functions\r
10171         ret += gen_full_unpack_partial_fcn(schema, partial_fcns, pfcn_refs,\r
10172                                 new_cids, NULL, "NULL", needs_xform);\r
10173 \r
10174 //                      test passed -- unpack remaining cids.\r
10175         ret += gen_remaining_colrefs(schema, local_cids, new_cids, "NULL", needs_xform);\r
10176 \r
10177 //                      Alloc and load a key object\r
10178         ret += "\t\tretval = new "+this->generate_functor_name()+"_keydef();\n";\r
10179         for(p=0;p<hash_eq.size();p++){\r
10180                 data_type *hdt = hash_eq[p]->pr->get_right_se()->get_data_type();\r
10181                 if(hdt->is_buffer_type()){\r
10182                         string vname = "tmp_keyvar"+int_to_string(p);\r
10183                         ret += "\t\t"+hdt->make_host_cvar(vname)+" = "+generate_se_code(hash_eq[p]->pr->get_right_se(),schema)+";\n";\r
10184                         ret += "\t\t"+hdt->get_hfta_buffer_assign_copy()+"(&(retval->hashkey_var"+int_to_string(p)+"),&"+vname+");\n";\r
10185                 }else{\r
10186                   sprintf(tmpstr,"\t\tretval->hashkey_var%d = %s;\n",\r
10187                         p,generate_se_code(hash_eq[p]->pr->get_right_se(),schema).c_str() );\r
10188                   ret += tmpstr;\r
10189                 }\r
10190         }\r
10191         ret += "\t}\n";\r
10192 \r
10193         ret += "\tfailed = false;\n";\r
10194         ret += "\t return retval;\n";\r
10195         ret += "}\n";\r
10196 \r
10197 \r
10198 //-------------------\r
10199 //                      The load_ts method.\r
10200 //                      load into an allocated buffer.\r
10201 //                      ASSUME : the LHS of the preds reference channel 0 attributes\r
10202 //                      NOTE : it may fail if a partial function fails.\r
10203 //                      NOTE : cann't handle buffer attributes\r
10204 \r
10205         ret += "bool load_ts_from_tup("+this->generate_functor_name()+"_tempeqdef *ts, host_tuple &tup){\n";\r
10206 //              Variables for execution of the function.\r
10207         ret+="\tgs_int32_t problem = 0;\n";\r
10208 \r
10209 //              Switch the processing based on the channel\r
10210         ret+="\tif(tup.channel == 0){\n";\r
10211         ret+="// ------------ processing for channel 0\n";\r
10212         ret+="\t\thost_tuple &tup0 = tup;\n";\r
10213 \r
10214 //              Gather partial fcns and colids ref'd by this branch\r
10215         pfcn_refs.clear();\r
10216         new_cids.clear(); local_cids.clear();\r
10217         for(p=0;p<temporal_eq.size();p++){\r
10218                 collect_partial_fcns(temporal_eq[p]->pr->get_left_se(), pfcn_refs);\r
10219                 gather_se_col_ids(temporal_eq[p]->pr->get_left_se(),local_cids,NULL);\r
10220         }\r
10221 \r
10222 //              Start by cleaning up partial function results\r
10223         ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";\r
10224         ret += gen_partial_fcn_dtr(partial_fcns,pfcn_refs);\r
10225 \r
10226 //                      Evaluate the partial functions\r
10227         ret += gen_full_unpack_partial_fcn(schema, partial_fcns, pfcn_refs,\r
10228                                 new_cids, NULL, "false", needs_xform);\r
10229 \r
10230 //                      test passed -- unpack remaining cids.\r
10231         ret += gen_remaining_colrefs(schema, local_cids, new_cids, "false", needs_xform);\r
10232 \r
10233 //                      load the temporal key object\r
10234         for(p=0;p<temporal_eq.size();p++){\r
10235                 sprintf(tmpstr,"\t\tts->tempeq_var%d = %s;\n",\r
10236                         p,generate_se_code(temporal_eq[p]->pr->get_left_se(),schema).c_str() );\r
10237                 ret += tmpstr;\r
10238         }\r
10239 \r
10240         ret += "\t}else{\n";\r
10241 \r
10242         ret+="// ------------ processing for channel 1\n";\r
10243         ret+="\t\thost_tuple &tup1 = tup;\n";\r
10244 \r
10245 //              Gather partial fcns and colids ref'd by this branch\r
10246         pfcn_refs.clear();\r
10247         new_cids.clear(); local_cids.clear();\r
10248         for(p=0;p<temporal_eq.size();p++){\r
10249                 collect_partial_fcns(temporal_eq[p]->pr->get_right_se(), pfcn_refs);\r
10250                 gather_se_col_ids(temporal_eq[p]->pr->get_right_se(),local_cids,NULL);\r
10251         }\r
10252 \r
10253 //              Start by cleaning up partial function results\r
10254         ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";\r
10255         ret += gen_partial_fcn_dtr(partial_fcns,pfcn_refs);\r
10256 \r
10257 //                      Evaluate the partial functions\r
10258         ret += gen_full_unpack_partial_fcn(schema, partial_fcns, pfcn_refs,\r
10259                                 new_cids, NULL, "false", needs_xform);\r
10260 \r
10261 //                      test passed -- unpack remaining cids.\r
10262         ret += gen_remaining_colrefs(schema, local_cids, new_cids, "false", needs_xform);\r
10263 \r
10264 //                      load the key object\r
10265         for(p=0;p<temporal_eq.size();p++){\r
10266                 sprintf(tmpstr,"\t\tts->tempeq_var%d = %s;\n",\r
10267                         p,generate_se_code(temporal_eq[p]->pr->get_right_se(),schema).c_str() );\r
10268                 ret += tmpstr;\r
10269         }\r
10270 \r
10271         ret += "\t}\n";\r
10272 \r
10273         ret += "\t return true;\n";\r
10274         ret += "}\n";\r
10275 \r
10276 \r
10277 //      ------------------------------\r
10278 //              Load ts from ts\r
10279 //              (i.e make a copy)\r
10280 \r
10281         ret += "bool load_ts_from_ts("+this->generate_functor_name()+"_tempeqdef *lts,"+this->generate_functor_name()+"_tempeqdef *rts){\n";\r
10282         for(p=0;p<temporal_eq.size();p++){\r
10283                 sprintf(tmpstr,"\tlts->tempeq_var%d = rts->tempeq_var%d;\n",p,p);\r
10284                 ret += tmpstr;\r
10285         }\r
10286         ret += "}\n";\r
10287 \r
10288 //      -------------------------------------\r
10289 //              compare_ts_to_ts\r
10290 //              There should be only one variable to compare.\r
10291 //              If there is more, assume an arbitrary lexicographic order.\r
10292 \r
10293         ret += "int compare_ts_with_ts("+this->generate_functor_name()+"_tempeqdef *lts,"+this->generate_functor_name()+"_tempeqdef *rts){\n";\r
10294         for(p=0;p<temporal_eq.size();p++){\r
10295                 sprintf(tmpstr,"\tif(lts->tempeq_var%d < rts->tempeq_var%d) return(-1);\n",p,p);\r
10296                 ret += tmpstr;\r
10297                 sprintf(tmpstr,"\tif(lts->tempeq_var%d > rts->tempeq_var%d) return(1);\n",p,p);\r
10298                 ret += tmpstr;\r
10299         }\r
10300         ret += "\treturn(0);\n";\r
10301         ret += "}\n";\r
10302 \r
10303 //      ------------------------------------------\r
10304 //              apply_prefilter\r
10305 //              apply the prefilter\r
10306 \r
10307         ret += "bool apply_prefilter(host_tuple &tup){\n";\r
10308 \r
10309 //              Variables for this procedure\r
10310         ret+="\tgs_int32_t problem = 0;\n";\r
10311         ret+="\tgs_retval_t retval;\n";\r
10312 \r
10313 //              Switch the processing based on the channel\r
10314         ret+="\tif(tup.channel == 0){\n";\r
10315         ret+="// ------------ processing for channel 0\n";\r
10316         ret+="\t\thost_tuple &tup0 = tup;\n";\r
10317 //              Gather partial fcns and colids ref'd by this branch\r
10318         pfcn_refs.clear();\r
10319         new_cids.clear(); local_cids.clear();\r
10320         for(p=0;p<prefilter[0].size();p++){\r
10321                 collect_partial_fcns_pr((prefilter[0])[p]->pr, pfcn_refs);\r
10322         }\r
10323 \r
10324 //              Start by cleaning up partial function results\r
10325         ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";\r
10326         ret += gen_partial_fcn_dtr(partial_fcns,pfcn_refs);\r
10327 \r
10328         for(p=0;p<(prefilter[0]).size();++p){\r
10329                 sprintf(tmpstr,"//\t\tPredicate clause %d.\n",p);\r
10330                 ret += tmpstr;\r
10331 //                      Find the set of variables accessed in this CNF elem,\r
10332 //                      but in no previous element.\r
10333                 col_id_set new_pr_cids;\r
10334                 get_new_pred_cids((prefilter[0])[p]->pr,local_cids,new_pr_cids, NULL);\r
10335 //                      Unpack these values.\r
10336                 ret += gen_unpack_cids(schema, new_pr_cids, "false", needs_xform);\r
10337 //                      Find partial fcns ref'd in this cnf element\r
10338                 set<int> pr_pfcn_refs;\r
10339                 collect_partial_fcns_pr((prefilter[0])[p]->pr, pr_pfcn_refs);\r
10340                 ret += gen_unpack_partial_fcn(schema,partial_fcns,pr_pfcn_refs,"false");\r
10341 \r
10342                 ret += "\t\tif( !("+generate_predicate_code((prefilter[0])[p]->pr,schema)+") ) return(false);\n";\r
10343         }\r
10344         ret += "\t}else{\n";\r
10345         ret+="// ------------ processing for channel 1\n";\r
10346         ret+="\t\thost_tuple &tup1 = tup;\n";\r
10347 //              Gather partial fcns and colids ref'd by this branch\r
10348         pfcn_refs.clear();\r
10349         new_cids.clear(); local_cids.clear();\r
10350         for(p=0;p<prefilter[1].size();p++){\r
10351                 collect_partial_fcns_pr((prefilter[1])[p]->pr, pfcn_refs);\r
10352         }\r
10353 \r
10354 //              Start by cleaning up partial function results\r
10355         ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";\r
10356         ret += gen_partial_fcn_dtr(partial_fcns,pfcn_refs);\r
10357 \r
10358         for(p=0;p<(prefilter[1]).size();++p){\r
10359                 sprintf(tmpstr,"//\t\tPredicate clause %d.\n",p);\r
10360                 ret += tmpstr;\r
10361 //                      Find the set of variables accessed in this CNF elem,\r
10362 //                      but in no previous element.\r
10363                 col_id_set pr_new_cids;\r
10364                 get_new_pred_cids((prefilter[1])[p]->pr,local_cids, pr_new_cids, NULL);\r
10365 //                      Unpack these values.\r
10366                 ret += gen_unpack_cids(schema, pr_new_cids, "false", needs_xform);\r
10367 //                      Find partial fcns ref'd in this cnf element\r
10368                 set<int> pr_pfcn_refs;\r
10369                 collect_partial_fcns_pr((prefilter[1])[p]->pr, pr_pfcn_refs);\r
10370                 ret += gen_unpack_partial_fcn(schema,partial_fcns,pr_pfcn_refs,"false");\r
10371 \r
10372                 ret += "\t\tif( !("+generate_predicate_code((prefilter[1])[p]->pr,schema)+ ") ) return(false);\n";\r
10373         }\r
10374 \r
10375         ret += "\t}\n";\r
10376         ret+="\treturn true;\n";\r
10377         ret += "}\n";\r
10378 \r
10379 \r
10380 //      -------------------------------------\r
10381 //                      create_output_tuple\r
10382 //                      If the postfilter on the pair of tuples passes,\r
10383 //                      create an output tuple from the combined information.\r
10384 //                      (Plus, outer join processing)\r
10385 \r
10386         ret += "host_tuple create_output_tuple(const host_tuple &tup0, const host_tuple &tup1, bool &failed){\n";\r
10387 \r
10388         ret += "\thost_tuple tup;\n";\r
10389         ret += "\tfailed = true;\n";\r
10390         ret += "\tgs_retval_t retval = 0;\n";\r
10391         ret += "\tgs_int32_t problem = 0;\n";\r
10392 \r
10393 //              Start by cleaning up partial function results\r
10394         ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";\r
10395         pfcn_refs.clear();\r
10396         new_cids.clear(); local_cids.clear();\r
10397         for(p=0;p<postfilter.size();p++){\r
10398                 collect_partial_fcns_pr(postfilter[p]->pr, pfcn_refs);\r
10399         }\r
10400         for(s=0;s<select_list.size();s++){\r
10401                 collect_partial_fcns(select_list[s]->se, pfcn_refs);\r
10402         }\r
10403         ret += gen_partial_fcn_dtr(partial_fcns,pfcn_refs);\r
10404 \r
10405 \r
10406         ret+="\tif(tup0.data && tup1.data){\n";\r
10407 //                      Evaluate the postfilter\r
10408         new_cids.clear(); local_cids.clear();\r
10409         for(p=0;p<postfilter.size();p++){\r
10410                 sprintf(tmpstr,"//\t\tPredicate clause %d.\n",p);\r
10411                 ret += tmpstr;\r
10412 //                      Find the set of variables accessed in this CNF elem,\r
10413 //                      but in no previous element.\r
10414                 col_id_set pr_new_cids;\r
10415                 get_new_pred_cids(postfilter[p]->pr,local_cids, pr_new_cids, NULL);\r
10416 //                      Unpack these values.\r
10417                 ret += gen_unpack_cids(schema, pr_new_cids, "tup", needs_xform);\r
10418 //                      Find partial fcns ref'd in this cnf element\r
10419                 set<int> pr_pfcn_refs;\r
10420                 collect_partial_fcns_pr(postfilter[p]->pr, pr_pfcn_refs);\r
10421                 ret += gen_unpack_partial_fcn(schema,partial_fcns,pr_pfcn_refs,"tup");\r
10422 \r
10423                 ret += "\t\tif( !("+generate_predicate_code(postfilter[p]->pr,schema)+ ") ) return(tup);\n";\r
10424         }\r
10425 \r
10426 \r
10427 //              postfilter passed, evaluate partial functions for select list\r
10428 \r
10429         set<int> sl_pfcns;\r
10430         col_id_set se_cids;\r
10431         for(s=0;s<select_list.size();s++){\r
10432                 collect_partial_fcns(select_list[s]->se, sl_pfcns);\r
10433         }\r
10434 \r
10435         if(sl_pfcns.size() > 0)\r
10436                 ret += "//\t\tUnpack remaining partial fcns.\n";\r
10437         ret += gen_full_unpack_partial_fcn(schema, partial_fcns, sl_pfcns,\r
10438                                         local_cids, NULL, "tup", needs_xform);\r
10439 \r
10440 //                      Unpack remaining fields\r
10441         ret += "//\t\tunpack any remaining fields from the input tuples.\n";\r
10442         for(s=0;s<select_list.size();s++)\r
10443                 get_new_se_cids(select_list[s]->se, local_cids,se_cids,NULL);\r
10444         ret += gen_unpack_cids(schema,  se_cids,"tup", needs_xform);\r
10445 \r
10446 \r
10447 //                      Deal with outer join stuff\r
10448         col_id_set l_cids, r_cids;\r
10449         col_id_set::iterator ocsi;\r
10450         for(ocsi=local_cids.begin();ocsi!=local_cids.end();++ocsi){\r
10451                 if((*ocsi).tblvar_ref == 0) l_cids.insert((*ocsi));\r
10452                 else                                            r_cids.insert((*ocsi));\r
10453         }\r
10454         for(ocsi=se_cids.begin();ocsi!=se_cids.end();++ocsi){\r
10455                 if((*ocsi).tblvar_ref == 0) l_cids.insert((*ocsi));\r
10456                 else                                            r_cids.insert((*ocsi));\r
10457         }\r
10458 \r
10459         ret += "\t}else if(tup0.data){\n";\r
10460         string unpack_null = ""; col_id_set extra_cids;\r
10461         for(ocsi=r_cids.begin();ocsi!=r_cids.end();++ocsi){\r
10462                 string field = (*ocsi).field;\r
10463                 if(r_equiv.count(field)){\r
10464                         unpack_null+="\t\tunpack_var_"+field+"_1="+generate_se_code(r_equiv[field],schema)+";\n";\r
10465                         get_new_se_cids(r_equiv[field],l_cids,new_cids,NULL);\r
10466                 }else{\r
10467                 int schref = (*ocsi).schema_ref;\r
10468                         data_type dt(schema->get_type_name(schref,field));\r
10469                         literal_t empty_lit(dt.type_indicator());\r
10470                         if(empty_lit.is_cpx_lit()){\r
10471 //                              sprintf(tmpstr,"&(unpack_var_%s_1)",field.c_str());\r
10472 //                              unpack_null += "\t"+empty_lit.to_hfta_C_code(tmpstr)+";\n";\r
10473 //                                      NB : works for string type only\r
10474 //                                      NNB: installed fix for ipv6, more of this should be pushed\r
10475 //                                              into the literal_t code.\r
10476                                 unpack_null+="\tunpack_var_"+field+"_1= "+empty_lit.hfta_empty_literal_name()+";\n";\r
10477                         }else{\r
10478                                 unpack_null+="\tunpack_var_"+field+"_1="+empty_lit.to_hfta_C_code("")+";\n";\r
10479                         }\r
10480                 }\r
10481         }\r
10482         ret += gen_unpack_cids(schema,  l_cids, "tup", needs_xform);\r
10483         ret += gen_unpack_cids(schema,  extra_cids, "tup", needs_xform);\r
10484         ret += unpack_null;\r
10485         ret += gen_unpack_partial_fcn(schema, partial_fcns, sl_pfcns, "tup");\r
10486 \r
10487         ret+="\t}else{\n";\r
10488         unpack_null = ""; extra_cids.clear();\r
10489         for(ocsi=l_cids.begin();ocsi!=l_cids.end();++ocsi){\r
10490                 string field = (*ocsi).field;\r
10491                 if(l_equiv.count(field)){\r
10492                         unpack_null+="\t\tunpack_var_"+field+"_0="+generate_se_code(l_equiv[field],schema)+";\n";\r
10493                         get_new_se_cids(l_equiv[field],r_cids,new_cids,NULL);\r
10494                 }else{\r
10495                 int schref = (*ocsi).schema_ref;\r
10496                         data_type dt(schema->get_type_name(schref,field));\r
10497                         literal_t empty_lit(dt.type_indicator());\r
10498                         if(empty_lit.is_cpx_lit()){\r
10499 //                              sprintf(tmpstr,"&(unpack_var_%s_0)",field.c_str());\r
10500 //                              unpack_null += "\t"+empty_lit.to_hfta_C_code(tmpstr)+";\n";\r
10501 //                                      NB : works for string type only\r
10502 //                                      NNB: installed fix for ipv6, more of this should be pushed\r
10503 //                                              into the literal_t code.\r
10504                                 unpack_null+="\tunpack_var_"+field+"_0= "+empty_lit.hfta_empty_literal_name()+";\n";\r
10505                         }else{\r
10506                                 unpack_null+="\tunpack_var_"+field+"_0="+empty_lit.to_hfta_C_code("")+";\n";\r
10507                         }\r
10508                 }\r
10509         }\r
10510         ret += gen_unpack_cids(schema,  r_cids, "tup", needs_xform);\r
10511         ret += gen_unpack_cids(schema,  extra_cids, "tup", needs_xform);\r
10512         ret += unpack_null;\r
10513         ret += gen_unpack_partial_fcn(schema, partial_fcns, sl_pfcns, "tup");\r
10514         ret+="\t}\n";\r
10515 \r
10516 \r
10517 \r
10518 //          Unpack any BUFFER type selections into temporaries\r
10519 //          so that I can compute their size and not have\r
10520 //          to recompute their value during tuple packing.\r
10521 //          I can use regular assignment here because\r
10522 //          these temporaries are non-persistent.\r
10523 \r
10524         ret += "//\t\tCompute the size of the tuple.\n";\r
10525         ret += "//\t\t\tNote: buffer storage packed at the end of the tuple.\n";\r
10526 \r
10527 //                      Unpack all buffer type selections, to be able to compute their size\r
10528         ret += gen_buffer_selvars(schema, select_list);\r
10529 \r
10530 //      The size of the tuple is the size of the tuple struct plus the\r
10531 //      size of the buffers to be copied in.\r
10532 \r
10533     ret+="\ttup.tuple_size = sizeof(" + generate_tuple_name( this->get_node_name()) +") + sizeof(gs_uint8_t)";\r
10534         ret += gen_buffer_selvars_size(select_list,schema);\r
10535       ret.append(";\n");\r
10536 \r
10537 //              Allocate tuple data block.\r
10538         ret += "//\t\tCreate the tuple block.\n";\r
10539           ret += "\ttup.data = malloc(tup.tuple_size);\n";\r
10540           ret += "\ttup.heap_resident = true;\n";\r
10541 //        ret += "\ttup.channel = 0;\n";\r
10542 \r
10543 //              Mark tuple as regular\r
10544           ret += "\t*((gs_sp_t )tup.data + sizeof(" + generate_tuple_name( this->get_node_name()) +")) = REGULAR_TUPLE;\n";\r
10545 \r
10546 \r
10547           ret += "\t"+generate_tuple_name( this->get_node_name())+" *tuple = ("+\r
10548                                 generate_tuple_name( this->get_node_name())+" *)(tup.data);\n";\r
10549 \r
10550 //              Start packing.\r
10551 //                      (Here, offsets are hard-wired.  is this a problem?)\r
10552 \r
10553         ret += "//\t\tPack the fields into the tuple.\n";\r
10554         ret += gen_pack_tuple(schema,select_list,this->get_node_name(), false );\r
10555 \r
10556 //                      Delete string temporaries\r
10557         ret += gen_buffer_selvars_dtr(select_list);\r
10558 \r
10559         ret += "\tfailed = false;\n";\r
10560         ret += "\treturn tup;\n";\r
10561         ret += "};\n";\r
10562 \r
10563 \r
10564 \r
10565 //-----------------------------\r
10566 //                      Method for checking whether tuple is temporal\r
10567 \r
10568         ret += "bool temp_status_received(host_tuple &tup){\n";\r
10569 \r
10570 //              Switch the processing based on the channel\r
10571         ret+="\tif(tup.channel == 0){\n";\r
10572         ret+="\t\thost_tuple &tup0 = tup;\n";\r
10573         ret += gen_temp_tuple_check(this->node_name, 0);\r
10574         ret += "\t}else{\n";\r
10575         ret+="\t\thost_tuple &tup1 = tup;\n";\r
10576         ret += gen_temp_tuple_check(this->node_name, 1);\r
10577         ret += "\t}\n";\r
10578         ret += "\treturn temp_tuple_received;\n};\n\n";\r
10579 \r
10580 \r
10581 //-------------------------------------------------------------------\r
10582 //              Temporal update functions\r
10583 \r
10584 \r
10585 //              create a temp status tuple\r
10586         ret += "int create_temp_status_tuple(const host_tuple &tup0, const host_tuple &tup1, host_tuple& result) {\n\n";\r
10587 \r
10588         ret += "\tgs_retval_t retval = 0;\n";\r
10589         ret += "\tgs_int32_t problem = 0;\n";\r
10590 \r
10591         ret += "\tif(tup0.data){\n";\r
10592 \r
10593 //              Unpack all the temporal attributes references in select list\r
10594         col_id_set found_cids;\r
10595 \r
10596         for(s=0;s<select_list.size();s++){\r
10597                 if (select_list[s]->se->get_data_type()->is_temporal()) {\r
10598 //                      Find the set of attributes accessed in this SE\r
10599                         col_id_set new_cids;\r
10600                         get_new_se_cids(select_list[s]->se,found_cids, new_cids, NULL);\r
10601                 }\r
10602         }\r
10603 \r
10604         //                      Deal with outer join stuff\r
10605         l_cids.clear(), r_cids.clear();\r
10606         for(ocsi=found_cids.begin();ocsi!=found_cids.end();++ocsi){\r
10607                 if((*ocsi).tblvar_ref == 0) l_cids.insert((*ocsi));\r
10608                 else                                            r_cids.insert((*ocsi));\r
10609         }\r
10610         unpack_null = "";\r
10611         extra_cids.clear();\r
10612         for(ocsi=r_cids.begin();ocsi!=r_cids.end();++ocsi){\r
10613                 string field = (*ocsi).field;\r
10614                 if(r_equiv.count(field)){\r
10615                         unpack_null+="\t\tunpack_var_"+field+"_1="+generate_se_code(r_equiv[field],schema)+";\n";\r
10616                         col_id_set addnl_cids;\r
10617                         get_new_se_cids(r_equiv[field],l_cids,addnl_cids,NULL);\r
10618                 }else{\r
10619                 int schref = (*ocsi).schema_ref;\r
10620                         data_type dt(schema->get_type_name(schref,field));\r
10621                         literal_t empty_lit(dt.type_indicator());\r
10622                         if(empty_lit.is_cpx_lit()){\r
10623                                 sprintf(tmpstr,"&(unpack_var_%s_1)",field.c_str());\r
10624                                 unpack_null += "\t"+empty_lit.to_hfta_C_code(tmpstr)+";\n";\r
10625                         }else{\r
10626                                 unpack_null+="\tunpack_var_"+field+"_1="+empty_lit.to_hfta_C_code("")+";\n";\r
10627                         }\r
10628                 }\r
10629         }\r
10630         ret += gen_unpack_cids(schema,  l_cids, "1", needs_xform);\r
10631         ret += gen_unpack_cids(schema,  extra_cids, "1", needs_xform);\r
10632         ret += unpack_null;\r
10633 \r
10634         ret+="\t}else if (tup1.data) {\n";\r
10635         unpack_null = ""; extra_cids.clear();\r
10636         for(ocsi=l_cids.begin();ocsi!=l_cids.end();++ocsi){\r
10637                 string field = (*ocsi).field;\r
10638                 if(l_equiv.count(field)){\r
10639                         unpack_null+="\t\tunpack_var_"+field+"_0="+generate_se_code(l_equiv[field],schema)+";\n";\r
10640                         col_id_set addnl_cids;\r
10641                         get_new_se_cids(l_equiv[field],r_cids,addnl_cids,NULL);\r
10642                 }else{\r
10643                 int schref = (*ocsi).schema_ref;\r
10644                         data_type dt(schema->get_type_name(schref,field));\r
10645                         literal_t empty_lit(dt.type_indicator());\r
10646                         if(empty_lit.is_cpx_lit()){\r
10647                                 sprintf(tmpstr,"&(unpack_var_%s_0)",field.c_str());\r
10648                                 unpack_null += "\t"+empty_lit.to_hfta_C_code(tmpstr)+";\n";\r
10649                         }else{\r
10650                                 unpack_null+="\tunpack_var_"+field+"_0="+empty_lit.to_hfta_C_code("")+";\n";\r
10651                         }\r
10652                 }\r
10653         }\r
10654         ret += gen_unpack_cids(schema,  r_cids, "1", needs_xform);\r
10655         ret += gen_unpack_cids(schema,  extra_cids, "1", needs_xform);\r
10656         ret += unpack_null;\r
10657         ret+="\t}\n";\r
10658 \r
10659         ret += gen_init_temp_status_tuple(this->get_node_name());\r
10660 \r
10661 //              Start packing.\r
10662         ret += "//\t\tPack the fields into the tuple.\n";\r
10663         ret += gen_pack_tuple(schema,select_list,this->get_node_name(), true );\r
10664 \r
10665 \r
10666         ret += "\treturn 0;\n";\r
10667         ret += "};\n\n";\r
10668 \r
10669 \r
10670         ret += "};\n\n\n";\r
10671 \r
10672 //----------------------------------------------------------\r
10673 //                      The hash function\r
10674 \r
10675         ret += "struct "+generate_functor_name()+"_hash_func{\n";\r
10676         ret += "\tgs_uint32_t operator()(const "+generate_functor_name()+\r
10677                                 "_keydef *key) const{\n";\r
10678         ret += "\t\treturn( (";\r
10679         if(hashkey_dt.size() > 0){\r
10680           for(p=0;p<hashkey_dt.size();p++){\r
10681                 if(p>0) ret += "^";\r
10682                 if(hashkey_dt[p]->use_hashfunc()){\r
10683 //                      sprintf(tmpstr,"%s(&(key->hashkey_var%d))",hashkey_dt[p]->get_hfta_hashfunc().c_str(),p);\r
10684                         if(hashkey_dt[p]->is_buffer_type())\r
10685                                 sprintf(tmpstr,"(%s*%s(&(key->hashkey_var%d)))",hash_nums[p%NRANDS].c_str(),hashkey_dt[p]->get_hfta_hashfunc().c_str(),p);\r
10686                         else\r
10687                                 sprintf(tmpstr,"(%s*%s(key->hashkey_var%d))",hash_nums[p%NRANDS].c_str(),hashkey_dt[p]->get_hfta_hashfunc().c_str(),p);\r
10688                 }else{\r
10689                         sprintf(tmpstr,"(%s*key->hashkey_var%d)",hash_nums[p%NRANDS].c_str(),p);\r
10690                 }\r
10691                 ret += tmpstr;\r
10692           }\r
10693         }else{\r
10694                 ret += "0";\r
10695         }\r
10696         ret += ") >> 32);\n";\r
10697         ret += "\t}\n";\r
10698         ret += "};\n\n";\r
10699 \r
10700 //----------------------------------------------------------\r
10701 //                      The comparison function\r
10702 \r
10703         ret += "struct "+generate_functor_name()+"_equal_func{\n";\r
10704         ret += "\tbool operator()(const "+generate_functor_name()+"_keydef *key1, "+\r
10705                         generate_functor_name()+"_keydef *key2) const{\n";\r
10706         ret += "\t\treturn( (";\r
10707         if(hashkey_dt.size() > 0){\r
10708           for(p=0;p<hashkey_dt.size();p++){\r
10709                 if(p>0) ret += ") && (";\r
10710                 if(hashkey_dt[p]->complex_comparison(hashkey_dt[p])){\r
10711                   if(hashkey_dt[p]->is_buffer_type())\r
10712                         sprintf(tmpstr,"(%s(&(key1->hashkey_var%d), &(key2->hashkey_var%d))==0)",\r
10713                                 hashkey_dt[p]->get_hfta_comparison_fcn(hashkey_dt[p]).c_str(),p,p);\r
10714                   else\r
10715                         sprintf(tmpstr,"(%s((key1->hashkey_var%d), (key2->hashkey_var%d))==0)",\r
10716                                 hashkey_dt[p]->get_hfta_comparison_fcn(hashkey_dt[p]).c_str(),p,p);\r
10717                 }else{\r
10718                         sprintf(tmpstr,"key1->hashkey_var%d == key2->hashkey_var%d",p,p);\r
10719                 }\r
10720                 ret += tmpstr;\r
10721           }\r
10722         }else{\r
10723                 ret += "1";\r
10724         }\r
10725         ret += ") );\n";\r
10726         ret += "\t}\n";\r
10727         ret += "};\n\n";\r
10728 \r
10729 \r
10730         return(ret);\r
10731 }\r
10732 \r
10733 \r
10734 \r
10735 string join_eq_hash_qpn::generate_operator(int i, string params){\r
10736 \r
10737                 return(\r
10738                         "       join_eq_hash_operator<" +\r
10739                         generate_functor_name()+ ","+\r
10740                         generate_functor_name() + "_tempeqdef,"+\r
10741                         generate_functor_name() + "_keydef,"+\r
10742                         generate_functor_name()+"_hash_func,"+\r
10743                         generate_functor_name()+"_equal_func"\r
10744                         "> *op"+int_to_string(i)+" = new join_eq_hash_operator<"+\r
10745                         generate_functor_name()+","+\r
10746                         generate_functor_name() + "_tempeqdef,"+\r
10747                         generate_functor_name() + "_keydef,"+\r
10748                         generate_functor_name()+"_hash_func,"+\r
10749                         generate_functor_name()+"_equal_func"\r
10750                         ">("+params+", "+\r
10751                         int_to_string(from[0]->get_property()+2*from[1]->get_property())+", \"" + get_node_name() +\r
10752 "\");\n"\r
10753                 );\r
10754 }\r
10755 \r
10756 \r
10757 \r
10758 ////////////////////////////////////////////////////////////////\r
10759 ////    SGAHCWCB functor\r
10760 \r
10761 \r
10762 \r
10763 string sgahcwcb_qpn::generate_functor_name(){\r
10764         return("sgahcwcb_functor_" + normalize_name(this->get_node_name()));\r
10765 }\r
10766 \r
10767 \r
10768 string sgahcwcb_qpn::generate_functor(table_list *schema, ext_fcn_list *Ext_fcns, vector<bool> &needs_xform){\r
10769         int a,g,w,s;\r
10770 \r
10771 \r
10772 //                      Initialize generate utility globals\r
10773         segen_gb_tbl = &(gb_tbl);\r
10774 \r
10775 \r
10776 //--------------------------------\r
10777 //                      group definition class\r
10778         string ret = "class " + generate_functor_name() + "_groupdef{\n";\r
10779         ret += "public:\n";\r
10780         ret += "\tbool valid;\n";\r
10781         for(g=0;g<this->gb_tbl.size();g++){\r
10782                 sprintf(tmpstr,"gb_var%d",g);\r
10783                 ret+="\t"+this->gb_tbl.get_data_type(g)->make_host_cvar(tmpstr)+";\n";\r
10784         }\r
10785 //              Constructors\r
10786         ret += "\t"+generate_functor_name() + "_groupdef(){valid=true;};\n";\r
10787         ret += "\t"+generate_functor_name() + "_groupdef("+\r
10788                 this->generate_functor_name() + "_groupdef *gd){\n";\r
10789         for(g=0;g<gb_tbl.size();g++){\r
10790                 data_type *gdt = gb_tbl.get_data_type(g);\r
10791                 if(gdt->is_buffer_type()){\r
10792                         sprintf(tmpstr,"\t\t%s(&gb_var%d, &(gd->gb_var%d));\n",\r
10793                           gdt->get_hfta_buffer_assign_copy().c_str(),g,g );\r
10794                         ret += tmpstr;\r
10795                 }else{\r
10796                         sprintf(tmpstr,"\t\tgb_var%d = gd->gb_var%d;\n",g,g);\r
10797                         ret += tmpstr;\r
10798                 }\r
10799         }\r
10800         ret += "\tvalid=true;\n";\r
10801         ret += "\t};\n";\r
10802 //              destructor\r
10803         ret += "\t~"+ generate_functor_name() + "_groupdef(){\n";\r
10804         for(g=0;g<gb_tbl.size();g++){\r
10805                 data_type *gdt = gb_tbl.get_data_type(g);\r
10806                 if(gdt->is_buffer_type()){\r
10807                         sprintf(tmpstr,"\t\t%s(&gb_var%d);\n",\r
10808                           gdt->get_hfta_buffer_destroy().c_str(), g );\r
10809                         ret += tmpstr;\r
10810                 }\r
10811         }\r
10812         ret += "\t};\n";\r
10813         ret +="};\n\n";\r
10814 \r
10815 //--------------------------------\r
10816 //                      aggr definition class\r
10817         ret += "class " + this->generate_functor_name() + "_aggrdef{\n";\r
10818         ret += "public:\n";\r
10819         for(a=0;a<aggr_tbl.size();a++){\r
10820 aggr_table_entry *ate = aggr_tbl.agr_tbl[a];\r
10821                 sprintf(tmpstr,"aggr_var%d",a);\r
10822                 if(aggr_tbl.is_builtin(a))\r
10823                 ret+="\t"+ aggr_tbl.get_data_type(a)->make_host_cvar(tmpstr)+";\n";\r
10824                 else\r
10825                 ret+="\t"+ aggr_tbl.get_storage_type(a)->make_host_cvar(tmpstr)+";\n";\r
10826         }\r
10827 //              Constructors\r
10828         ret += "\t"+this->generate_functor_name() + "_aggrdef(){};\n";\r
10829 //              destructor\r
10830         ret += "\t~"+this->generate_functor_name() + "_aggrdef(){\n";\r
10831         for(a=0;a<aggr_tbl.size();a++){\r
10832 aggr_table_entry *ate = aggr_tbl.agr_tbl[a];\r
10833                 if(aggr_tbl.is_builtin(a)){\r
10834                         data_type *adt = aggr_tbl.get_data_type(a);\r
10835                         if(adt->is_buffer_type()){\r
10836                                 sprintf(tmpstr,"\t\t%s(&aggr_var%d);\n",\r
10837                                 adt->get_hfta_buffer_destroy().c_str(), a );\r
10838                                 ret += tmpstr;\r
10839                         }\r
10840                 }else{\r
10841                         ret+="\t\t"+aggr_tbl.get_op(a)+"_HFTA_AGGR_DESTROY_(";\r
10842                         if(aggr_tbl.get_storage_type(a)->get_type() != fstring_t) ret+="&";\r
10843                         ret+="(aggr_var"+int_to_string(a)+"));\n";\r
10844                 }\r
10845         }\r
10846         ret += "\t};\n";\r
10847         ret +="};\n\n";\r
10848 \r
10849 //--------------------------------\r
10850 //                      superaggr definition class\r
10851         ret += "class " + this->generate_functor_name() + "_statedef{\n";\r
10852         ret += "public:\n";\r
10853         for(a=0;a<aggr_tbl.size();a++){\r
10854 aggr_table_entry *ate = aggr_tbl.agr_tbl[a];\r
10855                 if(ate->is_superaggr()){\r
10856                         sprintf(tmpstr,"aggr_var%d",a);\r
10857                         if(aggr_tbl.is_builtin(a))\r
10858                         ret+="\t"+ aggr_tbl.get_data_type(a)->make_host_cvar(tmpstr)+";\n";\r
10859                         else\r
10860                         ret+="\t"+ aggr_tbl.get_storage_type(a)->make_host_cvar(tmpstr)+";\n";\r
10861                 }\r
10862         }\r
10863         set<string>::iterator ssi;\r
10864         for(ssi=states_refd.begin(); ssi!=states_refd.end(); ++ssi){\r
10865                 string state_nm = (*ssi);\r
10866                 int state_id = Ext_fcns->lookup_state(state_nm);\r
10867                 data_type *dt = Ext_fcns->get_storage_dt(state_id);\r
10868                 string state_var = "state_var_"+state_nm;\r
10869                 ret += "\t"+dt->make_host_cvar(state_var)+";\n";\r
10870         }\r
10871 //              Constructors\r
10872         ret += "\t"+this->generate_functor_name() + "_statedef(){};\n";\r
10873 //              destructor\r
10874         ret += "\t~"+this->generate_functor_name() + "_statedef(){\n";\r
10875         for(a=0;a<aggr_tbl.size();a++){\r
10876 aggr_table_entry *ate = aggr_tbl.agr_tbl[a];\r
10877                 if(ate->is_superaggr()){\r
10878                         if(aggr_tbl.is_builtin(a)){\r
10879                                 data_type *adt = aggr_tbl.get_data_type(a);\r
10880                                 if(adt->is_buffer_type()){\r
10881                                         sprintf(tmpstr,"\t\t%s(&aggr_var%d);\n",\r
10882                                         adt->get_hfta_buffer_destroy().c_str(), a );\r
10883                                         ret += tmpstr;\r
10884                                 }\r
10885                         }else{\r
10886                                 ret+="\t\t"+aggr_tbl.get_op(a)+"_HFTA_AGGR_DESTROY_(";\r
10887                                 if(aggr_tbl.get_storage_type(a)->get_type() != fstring_t) ret+="&";\r
10888                                 ret+="(aggr_var"+int_to_string(a)+"));\n";\r
10889                         }\r
10890                 }\r
10891         }\r
10892         for(ssi=states_refd.begin(); ssi!=states_refd.end(); ++ssi){\r
10893                 string state_nm = (*ssi);\r
10894                 int state_id = Ext_fcns->lookup_state(state_nm);\r
10895                 string state_var = "state_var_"+state_nm;\r
10896                 ret += "\t_sfun_state_destroy_"+state_nm+"(&"+state_var+");\n";\r
10897         }\r
10898 \r
10899         ret += "\t};\n";\r
10900         ret +="};\n\n";\r
10901 \r
10902 \r
10903 //--------------------------------\r
10904 //                      gb functor class\r
10905         ret += "class " + this->generate_functor_name() + "{\n";\r
10906 \r
10907 //                      Find variables referenced in this query node.\r
10908 \r
10909   col_id_set cid_set;\r
10910   col_id_set::iterator csi;\r
10911 \r
10912     for(w=0;w<where.size();++w)\r
10913         gather_pr_col_ids(where[w]->pr,cid_set,segen_gb_tbl);\r
10914     for(w=0;w<having.size();++w)\r
10915         gather_pr_col_ids(having[w]->pr,cid_set,segen_gb_tbl);\r
10916     for(w=0;w<cleanby.size();++w)\r
10917         gather_pr_col_ids(cleanby[w]->pr,cid_set,segen_gb_tbl);\r
10918     for(w=0;w<cleanwhen.size();++w)\r
10919         gather_pr_col_ids(cleanwhen[w]->pr,cid_set,segen_gb_tbl);\r
10920         for(g=0;g<gb_tbl.size();g++)\r
10921                 gather_se_col_ids(gb_tbl.get_def(g),cid_set,segen_gb_tbl);\r
10922 \r
10923     for(s=0;s<select_list.size();s++){\r
10924         gather_se_col_ids(select_list[s]->se,cid_set,segen_gb_tbl);     // descends into aggregates\r
10925     }\r
10926 \r
10927 \r
10928 //                      Private variables : store the state of the functor.\r
10929 //                      1) variables for unpacked attributes\r
10930 //                      2) offsets of the upacked attributes\r
10931 //                      3) storage of partial functions\r
10932 //                      4) storage of complex literals (i.e., require a constructor)\r
10933 \r
10934         ret += "private:\n";\r
10935 \r
10936         // var to save the schema handle\r
10937         ret += "\tint schema_handle0;\n";\r
10938 \r
10939         // generate the declaration of all the variables related to\r
10940         // temp tuples generation\r
10941         ret += gen_decl_temp_vars();\r
10942 \r
10943 //                      unpacked attribute storage, offsets\r
10944         ret += "//\t\tstorage and offsets of accessed fields.\n";\r
10945         ret += generate_access_vars(cid_set, schema);\r
10946 //              tuple metadata offset\r
10947         ret += "\ttuple_metadata_offset0;\n";\r
10948 \r
10949 //                      Variables to store results of partial functions.\r
10950 //                      WARNING find_partial_functions modifies the SE\r
10951 //                      (it marks the partial function id).\r
10952         ret += "//\t\tParital function result storage\n";\r
10953         vector<scalarexp_t *> partial_fcns;\r
10954         vector<int> fcn_ref_cnt;\r
10955         vector<bool> is_partial_fcn;\r
10956         for(s=0;s<select_list.size();s++){\r
10957                 find_partial_fcns(select_list[s]->se, &partial_fcns, NULL,NULL, Ext_fcns);\r
10958         }\r
10959         for(w=0;w<where.size();w++){\r
10960                 find_partial_fcns_pr(where[w]->pr, &partial_fcns, NULL,NULL, Ext_fcns);\r
10961         }\r
10962         for(w=0;w<having.size();w++){\r
10963                 find_partial_fcns_pr(having[w]->pr, &partial_fcns, NULL,NULL, Ext_fcns);\r
10964         }\r
10965         for(w=0;w<cleanby.size();w++){\r
10966                 find_partial_fcns_pr(cleanby[w]->pr, &partial_fcns, NULL,NULL, Ext_fcns);\r
10967         }\r
10968         for(w=0;w<cleanwhen.size();w++){\r
10969                 find_partial_fcns_pr(cleanwhen[w]->pr, &partial_fcns, NULL,NULL, Ext_fcns);\r
10970         }\r
10971         for(g=0;g<gb_tbl.size();g++){\r
10972                 find_partial_fcns(gb_tbl.get_def(g), &partial_fcns, NULL,NULL, Ext_fcns);\r
10973         }\r
10974         for(a=0;a<aggr_tbl.size();a++){\r
10975                 find_partial_fcns(aggr_tbl.get_aggr_se(a), &partial_fcns, NULL,NULL, Ext_fcns);\r
10976         }\r
10977         if(partial_fcns.size()>0){\r
10978           ret += "/*\t\tVariables for storing results of partial functions. \t*/\n";\r
10979           ret += generate_partial_fcn_vars(partial_fcns,fcn_ref_cnt,is_partial_fcn,false);\r
10980         }\r
10981 \r
10982 //                      Complex literals (i.e., they need constructors)\r
10983         ret += "//\t\tComplex literal storage.\n";\r
10984         cplx_lit_table *complex_literals = this->get_cplx_lit_tbl(Ext_fcns);\r
10985         ret += generate_complex_lit_vars(complex_literals);\r
10986 \r
10987 //                      Pass-by-handle parameters\r
10988         ret += "//\t\tPass-by-handle storage.\n";\r
10989         vector<handle_param_tbl_entry *> param_handle_table = this->get_handle_param_tbl(Ext_fcns);\r
10990         ret += generate_pass_by_handle_vars(param_handle_table);\r
10991 \r
10992 //                      Create cached temporaries for UDAF return values.\r
10993         ret += "//\t\tTemporaries for UDAF return values.\n";\r
10994         for(a=0;a<aggr_tbl.size();a++){\r
10995                 if(! aggr_tbl.is_builtin(a)){\r
10996                         int afcn_id = aggr_tbl.get_fcn_id(a);\r
10997                         data_type *adt = Ext_fcns->get_fcn_dt(afcn_id);\r
10998                         sprintf(tmpstr,"udaf_ret_%d", a);\r
10999                         ret+="\t"+adt->make_host_cvar(tmpstr)+";\n";\r
11000                 }\r
11001         }\r
11002 \r
11003 \r
11004 \r
11005 //                      variables to hold parameters.\r
11006         ret += "//\tfor query parameters\n";\r
11007         ret += generate_param_vars(param_tbl);\r
11008 \r
11009 //              Is there a temporal flush?  If so create flush temporaries,\r
11010 //              create flush indicator.\r
11011         bool uses_temporal_flush = false;\r
11012         for(g=0;g<gb_tbl.size();g++){\r
11013                 data_type *gdt = gb_tbl.get_data_type(g);\r
11014                 if(gdt->is_temporal())\r
11015                         uses_temporal_flush = true;\r
11016         }\r
11017 \r
11018         if(uses_temporal_flush){\r
11019                 ret += "//\t\tFor temporal flush\n";\r
11020                 for(g=0;g<gb_tbl.size();g++){\r
11021                         data_type *gdt = gb_tbl.get_data_type(g);\r
11022                         if(gdt->is_temporal()){\r
11023                           sprintf(tmpstr,"last_gb%d",g);\r
11024                           ret+="\t"+gb_tbl.get_data_type(g)->make_host_cvar(tmpstr)+";\n";\r
11025                           sprintf(tmpstr,"last_flushed_gb%d",g);\r
11026                           ret+="\t"+gb_tbl.get_data_type(g)->make_host_cvar(tmpstr)+";\n";\r
11027                         }\r
11028                 }\r
11029                 ret += "\tbool needs_temporal_flush;\n";\r
11030         }\r
11031 \r
11032 //                      The publicly exposed functions\r
11033 \r
11034         ret += "\npublic:\n";\r
11035 \r
11036 \r
11037 //-------------------\r
11038 //                      The functor constructor\r
11039 //                      pass in the schema handle.\r
11040 //                      1) make assignments to the unpack offset variables\r
11041 //                      2) initialize the complex literals\r
11042 \r
11043         ret += "//\t\tFunctor constructor.\n";\r
11044         ret +=  this->generate_functor_name()+"(int schema_handle0){\n";\r
11045 \r
11046         // save the schema handle\r
11047         ret += "\t\tthis->schema_handle0 = schema_handle0;\n";\r
11048 //              tuple metadata offset\r
11049         ret += "\ttuple_metadata_offset0 = ftaschema_get_tuple_metadata_offset(schema_handle0);\n";\r
11050 \r
11051 //              unpack vars\r
11052         ret += "//\t\tGet offsets for unpacking fields from input tuple.\n";\r
11053         ret += gen_access_var_init(cid_set);\r
11054 \r
11055 //              aggregate return vals : refd in both final_sample\r
11056 //              and create_output_tuple\r
11057 //                      Create cached temporaries for UDAF return values.\r
11058         for(a=0;a<aggr_tbl.size();a++){\r
11059                 if(! aggr_tbl.is_builtin(a)){\r
11060                         int afcn_id = aggr_tbl.get_fcn_id(a);\r
11061                         data_type *adt = Ext_fcns->get_fcn_dt(afcn_id);\r
11062                         sprintf(tmpstr,"udaf_ret_%d", a);\r
11063                         ret+="\t"+adt->make_host_cvar(tmpstr)+";\n";\r
11064                 }\r
11065         }\r
11066 \r
11067 //              complex literals\r
11068         ret += "//\t\tInitialize complex literals.\n";\r
11069         ret += gen_complex_lit_init(complex_literals);\r
11070 \r
11071 //              Initialize partial function results so they can be safely GC'd\r
11072         ret += gen_partial_fcn_init(partial_fcns);\r
11073 \r
11074 //              Initialize non-query-parameter parameter handles\r
11075         ret += gen_pass_by_handle_init(param_handle_table);\r
11076 \r
11077 //              temporal flush variables\r
11078 //              ASSUME that structured values won't be temporal.\r
11079         if(uses_temporal_flush){\r
11080                 ret += "//\t\tInitialize temporal flush variables.\n";\r
11081                 for(g=0;g<gb_tbl.size();g++){\r
11082                         data_type *gdt = gb_tbl.get_data_type(g);\r
11083                         if(gdt->is_temporal()){\r
11084                                 literal_t gl(gdt->type_indicator());\r
11085                                 sprintf(tmpstr,"\tlast_gb%d = %s;\n",g, gl.to_hfta_C_code("").c_str());\r
11086                                 ret.append(tmpstr);\r
11087                         }\r
11088                 }\r
11089                 ret += "\tneeds_temporal_flush = false;\n";\r
11090         }\r
11091 \r
11092         //              Init temporal attributes referenced in select list\r
11093         ret += gen_init_temp_vars(schema, select_list, segen_gb_tbl);\r
11094 \r
11095         ret += "};\n";\r
11096 \r
11097 \r
11098 //-------------------\r
11099 //                      Functor destructor\r
11100         ret += "//\t\tFunctor destructor.\n";\r
11101         ret +=  "~"+this->generate_functor_name()+"(){\n";\r
11102 \r
11103 //                      clean up buffer type complex literals\r
11104         ret += gen_complex_lit_dtr(complex_literals);\r
11105 \r
11106 //                      Deregister the pass-by-handle parameters\r
11107         ret += "/* register and de-register the pass-by-handle parameters */\n";\r
11108         ret += gen_pass_by_handle_dtr(param_handle_table);\r
11109 \r
11110 //                      clean up partial function results.\r
11111         ret += "/* clean up partial function storage    */\n";\r
11112         ret += gen_partial_fcn_dtr(partial_fcns);\r
11113 \r
11114 //                      Destroy the parameters, if any need to be destroyed\r
11115         ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";\r
11116 \r
11117         ret += "};\n\n";\r
11118 \r
11119 \r
11120 //-------------------\r
11121 //                      Parameter manipulation routines\r
11122         ret += generate_load_param_block(this->generate_functor_name(),\r
11123                                                                         this->param_tbl,param_handle_table);\r
11124         ret += generate_delete_param_block(this->generate_functor_name(),\r
11125                                                                         this->param_tbl,param_handle_table);\r
11126 \r
11127 //-------------------\r
11128 //                      Register new parameter block\r
11129 \r
11130         ret += "int set_param_block(gs_int32_t sz, void* value){\n";\r
11131           ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";\r
11132           ret += "\treturn this->load_params_"+this->generate_functor_name()+\r
11133                                 "(sz, value);\n";\r
11134         ret += "};\n\n";\r
11135 \r
11136 //-------------------\r
11137 //              the create_group method.\r
11138 //              This method creates a group in a buffer passed in\r
11139 //              (to allow for creation on the stack).\r
11140 //              There are also a couple of side effects:\r
11141 //              1) evaluate the WHERE clause (and therefore, unpack all partial fcns)\r
11142 //              2) determine if a temporal flush is required.\r
11143 \r
11144         ret += this->generate_functor_name()+"_groupdef *create_group(host_tuple &tup0, gs_sp_t buffer){\n";\r
11145         //              Variables for execution of the function.\r
11146         ret += "\tgs_int32_t problem = 0;\n";   // return unpack failure\r
11147 \r
11148         if(partial_fcns.size()>0){              // partial fcn access failure\r
11149           ret += "\tgs_retval_t retval = 0;\n";\r
11150           ret += "\n";\r
11151         }\r
11152 //              return value\r
11153         ret += "\t"+generate_functor_name()+"_groupdef *gbval = ("+generate_functor_name()+\r
11154                         "_groupdef *) buffer;\n";\r
11155 \r
11156 //              Start by cleaning up partial function results\r
11157         ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";\r
11158 \r
11159         set<int> gb_pfcns;      // partial fcns in gbdefs, aggr se's\r
11160         for(g=0;g<gb_tbl.size();g++){\r
11161                 collect_partial_fcns(gb_tbl.get_def(g), gb_pfcns);\r
11162         }\r
11163         ret += gen_partial_fcn_dtr(partial_fcns,gb_pfcns);\r
11164 //      ret += gen_partial_fcn_dtr(partial_fcns);\r
11165 \r
11166 \r
11167         ret += gen_temp_tuple_check(this->node_name, 0);\r
11168         col_id_set found_cids;  // colrefs unpacked thus far.\r
11169         ret += gen_unpack_temp_vars(schema, found_cids, select_list, segen_gb_tbl, needs_xform);\r
11170 \r
11171 \r
11172 \r
11173 //                      Save temporal group-by variables\r
11174 \r
11175 \r
11176         ret.append("\n\t//\t\tCompute temporal groupby attributes\n\n");\r
11177 \r
11178           for(g=0;g<gb_tbl.size();g++){\r
11179 \r
11180                         data_type *gdt = gb_tbl.get_data_type(g);\r
11181 \r
11182                         if(gdt->is_temporal()){\r
11183                                 sprintf(tmpstr,"\tgbval->gb_var%d = %s;\n",\r
11184                                         g, generate_se_code(gb_tbl.get_def(g),schema).c_str() );\r
11185                                 ret.append(tmpstr);\r
11186                         }\r
11187                 }\r
11188                 ret.append("\n");\r
11189 \r
11190 \r
11191 \r
11192 //                      Compare the temporal GB vars with the stored ones,\r
11193 //                      set flush indicator and update stored GB vars if there is any change.\r
11194 \r
11195         if(uses_temporal_flush){\r
11196                 ret+= "\tif( !( (";\r
11197                 bool first_one = true;\r
11198                 for(g=0;g<gb_tbl.size();g++){\r
11199                         data_type *gdt = gb_tbl.get_data_type(g);\r
11200 \r
11201                         if(gdt->is_temporal()){\r
11202                           sprintf(tmpstr,"last_gb%d",g);   string lhs_op = tmpstr;\r
11203                           sprintf(tmpstr,"gbval->gb_var%d",g);   string rhs_op = tmpstr;\r
11204                           if(first_one){first_one = false;} else {ret += ") && (";}\r
11205                           ret += generate_equality_test(lhs_op, rhs_op, gdt);\r
11206                         }\r
11207                 }\r
11208                 ret += ") ) ){\n";\r
11209                 for(g=0;g<gb_tbl.size();g++){\r
11210                   data_type *gdt = gb_tbl.get_data_type(g);\r
11211                   if(gdt->is_temporal()){\r
11212                           if(gdt->is_buffer_type()){\r
11213                                 sprintf(tmpstr,"\t\t%s(&(gbval->gb_var%d),&last_gb%d);\n",gdt->get_hfta_buffer_replace().c_str(),g,g);\r
11214                           }else{\r
11215                                 sprintf(tmpstr,"\t\tlast_flushed_gb%d = last_gb%d;\n",g,g);\r
11216                                 ret += tmpstr;\r
11217                                 sprintf(tmpstr,"\t\tlast_gb%d = gbval->gb_var%d;\n",g,g);\r
11218                           }\r
11219                           ret += tmpstr;\r
11220                         }\r
11221                 }\r
11222 /*\r
11223                 if(uses_temporal_flush){\r
11224                         for(g=0;g<gb_tbl.size();g++){\r
11225                                 data_type *gdt = gb_tbl.get_data_type(g);\r
11226                                 if(gdt->is_temporal()){\r
11227                                         ret+="if(last_flushed_gb"+int_to_string(g)+">0)\n";\r
11228                                         break;\r
11229                                 }\r
11230                         }\r
11231                 }\r
11232 */\r
11233                 ret += "\t\tneeds_temporal_flush=true;\n";\r
11234                 ret += "\t\t}else{\n"\r
11235                         "\t\t\tneeds_temporal_flush=false;\n"\r
11236                         "\t\t}\n";\r
11237         }\r
11238 \r
11239 \r
11240 //              For temporal status tuple we don't need to do anything else\r
11241         ret += "\tif (temp_tuple_received) return NULL;\n\n";\r
11242 \r
11243 \r
11244 //              The partial functions ref'd in the group-by var\r
11245 //              definitions must be evaluated.  If one returns false,\r
11246 //              then implicitly the predicate is false.\r
11247         set<int>::iterator pfsi;\r
11248 \r
11249         if(gb_pfcns.size() > 0)\r
11250                 ret += "//\t\tUnpack partial fcns.\n";\r
11251         ret += gen_full_unpack_partial_fcn(schema, partial_fcns, gb_pfcns,\r
11252                                                                                 found_cids, segen_gb_tbl, "NULL", needs_xform);\r
11253 \r
11254 //                      Unpack the group-by variables\r
11255 \r
11256           for(g=0;g<gb_tbl.size();g++){\r
11257 //                      Find the new fields ref'd by this GBvar def.\r
11258                 col_id_set new_cids;\r
11259                 get_new_se_cids(gb_tbl.get_def(g), found_cids, new_cids, segen_gb_tbl);\r
11260 //                      Unpack these values.\r
11261                 ret += gen_unpack_cids(schema, new_cids, "NULL", needs_xform);\r
11262 \r
11263                 sprintf(tmpstr,"\tgbval->gb_var%d = %s;\n",\r
11264                                 g, generate_se_code(gb_tbl.get_def(g),schema).c_str() );\r
11265 /*\r
11266 //                              There seems to be no difference between the two\r
11267 //                              branches of the IF statement.\r
11268                 data_type *gdt = gb_tbl.get_data_type(g);\r
11269                   if(gdt->is_buffer_type()){\r
11270 //                              Create temporary copy.\r
11271                         sprintf(tmpstr,"\tgbval->gb_var%d = %s;\n",\r
11272                                 g, generate_se_code(gb_tbl.get_def(g),schema).c_str() );\r
11273                   }else{\r
11274                         scalarexp_t *gse = gb_tbl.get_def(g);\r
11275                         sprintf(tmpstr,"\tgbval->gb_var%d = %s;\n",\r
11276                                         g,generate_se_code(gse,schema).c_str());\r
11277                   }\r
11278 */\r
11279                   ret.append(tmpstr);\r
11280           }\r
11281           ret.append("\n");\r
11282 \r
11283 \r
11284         ret+= "\treturn gbval;\n";\r
11285         ret += "};\n\n\n";\r
11286 \r
11287 \r
11288 \r
11289 //-------------------\r
11290 //              the create_group method.\r
11291 //              This method creates a group in a buffer passed in\r
11292 //              (to allow for creation on the stack).\r
11293 //              There are also a couple of side effects:\r
11294 //              1) evaluate the WHERE clause (and therefore, unpack all partial fcns)\r
11295 //              2) determine if a temporal flush is required.\r
11296 \r
11297         ret += "bool evaluate_predicate(host_tuple &tup0, "+generate_functor_name()+"_groupdef *gbval, "+generate_functor_name()+"_statedef *stval, int cd){\n";\r
11298         //              Variables for execution of the function.\r
11299         ret += "\tgs_int32_t problem = 0;\n";   // return unpack failure\r
11300 \r
11301         if(partial_fcns.size()>0){              // partial fcn access failure\r
11302           ret += "\tgs_retval_t retval = 0;\n";\r
11303           ret += "\n";\r
11304         }\r
11305 \r
11306 //              Start by cleaning up partial function results\r
11307         ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";\r
11308         set<int> w_pfcns;       // partial fcns in where clause\r
11309         for(w=0;w<where.size();++w)\r
11310                 collect_partial_fcns_pr(where[w]->pr, w_pfcns);\r
11311 \r
11312         set<int> ag_pfcns;      // partial fcns in gbdefs, aggr se's\r
11313         for(a=0;a<aggr_tbl.size();a++){\r
11314                 collect_partial_fcns(aggr_tbl.get_aggr_se(a), ag_pfcns);\r
11315         }\r
11316         ret += gen_partial_fcn_dtr(partial_fcns,w_pfcns);\r
11317         ret += gen_partial_fcn_dtr(partial_fcns,ag_pfcns);\r
11318 \r
11319         ret+="//\t\tEvaluate clauses which don't reference stateful fcns first \n";\r
11320         for(w=0;w<where.size();++w){\r
11321                 if(! pred_refs_sfun(where[w]->pr)){\r
11322                         sprintf(tmpstr,"//\t\tPredicate clause %d.\n",w);\r
11323                         ret += tmpstr;\r
11324 //                      Find the set of variables accessed in this CNF elem,\r
11325 //                      but in no previous element.\r
11326                         col_id_set new_cids;\r
11327                         get_new_pred_cids(where[w]->pr, found_cids, new_cids, segen_gb_tbl);\r
11328 \r
11329 //                      Unpack these values.\r
11330                         ret += gen_unpack_cids(schema, new_cids, "false", needs_xform);\r
11331 //                      Find partial fcns ref'd in this cnf element\r
11332                         set<int> pfcn_refs;\r
11333                         collect_partial_fcns_pr(where[w]->pr, pfcn_refs);\r
11334                         ret += gen_unpack_partial_fcn(schema, partial_fcns, pfcn_refs,"false");\r
11335 \r
11336                         ret += "\tif( !("+generate_predicate_code(where[w]->pr,schema)+\r
11337                                 +") ) return(false);\n";\r
11338                 }\r
11339         }\r
11340 \r
11341 \r
11342 //              The partial functions ref'd in the and aggregate\r
11343 //              definitions must also be evaluated.  If one returns false,\r
11344 //              then implicitly the predicate is false.\r
11345 //              ASSUME that aggregates cannot reference stateful fcns.\r
11346 \r
11347         if(ag_pfcns.size() > 0)\r
11348                 ret += "//\t\tUnpack remaining partial fcns.\n";\r
11349         ret += gen_full_unpack_partial_fcn(schema, partial_fcns, ag_pfcns,\r
11350                                                                                 found_cids, segen_gb_tbl, "false", needs_xform);\r
11351 \r
11352         ret+="//\t\tEvaluate all remaining where clauses.\n";\r
11353         ret+="\tbool retval = true;\n";\r
11354         for(w=0;w<where.size();++w){\r
11355                 if( pred_refs_sfun(where[w]->pr)){\r
11356                         sprintf(tmpstr,"//\t\tPredicate clause %d.\n",w);\r
11357                         ret += tmpstr;\r
11358 //                      Find the set of variables accessed in this CNF elem,\r
11359 //                      but in no previous element.\r
11360                         col_id_set new_cids;\r
11361                         get_new_pred_cids(where[w]->pr, found_cids, new_cids, segen_gb_tbl);\r
11362 \r
11363 //                      Unpack these values.\r
11364                         ret += gen_unpack_cids(schema, new_cids, "false", needs_xform);\r
11365 //                      Find partial fcns ref'd in this cnf element\r
11366                         set<int> pfcn_refs;\r
11367                         collect_partial_fcns_pr(where[w]->pr, pfcn_refs);\r
11368                         ret += gen_unpack_partial_fcn(schema, partial_fcns, pfcn_refs,"false");\r
11369 \r
11370                         ret += "\tif( !("+generate_predicate_code(where[w]->pr,schema)+\r
11371                                 +") ) retval = false;\n";\r
11372                 }\r
11373         }\r
11374 \r
11375         ret+="//                Unpack all remaining attributes\n";\r
11376         ret += gen_remaining_colrefs(schema, cid_set, found_cids, "false", needs_xform);\r
11377 \r
11378     ret += "\n\treturn retval;\n";\r
11379         ret += "};\n\n\n";\r
11380 \r
11381 //--------------------------------------------------------\r
11382 //                      Create and initialize an aggregate object\r
11383 \r
11384         ret += this->generate_functor_name()+"_aggrdef *create_aggregate(host_tuple &tup0, "+generate_functor_name()+"_groupdef *gbval, gs_sp_t a,"+generate_functor_name()+"_statedef *stval, int cd){\n";\r
11385         //              Variables for execution of the function.\r
11386         ret += "\tgs_int32_t problem = 0;\n";   // return unpack failure\r
11387 \r
11388 //              return value\r
11389         ret += "\t"+generate_functor_name()+"_aggrdef *aggval = ("+generate_functor_name()+ "_aggrdef *)a;\n";\r
11390 \r
11391         for(a=0;a<aggr_tbl.size();a++){\r
11392                 if(aggr_tbl.is_builtin(a)){\r
11393 //                      Create temporaries for buffer return values\r
11394                   data_type *adt = aggr_tbl.get_data_type(a);\r
11395                   if(adt->is_buffer_type()){\r
11396                         sprintf(tmpstr,"aggr_tmp_%d", a);\r
11397                         ret+=adt->make_host_cvar(tmpstr)+";\n";\r
11398                   }\r
11399                 }\r
11400         }\r
11401 \r
11402         for(a=0;a<aggr_tbl.size();a++){\r
11403                 sprintf(tmpstr,"aggval->aggr_var%d",a);\r
11404                 string assignto_var = tmpstr;\r
11405                 ret += "\t"+generate_aggr_init(assignto_var,&aggr_tbl,a, schema);\r
11406         }\r
11407 \r
11408         ret += "\treturn aggval;\n";\r
11409         ret += "};\n\n";\r
11410 \r
11411 \r
11412 //--------------------------------------------------------\r
11413 //                      initialize an aggregate object inplace\r
11414 \r
11415         ret += "void create_aggregate(host_tuple &tup0, "+this->generate_functor_name()+"_aggrdef *aggval,"+generate_functor_name()+"_statedef *stval, int cd){\n";\r
11416         //              Variables for execution of the function.\r
11417         ret += "\tgs_int32_t problem = 0;\n";   // return unpack failure\r
11418 \r
11419 //              return value\r
11420 \r
11421         for(a=0;a<aggr_tbl.size();a++){\r
11422                 if(aggr_tbl.is_builtin(a)){\r
11423 //                      Create temporaries for buffer return values\r
11424                   data_type *adt = aggr_tbl.get_data_type(a);\r
11425                   if(adt->is_buffer_type()){\r
11426                         sprintf(tmpstr,"aggr_tmp_%d", a);\r
11427                         ret+=adt->make_host_cvar(tmpstr)+";\n";\r
11428                   }\r
11429                 }\r
11430         }\r
11431 \r
11432         for(a=0;a<aggr_tbl.size();a++){\r
11433                 sprintf(tmpstr,"aggval->aggr_var%d",a);\r
11434                 string assignto_var = tmpstr;\r
11435                 ret += "\t"+generate_aggr_init(assignto_var,&aggr_tbl,a, schema);\r
11436         }\r
11437 \r
11438         ret += "};\n\n";\r
11439 \r
11440 \r
11441 //--------------------------------------------------------\r
11442 //                      Create and clean-initialize an state object\r
11443 \r
11444         ret += "void initialize_state(host_tuple &tup0, "+generate_functor_name()+"_groupdef *gbval, "+generate_functor_name()+"_statedef *stval){\n";\r
11445         //              Variables for execution of the function.\r
11446         ret += "\tgs_int32_t problem = 0;\n";   // return unpack failure\r
11447 \r
11448 //              return value\r
11449 //      ret += "\t"+generate_functor_name()+"_statedef *stval = ("+generate_functor_name()+ "_statedef *)s;\n";\r
11450 \r
11451         for(a=0;a<aggr_tbl.size();a++){\r
11452                 if( aggr_tbl.is_superaggr(a)){\r
11453                         if(aggr_tbl.is_builtin(a)){\r
11454 //                      Create temporaries for buffer return values\r
11455                           data_type *adt = aggr_tbl.get_data_type(a);\r
11456                           if(adt->is_buffer_type()){\r
11457                                 sprintf(tmpstr,"aggr_tmp_%d", a);\r
11458                                 ret+=adt->make_host_cvar(tmpstr)+";\n";\r
11459                           }\r
11460                         }\r
11461                 }\r
11462         }\r
11463 \r
11464         for(a=0;a<aggr_tbl.size();a++){\r
11465                 if( aggr_tbl.is_superaggr(a)){\r
11466                         sprintf(tmpstr,"stval->aggr_var%d",a);\r
11467                         string assignto_var = tmpstr;\r
11468                         ret += "\t"+generate_aggr_init(assignto_var,&aggr_tbl,a, schema);\r
11469                 }\r
11470         }\r
11471 \r
11472         for(ssi=states_refd.begin(); ssi!=states_refd.end();++ssi){\r
11473                 string state_nm = (*ssi);\r
11474                 ret += "_sfun_state_clean_init_"+state_nm+"(&(stval->state_var_"+state_nm+"));\n";\r
11475         }\r
11476 \r
11477         ret += "};\n\n";\r
11478 \r
11479 \r
11480 //--------------------------------------------------------\r
11481 //                      Create and dirty-initialize an state object\r
11482 \r
11483         ret += "void reinitialize_state(host_tuple &tup0, "+generate_functor_name()+"_groupdef *gbval, "+generate_functor_name()+"_statedef *stval, "+generate_functor_name()+"_statedef *old_stval, int cd){\n";\r
11484         //              Variables for execution of the function.\r
11485         ret += "\tgs_int32_t problem = 0;\n";   // return unpack failure\r
11486 \r
11487 //              return value\r
11488 //      ret += "\t"+generate_functor_name()+"_statedef *stval = ("+generate_functor_name()+ "_statedef *)s;\n";\r
11489 \r
11490         for(a=0;a<aggr_tbl.size();a++){\r
11491                 if( aggr_tbl.is_superaggr(a)){\r
11492                         if(aggr_tbl.is_builtin(a)){\r
11493 //                      Create temporaries for buffer return values\r
11494                           data_type *adt = aggr_tbl.get_data_type(a);\r
11495                           if(adt->is_buffer_type()){\r
11496                                 sprintf(tmpstr,"aggr_tmp_%d", a);\r
11497                                 ret+=adt->make_host_cvar(tmpstr)+";\n";\r
11498                           }\r
11499                         }\r
11500                 }\r
11501         }\r
11502 \r
11503 //              initialize superaggregates\r
11504         for(a=0;a<aggr_tbl.size();a++){\r
11505                 if( aggr_tbl.is_superaggr(a)){\r
11506                         sprintf(tmpstr,"stval->aggr_var%d",a);\r
11507                         string assignto_var = tmpstr;\r
11508                         ret += "\t"+generate_aggr_init(assignto_var,&aggr_tbl,a, schema);\r
11509                 }\r
11510         }\r
11511 \r
11512         for(ssi=states_refd.begin(); ssi!=states_refd.end();++ssi){\r
11513                 string state_nm = (*ssi);\r
11514                 ret += "_sfun_state_dirty_init_"+state_nm+"(&(stval->state_var_"+state_nm+"),&(old_stval->state_var_"+state_nm+"), cd );\n";\r
11515         }\r
11516 \r
11517         ret += "};\n\n";\r
11518 \r
11519 //--------------------------------------------------------\r
11520 //              Finalize_state : call the finalize fcn on all states\r
11521 \r
11522 \r
11523         ret += "void finalize_state( "+generate_functor_name()+"_statedef *stval, int cd){\n";\r
11524 \r
11525         for(ssi=states_refd.begin(); ssi!=states_refd.end();++ssi){\r
11526                 string state_nm = (*ssi);\r
11527                 ret += "_sfun_state_final_init_"+state_nm+"(&(stval->state_var_"+state_nm+"), cd);\n";\r
11528         }\r
11529 \r
11530         ret += "};\n\n";\r
11531 \r
11532 \r
11533 \r
11534 \r
11535 //--------------------------------------------------------\r
11536 //                      update (plus) a superaggregate object\r
11537 \r
11538         ret += "void update_plus_superaggr(host_tuple &tup0, " +\r
11539                 generate_functor_name()+"_groupdef *gbval, "+\r
11540                 generate_functor_name()+"_statedef *stval){\n";\r
11541         //              Variables for execution of the function.\r
11542         ret += "\tgs_int32_t problem = 0;\n";   // return unpack failure\r
11543 \r
11544 //                      use of temporaries depends on the aggregate,\r
11545 //                      generate them in generate_aggr_update\r
11546 \r
11547 \r
11548         for(a=0;a<aggr_tbl.size();a++){\r
11549           if(aggr_tbl.is_superaggr(a)){\r
11550                 sprintf(tmpstr,"stval->aggr_var%d",a);\r
11551                 string varname = tmpstr;\r
11552                 ret.append(generate_aggr_update(varname,&aggr_tbl,a, schema));\r
11553           }\r
11554         }\r
11555 \r
11556         ret += "\treturn;\n";\r
11557         ret += "};\n";\r
11558 \r
11559 \r
11560 \r
11561 //--------------------------------------------------------\r
11562 //                      update (minus) a superaggregate object\r
11563 \r
11564         ret += "void update_minus_superaggr( "+\r
11565                 generate_functor_name()+"_groupdef *gbval, "+\r
11566                 generate_functor_name()+"_aggrdef *aggval,"+\r
11567                 generate_functor_name()+"_statedef *stval"+\r
11568                 "){\n";\r
11569         //              Variables for execution of the function.\r
11570         ret += "\tgs_int32_t problem = 0;\n";   // return unpack failure\r
11571 \r
11572 //                      use of temporaries depends on the aggregate,\r
11573 //                      generate them in generate_aggr_update\r
11574 \r
11575 \r
11576         for(a=0;a<aggr_tbl.size();a++){\r
11577           if(aggr_tbl.is_superaggr(a)){\r
11578                 sprintf(tmpstr,"stval->aggr_var%d",a);\r
11579                 string super_varname = tmpstr;\r
11580                 sprintf(tmpstr,"aggval->aggr_var%d",a);\r
11581                 string sub_varname = tmpstr;\r
11582                 ret.append(generate_superaggr_minus(sub_varname, super_varname,&aggr_tbl,a, schema));\r
11583           }\r
11584         }\r
11585 \r
11586         ret += "\treturn;\n";\r
11587         ret += "};\n";\r
11588 \r
11589 \r
11590 //--------------------------------------------------------\r
11591 //                      update an aggregate object\r
11592 \r
11593         ret += "void update_aggregate(host_tuple &tup0, "\r
11594                 +generate_functor_name()+"_groupdef *gbval, "+\r
11595                 generate_functor_name()+"_aggrdef *aggval,"+generate_functor_name()+"_statedef *stval, int cd){\n";\r
11596         //              Variables for execution of the function.\r
11597         ret += "\tgs_int32_t problem = 0;\n";   // return unpack failure\r
11598 \r
11599 //                      use of temporaries depends on the aggregate,\r
11600 //                      generate them in generate_aggr_update\r
11601 \r
11602 \r
11603         for(a=0;a<aggr_tbl.size();a++){\r
11604           sprintf(tmpstr,"aggval->aggr_var%d",a);\r
11605           string varname = tmpstr;\r
11606           ret.append(generate_aggr_update(varname,&aggr_tbl,a, schema));\r
11607         }\r
11608 \r
11609         ret += "\treturn;\n";\r
11610         ret += "};\n";\r
11611 \r
11612 //---------------------------------------------------\r
11613 //                      Flush test\r
11614 \r
11615         ret += "\tbool flush_needed(){\n";\r
11616         if(uses_temporal_flush){\r
11617                 ret += "\t\treturn needs_temporal_flush;\n";\r
11618         }else{\r
11619                 ret += "\t\treturn false;\n";\r
11620         }\r
11621         ret += "\t};\n";\r
11622 \r
11623 \r
11624 //------------------------------------------------------\r
11625 //                      THe cleaning_when predicate\r
11626 \r
11627         string gbvar = "gbval->gb_var";\r
11628         string aggvar = "aggval->";\r
11629 \r
11630         ret += "bool need_to_clean( "\r
11631                 +generate_functor_name()+"_groupdef *gbval, "+\r
11632                 generate_functor_name()+"_statedef *stval, int cd"+\r
11633                 "){\n";\r
11634 \r
11635         if(cleanwhen.size()>0)\r
11636                 ret += "\tbool predval = true;\n";\r
11637         else\r
11638                 ret += "\tbool predval = false;\n";\r
11639 \r
11640 //                      Find the udafs ref'd in the having clause\r
11641         set<int> cw_aggs;\r
11642         for(w=0;w<cleanwhen.size();++w)\r
11643                 collect_aggr_refs_pr(cleanwhen[w]->pr, cw_aggs);\r
11644 \r
11645 \r
11646 //                      get the return values from the UDAFS\r
11647         for(a=0;a<aggr_tbl.size();a++){\r
11648                 if(! aggr_tbl.is_builtin(a) && cw_aggs.count(a)){\r
11649                         ret += "\t"+aggr_tbl.get_op(a)+"_HFTA_AGGR_OUTPUT_(&(udaf_ret_"+int_to_string(a)+"),";\r
11650                         if(aggr_tbl.get_storage_type(a)->get_type() != fstring_t) ret+="&";\r
11651                         ret+="("+aggvar+"aggr_var"+int_to_string(a)+"));\n";\r
11652                 }\r
11653         }\r
11654 \r
11655 \r
11656 //              Start by cleaning up partial function results\r
11657         ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";\r
11658         set<int> cw_pfcns;      // partial fcns in where clause\r
11659         for(w=0;w<cleanwhen.size();++w)\r
11660                 collect_partial_fcns_pr(cleanwhen[w]->pr, cw_pfcns);\r
11661 \r
11662         ret += gen_partial_fcn_dtr(partial_fcns,cw_pfcns);\r
11663 \r
11664 \r
11665         for(w=0;w<cleanwhen.size();++w){\r
11666                 sprintf(tmpstr,"//\t\tPredicate clause %d.\n",w);\r
11667                 ret += tmpstr;\r
11668 //                      Find partial fcns ref'd in this cnf element\r
11669                 set<int> pfcn_refs;\r
11670                 collect_partial_fcns_pr(cleanwhen[w]->pr, pfcn_refs);\r
11671                 for(pfsi=pfcn_refs.begin();pfsi!=pfcn_refs.end();++pfsi){\r
11672                         ret += unpack_partial_fcn_fm_aggr(partial_fcns[(*pfsi)], (*pfsi), gbvar, aggvar, schema);\r
11673                         ret += "\tif(retval){ return false;}\n";\r
11674                 }\r
11675 //              ret += unpack_partial_fcn_fm_aggr(schema, partial_fcns, pfcn_refs,"false");\r
11676 \r
11677                 ret += "\tif( !("+generate_predicate_code_fm_aggr(cleanwhen[w]->pr,gbvar, aggvar, schema)+\r
11678                                 ") ) predval = false;\n";\r
11679         }\r
11680 \r
11681         ret += "\treturn predval;\n";\r
11682         ret += "\t};\n";\r
11683 \r
11684 //------------------------------------------------------\r
11685 //                      THe cleaning_by predicate\r
11686 \r
11687         ret += "bool sample_group("\r
11688                 +generate_functor_name()+"_groupdef *gbval, "+\r
11689                 generate_functor_name()+"_aggrdef *aggval,"+\r
11690                 generate_functor_name()+"_statedef *stval, int cd"+\r
11691                 "){\n";\r
11692 \r
11693         if(cleanby.size()>0)\r
11694                 ret += "\tbool retval = true;\n";\r
11695         else\r
11696                 ret += "\tbool retval = false;\n";\r
11697 \r
11698 //                      Find the udafs ref'd in the having clause\r
11699         set<int> cb_aggs;\r
11700         for(w=0;w<cleanby.size();++w)\r
11701                 collect_aggr_refs_pr(cleanby[w]->pr, cb_aggs);\r
11702 \r
11703 \r
11704 //                      get the return values from the UDAFS\r
11705         for(a=0;a<aggr_tbl.size();a++){\r
11706                 if(! aggr_tbl.is_builtin(a) && cb_aggs.count(a)){\r
11707                         ret += "\t"+aggr_tbl.get_op(a)+"_HFTA_AGGR_OUTPUT_(&(udaf_ret_"+int_to_string(a)+"),";\r
11708                         if(aggr_tbl.get_storage_type(a)->get_type() != fstring_t) ret+="&";\r
11709                         ret+="("+aggvar+"aggr_var"+int_to_string(a)+"));\n";\r
11710                 }\r
11711         }\r
11712 \r
11713 \r
11714 //              Start by cleaning up partial function results\r
11715         ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";\r
11716         set<int> cb_pfcns;      // partial fcns in where clause\r
11717         for(w=0;w<cleanby.size();++w)\r
11718                 collect_partial_fcns_pr(cleanby[w]->pr, cb_pfcns);\r
11719 \r
11720         ret += gen_partial_fcn_dtr(partial_fcns,cb_pfcns);\r
11721 \r
11722 \r
11723         for(w=0;w<cleanwhen.size();++w){\r
11724                 sprintf(tmpstr,"//\t\tPredicate clause %d.\n",w);\r
11725                 ret += tmpstr;\r
11726 \r
11727 /*\r
11728 //                      Find the set of variables accessed in this CNF elem,\r
11729 //                      but in no previous element.\r
11730                 col_id_set new_cids;\r
11731                 get_new_pred_cids(cleanby[w]->pr, found_cids, new_cids, segen_gb_tbl);\r
11732 \r
11733 //                      Unpack these values.\r
11734                 ret += gen_unpack_cids(schema, new_cids, "false", needs_xform);\r
11735 */\r
11736 \r
11737 //                      Find partial fcns ref'd in this cnf element\r
11738                 set<int> pfcn_refs;\r
11739                 collect_partial_fcns_pr(cleanby[w]->pr, pfcn_refs);\r
11740                 for(pfsi=pfcn_refs.begin();pfsi!=pfcn_refs.end();++pfsi){\r
11741                         ret += unpack_partial_fcn_fm_aggr(partial_fcns[(*pfsi)], (*pfsi), gbvar, aggvar, schema);\r
11742                         ret += "\tif(retval){ return false;}\n";\r
11743                 }\r
11744 //              ret += gen_unpack_partial_fcn(schema, partial_fcns, pfcn_refs,"false");\r
11745 \r
11746                 ret += "\tif( !("+generate_predicate_code_fm_aggr(cleanby[w]->pr,gbvar, aggvar, schema)+\r
11747                         +") ) retval = false;\n";\r
11748         }\r
11749 \r
11750         ret += "\treturn retval;\n";\r
11751         ret += "\t};\n";\r
11752 \r
11753 \r
11754 //-----------------------------------------------------\r
11755 //\r
11756         ret += "bool final_sample_group("\r
11757                 +generate_functor_name()+"_groupdef *gbval, "+\r
11758                 generate_functor_name()+"_aggrdef *aggval,"+\r
11759                 generate_functor_name()+"_statedef *stval,"+\r
11760                 "int cd){\n";\r
11761 \r
11762         ret += "\tgs_retval_t retval = 0;\n";\r
11763 \r
11764 //                      Find the udafs ref'd in the having clause\r
11765         set<int> hv_aggs;\r
11766         for(w=0;w<having.size();++w)\r
11767                 collect_aggr_refs_pr(having[w]->pr, hv_aggs);\r
11768 \r
11769 \r
11770 //                      get the return values from the UDAFS\r
11771         for(a=0;a<aggr_tbl.size();a++){\r
11772                 if(! aggr_tbl.is_builtin(a) && hv_aggs.count(a)){\r
11773                         ret += "\t"+aggr_tbl.get_op(a)+"_HFTA_AGGR_OUTPUT_(&(udaf_ret_"+int_to_string(a)+"),";\r
11774                         if(aggr_tbl.get_storage_type(a)->get_type() != fstring_t) ret+="&";\r
11775                         ret+="("+aggvar+"aggr_var"+int_to_string(a)+"));\n";\r
11776                 }\r
11777         }\r
11778 \r
11779 \r
11780         set<int> hv_sl_pfcns;\r
11781         for(w=0;w<having.size();w++){\r
11782                 collect_partial_fcns_pr(having[w]->pr, hv_sl_pfcns);\r
11783         }\r
11784 \r
11785 //              clean up the partial fcn results from any previous execution\r
11786         ret += gen_partial_fcn_dtr(partial_fcns,hv_sl_pfcns);\r
11787 \r
11788 //              Unpack them now\r
11789         for(pfsi=hv_sl_pfcns.begin();pfsi!=hv_sl_pfcns.end();++pfsi){\r
11790                 ret += unpack_partial_fcn_fm_aggr(partial_fcns[(*pfsi)], (*pfsi), gbvar, aggvar, schema);\r
11791                 ret += "\tif(retval){ return false;}\n";\r
11792         }\r
11793 \r
11794 //              Evalaute the HAVING clause\r
11795 //              TODO: this seems to have a ++ operator rather than a + operator.\r
11796         for(w=0;w<having.size();++w){\r
11797                 ret += "\tif( !("+generate_predicate_code_fm_aggr(having[w]->pr,gbvar, aggvar, schema) +") ) { return false;}\n";\r
11798         }\r
11799 \r
11800         ret += "\treturn true;\n";\r
11801         ret+="}\n\n";\r
11802 \r
11803 //---------------------------------------------------\r
11804 //                      create output tuple\r
11805 //                      Unpack the partial functions ref'd in the where clause,\r
11806 //                      select clause.  Evaluate the where clause.\r
11807 //                      Finally, pack the tuple.\r
11808 \r
11809 //                      I need to use special code generation here,\r
11810 //                      so I'll leave it in longhand.\r
11811 \r
11812         ret += "host_tuple create_output_tuple("\r
11813                 +generate_functor_name()+"_groupdef *gbval, "+\r
11814                 generate_functor_name()+"_aggrdef *aggval,"+\r
11815                 generate_functor_name()+"_statedef *stval,"+\r
11816                 "int cd, bool &failed){\n";\r
11817 \r
11818         ret += "\thost_tuple tup;\n";\r
11819         ret += "\tfailed = false;\n";\r
11820         ret += "\tgs_retval_t retval = 0;\n";\r
11821 \r
11822 \r
11823 //                      Find the udafs ref'd in the select clause\r
11824         set<int> sl_aggs;\r
11825         for(s=0;s<select_list.size();s++)\r
11826                 collect_agg_refs(select_list[s]->se, sl_aggs);\r
11827 \r
11828 \r
11829 //                      get the return values from the UDAFS\r
11830         for(a=0;a<aggr_tbl.size();a++){\r
11831                 if(! aggr_tbl.is_builtin(a) && sl_aggs.count(a)){\r
11832                         ret += "\t"+aggr_tbl.get_op(a)+"_HFTA_AGGR_OUTPUT_(&(udaf_ret_"+int_to_string(a)+"),";\r
11833                         if(aggr_tbl.get_storage_type(a)->get_type() != fstring_t) ret+="&";\r
11834                         ret+="("+aggvar+"aggr_var"+int_to_string(a)+"));\n";\r
11835                 }\r
11836         }\r
11837 \r
11838 \r
11839 //                      I can't cache partial fcn results from the having\r
11840 //                      clause because evaluation is separated.\r
11841         set<int> sl_pfcns;\r
11842         for(s=0;s<select_list.size();s++){\r
11843                 collect_partial_fcns(select_list[s]->se, sl_pfcns);\r
11844         }\r
11845 //              Unpack them now\r
11846         for(pfsi=sl_pfcns.begin();pfsi!=sl_pfcns.end();++pfsi){\r
11847                 ret += unpack_partial_fcn_fm_aggr(partial_fcns[(*pfsi)], (*pfsi), gbvar, aggvar, schema);\r
11848                 ret += "\tif(retval){ failed=true; return tup;}\n";\r
11849         }\r
11850 \r
11851 \r
11852 //          Now, compute the size of the tuple.\r
11853 \r
11854 //          Unpack any BUFFER type selections into temporaries\r
11855 //          so that I can compute their size and not have\r
11856 //          to recompute their value during tuple packing.\r
11857 //          I can use regular assignment here because\r
11858 //          these temporaries are non-persistent.\r
11859 //                      TODO: should I be using the selvar generation routine?\r
11860 \r
11861         ret += "//\t\tCompute the size of the tuple.\n";\r
11862         ret += "//\t\t\tNote: buffer storage packed at the end of the tuple.\n";\r
11863       for(s=0;s<select_list.size();s++){\r
11864                 scalarexp_t *se = select_list[s]->se;\r
11865         data_type *sdt = se->get_data_type();\r
11866         if(sdt->is_buffer_type() &&\r
11867                          !( (se->get_operator_type() == SE_COLREF) ||\r
11868                                 (se->get_operator_type() == SE_AGGR_STAR) ||\r
11869                                 (se->get_operator_type() == SE_AGGR_SE) ||\r
11870                            (se->get_operator_type() == SE_FUNC && se->is_partial()) ||\r
11871                            (se->get_operator_type() == SE_FUNC && se->get_aggr_ref() >= 0))\r
11872                 ){\r
11873             sprintf(tmpstr,"selvar_%d",s);\r
11874                         ret+="\t"+sdt->make_host_cvar(tmpstr)+" = ";\r
11875                         ret += generate_se_code_fm_aggr(se,gbvar, aggvar, schema) +";\n";\r
11876         }\r
11877       }\r
11878 \r
11879 //      The size of the tuple is the size of the tuple struct plus the\r
11880 //      size of the buffers to be copied in.\r
11881 \r
11882       ret+="\ttup.tuple_size = sizeof(" + generate_tuple_name( this->get_node_name()) +") + sizeof(gs_uint8_t)";\r
11883       for(s=0;s<select_list.size();s++){\r
11884 //              if(s>0) ret += "+";\r
11885                 scalarexp_t *se = select_list[s]->se;\r
11886         data_type *sdt = select_list[s]->se->get_data_type();\r
11887         if(sdt->is_buffer_type()){\r
11888                   if(!( (se->get_operator_type() == SE_COLREF) ||\r
11889                                 (se->get_operator_type() == SE_AGGR_STAR) ||\r
11890                                 (se->get_operator_type() == SE_AGGR_SE) ||\r
11891                            (se->get_operator_type() == SE_FUNC && se->is_partial()) ||\r
11892                            (se->get_operator_type() == SE_FUNC && se->get_aggr_ref() >= 0))\r
11893                   ){\r
11894             sprintf(tmpstr," + %s(&selvar_%d)", sdt->get_hfta_buffer_size().c_str(),s);\r
11895             ret.append(tmpstr);\r
11896                   }else{\r
11897             sprintf(tmpstr," + %s(&%s)", sdt->get_hfta_buffer_size().c_str(),generate_se_code_fm_aggr(se,gbvar, aggvar, schema).c_str());\r
11898             ret.append(tmpstr);\r
11899                   }\r
11900         }\r
11901       }\r
11902       ret.append(";\n");\r
11903 \r
11904 //              Allocate tuple data block.\r
11905         ret += "//\t\tCreate the tuple block.\n";\r
11906           ret += "\ttup.data = malloc(tup.tuple_size);\n";\r
11907           ret += "\ttup.heap_resident = true;\n";\r
11908 \r
11909 //              Mark tuple as regular\r
11910           ret += "\t*((gs_sp_t )tup.data + sizeof(" + generate_tuple_name( this->get_node_name()) +")) = REGULAR_TUPLE;\n";\r
11911 \r
11912 //        ret += "\ttup.channel = 0;\n";\r
11913           ret += "\t"+generate_tuple_name( this->get_node_name())+" *tuple = ("+\r
11914                                 generate_tuple_name( this->get_node_name())+" *)(tup.data);\n";\r
11915 \r
11916 //              Start packing.\r
11917 //                      (Here, offsets are hard-wired.  is this a problem?)\r
11918 \r
11919         ret += "//\t\tPack the fields into the tuple.\n";\r
11920           ret += "\tint tuple_pos = sizeof("+generate_tuple_name( this->get_node_name()) +") + sizeof(gs_uint8_t);\n";\r
11921       for(s=0;s<select_list.size();s++){\r
11922                 scalarexp_t *se = select_list[s]->se;\r
11923         data_type *sdt = se->get_data_type();\r
11924         if(sdt->is_buffer_type()){\r
11925                   if(!( (se->get_operator_type() == SE_COLREF) ||\r
11926                                 (se->get_operator_type() == SE_AGGR_STAR) ||\r
11927                                 (se->get_operator_type() == SE_AGGR_SE) ||\r
11928                            (se->get_operator_type() == SE_FUNC && se->is_partial()) ||\r
11929                            (se->get_operator_type() == SE_FUNC && se->get_aggr_ref() >= 0))\r
11930                   ){\r
11931             sprintf(tmpstr,"\t%s(&(tuple->tuple_var%d), &selvar_%d,  ((gs_sp_t )tuple)+tuple_pos, tuple_pos);\n", sdt->get_hfta_buffer_tuple_copy().c_str(),s, s);\r
11932             ret.append(tmpstr);\r
11933             sprintf(tmpstr,"\ttuple_pos += %s(&selvar_%d);\n", sdt->get_hfta_buffer_size().c_str(), s);\r
11934             ret.append(tmpstr);\r
11935                   }else{\r
11936             sprintf(tmpstr,"\t%s(&(tuple->tuple_var%d), &%s,  ((gs_sp_t )tuple)+tuple_pos, tuple_pos);\n", sdt->get_hfta_buffer_tuple_copy().c_str(),s, generate_se_code_fm_aggr(se,gbvar, aggvar, schema).c_str());\r
11937             ret.append(tmpstr);\r
11938             sprintf(tmpstr,"\ttuple_pos += %s(&%s);\n", sdt->get_hfta_buffer_size().c_str(), generate_se_code_fm_aggr(se,gbvar, aggvar, schema).c_str());\r
11939             ret.append(tmpstr);\r
11940                   }\r
11941         }else{\r
11942             sprintf(tmpstr,"\ttuple->tuple_var%d = ",s);\r
11943             ret.append(tmpstr);\r
11944             ret.append(generate_se_code_fm_aggr(se,gbvar, aggvar, schema) );\r
11945             ret.append(";\n");\r
11946         }\r
11947       }\r
11948 \r
11949 //                      Destroy string temporaries\r
11950           ret += gen_buffer_selvars_dtr(select_list);\r
11951 //                      Destroy string return vals of UDAFs\r
11952         for(a=0;a<aggr_tbl.size();a++){\r
11953                 if(! aggr_tbl.is_builtin(a)){\r
11954                         int afcn_id = aggr_tbl.get_fcn_id(a);\r
11955                         data_type *adt = Ext_fcns->get_fcn_dt(afcn_id);\r
11956                         if(adt->is_buffer_type()){\r
11957                                 sprintf(tmpstr,"\t%s(&udaf_ret_%d);\n",\r
11958                                 adt->get_hfta_buffer_destroy().c_str(), a );\r
11959                                 ret += tmpstr;\r
11960                         }\r
11961                 }\r
11962         }\r
11963 \r
11964 \r
11965           ret += "\treturn tup;\n";\r
11966           ret += "};\n";\r
11967 \r
11968 \r
11969 //-------------------------------------------------------------------\r
11970 //              Temporal update functions\r
11971 \r
11972         ret+="bool temp_status_received(){return temp_tuple_received;};\n\n";\r
11973 \r
11974 //              create a temp status tuple\r
11975         ret += "int create_temp_status_tuple(host_tuple& result, bool flush_finished) {\n\n";\r
11976 \r
11977         ret += gen_init_temp_status_tuple(this->get_node_name());\r
11978 \r
11979 //              Start packing.\r
11980 //                      (Here, offsets are hard-wired.  is this a problem?)\r
11981 \r
11982         ret += "//\t\tPack the fields into the tuple.\n";\r
11983         for(s=0;s<select_list.size();s++){\r
11984                 data_type *sdt = select_list[s]->se->get_data_type();\r
11985                 if(sdt->is_temporal()){\r
11986                         sprintf(tmpstr,"\ttuple->tuple_var%d = ",s);\r
11987                         ret += tmpstr;\r
11988                         sprintf(tmpstr,"(flush_finished) ? %s : %s ", generate_se_code(select_list[s]->se,schema).c_str(), generate_se_code_fm_aggr(select_list[s]->se,"last_flushed_gb", "", schema).c_str());\r
11989                         ret += tmpstr;\r
11990                         ret += ";\n";\r
11991                 }\r
11992         }\r
11993 \r
11994         ret += "\treturn 0;\n";\r
11995         ret += "};};\n\n\n";\r
11996 \r
11997 \r
11998 //----------------------------------------------------------\r
11999 //                      The hash function\r
12000 \r
12001         ret += "struct "+generate_functor_name()+"_hash_func{\n";\r
12002         ret += "\tgs_uint32_t operator()(const "+generate_functor_name()+\r
12003                                 "_groupdef *grp) const{\n";\r
12004         ret += "\t\treturn(";\r
12005         for(g=0;g<gb_tbl.size();g++){\r
12006                 if(g>0) ret += "^";\r
12007                 data_type *gdt = gb_tbl.get_data_type(g);\r
12008                 if(gdt->use_hashfunc()){\r
12009                         if(gdt->is_buffer_type())\r
12010                                 sprintf(tmpstr,"(%s*%s(&)grp->gb_var%d)))",hash_nums[g%NRANDS].c_str(),gdt->get_hfta_hashfunc().c_str(),g);\r
12011                         else\r
12012                                 sprintf(tmpstr,"(%s*%s(grp->gb_var%d))",hash_nums[g%NRANDS].c_str(),gdt->get_hfta_hashfunc().c_str(),g);\r
12013                 }else{\r
12014                         sprintf(tmpstr,"(%s*grp->gb_var%d)",hash_nums[g%NRANDS].c_str(),g);\r
12015                 }\r
12016                 ret += tmpstr;\r
12017         }\r
12018         ret += ") >> 32);\n";\r
12019         ret += "\t}\n";\r
12020         ret += "};\n\n";\r
12021 \r
12022 //----------------------------------------------------------\r
12023 //                      The superhash function\r
12024 \r
12025         ret += "struct "+generate_functor_name()+"_superhash_func{\n";\r
12026         ret += "\tgs_uint32_t operator()(const "+generate_functor_name()+\r
12027                                 "_groupdef *grp) const{\n";\r
12028         ret += "\t\treturn(0";\r
12029 \r
12030         for(g=0;g<gb_tbl.size();g++){\r
12031                 if(sg_tbl.count(g)>0){\r
12032                         ret += "^";\r
12033                         data_type *gdt = gb_tbl.get_data_type(g);\r
12034                         if(gdt->use_hashfunc()){\r
12035                                 sprintf(tmpstr,"(%s*%s(&(grp->gb_var%d)))",hash_nums[g%NRANDS].c_str(),gdt->get_hfta_hashfunc().c_str(),g);\r
12036                         }else{\r
12037                                 sprintf(tmpstr,"(%s*grp->gb_var%d)",hash_nums[g%NRANDS].c_str(),g);\r
12038                         }\r
12039                         ret += tmpstr;\r
12040                 }\r
12041         }\r
12042         ret += ") >> 32);\n";\r
12043 \r
12044         ret += "\t}\n";\r
12045         ret += "};\n\n";\r
12046 \r
12047 //----------------------------------------------------------\r
12048 //                      The comparison function\r
12049 \r
12050         ret += "struct "+generate_functor_name()+"_equal_func{\n";\r
12051         ret += "\tbool operator()(const "+generate_functor_name()+"_groupdef *grp1, "+\r
12052                         generate_functor_name()+"_groupdef *grp2) const{\n";\r
12053         ret += "\t\treturn( (";\r
12054         for(g=0;g<gb_tbl.size();g++){\r
12055                 if(g>0) ret += ") && (";\r
12056                 data_type *gdt = gb_tbl.get_data_type(g);\r
12057                 if(gdt->complex_comparison(gdt)){\r
12058                   if(gdt->is_buffer_type())\r
12059                         sprintf(tmpstr,"(%s(&(grp1->gb_var%d), &(grp2->gb_var%d))==0)",\r
12060                                 gdt->get_hfta_comparison_fcn(gdt).c_str(),g,g);\r
12061                   else\r
12062                         sprintf(tmpstr,"(%s((grp1->gb_var%d), (grp2->gb_var%d))==0)",\r
12063                                 gdt->get_hfta_comparison_fcn(gdt).c_str(),g,g);\r
12064                 }else{\r
12065                         sprintf(tmpstr,"grp1->gb_var%d == grp2->gb_var%d",g,g);\r
12066                 }\r
12067                 ret += tmpstr;\r
12068         }\r
12069         ret += ") );\n";\r
12070         ret += "\t}\n";\r
12071         ret += "};\n\n";\r
12072 \r
12073 \r
12074 //----------------------------------------------------------\r
12075 //                      The superhashcomparison function\r
12076 \r
12077         ret += "struct "+generate_functor_name()+"_superequal_func{\n";\r
12078         ret += "\tbool operator()(const "+generate_functor_name()+"_groupdef *grp1, "+\r
12079                         generate_functor_name()+"_groupdef *grp2) const{\n";\r
12080         ret += "\t\treturn( (";\r
12081     if(sg_tbl.size()){\r
12082                 bool first_elem = true;\r
12083                 for(g=0;g<gb_tbl.size();g++){\r
12084                         if(sg_tbl.count(g)){\r
12085                                 if(first_elem) first_elem=false; else ret += ") && (";\r
12086                                 data_type *gdt = gb_tbl.get_data_type(g);\r
12087                                 if(gdt->complex_comparison(gdt)){\r
12088                                   if(gdt->is_buffer_type())\r
12089                                         sprintf(tmpstr,"(%s(&(grp1->gb_var%d), &(grp2->gb_var%d))==0)",\r
12090                                                 gdt->get_hfta_comparison_fcn(gdt).c_str(),g,g);\r
12091                                   else\r
12092                                         sprintf(tmpstr,"(%s((grp1->gb_var%d), (grp2->gb_var%d))==0)",\r
12093                                                 gdt->get_hfta_comparison_fcn(gdt).c_str(),g,g);\r
12094                                 }else{\r
12095                                         sprintf(tmpstr,"grp1->gb_var%d == grp2->gb_var%d",g,g);\r
12096                                 }\r
12097                         ret += tmpstr;\r
12098                         }\r
12099                 }\r
12100         }else{\r
12101                 ret += "true";\r
12102         }\r
12103 \r
12104         ret += ") );\n";\r
12105         ret += "\t}\n";\r
12106 \r
12107 \r
12108         ret += "};\n\n";\r
12109         return(ret);\r
12110 }\r
12111 \r
12112 string sgahcwcb_qpn::generate_operator(int i, string params){\r
12113 \r
12114                 return(\r
12115                         "       clean_operator<" +\r
12116                         generate_functor_name()+",\n\t"+\r
12117                         generate_functor_name() + "_groupdef, \n\t" +\r
12118                         generate_functor_name() + "_aggrdef, \n\t" +\r
12119                         generate_functor_name() + "_statedef, \n\t" +\r
12120                         generate_functor_name()+"_hash_func, \n\t"+\r
12121                         generate_functor_name()+"_equal_func ,\n\t"+\r
12122                         generate_functor_name()+"_superhash_func,\n\t "+\r
12123                         generate_functor_name()+"_superequal_func \n\t"+\r
12124                         "> *op"+int_to_string(i)+" = new clean_operator<"+\r
12125                         generate_functor_name()+",\n\t"+\r
12126                         generate_functor_name() + "_groupdef,\n\t " +\r
12127                         generate_functor_name() + "_aggrdef, \n\t" +\r
12128                         generate_functor_name() + "_statedef, \n\t" +\r
12129                         generate_functor_name()+"_hash_func, \n\t"+\r
12130                         generate_functor_name()+"_equal_func, \n\t"+\r
12131                         generate_functor_name()+"_superhash_func, \n\t"+\r
12132                         generate_functor_name()+"_superequal_func\n\t "\r
12133                         ">("+params+", \"" + get_node_name() + "\");\n"\r
12134                 );\r
12135 }\r
12136 \r
12137 ////////////////////////////////////////////////////////////////\r
12138 ////    RSGAH functor\r
12139 \r
12140 \r
12141 \r
12142 string rsgah_qpn::generate_functor_name(){\r
12143         return("rsgah_functor_" + normalize_name(this->get_node_name()));\r
12144 }\r
12145 \r
12146 \r
12147 string rsgah_qpn::generate_functor(table_list *schema, ext_fcn_list *Ext_fcns, vector<bool> &needs_xform){\r
12148         int a,g,w,s;\r
12149 \r
12150 \r
12151 //                      Initialize generate utility globals\r
12152         segen_gb_tbl = &(gb_tbl);\r
12153 \r
12154 \r
12155 //--------------------------------\r
12156 //                      group definition class\r
12157         string ret = "class " + generate_functor_name() + "_groupdef{\n";\r
12158         ret += "public:\n";\r
12159         for(g=0;g<this->gb_tbl.size();g++){\r
12160                 sprintf(tmpstr,"gb_var%d",g);\r
12161                 ret+="\t"+this->gb_tbl.get_data_type(g)->make_host_cvar(tmpstr)+";\n";\r
12162         }\r
12163 //              Constructors\r
12164         ret += "\t"+generate_functor_name() + "_groupdef(){};\n";\r
12165         ret += "\t"+generate_functor_name() + "_groupdef("+\r
12166                 this->generate_functor_name() + "_groupdef *gd){\n";\r
12167         for(g=0;g<gb_tbl.size();g++){\r
12168                 data_type *gdt = gb_tbl.get_data_type(g);\r
12169                 if(gdt->is_buffer_type()){\r
12170                         sprintf(tmpstr,"\t\t%s(&gb_var%d, &(gd->gb_var%d));\n",\r
12171                           gdt->get_hfta_buffer_assign_copy().c_str(),g,g );\r
12172                         ret += tmpstr;\r
12173                 }else{\r
12174                         sprintf(tmpstr,"\t\tgb_var%d = gd->gb_var%d;\n",g,g);\r
12175                         ret += tmpstr;\r
12176                 }\r
12177         }\r
12178         ret += "\t};\n";\r
12179 //              destructor\r
12180         ret += "\t~"+ generate_functor_name() + "_groupdef(){\n";\r
12181         for(g=0;g<gb_tbl.size();g++){\r
12182                 data_type *gdt = gb_tbl.get_data_type(g);\r
12183                 if(gdt->is_buffer_type()){\r
12184                         sprintf(tmpstr,"\t\t%s(&gb_var%d);\n",\r
12185                           gdt->get_hfta_buffer_destroy().c_str(), g );\r
12186                         ret += tmpstr;\r
12187                 }\r
12188         }\r
12189         ret += "\t};\n";\r
12190         ret +="};\n\n";\r
12191 \r
12192 //--------------------------------\r
12193 //                      aggr definition class\r
12194         ret += "class " + this->generate_functor_name() + "_aggrdef{\n";\r
12195         ret += "public:\n";\r
12196         for(a=0;a<aggr_tbl.size();a++){\r
12197 aggr_table_entry *ate = aggr_tbl.agr_tbl[a];\r
12198                 sprintf(tmpstr,"aggr_var%d",a);\r
12199                 if(aggr_tbl.is_builtin(a))\r
12200                   ret+="\t"+ aggr_tbl.get_data_type(a)->make_host_cvar(tmpstr)+";\n";\r
12201                 else\r
12202                   ret+="\t"+ aggr_tbl.get_storage_type(a)->make_host_cvar(tmpstr)+";\n";\r
12203         }\r
12204 //              Constructors\r
12205         ret += "\t"+this->generate_functor_name() + "_aggrdef(){};\n";\r
12206 //              destructor\r
12207         ret += "\t~"+this->generate_functor_name() + "_aggrdef(){\n";\r
12208         for(a=0;a<aggr_tbl.size();a++){\r
12209                 if(aggr_tbl.is_builtin(a)){\r
12210                         data_type *adt = aggr_tbl.get_data_type(a);\r
12211                         if(adt->is_buffer_type()){\r
12212                                 sprintf(tmpstr,"\t\t%s(&aggr_var%d);\n",\r
12213                                 adt->get_hfta_buffer_destroy().c_str(), a );\r
12214                                 ret += tmpstr;\r
12215                         }\r
12216                 }else{\r
12217                         ret+="\t\t"+aggr_tbl.get_op(a)+"_HFTA_AGGR_DESTROY_(";\r
12218                         if(aggr_tbl.get_storage_type(a)->get_type() != fstring_t) ret+="&";\r
12219                         ret+="(aggr_var"+int_to_string(a)+"));\n";\r
12220                 }\r
12221         }\r
12222         ret += "\t};\n";\r
12223         ret +="};\n\n";\r
12224 \r
12225 //--------------------------------\r
12226 //                      gb functor class\r
12227         ret += "class " + this->generate_functor_name() + "{\n";\r
12228 \r
12229 //                      Find variables referenced in this query node.\r
12230 \r
12231   col_id_set cid_set;\r
12232   col_id_set::iterator csi;\r
12233 \r
12234     for(w=0;w<where.size();++w)\r
12235         gather_pr_col_ids(where[w]->pr,cid_set,segen_gb_tbl);\r
12236     for(w=0;w<having.size();++w)\r
12237         gather_pr_col_ids(having[w]->pr,cid_set,segen_gb_tbl);\r
12238     for(w=0;w<closing_when.size();++w)\r
12239         gather_pr_col_ids(closing_when[w]->pr,cid_set,segen_gb_tbl);\r
12240         for(g=0;g<gb_tbl.size();g++)\r
12241                 gather_se_col_ids(gb_tbl.get_def(g),cid_set,segen_gb_tbl);\r
12242 \r
12243     for(s=0;s<select_list.size();s++){\r
12244         gather_se_col_ids(select_list[s]->se,cid_set,segen_gb_tbl);     // descends into aggregates\r
12245     }\r
12246 \r
12247 \r
12248 //                      Private variables : store the state of the functor.\r
12249 //                      1) variables for unpacked attributes\r
12250 //                      2) offsets of the upacked attributes\r
12251 //                      3) storage of partial functions\r
12252 //                      4) storage of complex literals (i.e., require a constructor)\r
12253 \r
12254         ret += "private:\n";\r
12255 \r
12256         // var to save the schema handle\r
12257         ret += "\tint schema_handle0;\n";\r
12258 \r
12259         // generate the declaration of all the variables related to\r
12260         // temp tuples generation\r
12261         ret += gen_decl_temp_vars();\r
12262 \r
12263 //                      unpacked attribute storage, offsets\r
12264         ret += "//\t\tstorage and offsets of accessed fields.\n";\r
12265         ret += generate_access_vars(cid_set, schema);\r
12266 //                      tuple metadata offset\r
12267         ret += "\tint tuple_metadata_offset0;\n";\r
12268 \r
12269 //                      Variables to store results of partial functions.\r
12270 //                      WARNING find_partial_functions modifies the SE\r
12271 //                      (it marks the partial function id).\r
12272         ret += "//\t\tParital function result storage\n";\r
12273         vector<scalarexp_t *> partial_fcns;\r
12274         vector<int> fcn_ref_cnt;\r
12275         vector<bool> is_partial_fcn;\r
12276         for(s=0;s<select_list.size();s++){\r
12277                 find_partial_fcns(select_list[s]->se, &partial_fcns, NULL,NULL, Ext_fcns);\r
12278         }\r
12279         for(w=0;w<where.size();w++){\r
12280                 find_partial_fcns_pr(where[w]->pr, &partial_fcns, NULL,NULL, Ext_fcns);\r
12281         }\r
12282         for(w=0;w<having.size();w++){\r
12283                 find_partial_fcns_pr(having[w]->pr, &partial_fcns, NULL,NULL, Ext_fcns);\r
12284         }\r
12285         for(w=0;w<closing_when.size();w++){\r
12286                 find_partial_fcns_pr(closing_when[w]->pr, &partial_fcns, NULL,NULL, Ext_fcns);\r
12287         }\r
12288         for(g=0;g<gb_tbl.size();g++){\r
12289                 find_partial_fcns(gb_tbl.get_def(g), &partial_fcns, NULL,NULL, Ext_fcns);\r
12290         }\r
12291         for(a=0;a<aggr_tbl.size();a++){\r
12292                 find_partial_fcns(aggr_tbl.get_aggr_se(a), &partial_fcns, NULL,NULL, Ext_fcns);\r
12293         }\r
12294         if(partial_fcns.size()>0){\r
12295           ret += "/*\t\tVariables for storing results of partial functions. \t*/\n";\r
12296           ret += generate_partial_fcn_vars(partial_fcns,fcn_ref_cnt,is_partial_fcn,false);\r
12297         }\r
12298 \r
12299 //                      Create cached temporaries for UDAF return values.\r
12300         for(a=0;a<aggr_tbl.size();a++){\r
12301                 if(! aggr_tbl.is_builtin(a)){\r
12302                         int afcn_id = aggr_tbl.get_fcn_id(a);\r
12303                         data_type *adt = Ext_fcns->get_fcn_dt(afcn_id);\r
12304                         sprintf(tmpstr,"udaf_ret_%d", a);\r
12305                         ret+="\t"+adt->make_host_cvar(tmpstr)+";\n";\r
12306                 }\r
12307         }\r
12308 \r
12309 \r
12310 //                      Complex literals (i.e., they need constructors)\r
12311         ret += "//\t\tComplex literal storage.\n";\r
12312         cplx_lit_table *complex_literals = this->get_cplx_lit_tbl(Ext_fcns);\r
12313         ret += generate_complex_lit_vars(complex_literals);\r
12314 \r
12315 //                      Pass-by-handle parameters\r
12316         ret += "//\t\tPass-by-handle storage.\n";\r
12317         vector<handle_param_tbl_entry *> param_handle_table = this->get_handle_param_tbl(Ext_fcns);\r
12318         ret += generate_pass_by_handle_vars(param_handle_table);\r
12319 \r
12320 \r
12321 //                      variables to hold parameters.\r
12322         ret += "//\tfor query parameters\n";\r
12323         ret += generate_param_vars(param_tbl);\r
12324 \r
12325 //              Is there a temporal flush?  If so create flush temporaries,\r
12326 //              create flush indicator.\r
12327         bool uses_temporal_flush = false;\r
12328         for(g=0;g<gb_tbl.size();g++){\r
12329                 data_type *gdt = gb_tbl.get_data_type(g);\r
12330                 if(gdt->is_temporal())\r
12331                         uses_temporal_flush = true;\r
12332         }\r
12333 \r
12334         if(uses_temporal_flush){\r
12335                 ret += "//\t\tFor temporal flush\n";\r
12336                 for(g=0;g<gb_tbl.size();g++){\r
12337                         data_type *gdt = gb_tbl.get_data_type(g);\r
12338                         if(gdt->is_temporal()){\r
12339                           sprintf(tmpstr,"last_gb%d",g);\r
12340                           ret+="\t"+gb_tbl.get_data_type(g)->make_host_cvar(tmpstr)+";\n";\r
12341                           sprintf(tmpstr,"last_flushed_gb%d",g);\r
12342                           ret+="\t"+gb_tbl.get_data_type(g)->make_host_cvar(tmpstr)+";\n";\r
12343                         }\r
12344                 }\r
12345                 ret += "\tbool needs_temporal_flush;\n";\r
12346         }\r
12347 \r
12348 //                      The publicly exposed functions\r
12349 \r
12350         ret += "\npublic:\n";\r
12351 \r
12352 \r
12353 //-------------------\r
12354 //                      The functor constructor\r
12355 //                      pass in the schema handle.\r
12356 //                      1) make assignments to the unpack offset variables\r
12357 //                      2) initialize the complex literals\r
12358 \r
12359         ret += "//\t\tFunctor constructor.\n";\r
12360         ret +=  this->generate_functor_name()+"(int schema_handle0){\n";\r
12361 \r
12362         // save the schema handle\r
12363         ret += "\t\tthis->schema_handle0 = schema_handle0;\n";\r
12364 //              metadata offset\r
12365         ret += "\ttuple_metadata_offset0 = ftaschema_get_tuple_metadata_offset(schema_handle0);\n";\r
12366 \r
12367 //              unpack vars\r
12368         ret += "//\t\tGet offsets for unpacking fields from input tuple.\n";\r
12369         ret += gen_access_var_init(cid_set);\r
12370 \r
12371 //              complex literals\r
12372         ret += "//\t\tInitialize complex literals.\n";\r
12373         ret += gen_complex_lit_init(complex_literals);\r
12374 \r
12375 //              Initialize partial function results so they can be safely GC'd\r
12376         ret += gen_partial_fcn_init(partial_fcns);\r
12377 \r
12378 //              Initialize non-query-parameter parameter handles\r
12379         ret += gen_pass_by_handle_init(param_handle_table);\r
12380 \r
12381 //              temporal flush variables\r
12382 //              ASSUME that structured values won't be temporal.\r
12383         if(uses_temporal_flush){\r
12384                 ret += "//\t\tInitialize temporal flush variables.\n";\r
12385                 for(g=0;g<gb_tbl.size();g++){\r
12386                         data_type *gdt = gb_tbl.get_data_type(g);\r
12387                         if(gdt->is_temporal()){\r
12388                                 literal_t gl(gdt->type_indicator());\r
12389                                 sprintf(tmpstr,"\tlast_gb%d = %s;\n",g, gl.to_hfta_C_code("").c_str());\r
12390                                 ret.append(tmpstr);\r
12391                         }\r
12392                 }\r
12393                 ret += "\tneeds_temporal_flush = false;\n";\r
12394         }\r
12395 \r
12396         //              Init temporal attributes referenced in select list\r
12397         ret += gen_init_temp_vars(schema, select_list, segen_gb_tbl);\r
12398 \r
12399         ret += "};\n";\r
12400 \r
12401 \r
12402 //-------------------\r
12403 //                      Functor destructor\r
12404         ret += "//\t\tFunctor destructor.\n";\r
12405         ret +=  "~"+this->generate_functor_name()+"(){\n";\r
12406 \r
12407 //                      clean up buffer type complex literals\r
12408         ret += gen_complex_lit_dtr(complex_literals);\r
12409 \r
12410 //                      Deregister the pass-by-handle parameters\r
12411         ret += "/* register and de-register the pass-by-handle parameters */\n";\r
12412         ret += gen_pass_by_handle_dtr(param_handle_table);\r
12413 \r
12414 //                      clean up partial function results.\r
12415         ret += "/* clean up partial function storage    */\n";\r
12416         ret += gen_partial_fcn_dtr(partial_fcns);\r
12417 \r
12418 //                      Destroy the parameters, if any need to be destroyed\r
12419         ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";\r
12420 \r
12421         ret += "};\n\n";\r
12422 \r
12423 \r
12424 //-------------------\r
12425 //                      Parameter manipulation routines\r
12426         ret += generate_load_param_block(this->generate_functor_name(),\r
12427                                                                         this->param_tbl,param_handle_table);\r
12428         ret += generate_delete_param_block(this->generate_functor_name(),\r
12429                                                                         this->param_tbl,param_handle_table);\r
12430 \r
12431 //-------------------\r
12432 //                      Register new parameter block\r
12433 \r
12434         ret += "int set_param_block(gs_int32_t sz, void* value){\n";\r
12435           ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";\r
12436           ret += "\treturn this->load_params_"+this->generate_functor_name()+\r
12437                                 "(sz, value);\n";\r
12438         ret += "};\n\n";\r
12439 \r
12440 \r
12441 //-------------------\r
12442 //              the create_group method.\r
12443 //              This method creates a group in a buffer passed in\r
12444 //              (to allow for creation on the stack).\r
12445 //              There are also a couple of side effects:\r
12446 //              1) evaluate the WHERE clause (and therefore, unpack all partial fcns)\r
12447 //              2) determine if a temporal flush is required.\r
12448 \r
12449         ret += this->generate_functor_name()+"_groupdef *create_group(host_tuple &tup0, gs_sp_t buffer){\n";\r
12450         //              Variables for execution of the function.\r
12451         ret += "\tgs_int32_t problem = 0;\n";   // return unpack failure\r
12452 \r
12453         if(partial_fcns.size()>0){              // partial fcn access failure\r
12454           ret += "\tgs_retval_t retval = 0;\n";\r
12455           ret += "\n";\r
12456         }\r
12457 //              return value\r
12458         ret += "\t"+generate_functor_name()+"_groupdef *gbval = ("+generate_functor_name()+\r
12459                         "_groupdef *) buffer;\n";\r
12460 \r
12461 //              Start by cleaning up partial function results\r
12462         ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";\r
12463         set<int> w_pfcns;       // partial fcns in where clause\r
12464         for(w=0;w<where.size();++w)\r
12465                 collect_partial_fcns_pr(where[w]->pr, w_pfcns);\r
12466 \r
12467         set<int> ag_gb_pfcns;   // partial fcns in gbdefs, aggr se's\r
12468         for(g=0;g<gb_tbl.size();g++){\r
12469                 collect_partial_fcns(gb_tbl.get_def(g), ag_gb_pfcns);\r
12470         }\r
12471         for(a=0;a<aggr_tbl.size();a++){\r
12472                 collect_partial_fcns(aggr_tbl.get_aggr_se(a), ag_gb_pfcns);\r
12473         }\r
12474         ret += gen_partial_fcn_dtr(partial_fcns,w_pfcns);\r
12475         ret += gen_partial_fcn_dtr(partial_fcns,ag_gb_pfcns);\r
12476 //      ret += gen_partial_fcn_dtr(partial_fcns);\r
12477 \r
12478 \r
12479         ret += gen_temp_tuple_check(this->node_name, 0);\r
12480         col_id_set found_cids;  // colrefs unpacked thus far.\r
12481         ret += gen_unpack_temp_vars(schema, found_cids, select_list, segen_gb_tbl, needs_xform);\r
12482 \r
12483 \r
12484 //                      Save temporal group-by variables\r
12485 \r
12486 \r
12487         ret.append("\n\t//\t\tCompute temporal groupby attributes\n\n");\r
12488 \r
12489           for(g=0;g<gb_tbl.size();g++){\r
12490 \r
12491                         data_type *gdt = gb_tbl.get_data_type(g);\r
12492 \r
12493                         if(gdt->is_temporal()){\r
12494                                 sprintf(tmpstr,"\tgbval->gb_var%d = %s;\n",\r
12495                                         g, generate_se_code(gb_tbl.get_def(g),schema).c_str() );\r
12496                                 ret.append(tmpstr);\r
12497                         }\r
12498                 }\r
12499                 ret.append("\n");\r
12500 \r
12501 \r
12502 \r
12503 //                      Compare the temporal GB vars with the stored ones,\r
12504 //                      set flush indicator and update stored GB vars if there is any change.\r
12505 \r
12506         if(uses_temporal_flush){\r
12507                 ret+= "\tif( !( (";\r
12508                 bool first_one = true;\r
12509                 for(g=0;g<gb_tbl.size();g++){\r
12510                         data_type *gdt = gb_tbl.get_data_type(g);\r
12511 \r
12512                         if(gdt->is_temporal()){\r
12513                           sprintf(tmpstr,"last_gb%d",g);   string lhs_op = tmpstr;\r
12514                           sprintf(tmpstr,"gbval->gb_var%d",g);   string rhs_op = tmpstr;\r
12515                           if(first_one){first_one = false;} else {ret += ") && (";}\r
12516                           ret += generate_equality_test(lhs_op, rhs_op, gdt);\r
12517                         }\r
12518                 }\r
12519                 ret += ") ) ){\n";\r
12520                 for(g=0;g<gb_tbl.size();g++){\r
12521                   data_type *gdt = gb_tbl.get_data_type(g);\r
12522                   if(gdt->is_temporal()){\r
12523                           if(gdt->is_buffer_type()){\r
12524                                 sprintf(tmpstr,"\t\t%s(&(gbval->gb_var%d),&last_gb%d);\n",gdt->get_hfta_buffer_replace().c_str(),g,g);\r
12525                           }else{\r
12526                                 sprintf(tmpstr,"\t\tlast_flushed_gb%d = last_gb%d;\n",g,g);\r
12527                                 ret += tmpstr;\r
12528                                 sprintf(tmpstr,"\t\tlast_gb%d = gbval->gb_var%d;\n",g,g);\r
12529                           }\r
12530                           ret += tmpstr;\r
12531                         }\r
12532                 }\r
12533                 ret += "\t\tneeds_temporal_flush=true;\n";\r
12534                 ret += "\t\t}else{\n"\r
12535                         "\t\t\tneeds_temporal_flush=false;\n"\r
12536                         "\t\t}\n";\r
12537         }\r
12538 \r
12539 \r
12540 //              For temporal status tuple we don't need to do anything else\r
12541         ret += "\tif (temp_tuple_received) return NULL;\n\n";\r
12542 \r
12543         for(w=0;w<where.size();++w){\r
12544                 sprintf(tmpstr,"//\t\tPredicate clause %d.\n",w);\r
12545                 ret += tmpstr;\r
12546 //                      Find the set of variables accessed in this CNF elem,\r
12547 //                      but in no previous element.\r
12548                 col_id_set new_cids;\r
12549                 get_new_pred_cids(where[w]->pr, found_cids, new_cids, segen_gb_tbl);\r
12550 \r
12551 //                      Unpack these values.\r
12552                 ret += gen_unpack_cids(schema, new_cids, "NULL", needs_xform);\r
12553 //                      Find partial fcns ref'd in this cnf element\r
12554                 set<int> pfcn_refs;\r
12555                 collect_partial_fcns_pr(where[w]->pr, pfcn_refs);\r
12556                 ret += gen_unpack_partial_fcn(schema, partial_fcns, pfcn_refs,"NULL");\r
12557 \r
12558                 ret += "\tif( !("+generate_predicate_code(where[w]->pr,schema)+\r
12559                                 +") ) return(NULL);\n";\r
12560         }\r
12561 \r
12562 //              The partial functions ref'd in the group-by var and aggregate\r
12563 //              definitions must also be evaluated.  If one returns false,\r
12564 //              then implicitly the predicate is false.\r
12565         set<int>::iterator pfsi;\r
12566 \r
12567         if(ag_gb_pfcns.size() > 0)\r
12568                 ret += "//\t\tUnpack remaining partial fcns.\n";\r
12569         ret += gen_full_unpack_partial_fcn(schema, partial_fcns, ag_gb_pfcns,\r
12570                                                                                 found_cids, segen_gb_tbl, "NULL", needs_xform);\r
12571 \r
12572 //                      Unpack the group-by variables\r
12573 \r
12574           for(g=0;g<gb_tbl.size();g++){\r
12575                 data_type *gdt = gb_tbl.get_data_type(g);\r
12576                 if(!gdt->is_temporal()){        // temproal gbs already computed\r
12577 //                      Find the new fields ref'd by this GBvar def.\r
12578                         col_id_set new_cids;\r
12579                         get_new_se_cids(gb_tbl.get_def(g), found_cids, new_cids, segen_gb_tbl);\r
12580 //                      Unpack these values.\r
12581                         ret += gen_unpack_cids(schema, new_cids, "NULL", needs_xform);\r
12582 \r
12583                         sprintf(tmpstr,"\tgbval->gb_var%d = %s;\n",\r
12584                                 g, generate_se_code(gb_tbl.get_def(g),schema).c_str() );\r
12585 /*\r
12586 //                              There seems to be no difference between the two\r
12587 //                              branches of the IF statement.\r
12588                 data_type *gdt = gb_tbl.get_data_type(g);\r
12589                   if(gdt->is_buffer_type()){\r
12590 //                              Create temporary copy.\r
12591                         sprintf(tmpstr,"\tgbval->gb_var%d = %s;\n",\r
12592                                 g, generate_se_code(gb_tbl.get_def(g),schema).c_str() );\r
12593                   }else{\r
12594                         scalarexp_t *gse = gb_tbl.get_def(g);\r
12595                         sprintf(tmpstr,"\tgbval->gb_var%d = %s;\n",\r
12596                                         g,generate_se_code(gse,schema).c_str());\r
12597                   }\r
12598 */\r
12599                         ret.append(tmpstr);\r
12600                 }\r
12601           }\r
12602           ret.append("\n");\r
12603 \r
12604 \r
12605         ret+= "\treturn gbval;\n";\r
12606         ret += "};\n\n\n";\r
12607 \r
12608 //--------------------------------------------------------\r
12609 //                      Create and initialize an aggregate object\r
12610 \r
12611         ret += this->generate_functor_name()+"_aggrdef *create_aggregate(host_tuple &tup0, gs_sp_t buffer){\n";\r
12612         //              Variables for execution of the function.\r
12613         ret += "\tgs_int32_t problem = 0;\n";   // return unpack failure\r
12614 \r
12615 //              return value\r
12616         ret += "\t"+generate_functor_name()+"_aggrdef *aggval = ("+generate_functor_name()+\r
12617                         "_aggrdef *)buffer;\n";\r
12618 \r
12619         for(a=0;a<aggr_tbl.size();a++){\r
12620                 if(aggr_tbl.is_builtin(a)){\r
12621 //                      Create temporaries for buffer return values\r
12622                   data_type *adt = aggr_tbl.get_data_type(a);\r
12623                   if(adt->is_buffer_type()){\r
12624                         sprintf(tmpstr,"aggr_tmp_%d", a);\r
12625                         ret+=adt->make_host_cvar(tmpstr)+";\n";\r
12626                   }\r
12627                 }\r
12628         }\r
12629 \r
12630 //              Unpack all remaining attributes\r
12631         ret += gen_remaining_colrefs(schema, cid_set, found_cids, "NULL", needs_xform);\r
12632         for(a=0;a<aggr_tbl.size();a++){\r
12633           sprintf(tmpstr,"aggval->aggr_var%d",a);\r
12634           string assignto_var = tmpstr;\r
12635           ret += "\t"+generate_aggr_init(assignto_var,&aggr_tbl,a, schema);\r
12636         }\r
12637 \r
12638         ret += "\treturn aggval;\n";\r
12639         ret += "};\n\n";\r
12640 \r
12641 //--------------------------------------------------------\r
12642 //                      update an aggregate object\r
12643 \r
12644         ret += "void update_aggregate(host_tuple &tup0, "\r
12645                 +generate_functor_name()+"_groupdef *gbval, "+\r
12646                 generate_functor_name()+"_aggrdef *aggval){\n";\r
12647         //              Variables for execution of the function.\r
12648         ret += "\tgs_int32_t problem = 0;\n";   // return unpack failure\r
12649 \r
12650 //                      use of temporaries depends on the aggregate,\r
12651 //                      generate them in generate_aggr_update\r
12652 \r
12653 \r
12654 //              Unpack all remaining attributes\r
12655         ret += gen_remaining_colrefs(schema, cid_set, found_cids, "", needs_xform);\r
12656         for(a=0;a<aggr_tbl.size();a++){\r
12657           sprintf(tmpstr,"aggval->aggr_var%d",a);\r
12658           string varname = tmpstr;\r
12659           ret.append(generate_aggr_update(varname,&aggr_tbl,a, schema));\r
12660         }\r
12661 \r
12662         ret += "\treturn;\n";\r
12663         ret += "};\n";\r
12664 \r
12665 //--------------------------------------------------------\r
12666 //                      reinitialize an aggregate object\r
12667 \r
12668         ret += "void reinit_aggregates( "+\r
12669                 generate_functor_name()+"_groupdef *gbval, "+\r
12670                 generate_functor_name()+"_aggrdef *aggval){\n";\r
12671         //              Variables for execution of the function.\r
12672         ret += "\tgs_int32_t problem = 0;\n";   // return unpack failure\r
12673 \r
12674 //                      use of temporaries depends on the aggregate,\r
12675 //                      generate them in generate_aggr_update\r
12676 \r
12677         for(g=0;g<gb_tbl.size();g++){\r
12678           data_type *gdt = gb_tbl.get_data_type(g);\r
12679           if(gdt->is_temporal()){\r
12680                   if(gdt->is_buffer_type()){\r
12681                         sprintf(tmpstr,"\t\t%s(&(gbval->gb_var%d),&last_gb%d);\n",gdt->get_hfta_buffer_replace().c_str(),g,g);\r
12682                   }else{\r
12683                         sprintf(tmpstr,"\t\t gbval->gb_var%d =last_gb%d;\n",g,g);\r
12684                   }\r
12685                   ret += tmpstr;\r
12686                 }\r
12687         }\r
12688 \r
12689 //              Unpack all remaining attributes\r
12690         for(a=0;a<aggr_tbl.size();a++){\r
12691           sprintf(tmpstr,"aggval->aggr_var%d",a);\r
12692           string varname = tmpstr;\r
12693           ret.append(generate_aggr_reinitialize(varname,&aggr_tbl,a, schema));\r
12694         }\r
12695 \r
12696         ret += "\treturn;\n";\r
12697         ret += "};\n";\r
12698 \r
12699 \r
12700 \r
12701 \r
12702 \r
12703 //---------------------------------------------------\r
12704 //                      Flush test\r
12705 \r
12706         ret += "\tbool flush_needed(){\n";\r
12707         if(uses_temporal_flush){\r
12708                 ret += "\t\treturn needs_temporal_flush;\n";\r
12709         }else{\r
12710                 ret += "\t\treturn false;\n";\r
12711         }\r
12712         ret += "\t};\n";\r
12713 \r
12714 //---------------------------------------------------\r
12715 //                      create output tuple\r
12716 //                      Unpack the partial functions ref'd in the where clause,\r
12717 //                      select clause.  Evaluate the where clause.\r
12718 //                      Finally, pack the tuple.\r
12719 \r
12720 //                      I need to use special code generation here,\r
12721 //                      so I'll leave it in longhand.\r
12722 \r
12723         ret += "host_tuple create_output_tuple("\r
12724                 +generate_functor_name()+"_groupdef *gbval, "+\r
12725                 generate_functor_name()+"_aggrdef *aggval, bool &failed){\n";\r
12726 \r
12727         ret += "\thost_tuple tup;\n";\r
12728         ret += "\tfailed = false;\n";\r
12729         ret += "\tgs_retval_t retval = 0;\n";\r
12730 \r
12731         string gbvar = "gbval->gb_var";\r
12732         string aggvar = "aggval->";\r
12733 \r
12734 \r
12735 //                      First, get the return values from the UDAFS\r
12736         for(a=0;a<aggr_tbl.size();a++){\r
12737                 if(! aggr_tbl.is_builtin(a)){\r
12738                         ret += "\t"+aggr_tbl.get_op(a)+"_HFTA_AGGR_OUTPUT_(&(udaf_ret_"+int_to_string(a)+"),";\r
12739                         if(aggr_tbl.get_storage_type(a)->get_type() != fstring_t) ret+="&";\r
12740                         ret+="("+aggvar+"aggr_var"+int_to_string(a)+"));\n";\r
12741                 }\r
12742         }\r
12743 \r
12744         set<int> hv_sl_pfcns;\r
12745         for(w=0;w<having.size();w++){\r
12746                 collect_partial_fcns_pr(having[w]->pr, hv_sl_pfcns);\r
12747         }\r
12748         for(s=0;s<select_list.size();s++){\r
12749                 collect_partial_fcns(select_list[s]->se, hv_sl_pfcns);\r
12750         }\r
12751 \r
12752 //              clean up the partial fcn results from any previous execution\r
12753         ret += gen_partial_fcn_dtr(partial_fcns,hv_sl_pfcns);\r
12754 \r
12755 //              Unpack them now\r
12756         for(pfsi=hv_sl_pfcns.begin();pfsi!=hv_sl_pfcns.end();++pfsi){\r
12757                 ret += unpack_partial_fcn_fm_aggr(partial_fcns[(*pfsi)], (*pfsi), gbvar, aggvar, schema);\r
12758                 ret += "\tif(retval){ failed = true; return(tup);}\n";\r
12759         }\r
12760 \r
12761 //              Evalaute the HAVING clause\r
12762 //              TODO: this seems to have a ++ operator rather than a + operator.\r
12763         for(w=0;w<having.size();++w){\r
12764                 ret += "\tif( !("+generate_predicate_code_fm_aggr(having[w]->pr,gbvar, aggvar, schema) +") ) { failed = true; return(tup);}\n";\r
12765         }\r
12766 \r
12767 //          Now, compute the size of the tuple.\r
12768 \r
12769 //          Unpack any BUFFER type selections into temporaries\r
12770 //          so that I can compute their size and not have\r
12771 //          to recompute their value during tuple packing.\r
12772 //          I can use regular assignment here because\r
12773 //          these temporaries are non-persistent.\r
12774 //                      TODO: should I be using the selvar generation routine?\r
12775 \r
12776         ret += "//\t\tCompute the size of the tuple.\n";\r
12777         ret += "//\t\t\tNote: buffer storage packed at the end of the tuple.\n";\r
12778       for(s=0;s<select_list.size();s++){\r
12779                 scalarexp_t *se = select_list[s]->se;\r
12780         data_type *sdt = se->get_data_type();\r
12781         if(sdt->is_buffer_type() &&\r
12782                          !( (se->get_operator_type() == SE_COLREF) ||\r
12783                                 (se->get_operator_type() == SE_AGGR_STAR) ||\r
12784                                 (se->get_operator_type() == SE_AGGR_SE) ||\r
12785                            (se->get_operator_type() == SE_FUNC && se->is_partial()) ||\r
12786                            (se->get_operator_type() == SE_FUNC && se->get_aggr_ref() >= 0))\r
12787                 ){\r
12788             sprintf(tmpstr,"selvar_%d",s);\r
12789                         ret+="\t"+sdt->make_host_cvar(tmpstr)+" = ";\r
12790                         ret += generate_se_code_fm_aggr(se,gbvar, aggvar, schema) +";\n";\r
12791         }\r
12792       }\r
12793 \r
12794 //      The size of the tuple is the size of the tuple struct plus the\r
12795 //      size of the buffers to be copied in.\r
12796 \r
12797       ret+="\ttup.tuple_size = sizeof(" + generate_tuple_name( this->get_node_name()) +") + sizeof(gs_uint8_t)";\r
12798       for(s=0;s<select_list.size();s++){\r
12799 //              if(s>0) ret += "+";\r
12800                 scalarexp_t *se = select_list[s]->se;\r
12801         data_type *sdt = select_list[s]->se->get_data_type();\r
12802         if(sdt->is_buffer_type()){\r
12803                   if(!( (se->get_operator_type() == SE_COLREF) ||\r
12804                                 (se->get_operator_type() == SE_AGGR_STAR) ||\r
12805                                 (se->get_operator_type() == SE_AGGR_SE) ||\r
12806                            (se->get_operator_type() == SE_FUNC && se->is_partial()) ||\r
12807                            (se->get_operator_type() == SE_FUNC && se->get_aggr_ref() >= 0))\r
12808                   ){\r
12809             sprintf(tmpstr," + %s(&selvar_%d)", sdt->get_hfta_buffer_size().c_str(),s);\r
12810             ret.append(tmpstr);\r
12811                   }else{\r
12812             sprintf(tmpstr," + %s(&%s)", sdt->get_hfta_buffer_size().c_str(),generate_se_code_fm_aggr(se,gbvar, aggvar, schema).c_str());\r
12813             ret.append(tmpstr);\r
12814                   }\r
12815         }\r
12816       }\r
12817       ret.append(";\n");\r
12818 \r
12819 //              Allocate tuple data block.\r
12820         ret += "//\t\tCreate the tuple block.\n";\r
12821           ret += "\ttup.data = malloc(tup.tuple_size);\n";\r
12822           ret += "\ttup.heap_resident = true;\n";\r
12823 \r
12824 //              Mark tuple as regular\r
12825           ret += "\t*((gs_sp_t )tup.data + sizeof(" + generate_tuple_name( this->get_node_name()) +")) = REGULAR_TUPLE;\n";\r
12826 \r
12827 //        ret += "\ttup.channel = 0;\n";\r
12828           ret += "\t"+generate_tuple_name( this->get_node_name())+" *tuple = ("+\r
12829                                 generate_tuple_name( this->get_node_name())+" *)(tup.data);\n";\r
12830 \r
12831 //              Start packing.\r
12832 //                      (Here, offsets are hard-wired.  is this a problem?)\r
12833 \r
12834         ret += "//\t\tPack the fields into the tuple.\n";\r
12835           ret += "\tint tuple_pos = sizeof("+generate_tuple_name( this->get_node_name()) +") + sizeof(gs_uint8_t);\n";\r
12836       for(s=0;s<select_list.size();s++){\r
12837                 scalarexp_t *se = select_list[s]->se;\r
12838         data_type *sdt = se->get_data_type();\r
12839         if(sdt->is_buffer_type()){\r
12840                   if(!( (se->get_operator_type() == SE_COLREF) ||\r
12841                                 (se->get_operator_type() == SE_AGGR_STAR) ||\r
12842                                 (se->get_operator_type() == SE_AGGR_SE) ||\r
12843                            (se->get_operator_type() == SE_FUNC && se->is_partial()) ||\r
12844                            (se->get_operator_type() == SE_FUNC && se->get_aggr_ref() >= 0))\r
12845                   ){\r
12846             sprintf(tmpstr,"\t%s(&(tuple->tuple_var%d), &selvar_%d,  ((gs_sp_t )tuple)+tuple_pos, tuple_pos);\n", sdt->get_hfta_buffer_tuple_copy().c_str(),s, s);\r
12847             ret.append(tmpstr);\r
12848             sprintf(tmpstr,"\ttuple_pos += %s(&selvar_%d);\n", sdt->get_hfta_buffer_size().c_str(), s);\r
12849             ret.append(tmpstr);\r
12850                   }else{\r
12851             sprintf(tmpstr,"\t%s(&(tuple->tuple_var%d), &%s,  ((gs_sp_t )tuple)+tuple_pos, tuple_pos);\n", sdt->get_hfta_buffer_tuple_copy().c_str(),s, generate_se_code_fm_aggr(se,gbvar, aggvar, schema).c_str());\r
12852             ret.append(tmpstr);\r
12853             sprintf(tmpstr,"\ttuple_pos += %s(&%s);\n", sdt->get_hfta_buffer_size().c_str(), generate_se_code_fm_aggr(se,gbvar, aggvar, schema).c_str());\r
12854             ret.append(tmpstr);\r
12855                   }\r
12856         }else{\r
12857             sprintf(tmpstr,"\ttuple->tuple_var%d = ",s);\r
12858             ret.append(tmpstr);\r
12859             ret.append(generate_se_code_fm_aggr(se,gbvar, aggvar, schema) );\r
12860             ret.append(";\n");\r
12861         }\r
12862       }\r
12863 \r
12864 //                      Destroy string temporaries\r
12865           ret += gen_buffer_selvars_dtr(select_list);\r
12866 \r
12867           ret += "\treturn tup;\n";\r
12868           ret += "};\n";\r
12869 \r
12870 //------------------------------------------------------------------\r
12871 //              Cleaning_when : evaluate the cleaning_when clause.\r
12872 //              ASSUME that the udaf return values have already\r
12873 //              been unpacked.  delete the string udaf return values at the end.\r
12874 \r
12875         ret += "bool cleaning_when("\r
12876                 +generate_functor_name()+"_groupdef *gbval, "+\r
12877                 generate_functor_name()+"_aggrdef *aggval){\n";\r
12878 \r
12879         ret += "\tbool retval = true;\n";\r
12880 \r
12881 \r
12882         gbvar = "gbval->gb_var";\r
12883         aggvar = "aggval->";\r
12884 \r
12885 \r
12886         set<int> clw_pfcns;\r
12887         for(w=0;w<closing_when.size();w++){\r
12888                 collect_partial_fcns_pr(closing_when[w]->pr, clw_pfcns);\r
12889         }\r
12890 \r
12891 //              clean up the partial fcn results from any previous execution\r
12892         ret += gen_partial_fcn_dtr(partial_fcns,clw_pfcns);\r
12893 \r
12894 //              Unpack them now\r
12895         for(pfsi=clw_pfcns.begin();pfsi!=clw_pfcns.end();++pfsi){\r
12896                 ret += unpack_partial_fcn_fm_aggr(partial_fcns[(*pfsi)], (*pfsi), gbvar, aggvar, schema);\r
12897                 ret += "\tif(retval){ return false;}\n";\r
12898         }\r
12899 \r
12900 //              Evalaute the Closing When clause\r
12901 //              TODO: this seems to have a ++ operator rather than a + operator.\r
12902         for(w=0;w<closing_when.size();++w){\r
12903                 ret += "\tif( !("+generate_predicate_code_fm_aggr(closing_when[w]->pr,gbvar, aggvar, schema) +") ) { return false;}\n";\r
12904         }\r
12905 \r
12906 \r
12907 //                      Destroy string return vals of UDAFs\r
12908         for(a=0;a<aggr_tbl.size();a++){\r
12909                 if(! aggr_tbl.is_builtin(a)){\r
12910                         int afcn_id = aggr_tbl.get_fcn_id(a);\r
12911                         data_type *adt = Ext_fcns->get_fcn_dt(afcn_id);\r
12912                         if(adt->is_buffer_type()){\r
12913                                 sprintf(tmpstr,"\t%s(&udaf_ret_%d);\n",\r
12914                                 adt->get_hfta_buffer_destroy().c_str(), a );\r
12915                                 ret += tmpstr;\r
12916                         }\r
12917                 }\r
12918         }\r
12919 \r
12920         ret += "\treturn retval;\n";\r
12921         ret += "};\n";\r
12922 \r
12923 \r
12924 \r
12925 \r
12926 //-------------------------------------------------------------------\r
12927 //              Temporal update functions\r
12928 \r
12929         ret+="bool temp_status_received(){return temp_tuple_received;};\n\n";\r
12930 \r
12931 //              create a temp status tuple\r
12932         ret += "int create_temp_status_tuple(host_tuple& result, bool flush_finished) {\n\n";\r
12933 \r
12934         ret += gen_init_temp_status_tuple(this->get_node_name());\r
12935 \r
12936 //              Start packing.\r
12937 //                      (Here, offsets are hard-wired.  is this a problem?)\r
12938 \r
12939         ret += "//\t\tPack the fields into the tuple.\n";\r
12940         for(s=0;s<select_list.size();s++){\r
12941                 data_type *sdt = select_list[s]->se->get_data_type();\r
12942                 if(sdt->is_temporal()){\r
12943                         sprintf(tmpstr,"\ttuple->tuple_var%d = ",s);\r
12944                         ret += tmpstr;\r
12945                         sprintf(tmpstr,"(flush_finished) ? %s : %s ", generate_se_code(select_list[s]->se,schema).c_str(), generate_se_code_fm_aggr(select_list[s]->se,"last_flushed_gb", "", schema).c_str());\r
12946                         ret += tmpstr;\r
12947                         ret += ";\n";\r
12948                 }\r
12949         }\r
12950 \r
12951         ret += "\treturn 0;\n";\r
12952         ret += "};};\n\n\n";\r
12953 \r
12954 \r
12955 //----------------------------------------------------------\r
12956 //                      The hash function\r
12957 \r
12958         ret += "struct "+generate_functor_name()+"_hash_func{\n";\r
12959         ret += "\tgs_uint32_t operator()(const "+generate_functor_name()+\r
12960                                 "_groupdef *grp) const{\n";\r
12961         ret += "\t\treturn(0";\r
12962         for(g=0;g<gb_tbl.size();g++){\r
12963                 data_type *gdt = gb_tbl.get_data_type(g);\r
12964                 if(! gdt->is_temporal()){\r
12965                         ret += "^";\r
12966                         if(gdt->use_hashfunc()){\r
12967                                 if(gdt->is_buffer_type())\r
12968                                         sprintf(tmpstr,"(%s*%s(&(grp->gb_var%d)))",hash_nums[g%NRANDS].c_str(),gdt->get_hfta_hashfunc().c_str(),g);\r
12969                                         else\r
12970                                 sprintf(tmpstr,"(%s*%s(grp->gb_var%d))",hash_nums[g%NRANDS].c_str(),gdt->get_hfta_hashfunc().c_str(),g);\r
12971                         }else{\r
12972                                 sprintf(tmpstr,"(%s*grp->gb_var%d)",hash_nums[g%NRANDS].c_str(),g);\r
12973                         }\r
12974                         ret += tmpstr;\r
12975                 }\r
12976         }\r
12977         ret += " >> 32);\n";\r
12978         ret += "\t}\n";\r
12979         ret += "};\n\n";\r
12980 \r
12981 //----------------------------------------------------------\r
12982 //                      The comparison function\r
12983 \r
12984         ret += "struct "+generate_functor_name()+"_equal_func{\n";\r
12985         ret += "\tbool operator()(const "+generate_functor_name()+"_groupdef *grp1, "+\r
12986                         generate_functor_name()+"_groupdef *grp2) const{\n";\r
12987         ret += "\t\treturn( (";\r
12988 \r
12989         string hcmpr = "";\r
12990         bool first_exec = true;\r
12991         for(g=0;g<gb_tbl.size();g++){\r
12992                 data_type *gdt = gb_tbl.get_data_type(g);\r
12993                 if(! gdt->is_temporal()){\r
12994                         if(first_exec){first_exec=false;}else{ hcmpr += ") && (";}\r
12995                         if(gdt->complex_comparison(gdt)){\r
12996                           if(gdt->is_buffer_type())\r
12997                                 sprintf(tmpstr,"(%s(&(grp1->gb_var%d), &(grp2->gb_var%d))==0)",\r
12998                                 gdt->get_hfta_comparison_fcn(gdt).c_str(),g,g);\r
12999                           else\r
13000                                 sprintf(tmpstr,"(%s((grp1->gb_var%d), (grp2->gb_var%d))==0)",\r
13001                                 gdt->get_hfta_comparison_fcn(gdt).c_str(),g,g);\r
13002                         }else{\r
13003                                 sprintf(tmpstr,"grp1->gb_var%d == grp2->gb_var%d",g,g);\r
13004                         }\r
13005                         hcmpr += tmpstr;\r
13006                 }\r
13007         }\r
13008         if(hcmpr == "")\r
13009                 hcmpr = "true";\r
13010         ret += hcmpr;\r
13011 \r
13012         ret += ") );\n";\r
13013         ret += "\t}\n";\r
13014         ret += "};\n\n";\r
13015 \r
13016 \r
13017         return(ret);\r
13018 }\r
13019 \r
13020 string rsgah_qpn::generate_operator(int i, string params){\r
13021 \r
13022                 return(\r
13023                         "       running_agg_operator<" +\r
13024                         generate_functor_name()+","+\r
13025                         generate_functor_name() + "_groupdef, " +\r
13026                         generate_functor_name() + "_aggrdef, " +\r
13027                         generate_functor_name()+"_hash_func, "+\r
13028                         generate_functor_name()+"_equal_func "\r
13029                         "> *op"+int_to_string(i)+" = new running_agg_operator<"+\r
13030                         generate_functor_name()+","+\r
13031                         generate_functor_name() + "_groupdef, " +\r
13032                         generate_functor_name() + "_aggrdef, " +\r
13033                         generate_functor_name()+"_hash_func, "+\r
13034                         generate_functor_name()+"_equal_func "\r
13035                         ">("+params+", \"" + get_node_name() + "\");\n"\r
13036                 );\r
13037 }\r
13038 \r
13039 \r
13040 \r
13041 //              Split aggregation into two HFTA components - sub and superaggregation\r
13042 //              If unable to split the aggreagates, empty vector will be returned\r
13043 vector<qp_node *> sgah_qpn::split_node_for_hfta(ext_fcn_list *Ext_fcns, table_list *Schema){\r
13044 \r
13045         vector<qp_node *> ret_vec;\r
13046         int s, p, g, a, o, i;\r
13047         int si;\r
13048 \r
13049         vector<string> fta_flds, stream_flds;\r
13050         int t = table_name->get_schema_ref();\r
13051 \r
13052 //                      Get the set of interfaces it accesses.\r
13053         int ierr;\r
13054         vector<string> sel_names;\r
13055 \r
13056 //                      Verify that all of the ref'd UDAFs can be split.\r
13057 \r
13058         for(a=0;a<aggr_tbl.size();++a){\r
13059                 if(! aggr_tbl.is_builtin(a)){\r
13060                         int afcn = aggr_tbl.get_fcn_id(a);\r
13061                         int hfta_super_id = Ext_fcns->get_hfta_superaggr_id(afcn);\r
13062                         int hfta_sub_id = Ext_fcns->get_hfta_subaggr_id(afcn);\r
13063                         if(hfta_super_id < 0 || hfta_sub_id < 0){\r
13064                                 return(ret_vec);\r
13065                         }\r
13066                 }\r
13067     }\r
13068 \r
13069 /////////////////////////////////////////////////////\r
13070 //                      Split into  aggr/aggr.\r
13071 \r
13072 \r
13073         sgah_qpn *low_hfta_node = new sgah_qpn();\r
13074         low_hfta_node->table_name = table_name;\r
13075         low_hfta_node->set_node_name( "_"+node_name );\r
13076         low_hfta_node->table_name->set_range_var(table_name->get_var_name());\r
13077 \r
13078 \r
13079         sgah_qpn *hi_hfta_node = new sgah_qpn();\r
13080         hi_hfta_node->table_name = new tablevar_t(  ("_"+node_name).c_str());\r
13081         hi_hfta_node->set_node_name( node_name );\r
13082         hi_hfta_node->table_name->set_range_var(table_name->get_var_name());\r
13083 \r
13084 //                      First, process the group-by variables.\r
13085 //                      both low and hi level queries duplicate group-by variables of original query\r
13086 \r
13087 \r
13088         for(g=0;g<gb_tbl.size();g++){\r
13089 //                      Insert the gbvar into both low- and hi level hfta.\r
13090                 scalarexp_t *gbvar_def = dup_se(gb_tbl.get_def(g), &aggr_tbl);\r
13091                 low_hfta_node->gb_tbl.add_gb_var(\r
13092                         gb_tbl.get_name(g), gb_tbl.get_tblvar_ref(g), gbvar_def, gb_tbl.get_reftype(g)\r
13093                 );\r
13094 \r
13095 //                      Insert a ref to the value of the gbvar into the low-level hfta select list.\r
13096                 colref_t *new_cr = new colref_t(gb_tbl.get_name(g).c_str() );\r
13097                 scalarexp_t *gbvar_fta = new scalarexp_t(new_cr);\r
13098                 gbvar_fta->set_gb_ref(g);\r
13099                 gbvar_fta->set_data_type( gb_tbl.get_def(g)->get_data_type() );\r
13100                 scalarexp_t *gbvar_stream = make_fta_se_ref(low_hfta_node->select_list, gbvar_fta,0);\r
13101 \r
13102 //                      Insert the corresponding gbvar ref (gbvar_stream) into the stream.\r
13103                 gbvar_stream->set_gb_ref(-1);   // used as GBvar def\r
13104                 hi_hfta_node->gb_tbl.add_gb_var(\r
13105                         gbvar_stream->get_colref()->get_field(), -1, gbvar_stream,  gb_tbl.get_reftype(g)\r
13106                 );\r
13107 \r
13108         }\r
13109 //      hi_hfta_node->gb_tbl.gb_patterns = gb_tbl.gb_patterns; // pattern processing at higtest level\r
13110         hi_hfta_node->gb_tbl.set_pattern_info( &gb_tbl); // pattern processing at higtest level\r
13111 \r
13112 //                      SEs in the aggregate definitions.\r
13113 //                      They are all safe, so split them up for later processing.\r
13114         map<int, scalarexp_t *> hfta_aggr_se;\r
13115         for(a=0;a<aggr_tbl.size();++a){\r
13116                 split_hfta_aggr( &(aggr_tbl), a,\r
13117                                                 &(hi_hfta_node->aggr_tbl), &(low_hfta_node->aggr_tbl)  ,\r
13118                                                 low_hfta_node->select_list,\r
13119                                                 hfta_aggr_se,\r
13120                                                 Ext_fcns\r
13121                                         );\r
13122         }\r
13123 \r
13124 \r
13125 //                      Next, the select list.\r
13126 \r
13127         for(s=0;s<select_list.size();s++){\r
13128                 bool fta_forbidden = false;\r
13129                 scalarexp_t *root_se = rehome_fta_se(select_list[s]->se, &hfta_aggr_se);\r
13130                 hi_hfta_node->select_list.push_back(\r
13131                         new select_element(root_se, select_list[s]->name));\r
13132         }\r
13133 \r
13134 \r
13135 \r
13136 //                      All the predicates in the where clause must execute\r
13137 //                      in the low-level hfta.\r
13138 \r
13139         for(p=0;p<where.size();p++){\r
13140                 predicate_t *new_pr = dup_pr(where[p]->pr, &aggr_tbl);\r
13141                 cnf_elem *new_cnf = new cnf_elem(new_pr);\r
13142                 analyze_cnf(new_cnf);\r
13143 \r
13144                 low_hfta_node->where.push_back(new_cnf);\r
13145         }\r
13146 \r
13147 //                      All of the predicates in the having clause must\r
13148 //                      execute in the high-level hfta node.\r
13149 \r
13150         for(p=0;p<having.size();p++){\r
13151                 predicate_t *pr_root = rehome_fta_pr( having[p]->pr,  &hfta_aggr_se);\r
13152                 cnf_elem *cnf_root = new cnf_elem(pr_root);\r
13153                 analyze_cnf(cnf_root);\r
13154 \r
13155                 hi_hfta_node->having.push_back(cnf_root);\r
13156         }\r
13157 \r
13158 \r
13159 //                      Copy parameters to both nodes\r
13160         vector<string> param_names = param_tbl->get_param_names();\r
13161         int pi;\r
13162         for(pi=0;pi<param_names.size();pi++){\r
13163                 data_type *dt = param_tbl->get_data_type(param_names[pi]);\r
13164                 low_hfta_node->param_tbl->add_param(param_names[pi],dt->duplicate(),\r
13165                                                                         param_tbl->handle_access(param_names[pi]));\r
13166                 hi_hfta_node->param_tbl->add_param(param_names[pi],dt->duplicate(),\r
13167                                                                         param_tbl->handle_access(param_names[pi]));\r
13168         }\r
13169         low_hfta_node->definitions = definitions;\r
13170         hi_hfta_node->definitions = definitions;\r
13171 \r
13172 \r
13173         low_hfta_node->table_name->set_machine(table_name->get_machine());\r
13174         low_hfta_node->table_name->set_interface(table_name->get_interface());\r
13175         low_hfta_node->table_name->set_ifq(false);\r
13176 \r
13177         hi_hfta_node->table_name->set_machine(table_name->get_machine());\r
13178         hi_hfta_node->table_name->set_interface(table_name->get_interface());\r
13179         hi_hfta_node->table_name->set_ifq(false);\r
13180 \r
13181         ret_vec.push_back(low_hfta_node);\r
13182         ret_vec.push_back(hi_hfta_node);\r
13183 \r
13184 \r
13185         return(ret_vec);\r
13186 \r
13187 \r
13188         // TODO: add splitting into selection/aggregation\r
13189 }\r
13190 \r
13191 \r
13192 //              Split aggregation into two HFTA components - sub and superaggregation\r
13193 //              If unable to split the aggreagates, empty vector will be returned\r
13194 //                      Similar to sgah, but super aggregate is rsgah, subaggr is sgah\r
13195 vector<qp_node *> rsgah_qpn::split_node_for_hfta(ext_fcn_list *Ext_fcns, table_list *Schema){\r
13196 \r
13197         vector<qp_node *> ret_vec;\r
13198         int s, p, g, a, o, i;\r
13199         int si;\r
13200 \r
13201         vector<string> fta_flds, stream_flds;\r
13202         int t = table_name->get_schema_ref();\r
13203 \r
13204 //                      Get the set of interfaces it accesses.\r
13205         int ierr;\r
13206         vector<string> sel_names;\r
13207 \r
13208 //                      Verify that all of the ref'd UDAFs can be split.\r
13209 \r
13210         for(a=0;a<aggr_tbl.size();++a){\r
13211                 if(! aggr_tbl.is_builtin(a)){\r
13212                         int afcn = aggr_tbl.get_fcn_id(a);\r
13213                         int hfta_super_id = Ext_fcns->get_hfta_superaggr_id(afcn);\r
13214                         int hfta_sub_id = Ext_fcns->get_hfta_subaggr_id(afcn);\r
13215                         if(hfta_super_id < 0 || hfta_sub_id < 0){\r
13216                                 return(ret_vec);\r
13217                         }\r
13218                 }\r
13219     }\r
13220 \r
13221 /////////////////////////////////////////////////////\r
13222 //                      Split into  aggr/aggr.\r
13223 \r
13224 \r
13225         sgah_qpn *low_hfta_node = new sgah_qpn();\r
13226         low_hfta_node->table_name = table_name;\r
13227         low_hfta_node->set_node_name( "_"+node_name );\r
13228         low_hfta_node->table_name->set_range_var(table_name->get_var_name());\r
13229 \r
13230 \r
13231         rsgah_qpn *hi_hfta_node = new rsgah_qpn();\r
13232         hi_hfta_node->table_name = new tablevar_t(  ("_"+node_name).c_str());\r
13233         hi_hfta_node->set_node_name( node_name );\r
13234         hi_hfta_node->table_name->set_range_var(table_name->get_var_name());\r
13235 \r
13236 //                      First, process the group-by variables.\r
13237 //                      both low and hi level queries duplicate group-by variables of original query\r
13238 \r
13239 \r
13240         for(g=0;g<gb_tbl.size();g++){\r
13241 //                      Insert the gbvar into both low- and hi level hfta.\r
13242                 scalarexp_t *gbvar_def = dup_se(gb_tbl.get_def(g), &aggr_tbl);\r
13243                 low_hfta_node->gb_tbl.add_gb_var(\r
13244                         gb_tbl.get_name(g), gb_tbl.get_tblvar_ref(g), gbvar_def, gb_tbl.get_reftype(g)\r
13245                 );\r
13246 \r
13247 //                      Insert a ref to the value of the gbvar into the low-level hfta select list.\r
13248                 colref_t *new_cr = new colref_t(gb_tbl.get_name(g).c_str() );\r
13249                 scalarexp_t *gbvar_fta = new scalarexp_t(new_cr);\r
13250                 gbvar_fta->set_gb_ref(g);\r
13251                 gbvar_fta->set_data_type( gb_tbl.get_def(g)->get_data_type() );\r
13252                 scalarexp_t *gbvar_stream = make_fta_se_ref(low_hfta_node->select_list, gbvar_fta,0);\r
13253 \r
13254 //                      Insert the corresponding gbvar ref (gbvar_stream) into the stream.\r
13255                 gbvar_stream->set_gb_ref(-1);   // used as GBvar def\r
13256                 hi_hfta_node->gb_tbl.add_gb_var(\r
13257                         gbvar_stream->get_colref()->get_field(), -1, gbvar_stream,  gb_tbl.get_reftype(g)\r
13258                 );\r
13259 \r
13260         }\r
13261 \r
13262 //                      SEs in the aggregate definitions.\r
13263 //                      They are all safe, so split them up for later processing.\r
13264         map<int, scalarexp_t *> hfta_aggr_se;\r
13265         for(a=0;a<aggr_tbl.size();++a){\r
13266                 split_hfta_aggr( &(aggr_tbl), a,\r
13267                                                 &(hi_hfta_node->aggr_tbl), &(low_hfta_node->aggr_tbl)  ,\r
13268                                                 low_hfta_node->select_list,\r
13269                                                 hfta_aggr_se,\r
13270                                                 Ext_fcns\r
13271                                         );\r
13272         }\r
13273 \r
13274 \r
13275 //                      Next, the select list.\r
13276 \r
13277         for(s=0;s<select_list.size();s++){\r
13278                 bool fta_forbidden = false;\r
13279                 scalarexp_t *root_se = rehome_fta_se(select_list[s]->se, &hfta_aggr_se);\r
13280                 hi_hfta_node->select_list.push_back(\r
13281                         new select_element(root_se, select_list[s]->name));\r
13282         }\r
13283 \r
13284 \r
13285 \r
13286 //                      All the predicates in the where clause must execute\r
13287 //                      in the low-level hfta.\r
13288 \r
13289         for(p=0;p<where.size();p++){\r
13290                 predicate_t *new_pr = dup_pr(where[p]->pr, &aggr_tbl);\r
13291                 cnf_elem *new_cnf = new cnf_elem(new_pr);\r
13292                 analyze_cnf(new_cnf);\r
13293 \r
13294                 low_hfta_node->where.push_back(new_cnf);\r
13295         }\r
13296 \r
13297 //                      All of the predicates in the having clause must\r
13298 //                      execute in the high-level hfta node.\r
13299 \r
13300         for(p=0;p<having.size();p++){\r
13301                 predicate_t *pr_root = rehome_fta_pr( having[p]->pr,  &hfta_aggr_se);\r
13302                 cnf_elem *cnf_root = new cnf_elem(pr_root);\r
13303                 analyze_cnf(cnf_root);\r
13304 \r
13305                 hi_hfta_node->having.push_back(cnf_root);\r
13306         }\r
13307 \r
13308 //              Similar for closing when\r
13309         for(p=0;p<closing_when.size();p++){\r
13310                 predicate_t *pr_root = rehome_fta_pr( closing_when[p]->pr,  &hfta_aggr_se);\r
13311                 cnf_elem *cnf_root = new cnf_elem(pr_root);\r
13312                 analyze_cnf(cnf_root);\r
13313 \r
13314                 hi_hfta_node->closing_when.push_back(cnf_root);\r
13315         }\r
13316 \r
13317 \r
13318 //                      Copy parameters to both nodes\r
13319         vector<string> param_names = param_tbl->get_param_names();\r
13320         int pi;\r
13321         for(pi=0;pi<param_names.size();pi++){\r
13322                 data_type *dt = param_tbl->get_data_type(param_names[pi]);\r
13323                 low_hfta_node->param_tbl->add_param(param_names[pi],dt->duplicate(),\r
13324                                                                         param_tbl->handle_access(param_names[pi]));\r
13325                 hi_hfta_node->param_tbl->add_param(param_names[pi],dt->duplicate(),\r
13326                                                                         param_tbl->handle_access(param_names[pi]));\r
13327         }\r
13328         low_hfta_node->definitions = definitions;\r
13329         hi_hfta_node->definitions = definitions;\r
13330 \r
13331 \r
13332         low_hfta_node->table_name->set_machine(table_name->get_machine());\r
13333         low_hfta_node->table_name->set_interface(table_name->get_interface());\r
13334         low_hfta_node->table_name->set_ifq(false);\r
13335 \r
13336         hi_hfta_node->table_name->set_machine(table_name->get_machine());\r
13337         hi_hfta_node->table_name->set_interface(table_name->get_interface());\r
13338         hi_hfta_node->table_name->set_ifq(false);\r
13339 \r
13340         ret_vec.push_back(low_hfta_node);\r
13341         ret_vec.push_back(hi_hfta_node);\r
13342 \r
13343 \r
13344         return(ret_vec);\r
13345 \r
13346 \r
13347         // TODO: add splitting into selection/aggregation\r
13348 }\r
13349 \r
13350 //---------------------------------------------------------------\r
13351 //              Code for propagating Protocol field source information\r
13352 \r
13353 \r
13354 scalarexp_t *resolve_protocol_se(scalarexp_t *se, vector<map<string, scalarexp_t *> *> &src_vec, gb_table *gb_tbl, table_list *Schema){\r
13355         scalarexp_t *rse, *lse,*p_se, *gb_se;\r
13356         int tno, schema_type;\r
13357         map<string, scalarexp_t *> *pse_map;\r
13358 \r
13359   switch(se->get_operator_type()){\r
13360     case SE_LITERAL:\r
13361                 return new scalarexp_t(se->get_literal());\r
13362     case SE_PARAM:\r
13363                 return scalarexp_t::make_param_reference(se->get_op().c_str());\r
13364     case SE_COLREF:\r
13365         if(se->is_gb()){\r
13366                         if(gb_tbl == NULL)\r
13367                                         fprintf(stderr,"INTERNAL ERROR, in resolve_protocol_se, se->gb_ref=%d, but gb_tbl is NULL\n",se->get_gb_ref());\r
13368                         gb_se = gb_tbl->get_def(se->get_gb_ref());\r
13369                         return resolve_protocol_se(gb_se,src_vec,gb_tbl,Schema);\r
13370                 }\r
13371 \r
13372                 schema_type = Schema->get_schema_type(se->get_colref()->get_schema_ref());\r
13373                 if(schema_type == PROTOCOL_SCHEMA)\r
13374                         return dup_se(se,NULL);\r
13375 \r
13376         tno = se->get_colref()->get_tablevar_ref();\r
13377         if(tno >= src_vec.size()){\r
13378                         fprintf(stderr,"INTERNAL ERROR, in resolve_protocol_se, tno=%d, src_vec.size()=%lu\n",tno,src_vec.size());\r
13379                 }\r
13380                 if(src_vec[tno] == NULL)\r
13381                         return NULL;\r
13382 \r
13383                 pse_map =src_vec[tno];\r
13384                 p_se = (*pse_map)[se->get_colref()->get_field()];\r
13385                 if(p_se == NULL)\r
13386                         return NULL;\r
13387                 return dup_se(p_se,NULL);\r
13388     case SE_UNARY_OP:\r
13389         lse = resolve_protocol_se(se->get_left_se(),src_vec,gb_tbl,Schema);\r
13390         if(lse == NULL)\r
13391                 return NULL;\r
13392         else\r
13393                 return new scalarexp_t(se->get_op().c_str(),lse);\r
13394     case SE_BINARY_OP:\r
13395         lse = resolve_protocol_se(se->get_left_se(),src_vec,gb_tbl,Schema);\r
13396         if(lse == NULL)\r
13397                 return NULL;\r
13398         rse = resolve_protocol_se(se->get_right_se(),src_vec,gb_tbl,Schema);\r
13399         if(rse == NULL)\r
13400                 return NULL;\r
13401                 return new scalarexp_t(se->get_op().c_str(),lse,rse);\r
13402     case SE_AGGR_STAR:\r
13403                 return( NULL );\r
13404     case SE_AGGR_SE:\r
13405                 return( NULL );\r
13406         case SE_FUNC:\r
13407                 return(NULL);\r
13408         default:\r
13409                 return(NULL);\r
13410         break;\r
13411   }\r
13412 \r
13413 }\r
13414 \r
13415 void spx_qpn::create_protocol_se(vector<qp_node *> q_sources, table_list *Schema){\r
13416         int i;\r
13417         vector<map<string, scalarexp_t *> *> src_vec;\r
13418 \r
13419         for(i=0;i<q_sources.size();i++){\r
13420                 if(q_sources[i] != NULL)\r
13421                         src_vec.push_back(q_sources[i]->get_protocol_se());\r
13422                 else\r
13423                         src_vec.push_back(NULL);\r
13424         }\r
13425 \r
13426         for(i=0;i<select_list.size();i++){\r
13427                 protocol_map[select_list[i]->name] = resolve_protocol_se(select_list[i]->se,src_vec,NULL,Schema);\r
13428         }\r
13429 }\r
13430 \r
13431 void join_eq_hash_qpn::create_protocol_se(vector<qp_node *> q_sources, table_list *Schema){\r
13432         int i;\r
13433         vector<map<string, scalarexp_t *> *> src_vec;\r
13434 \r
13435         for(i=0;i<q_sources.size();i++){\r
13436                 if(q_sources[i] != NULL)\r
13437                         src_vec.push_back(q_sources[i]->get_protocol_se());\r
13438                 else\r
13439                         src_vec.push_back(NULL);\r
13440         }\r
13441 \r
13442         for(i=0;i<select_list.size();i++){\r
13443                 protocol_map[select_list[i]->name] = resolve_protocol_se(select_list[i]->se,src_vec,NULL,Schema);\r
13444         }\r
13445 \r
13446         for(i=0;i<hash_eq.size();i++){\r
13447                 hash_src_l.push_back(resolve_protocol_se(hash_eq[i]->pr->get_left_se(),src_vec,NULL,Schema));\r
13448                 hash_src_r.push_back(resolve_protocol_se(hash_eq[i]->pr->get_right_se(),src_vec,NULL,Schema));\r
13449         }\r
13450 }\r
13451 \r
13452 void filter_join_qpn::create_protocol_se(vector<qp_node *> q_sources, table_list *Schema){\r
13453         int i;\r
13454         vector<map<string, scalarexp_t *> *> src_vec;\r
13455 \r
13456         for(i=0;i<q_sources.size();i++){\r
13457                 if(q_sources[i] != NULL)\r
13458                         src_vec.push_back(q_sources[i]->get_protocol_se());\r
13459                 else\r
13460                         src_vec.push_back(NULL);\r
13461         }\r
13462 \r
13463         for(i=0;i<select_list.size();i++){\r
13464                 protocol_map[select_list[i]->name] = resolve_protocol_se(select_list[i]->se,src_vec,NULL,Schema);\r
13465         }\r
13466 \r
13467         for(i=0;i<hash_eq.size();i++){\r
13468                 hash_src_l.push_back(resolve_protocol_se(hash_eq[i]->pr->get_left_se(),src_vec,NULL,Schema));\r
13469                 hash_src_r.push_back(resolve_protocol_se(hash_eq[i]->pr->get_right_se(),src_vec,NULL,Schema));\r
13470         }\r
13471 }\r
13472 \r
13473 void sgah_qpn::create_protocol_se(vector<qp_node *> q_sources, table_list *Schema){\r
13474         int i;\r
13475         vector<map<string, scalarexp_t *> *> src_vec;\r
13476 \r
13477         for(i=0;i<q_sources.size();i++){\r
13478                 if(q_sources[i] != NULL)\r
13479                         src_vec.push_back(q_sources[i]->get_protocol_se());\r
13480                 else\r
13481                         src_vec.push_back(NULL);\r
13482         }\r
13483 \r
13484         for(i=0;i<select_list.size();i++){\r
13485                 protocol_map[select_list[i]->name] = resolve_protocol_se(select_list[i]->se,src_vec,&gb_tbl,Schema);\r
13486         }\r
13487 \r
13488         for(i=0;i<gb_tbl.size();i++)\r
13489                 gb_sources.push_back(resolve_protocol_se(gb_tbl.get_def(i),src_vec,&gb_tbl,Schema));\r
13490 \r
13491 }\r
13492 \r
13493 void rsgah_qpn::create_protocol_se(vector<qp_node *> q_sources, table_list *Schema){\r
13494         int i;\r
13495         vector<map<string, scalarexp_t *> *> src_vec;\r
13496 \r
13497         for(i=0;i<q_sources.size();i++){\r
13498                 if(q_sources[i] != NULL)\r
13499                         src_vec.push_back(q_sources[i]->get_protocol_se());\r
13500                 else\r
13501                         src_vec.push_back(NULL);\r
13502         }\r
13503 \r
13504         for(i=0;i<select_list.size();i++){\r
13505                 protocol_map[select_list[i]->name] = resolve_protocol_se(select_list[i]->se,src_vec,&gb_tbl,Schema);\r
13506         }\r
13507 \r
13508         for(i=0;i<gb_tbl.size();i++)\r
13509                 gb_sources.push_back(resolve_protocol_se(gb_tbl.get_def(i),src_vec,&gb_tbl,Schema));\r
13510 }\r
13511 \r
13512 void sgahcwcb_qpn::create_protocol_se(vector<qp_node *> q_sources, table_list *Schema){\r
13513         int i;\r
13514         vector<map<string, scalarexp_t *> *> src_vec;\r
13515 \r
13516         for(i=0;i<q_sources.size();i++){\r
13517                 if(q_sources[i] != NULL)\r
13518                         src_vec.push_back(q_sources[i]->get_protocol_se());\r
13519                 else\r
13520                         src_vec.push_back(NULL);\r
13521         }\r
13522 \r
13523         for(i=0;i<select_list.size();i++){\r
13524                 protocol_map[select_list[i]->name] = resolve_protocol_se(select_list[i]->se,src_vec,&gb_tbl,Schema);\r
13525         }\r
13526 \r
13527         for(i=0;i<gb_tbl.size();i++)\r
13528                 gb_sources.push_back(resolve_protocol_se(gb_tbl.get_def(i),src_vec,&gb_tbl,Schema));\r
13529 }\r
13530 \r
13531 void mrg_qpn::create_protocol_se(vector<qp_node *> q_sources, table_list *Schema){\r
13532         int f,s,i;\r
13533         scalarexp_t *first_se;\r
13534 \r
13535         vector<map<string, scalarexp_t *> *> src_vec;\r
13536         map<string, scalarexp_t *> *pse_map;\r
13537 \r
13538         for(i=0;i<q_sources.size();i++){\r
13539                 if(q_sources[i] != NULL)\r
13540                         src_vec.push_back(q_sources[i]->get_protocol_se());\r
13541                 else\r
13542                         src_vec.push_back(NULL);\r
13543         }\r
13544 \r
13545         if(q_sources.size() == 0){\r
13546                 fprintf(stderr,"INTERNAL ERROR in mrg_qpn::create_protocol_se, q_sources.size() == 0\n");\r
13547                 exit(1);\r
13548         }\r
13549 \r
13550         vector<field_entry *> tbl_flds = table_layout->get_fields();\r
13551         for(f=0;f<tbl_flds.size();f++){\r
13552                 bool match = true;\r
13553                 string fld_nm = tbl_flds[f]->get_name();\r
13554                 pse_map = src_vec[0];\r
13555                 first_se = (*pse_map)[fld_nm];\r
13556                 if(first_se == NULL)\r
13557                         match = false;\r
13558                 for(s=1;s<src_vec.size() && match;s++){\r
13559                         pse_map = src_vec[s];\r
13560                         scalarexp_t *match_se = (*pse_map)[fld_nm];\r
13561                         if(match_se == false)\r
13562                                 match = false;\r
13563                         else\r
13564                                 match = is_equivalent_se_base(first_se, match_se, Schema);\r
13565                 }\r
13566                 if(match)\r
13567                         protocol_map[fld_nm] = first_se;\r
13568                 else\r
13569                         protocol_map[fld_nm] = NULL;\r
13570         }\r
13571 }\r