Fixed newline characters throughout the code
[com/gs-lite.git] / src / ftacmp / query_plan.cc
1 /* ------------------------------------------------
2 Copyright 2014 AT&T Intellectual Property
3    Licensed under the Apache License, Version 2.0 (the "License");
4    you may not use this file except in compliance with the License.
5    You may obtain a copy of the License at
6
7      http://www.apache.org/licenses/LICENSE-2.0
8
9    Unless required by applicable law or agreed to in writing, software
10    distributed under the License is distributed on an "AS IS" BASIS,
11    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12    See the License for the specific language governing permissions and
13    limitations under the License.
14  ------------------------------------------- */
15
16 //              Create, manipulate, and dump query plans.
17
18 #include "query_plan.h"
19 #include "analyze_fta.h"
20 #include "generate_utils.h"
21
22 #include<vector>
23
24 using namespace std;
25
26 extern string hash_nums[NRANDS];        // for fast hashing
27
28
29 char tmpstr[1000];
30
31 void untaboo(string &s){
32         int c;
33         for(c=0;c<s.size();++c){
34                 if(s[c] == '.'){
35                         s[c] = '_';
36                 }
37         }
38 }
39
40 //                      mrg_qpn constructor, define here to avoid
41 //                      circular references in the .h file
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){
43                 param_tbl = spx->param_tbl;
44                 int i;
45                 node_name = n_name;
46                 field_entry_list *fel = new field_entry_list();
47                 merge_fieldpos = -1;
48
49                 disorder = 1;
50
51                 for(i=0;i<spx->select_list.size();++i){
52                         data_type *dt = spx->select_list[i]->se->get_data_type()->duplicate();
53                         if(dt->is_temporal()){
54                                 if(merge_fieldpos < 0){
55                                         merge_fieldpos = i;
56                                 }else{
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() );
58                                         dt->reset_temporal();
59                                 }
60                         }
61
62                         field_entry *fe = dt->make_field_entry(spx->select_list[i]->name);
63                         fel->append_field(fe);
64                         delete dt;
65                 }
66                 if(merge_fieldpos<0){
67                         fprintf(stderr,"ERROR, no temporal attribute for merge subquery %s\n",n_name.c_str());
68                                 exit(1);
69                 }
70                 table_layout = new table_def( n_name.c_str(), NULL, NULL, fel, STREAM_SCHEMA);
71
72 //                              NEED TO HANDLE USER_SPECIFIED SLACK
73                 this->resolve_slack(spx->select_list[merge_fieldpos]->se,
74                                 spx->select_list[merge_fieldpos]->name, ifaces, ifdb,NULL);
75 //      if(this->slack == NULL)
76 //              fprintf(stderr,"Zero slack.\n");
77 //      else
78 //              fprintf(stderr,"slack is %s\n",slack->to_string().c_str());
79
80                 for(i=0;i<sources.size();i++){
81                         std::string rvar = "_m"+int_to_string(i);
82                         mvars.push_back(new colref_t(rvar.c_str(), spx->select_list[merge_fieldpos]->name.c_str()));
83                         mvars[i]->set_tablevar_ref(i);
84                         fm.push_back(new tablevar_t(sources[i].c_str()));
85                         fm[i]->set_range_var(rvar);
86                 }
87
88                 param_tbl = new param_table();
89                 std::vector<std::string> param_names = spx->param_tbl->get_param_names();
90                 int pi;
91                 for(pi=0;pi<param_names.size();pi++){
92                         data_type *dt = spx->param_tbl->get_data_type(param_names[pi]);
93                         param_tbl->add_param(param_names[pi],dt->duplicate(),
94                                                         spx->param_tbl->handle_access(param_names[pi]));
95                 }
96                 definitions = spx->definitions;
97
98 }
99
100
101
102 //              This function translates an analyzed parse tree
103 //              into one or more query nodes (qp_node).
104 //              Currently only one node is created, but some query
105 //              fragments might create more than one query node,
106 //              e.g. aggregation over a joim, or nested subqueries
107 //              in the FROM clause (unless this is handles at parse tree
108 //              analysis time).  At this stage, they will be linked
109 //              by the names in the FROM clause.
110 //              INVARIANT : if mroe than one query node is returned,
111 //              the last one represents the output of the query.
112 vector<qp_node *> create_query_nodes(query_summary_class *qs,table_list *Schema){
113
114 //              Classify the query.
115
116         vector <qp_node *> local_plan;
117         qp_node *plan_root;
118
119 //                      TODO
120 //                      I should probably move a lot of this code
121 //                      into the qp_node constructors,
122 //                      and have this code focus on building the query plan tree.
123
124 //              MERGE node
125         if(qs->query_type == MERGE_QUERY){
126                 mrg_qpn *merge_node = new mrg_qpn(qs,Schema);
127
128 //                      Done
129                 plan_root = merge_node;
130                 local_plan.push_back(merge_node);
131
132                 /*
133                 Do not split sources until we are done with optimizations
134                 vector<mrg_qpn *> split_merge = merge_node->split_sources();
135                 local_plan.insert(local_plan.begin(), split_merge.begin(), split_merge.end());
136                 */
137 //                      If children are created, add them to the schema.
138 /*
139                 int i;
140 printf("split_merge size is %d\n",split_merge.size());
141                 for(i=1;i<split_merge.size();++i){
142                         Schema->add_table(split_merge[i]->get_fields());
143 printf("Adding split merge table %d\n",i);
144                 }
145 */
146
147 /*
148 printf("Did split sources on %s:\n",qs->query_name.c_str());
149 int ss;
150 for(ss=0;ss<local_plan.size();ss++){
151 printf("node %d, name=%s, sources=",ss,local_plan[ss]->get_node_name().c_str());
152 vector<tablevar_t *> inv = local_plan[ss]->get_input_tbls();
153 int nn;
154 for(nn=0;nn<inv.size();nn++){
155 printf("%s ",inv[nn]->to_string().c_str());
156 }
157 printf("\n");
158 }
159 */
160
161
162         } else{
163
164 //              Select / Aggregation / Join
165           if(qs->gb_tbl->size() == 0 && qs->aggr_tbl->size() == 0){
166
167                 if(qs->fta_tree->get_from()->size() == 1){
168                         spx_qpn *spx_node = new spx_qpn(qs,Schema);
169
170                         plan_root = spx_node;
171                         local_plan.push_back(spx_node);
172                 }else{
173                         if(qs->fta_tree->get_from()->get_properties() == FILTER_JOIN_PROPERTY){
174                                 filter_join_qpn *join_node = new filter_join_qpn(qs,Schema);
175                                 plan_root = join_node;
176                                 local_plan.push_back(join_node);
177                         }else{
178                                 join_eq_hash_qpn *join_node = new join_eq_hash_qpn(qs,Schema);
179                                 plan_root = join_node;
180                                 local_plan.push_back(join_node);
181                         }
182                 }
183           }else{
184 //                      aggregation
185
186                 if(qs->states_refd.size() || qs->sg_tbl.size() || qs->cb_cnf.size()){
187                         sgahcwcb_qpn *sgahcwcb_node = new sgahcwcb_qpn(qs,Schema);
188                         plan_root = sgahcwcb_node;
189                         local_plan.push_back(sgahcwcb_node);
190                 }else{
191                         if(qs->closew_cnf.size()){
192                                 rsgah_qpn *rsgah_node = new rsgah_qpn(qs,Schema);
193                                 plan_root = rsgah_node;
194                                 local_plan.push_back(rsgah_node);
195                         }else{
196                                 sgah_qpn *sgah_node = new sgah_qpn(qs,Schema);
197                                 plan_root = sgah_node;
198                                 local_plan.push_back(sgah_node);
199                         }
200                 }
201           }
202         }
203
204
205 //              Get the query name and other definitions.
206         plan_root->set_node_name( qs->query_name);
207         plan_root->set_definitions( qs->definitions) ;
208
209
210 //      return(plan_root);
211         return(local_plan);
212
213 }
214
215
216 string se_to_query_string(scalarexp_t *se, aggregate_table *aggr_tbl){
217   string l_str;
218   string r_str;
219   string ret;
220   int p;
221   vector<scalarexp_t *> operand_list;
222   string su_ind = "";
223
224   if(se->is_superaggr())
225         su_ind = "$";
226
227   switch(se->get_operator_type()){
228     case SE_LITERAL:
229                 l_str = se->get_literal()->to_query_string();
230                 return l_str;
231     case SE_PARAM:
232                 l_str = "$" + se->get_op();
233                 return l_str;
234     case SE_COLREF:
235                 l_str =  se->get_colref()->to_query_string() ;
236                 return l_str;
237     case SE_UNARY_OP:
238                  l_str = se_to_query_string(se->get_left_se(),aggr_tbl);
239
240                 return se->get_op()+"( "+l_str+" )";;
241     case SE_BINARY_OP:
242                 l_str = se_to_query_string(se->get_left_se(),aggr_tbl);
243                 r_str = se_to_query_string(se->get_right_se(),aggr_tbl);
244                 return( "("+l_str+")"+se->get_op()+"("+r_str+")" );
245     case SE_AGGR_STAR:
246                 return( se->get_op() + su_ind + "(*)");
247     case SE_AGGR_SE:
248                 l_str = se_to_query_string(aggr_tbl->get_aggr_se(se->get_aggr_ref()),aggr_tbl);
249                 return( se->get_op() + su_ind + "(" + l_str + ")" );
250         case SE_FUNC:
251                 if(se->get_aggr_ref() >= 0)
252                         operand_list = aggr_tbl->get_operand_list(se->get_aggr_ref());
253                 else
254                         operand_list = se->get_operands();
255
256                 ret = se->get_op() + su_ind + "(";
257                 for(p=0;p<operand_list.size();p++){
258                         l_str = se_to_query_string(operand_list[p],aggr_tbl);
259                         if(p>0) ret += ", ";
260                         ret += l_str;
261                 }
262                 ret += ")";
263                 return(ret);
264         break;
265   }
266   return "ERROR SE op type not recognized in se_to_query_string.\n";
267 }
268
269
270 string pred_to_query_str(predicate_t *pr, aggregate_table *aggr_tbl){
271   string l_str;
272   string r_str;
273   string ret;
274   int o,l;
275   vector<literal_t *> llist;
276   vector<scalarexp_t *> op_list;
277
278         switch(pr->get_operator_type()){
279         case PRED_IN:
280                 l_str = se_to_query_string(pr->get_left_se(),aggr_tbl);
281                 ret = l_str + " IN [";
282                 llist = pr->get_lit_vec();
283                 for(l=0;l<llist.size();l++){
284                         if(l>0) ret += ", ";
285                         ret += llist[l]->to_query_string();
286                 }
287                 ret += "]";
288
289                 return(ret);
290         case PRED_COMPARE:
291                 l_str = se_to_query_string(pr->get_left_se(),aggr_tbl);
292                 r_str = se_to_query_string(pr->get_right_se(),aggr_tbl);
293                 return( l_str + " " + pr->get_op() + " " + r_str );
294         case PRED_UNARY_OP:
295                 l_str = pred_to_query_str(pr->get_left_pr(),aggr_tbl);
296                 return(pr->get_op() + "( " + l_str + " )");
297         case PRED_BINARY_OP:
298                 l_str = pred_to_query_str(pr->get_left_pr(),aggr_tbl);
299                 r_str = pred_to_query_str(pr->get_right_pr(),aggr_tbl);
300                 return("( " + r_str + " )" + pr->get_op() + "( " + l_str + " )");
301         case PRED_FUNC:
302                 ret = pr->get_op()+"[";
303                 op_list = pr->get_op_list();
304                 for(o=0;o<op_list.size();++o){
305                         if(o>0) ret += ", ";
306                         ret += se_to_query_string(op_list[o],aggr_tbl);
307                 }
308                 ret += "]";
309                 return(ret);
310         default:
311                 fprintf(stderr,"INTERNAL ERROR in pred_to_query_str, line %d, character %d, unknown predicate operator type %d\n",
312                         pr->get_lineno(), pr->get_charno(), pr->get_operator_type() );
313                 exit(1);
314         }
315
316         return(0);
317 }
318
319
320
321 //                      Build a selection list,
322 //                      but avoid adding duplicate SEs.
323
324
325 int add_select_list_nodup(vector<select_element *> &lfta_select_list, scalarexp_t *se,
326                                 bool &new_element){
327         new_element = false;
328         int s;
329         for(s=0;s<lfta_select_list.size();s++){
330                 if(is_equivalent_se(lfta_select_list[s]->se, se)){
331                         return(s);
332                 }
333         }
334         new_element = true;
335         lfta_select_list.push_back(new select_element(se,"NoNameIn:add_select_list_nodup"));
336         return(lfta_select_list.size()-1);
337 }
338
339
340
341 //              TODO: The generated colref should be tied to the tablevar
342 //              representing the lfta output.  For now, always 0.
343
344 scalarexp_t *make_fta_se_ref(vector<select_element *> &lfta_select_list, scalarexp_t *se, int h_tvref){
345         bool new_element;
346         int fta_se_nbr = add_select_list_nodup(lfta_select_list, se, new_element);
347         string colname;
348         if(!new_element){
349                 colname = lfta_select_list[fta_se_nbr]->name;
350         }else{
351                 colname = impute_colname(lfta_select_list, se);
352                 lfta_select_list[fta_se_nbr]->name = colname;
353         }
354 //
355 //              TODO: fill in the tablevar and schema of the colref here.
356         colref_t *new_cr = new colref_t(colname.c_str());
357         new_cr->set_tablevar_ref(h_tvref);
358
359
360         scalarexp_t *new_se= new scalarexp_t(new_cr);
361         new_se->use_decorations_of(se);
362
363         return(new_se);
364 }
365
366
367 //                      Build a selection list,
368 //                      but avoid adding duplicate SEs.
369
370
371 int add_select_list_nodup(vector<select_element *> *lfta_select_list, scalarexp_t *se,
372                                 bool &new_element){
373         new_element = false;
374         int s;
375         for(s=0;s<lfta_select_list->size();s++){
376                 if(is_equivalent_se((*lfta_select_list)[s]->se, se)){
377                         return(s);
378                 }
379         }
380         new_element = true;
381         lfta_select_list->push_back(new select_element(se,"NoNameIn:add_select_list_nodup"));
382         return(lfta_select_list->size()-1);
383 }
384
385
386
387 //              TODO: The generated colref should be tied to the tablevar
388 //              representing the lfta output.  For now, always 0.
389
390 scalarexp_t *make_fta_se_ref(vector<vector<select_element *> *> &lfta_select_list, scalarexp_t *se, int h_tvref){
391         bool new_element;
392     vector<select_element *> *the_sel_list = lfta_select_list[h_tvref];
393         int fta_se_nbr = add_select_list_nodup(the_sel_list, se, new_element);
394         string colname;
395         if(!new_element){
396                 colname = (*the_sel_list)[fta_se_nbr]->name;
397         }else{
398                 colname = impute_colname(*the_sel_list, se);
399                 (*the_sel_list)[fta_se_nbr]->name = colname;
400         }
401 //
402 //              TODO: fill in the tablevar and schema of the colref here.
403         colref_t *new_cr = new colref_t(colname.c_str());
404         new_cr->set_tablevar_ref(h_tvref);
405
406
407         scalarexp_t *new_se= new scalarexp_t(new_cr);
408         new_se->use_decorations_of(se);
409
410         return(new_se);
411 }
412
413
414
415
416 //
417 //                      Test if a se can be evaluated at the fta.
418 //                      check forbidden types (e.g. float), forbidden operations
419 //                      between types (e.g. divide a long long), forbidden operations
420 //                      (too expensive, not implemented).
421 //
422 //                      Return true if not forbidden, false if forbidden
423 //
424 //                      TODO: the parameter aggr_tbl is not used, delete it.
425
426 bool check_fta_forbidden_se(scalarexp_t *se,
427                                                  aggregate_table *aggr_tbl,
428                                                  ext_fcn_list *Ext_fcns
429                                                  ){
430
431   int p, fcn_id;
432   vector<scalarexp_t *> operand_list;
433   vector<data_type *> dt_signature;
434   data_type *dt = se->get_data_type();
435
436
437
438   switch(se->get_operator_type()){
439     case SE_LITERAL:
440     case SE_PARAM:
441     case SE_COLREF:
442                 return( se->get_data_type()->fta_legal_type() );
443         case SE_IFACE_PARAM:
444                 return true;
445     case SE_UNARY_OP:
446                 if(!check_fta_forbidden_se(se->get_left_se(), aggr_tbl, Ext_fcns))
447                          return(false);
448                 return(
449                    dt->fta_legal_operation(se->get_left_se()->get_data_type(), se->get_op())
450                 );
451     case SE_BINARY_OP:
452                  if(!check_fta_forbidden_se(se->get_left_se(),aggr_tbl, Ext_fcns))
453                          return(false);
454                  if(!check_fta_forbidden_se(se->get_right_se(),aggr_tbl, Ext_fcns))
455                          return(false);
456                  return(dt->fta_legal_operation(se->get_left_se()->get_data_type(),
457                                                                         se->get_right_se()->get_data_type(),
458                                                                         se->get_op()
459                                                                         )
460                 );
461
462 //                      return true, aggregate fta-safeness is determined elsewhere.
463     case SE_AGGR_STAR:
464                 return(true);
465     case SE_AGGR_SE:
466                 return(true);
467
468         case SE_FUNC:
469                 if(se->get_aggr_ref() >= 0) return true;
470
471                 operand_list = se->get_operands();
472                 for(p=0;p<operand_list.size();p++){
473                         if(!check_fta_forbidden_se(operand_list[p],aggr_tbl, Ext_fcns))
474                                 return(false);
475                         dt_signature.push_back(operand_list[p]->get_data_type() );
476                 }
477                 fcn_id = Ext_fcns->lookup_fcn(se->get_op(), dt_signature);
478                 if( fcn_id < 0 ){
479                         fprintf(stderr,"ERROR, no external function %s(",se->get_op().c_str());
480                         int o;
481                         for(o=0;o<operand_list.size();o++){
482                                 if(o>0) fprintf(stderr,", ");
483                                 fprintf(stderr,"%s",operand_list[o]->get_data_type()->to_string().c_str());
484                         }
485                         fprintf(stderr,") is defined, line %d, char %d\n", se->get_lineno(), se->get_charno() );
486                         if(fcn_id == -2) fprintf(stderr,"(multiple subsuming functions found)\n");
487                         return(false);
488                 }
489
490                 return(Ext_fcns->fta_legal(fcn_id) );
491         default:
492                 printf("INTERNAL ERROR in check_fta_forbidden_se: operator type %d\n",se->get_operator_type());
493                 exit(1);
494         break;
495   }
496   return(false);
497
498 }
499
500
501 //              test if a pr can be executed at the fta.
502 //
503 //                      Return true if not forbidden, false if forbidden
504
505 bool check_fta_forbidden_pr(predicate_t *pr,
506                                                  aggregate_table *aggr_tbl,
507                                                  ext_fcn_list *Ext_fcns
508                                                  ){
509
510   vector<literal_t *> llist;
511   data_type *dt;
512   int l,o, fcn_id;
513   vector<scalarexp_t *> op_list;
514   vector<data_type *> dt_signature;
515
516
517
518         switch(pr->get_operator_type()){
519         case PRED_IN:
520                 if(! check_fta_forbidden_se(pr->get_left_se(), aggr_tbl, Ext_fcns) )
521                         return(false);
522                 llist = pr->get_lit_vec();
523                 for(l=0;l<llist.size();l++){
524                         dt = new data_type(llist[l]->get_type());
525                         if(! dt->fta_legal_type()){
526                                 delete dt;
527                                 return(false);
528                         }
529                         delete dt;
530                 }
531                 return(true);
532         case PRED_COMPARE:
533                 if(! check_fta_forbidden_se(pr->get_left_se(), aggr_tbl, Ext_fcns))
534                         return(false);
535                 if(! check_fta_forbidden_se(pr->get_right_se(), aggr_tbl, Ext_fcns))
536                         return(false);
537                 return(true);
538         case PRED_UNARY_OP:
539                 return( check_fta_forbidden_pr(pr->get_left_pr(), aggr_tbl, Ext_fcns) );
540         case PRED_BINARY_OP:
541                 if(! check_fta_forbidden_pr(pr->get_left_pr(), aggr_tbl, Ext_fcns))
542                         return(false);
543                 if(! check_fta_forbidden_pr(pr->get_right_pr(), aggr_tbl, Ext_fcns))
544                         return(false);
545                 return(true);
546         case PRED_FUNC:
547                 op_list = pr->get_op_list();
548                 for(o=0;o<op_list.size();o++){
549                         if(!check_fta_forbidden_se(op_list[o],aggr_tbl, Ext_fcns))
550                                 return(false);
551                         dt_signature.push_back(op_list[o]->get_data_type() );
552                 }
553                 fcn_id = Ext_fcns->lookup_pred(pr->get_op(), dt_signature);
554                 if( fcn_id < 0 ){
555                         fprintf(stderr,"ERROR, no external predicate %s(",pr->get_op().c_str());
556                         int o;
557                         for(o=0;o<op_list.size();o++){
558                                 if(o>0) fprintf(stderr,", ");
559                                 fprintf(stderr,"%s",op_list[o]->get_data_type()->to_string().c_str());
560                         }
561                         fprintf(stderr,") is defined, line %d, char %d\n", pr->get_lineno(), pr->get_charno() );
562                         if(fcn_id == -2) fprintf(stderr,"(multiple subsuming predicates found)\n");
563                         return(false);
564                 }
565
566                 return(Ext_fcns->fta_legal(fcn_id) );
567         default:
568                 fprintf(stderr,"INTERNAL ERROR in check_fta_forbidden_pr, line %d, character %d, unknown predicate operator type %d\n",
569                         pr->get_lineno(), pr->get_charno(), pr->get_operator_type() );
570                 exit(1);
571         }
572
573         return(0);
574
575 }
576
577
578 //              Split the aggregates in orig_aggr_tbl, into superaggregates and
579 //              subaggregates.
580 //              (the value of the HFTA aggregate might be a SE of several LFTA
581 //               subaggregates, e.g. avg : sum / count )
582 //              Register the superaggregates in hfta_aggr_tbl, and the
583 //              subaggregates in lfta_aggr_tbl.
584 //              Insert references to the subaggregates into lfta_select_list.
585 //              (and record their names in the currnames list)
586 //              Create a SE for the superaggregate, put it in hfta_aggr_se,
587 //              keyed on agr_id.
588
589 void split_fta_aggr(aggregate_table *orig_aggr_tbl, int agr_id,
590                                         aggregate_table *hfta_aggr_tbl,
591                                         aggregate_table *lfta_aggr_tbl,
592                                         vector<select_element *> &lfta_select_list,
593                                         map<int,scalarexp_t *> &hfta_aggr_se,
594                                     ext_fcn_list *Ext_fcns
595                                         ){
596         bool new_element;
597         scalarexp_t *subaggr_se;
598         int fta_se_nbr;
599         string colname;
600         int ano;
601         colref_t *new_cr;
602         scalarexp_t *new_se, *l_se;
603         vector<scalarexp_t *> subaggr_ref_se;
604
605 //              UDAF processing
606         if(! orig_aggr_tbl->is_builtin(agr_id)){
607 //                      Construct the subaggregate
608                 int fcn_id = orig_aggr_tbl->get_fcn_id(agr_id);
609                 vector<scalarexp_t *> opl = orig_aggr_tbl->get_operand_list(agr_id);
610                 vector<scalarexp_t *> subopl;
611                 int o;
612                 for(o=0;o<opl.size();++o){
613                         subopl.push_back(dup_se(opl[o], NULL));
614                 }
615                 int sub_id = Ext_fcns->get_subaggr_id(fcn_id);
616                 subaggr_se = new scalarexp_t(Ext_fcns->get_fcn_name(sub_id).c_str(), subopl);
617                 subaggr_se->set_fcn_id(sub_id);
618                 subaggr_se->set_data_type(Ext_fcns->get_fcn_dt(sub_id));
619 //                      Add it to the lfta select list.
620                 fta_se_nbr = add_select_list_nodup(lfta_select_list, subaggr_se,new_element);
621                 if(!new_element){
622                         colname = lfta_select_list[fta_se_nbr]->name;
623                 }else{
624                         colname = impute_colname(lfta_select_list, subaggr_se);
625                         lfta_select_list[fta_se_nbr]->name = colname;
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));
627                         subaggr_se->set_aggr_id(ano);
628                 }
629
630 //                      Construct a reference to the subaggregate
631                 new_cr = new colref_t(colname.c_str());
632                 new_se = new scalarexp_t(new_cr);
633 //                              I'm not certain what the types should be ....
634 //                              This will need to be filled in by later analysis.
635 //                              NOTE: this might not capture all the meaning of data_type ...
636                 new_se->set_data_type(Ext_fcns->get_fcn_dt(sub_id));
637                 subaggr_ref_se.push_back(new_se);
638
639 //                      Construct the superaggregate
640                 int super_id = Ext_fcns->get_superaggr_id(fcn_id);
641                 scalarexp_t *ret_se = new scalarexp_t(Ext_fcns->get_fcn_name(super_id).c_str(), subaggr_ref_se);
642                 ret_se->set_fcn_id(super_id);
643                 ret_se->set_data_type(Ext_fcns->get_fcn_dt(super_id));
644 //                      Register it in the hfta aggregate table
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);
646                 ret_se->set_aggr_id(ano);
647                 hfta_aggr_se[agr_id] = ret_se;
648
649                 return;
650         }
651
652
653 //              builtin aggregate processing
654         bool l_forbid;
655
656         vector<bool> use_se;
657         vector<string> subaggr_names = orig_aggr_tbl->get_subaggr_fcns(agr_id, use_se);
658         vector<data_type *> subaggr_dt = orig_aggr_tbl->get_subaggr_dt(agr_id);
659         int sa;
660
661         if(orig_aggr_tbl->is_star_aggr(agr_id)){
662           for(sa=0;sa<subaggr_names.size();sa++){
663                 subaggr_se = scalarexp_t::make_star_aggr(subaggr_names[sa].c_str());
664                 subaggr_se->set_data_type(subaggr_dt[sa]);
665
666 //                      The following sequence is similar to the code in make_fta_se_ref,
667 //                      but there is special processing for the aggregate tables.
668                 int fta_se_nbr = add_select_list_nodup(lfta_select_list, subaggr_se,new_element);
669                 if(!new_element){
670                         colname = lfta_select_list[fta_se_nbr]->name;
671                 }else{
672                         colname = impute_colname(lfta_select_list, subaggr_se);
673                         lfta_select_list[fta_se_nbr]->name = colname;
674                         ano = lfta_aggr_tbl->add_aggr(subaggr_names[sa].c_str(),NULL, false);
675                         subaggr_se->set_aggr_id(ano);
676                 }
677                 new_cr = new colref_t(colname.c_str());
678                 new_cr->set_tablevar_ref(0);
679                 new_se = new scalarexp_t(new_cr);
680
681 //                                      I'm not certain what the types should be ....
682 //                                      This will need to be filled in by later analysis.
683 //                                              Actually, this is causing a problem.
684 //                                              I will assume a UINT data type. / change to INT
685 //                                              (consistent with assign_data_types in analyze_fta.cc)
686 //                      TODO: why can't I use subaggr_dt, as I do in the other IF branch?
687                 data_type *ndt = new data_type("Int");  // used to be Uint
688                 new_se->set_data_type(ndt);
689
690                 subaggr_ref_se.push_back(new_se);
691           }
692         }else{
693           for(sa=0;sa<subaggr_names.size();sa++){
694                 if(use_se[sa]){
695                         scalarexp_t *aggr_operand = orig_aggr_tbl->get_aggr_se(agr_id);
696                         l_se = dup_se(aggr_operand,  NULL);
697                         subaggr_se = scalarexp_t::make_se_aggr(subaggr_names[sa].c_str(),l_se);
698                 }else{
699                         subaggr_se = scalarexp_t::make_star_aggr(subaggr_names[sa].c_str());
700                 }
701                 subaggr_se->set_data_type(subaggr_dt[sa]);
702
703 //                      again, similar to make_fta_se_ref.
704                 fta_se_nbr = add_select_list_nodup(lfta_select_list, subaggr_se,new_element);
705                 if(!new_element){
706                         colname = lfta_select_list[fta_se_nbr]->name;
707                 }else{
708                         colname = impute_colname(lfta_select_list, subaggr_se);
709                         lfta_select_list[fta_se_nbr]->name = colname;
710                         if(use_se[sa])
711                                 ano = lfta_aggr_tbl->add_aggr(subaggr_names[sa].c_str(),l_se, false);
712                         else
713                                 ano = lfta_aggr_tbl->add_aggr(subaggr_names[sa].c_str(),NULL,false);
714                         subaggr_se->set_aggr_id(ano);
715                 }
716                 new_cr = new colref_t(colname.c_str());
717                 new_se = new scalarexp_t(new_cr);
718 //                              I'm not certain what the types should be ....
719 //                              This will need to be filled in by later analysis.
720 //                              NOTE: this might not capture all the meaning of data_type ...
721                 new_se->set_data_type(subaggr_dt[sa]);
722                 subaggr_ref_se.push_back(new_se);
723           }
724         }
725         scalarexp_t *ret_se = orig_aggr_tbl->make_superaggr_se(agr_id, subaggr_ref_se);
726         ret_se->set_data_type(orig_aggr_tbl->get_data_type(agr_id));
727
728 // ASSUME either the return value is an aggregation,
729 // or a binary_op between two aggregations
730         if(ret_se->get_operator_type() == SE_AGGR_SE || ret_se->get_operator_type() == SE_AGGR_SE){
731                 ano = hfta_aggr_tbl->add_aggr(ret_se->get_op(), ret_se->get_left_se(), false );
732                 ret_se->set_aggr_id(ano);
733         }else{
734 // Basically processing for AVG. 
735 // set the data type of the superagg to that of the subagg.
736                 scalarexp_t *left_se = ret_se->get_left_se();
737                 left_se->set_data_type(subaggr_dt[0]);
738                 ano = hfta_aggr_tbl->add_aggr(left_se->get_op(), left_se->get_left_se(), false );
739                 left_se->set_aggr_id(ano);
740
741                 scalarexp_t *right_se = ret_se->get_right_se();
742                 right_se->set_data_type(subaggr_dt[1]);
743                 ano = hfta_aggr_tbl->add_aggr(right_se->get_op(), right_se->get_left_se(), false );
744                 right_se->set_aggr_id(ano);
745         }
746
747         hfta_aggr_se[agr_id] = ret_se;
748
749 }
750
751
752 //              Split the aggregates in orig_aggr_tbl, into hfta_superaggregates and
753 //              hfta_subaggregates.
754 //              Register the superaggregates in hi_aggr_tbl, and the
755 //              subaggregates in loq_aggr_tbl.
756 //              Insert references to the subaggregates into low_select_list.
757 //              (and record their names in the currnames list)
758 //              Create a SE for the superaggregate, put it in hfta_aggr_se,
759 //              keyed on agr_id.
760
761 void split_hfta_aggr(aggregate_table *orig_aggr_tbl, int agr_id,
762                                         aggregate_table *hi_aggr_tbl,
763                                         aggregate_table *low_aggr_tbl,
764                                         vector<select_element *> &low_select_list,
765                                         map<int,scalarexp_t *> &hi_aggr_se,
766                                     ext_fcn_list *Ext_fcns
767                                         ){
768         bool new_element;
769         scalarexp_t *subaggr_se;
770         int fta_se_nbr;
771         string colname;
772         int ano;
773         colref_t *new_cr;
774         scalarexp_t *new_se, *l_se;
775         vector<scalarexp_t *> subaggr_ref_se;
776
777 //              UDAF processing
778         if(! orig_aggr_tbl->is_builtin(agr_id)){
779 //                      Construct the subaggregate
780                 int fcn_id = orig_aggr_tbl->get_fcn_id(agr_id);
781                 vector<scalarexp_t *> opl = orig_aggr_tbl->get_operand_list(agr_id);
782                 vector<scalarexp_t *> subopl;
783                 int o;
784                 for(o=0;o<opl.size();++o){
785                         subopl.push_back(dup_se(opl[o], NULL));
786                 }
787                 int sub_id = Ext_fcns->get_hfta_subaggr_id(fcn_id);
788                 subaggr_se = new scalarexp_t(Ext_fcns->get_fcn_name(sub_id).c_str(), subopl);
789                 subaggr_se->set_fcn_id(sub_id);
790                 subaggr_se->set_data_type(Ext_fcns->get_fcn_dt(sub_id));
791 //                      Add it to the low select list.
792                 fta_se_nbr = add_select_list_nodup(low_select_list, subaggr_se,new_element);
793                 if(!new_element){
794                         colname = low_select_list[fta_se_nbr]->name;
795                 }else{
796                         colname = impute_colname(low_select_list, subaggr_se);
797                         low_select_list[fta_se_nbr]->name = colname;
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);
799                         subaggr_se->set_aggr_id(ano);
800                 }
801
802 //                      Construct a reference to the subaggregate
803                 new_cr = new colref_t(colname.c_str());
804                 new_se = new scalarexp_t(new_cr);
805 //                              I'm not certain what the types should be ....
806 //                              This will need to be filled in by later analysis.
807 //                              NOTE: this might not capture all the meaning of data_type ...
808                 new_se->set_data_type(Ext_fcns->get_fcn_dt(sub_id));
809                 subaggr_ref_se.push_back(new_se);
810
811 //                      Construct the superaggregate
812                 int super_id = Ext_fcns->get_hfta_superaggr_id(fcn_id);
813                 scalarexp_t *ret_se = new scalarexp_t(Ext_fcns->get_fcn_name(super_id).c_str(), subaggr_ref_se);
814                 ret_se->set_fcn_id(super_id);
815                 ret_se->set_data_type(Ext_fcns->get_fcn_dt(super_id));
816 //                      Register it in the high aggregate table
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);
818                 ret_se->set_aggr_id(ano);
819                 hi_aggr_se[agr_id] = ret_se;
820
821                 return;
822         }
823
824
825 //              builtin aggregate processing
826         bool l_forbid;
827
828         vector<bool> use_se;
829         vector<string> subaggr_names = orig_aggr_tbl->get_subaggr_fcns(agr_id, use_se);
830         vector<data_type *> subaggr_dt = orig_aggr_tbl->get_subaggr_dt(agr_id);
831         int sa;
832
833         if(orig_aggr_tbl->is_star_aggr(agr_id)){
834           for(sa=0;sa<subaggr_names.size();sa++){
835                 subaggr_se = scalarexp_t::make_star_aggr(subaggr_names[sa].c_str());
836                 subaggr_se->set_data_type(subaggr_dt[sa]);
837
838 //                      The following sequence is similar to the code in make_fta_se_ref,
839 //                      but there is special processing for the aggregate tables.
840                 int fta_se_nbr = add_select_list_nodup(low_select_list, subaggr_se,new_element);
841                 if(!new_element){
842                         colname = low_select_list[fta_se_nbr]->name;
843                 }else{
844                         colname = impute_colname(low_select_list, subaggr_se);
845                         low_select_list[fta_se_nbr]->name = colname;
846                         ano = low_aggr_tbl->add_aggr(subaggr_names[sa].c_str(),NULL, false);
847                         subaggr_se->set_aggr_id(ano);
848                 }
849                 new_cr = new colref_t(colname.c_str());
850                 new_cr->set_tablevar_ref(0);
851                 new_se = new scalarexp_t(new_cr);
852
853 //                                      I'm not certain what the types should be ....
854 //                                      This will need to be filled in by later analysis.
855 //                                              Actually, this is causing a problem.
856 //                                              I will assume a UINT data type.
857 //                                              (consistent with assign_data_types in analyze_fta.cc)
858 //                      TODO: why can't I use subaggr_dt, as I do in the other IF branch?
859                 data_type *ndt = new data_type("Int");  // was Uint
860                 new_se->set_data_type(ndt);
861
862                 subaggr_ref_se.push_back(new_se);
863           }
864         }else{
865           for(sa=0;sa<subaggr_names.size();sa++){
866                 if(use_se[sa]){
867                         scalarexp_t *aggr_operand = orig_aggr_tbl->get_aggr_se(agr_id);
868                         l_se = dup_se(aggr_operand,  NULL);
869                         subaggr_se = scalarexp_t::make_se_aggr(subaggr_names[sa].c_str(),l_se);
870                 }else{
871                         subaggr_se = scalarexp_t::make_star_aggr(subaggr_names[sa].c_str());
872                 }
873                 subaggr_se->set_data_type(subaggr_dt[sa]);
874
875 //                      again, similar to make_fta_se_ref.
876                 fta_se_nbr = add_select_list_nodup(low_select_list, subaggr_se,new_element);
877                 if(!new_element){
878                         colname = low_select_list[fta_se_nbr]->name;
879                 }else{
880                         colname = impute_colname(low_select_list, subaggr_se);
881                         low_select_list[fta_se_nbr]->name = colname;
882                         if(use_se[sa])
883                                 ano = low_aggr_tbl->add_aggr(subaggr_names[sa].c_str(),l_se, false);
884                         else
885                                 ano = low_aggr_tbl->add_aggr(subaggr_names[sa].c_str(),NULL,false);
886                         subaggr_se->set_aggr_id(ano);
887                 }
888                 new_cr = new colref_t(colname.c_str());
889                 new_se = new scalarexp_t(new_cr);
890 //                              I'm not certain what the types should be ....
891 //                              This will need to be filled in by later analysis.
892 //                              NOTE: this might not capture all the meaning of data_type ...
893                 new_se->set_data_type(subaggr_dt[sa]);
894                 subaggr_ref_se.push_back(new_se);
895           }
896         }
897         scalarexp_t *ret_se = orig_aggr_tbl->make_superaggr_se(agr_id, subaggr_ref_se);
898 // ASSUME either the return value is an aggregation,
899 // or a binary_op between two aggregations
900         if(ret_se->get_operator_type() == SE_AGGR_SE || ret_se->get_operator_type() == SE_AGGR_SE){
901                 ret_se->set_data_type(orig_aggr_tbl->get_data_type(agr_id));
902                 ano = hi_aggr_tbl->add_aggr(ret_se->get_op(), ret_se->get_left_se(), false );
903         }else{
904 // Basically processing for AVG. 
905 // set the data type of the superagg to that of the subagg.
906                 scalarexp_t *left_se = ret_se->get_left_se();
907                 left_se->set_data_type(subaggr_dt[0]);
908                 ano = hi_aggr_tbl->add_aggr(left_se->get_op(), left_se->get_left_se(), false );
909                 left_se->set_aggr_id(ano);
910
911                 scalarexp_t *right_se = ret_se->get_right_se();
912                 right_se->set_data_type(subaggr_dt[1]);
913                 ano = hi_aggr_tbl->add_aggr(right_se->get_op(), right_se->get_left_se(), false );
914                 right_se->set_aggr_id(ano);
915         }
916
917         ret_se->set_aggr_id(ano);
918         hi_aggr_se[agr_id] = ret_se;
919
920 }
921
922
923
924
925
926 //              Split a scalar expression into one part which executes
927 //              at the stream and another set of parts which execute
928 //              at the FTA.
929 //              Because I'm actually modifying the SEs, I will make
930 //              copies.  But I will assume that literals, params, and
931 //              colrefs are immutable at this point.
932 //              (if there is ever a need to change one, must make a
933 //               new value).
934 //              NOTE : if se is constant (only refrences literals),
935 //                      avoid making the fta compute it.
936 //
937 //              NOTE : This will need to be generalized to
938 //              handle join expressions, namely to handle a vector
939 //              of lftas.
940 //
941 //              Return value is the HFTA se.
942 //              Add lftas select_elements to the fta_select_list.
943 //              set fta_forbidden if this node or any child cannot
944 //              execute at the lfta.
945
946 /*
947
948 scalarexp_t *split_fta_se(scalarexp_t *se,
949                                   bool &fta_forbidden,
950                                   vector<select_element *> &lfta_select_list,
951                                   ext_fcn_list *Ext_fcns
952                                  ){
953
954   int p, fcn_id;
955   vector<scalarexp_t *> operand_list;
956   vector<data_type *> dt_signature;
957   scalarexp_t *ret_se, *l_se, *r_se;
958   bool l_forbid, r_forbid, this_forbid;
959   colref_t *new_cr;
960   scalarexp_t *new_se;
961   data_type *dt = se->get_data_type();
962
963   switch(se->get_operator_type()){
964     case SE_LITERAL:
965                 fta_forbidden = ! se->get_data_type()->fta_legal_type();
966                 ret_se = new scalarexp_t(se->get_literal());
967                 ret_se->use_decorations_of(se);
968                 return(ret_se);
969
970     case SE_PARAM:
971                 fta_forbidden = ! se->get_data_type()->fta_legal_type();
972                 ret_se = scalarexp_t::make_param_reference(se->get_op().c_str());
973                 ret_se->use_decorations_of(se);
974                 return(ret_se);
975
976     case SE_COLREF:
977 //                      No colref should be forbidden,
978 //                      the schema is wrong, the fta_legal_type() fcn is wrong,
979 //                      or the source table is actually a stream.
980 //                      Issue a warning, but proceed with processing.
981 //                      Also, should not be a ref to a gbvar.
982 //                      (a gbvar ref only occurs in an aggregation node,
983 //                      and these SEs are rehomed, not split.
984                 fta_forbidden = ! se->get_data_type()->fta_legal_type();
985
986                 if(fta_forbidden){
987                         fprintf(stderr,"WARNING, a colref is a forbidden data type in split_fta_se,"
988                                                         " colref is %s,"
989                                                         " type is %s, line=%d, col=%d\n",
990                                                         se->get_colref()->to_string().c_str(),
991                                                         se->get_data_type()->get_type_str().c_str(),
992                                                         se->lineno, se->charno
993                                         );
994                 }
995
996                 if(se->is_gb()){
997                         fprintf(stderr,"INTERNAL ERROR, a colref is a gbvar ref in split_fta_se,"
998                                                         " type is %s, line=%d, col=%d\n",
999                                                         se->get_data_type()->get_type_str().c_str(),
1000                                                         se->lineno, se->charno
1001                                         );
1002                         exit(1);
1003                 }
1004
1005                 ret_se = new scalarexp_t(se->get_colref());
1006                 ret_se->use_decorations_of(se);
1007                 return(ret_se);
1008
1009     case SE_UNARY_OP:
1010                  l_se = split_fta_se(se->get_left_se(), l_forbid, lfta_select_list, Ext_fcns);
1011
1012                  this_forbid = ! dt->fta_legal_operation(l_se->get_data_type(), se->get_op());
1013
1014 //                      If this operation is forbidden but the child SE is not,
1015 //                      put the child se on the lfta_select_list, create a colref
1016 //                      which accesses this se, and make it the child of this op.
1017 //                      Exception : the child se is constant (only literal refs).
1018                  if(this_forbid && !l_forbid){
1019                          if(!is_literal_or_param_only(l_se)){
1020                                  new_se = make_fta_se_ref(lfta_select_list, l_se,0);
1021                                  ret_se = new scalarexp_t(se->get_op().c_str(), new_se);
1022                          }
1023                  }else{
1024                          ret_se = new scalarexp_t(se->get_op().c_str(), l_se);
1025                  }
1026                  ret_se->use_decorations_of(se);
1027                  fta_forbidden = this_forbid | l_forbid;
1028                  return(ret_se);
1029
1030     case SE_BINARY_OP:
1031                  l_se = split_fta_se(se->get_left_se(), l_forbid, lfta_select_list, Ext_fcns);
1032                  r_se = split_fta_se(se->get_right_se(), r_forbid, lfta_select_list, Ext_fcns);
1033
1034                  this_forbid = ! dt->fta_legal_operation(l_se->get_data_type(), r_se->get_data_type(), se->get_op());
1035
1036 //                      Replace the left se if it is not forbidden, but something else is.
1037                  if((this_forbid || r_forbid) & !l_forbid){
1038                          if(!is_literal_or_param_only(l_se)){
1039                                  new_se = make_fta_se_ref(lfta_select_list, l_se,0);
1040                                  l_se = new_se;
1041                          }
1042                  }
1043
1044 //                      Replace the right se if it is not forbidden, but something else is.
1045                  if((this_forbid || l_forbid) & !r_forbid){
1046                          if(!is_literal_or_param_only(r_se)){
1047                                  new_se = make_fta_se_ref(lfta_select_list, r_se,0);
1048                                  r_se = new_se;
1049                          }
1050                  }
1051
1052                  ret_se = new scalarexp_t(se->get_op().c_str(), l_se, r_se);
1053                  ret_se->use_decorations_of(se);
1054                  fta_forbidden = this_forbid || r_forbid || l_forbid;
1055
1056                  return(ret_se);
1057
1058     case SE_AGGR_STAR:
1059     case SE_AGGR_SE:
1060
1061                 fprintf(stderr,"INTERNAL ERROR, aggregate ref (%s) in split_fta_se."
1062                                                 " line=%d, col=%d\n",
1063                                                 se->get_op().c_str(),
1064                                                 se->lineno, se->charno
1065                                 );
1066                 exit(1);
1067                 break;
1068
1069         case SE_FUNC:
1070                 {
1071                         fta_forbidden = false;
1072                         operand_list = se->get_operands();
1073                         vector<scalarexp_t *> new_operands;
1074                         vector<bool> forbidden_op;
1075                         for(p=0;p<operand_list.size();p++){
1076                                 l_se = split_fta_se(operand_list[p], l_forbid, lfta_select_list, Ext_fcns);
1077
1078                                 fta_forbidden |= l_forbid;
1079                                 new_operands.push_back(l_se);
1080                                 forbidden_op.push_back(l_forbid);
1081                                 dt_signature.push_back(operand_list[p]->get_data_type() );
1082                         }
1083
1084                         fcn_id = Ext_fcns->lookup_fcn(se->get_op(), dt_signature);
1085                         if( fcn_id < 0 ){
1086                                 fprintf(stderr,"ERROR, no external function %s(",se->get_op().c_str());
1087                                 int o;
1088                                 for(o=0;o<operand_list.size();o++){
1089                                         if(o>0) fprintf(stderr,", ");
1090                                         fprintf(stderr,"%s",operand_list[o]->get_data_type()->get_type_str().c_str());
1091                                 }
1092                                 fprintf(stderr,") is defined, line %d, char %d\n", se->get_lineno(), se->get_charno() );
1093                         if(fcn_id == -2) fprintf(stderr,"(multiple subsuming functions found)\n");
1094                                 return(false);
1095                         }
1096
1097                         fta_forbidden |= (! Ext_fcns->fta_legal(fcn_id));
1098
1099 //                              Replace the non-forbidden operands.
1100 //                              the forbidden ones are already replaced.
1101                         if(fta_forbidden){
1102                                 for(p=0;p<new_operands.size();p++){
1103                                         if(! forbidden_op[p]){
1104 //                                        if(new_operands[p]->get_data_type()->get_temporal() != constant_t){
1105                                                 if(!is_literal_or_param_only(new_operands[p])){
1106                                                 new_se = make_fta_se_ref(lfta_select_list, new_operands[p],0);
1107                                                 new_operands[p] = new_se;
1108                                           }
1109                                         }
1110                                 }
1111                         }
1112
1113                         ret_se = new scalarexp_t(se->get_op().c_str(), new_operands);
1114                         ret_se->use_decorations_of(se);
1115
1116                         return(ret_se);
1117
1118                 }
1119         default:
1120                 printf("INTERNAL ERROR in check_fta_forbidden_se: operator type %d\n",se->get_operator_type());
1121                 exit(1);
1122         break;
1123   }
1124   return(false);
1125
1126 }
1127
1128 */
1129
1130
1131 //              The predicates have already been
1132 //              broken into conjunctions.
1133 //              If any part of a conjunction is fta-forbidden,
1134 //              it must be executed in the stream operator.
1135 //              Else it is executed in the FTA.
1136 //              A pre-analysis should determine whether this
1137 //              predicate is fta-safe.  This procedure will
1138 //              assume that it is fta-forbidden and will
1139 //              prepare it for execution in the stream.
1140
1141 /*
1142
1143 predicate_t *split_fta_pr(predicate_t *pr,
1144                                                  vector<select_element *> &lfta_select_list,
1145                                                  ext_fcn_list *Ext_fcns
1146                                                  ){
1147
1148   vector<literal_t *> llist;
1149   scalarexp_t *se_l, *se_r;
1150   bool l_forbid, r_forbid;
1151   predicate_t *ret_pr, *pr_l, *pr_r;
1152   vector<scalarexp_t *> op_list, new_op_list;
1153   int o;
1154   vector<data_type *> dt_signature;
1155
1156
1157         switch(pr->get_operator_type()){
1158         case PRED_IN:
1159                 se_l = split_fta_se(pr->get_left_se(), l_forbid, lfta_select_list, Ext_fcns);
1160
1161                 if(!l_forbid){
1162                   if(!is_literal_or_param_only(se_l)){
1163                         scalarexp_t *new_se = make_fta_se_ref(lfta_select_list, se_l,0);
1164                         se_l = new_se;
1165                   }
1166                 }
1167                 ret_pr = new predicate_t(se_l, pr->get_lit_vec());
1168
1169                 return(ret_pr);
1170
1171         case PRED_COMPARE:
1172                 se_l = split_fta_se(pr->get_left_se(), l_forbid, lfta_select_list, Ext_fcns);
1173                 if(!l_forbid){
1174                   if(!is_literal_or_param_only(se_l)){
1175                         scalarexp_t *new_se = make_fta_se_ref(lfta_select_list, se_l,0);
1176                         se_l = new_se;
1177                   }
1178                 }
1179
1180                 se_r = split_fta_se(pr->get_right_se(), r_forbid, lfta_select_list, Ext_fcns);
1181                 if(!r_forbid){
1182                   if(!is_literal_or_param_only(se_r)){
1183                         scalarexp_t *new_se = make_fta_se_ref(lfta_select_list, se_r,0);
1184                         se_r = new_se;
1185                   }
1186                 }
1187
1188                 ret_pr = new predicate_t(se_l, pr->get_op().c_str(), se_r);
1189                 return(ret_pr);
1190
1191         case PRED_UNARY_OP:
1192                 pr_l = split_fta_pr(pr->get_left_pr(), lfta_select_list, Ext_fcns);
1193                 ret_pr = new predicate_t(pr->get_op().c_str(), pr_l);
1194                 return(ret_pr);
1195
1196         case PRED_BINARY_OP:
1197                 pr_l = split_fta_pr(pr->get_left_pr(), lfta_select_list, Ext_fcns);
1198                 pr_r = split_fta_pr(pr->get_right_pr(), lfta_select_list, Ext_fcns);
1199                 ret_pr = new predicate_t(pr->get_op().c_str(), pr_l, pr_r);
1200                 return(ret_pr);
1201
1202         case PRED_FUNC:
1203 //                      I can't push the predicate into the lfta, except by
1204 //                      returning a bool value, and that is not worth the trouble,
1205                 op_list = pr->get_op_list();
1206                 for(o=0;o<op_list.size();++o){
1207                         se_l = split_fta_se(op_list[o],l_forbid,lfta_select_list,Ext_fcns);
1208                         if(!l_forbid){
1209                           if(!is_literal_or_param_only(se_l)){
1210                                 scalarexp_t *new_se = make_fta_se_ref(lfta_select_list, se_l,0);
1211                                 se_l = new_se;
1212                           }
1213                         }
1214                         new_op_list.push_back(se_l);
1215                 }
1216
1217                 ret_pr =  new predicate_t(pr->get_op().c_str(), new_op_list);
1218                 ret_pr->set_fcn_id(pr->get_fcn_id());
1219                 return(ret_pr);
1220         default:
1221                 fprintf(stderr,"INTERNAL ERROR in split_fta_pr, line %d, character %d, unknown predicate operator type %d\n",
1222                         pr->get_lineno(), pr->get_charno(), pr->get_operator_type() );
1223                 exit(1);
1224         }
1225
1226         return(0);
1227
1228 }
1229
1230 */
1231
1232
1233 //--------------------------------------------------------------------
1234
1235
1236
1237 //              Split a scalar expression into one part which executes
1238 //              at the stream and another set of parts which execute
1239 //              at the FTA.
1240 //              Because I'm actually modifying the SEs, I will make
1241 //              copies.  But I will assume that literals, params, and
1242 //              colrefs are immutable at this point.
1243 //              (if there is ever a need to change one, must make a
1244 //               new value).
1245 //              NOTE : if se is constant (only refrences literals),
1246 //                      avoid making the fta compute it.
1247 //
1248 //              NOTE : This will need to be generalized to
1249 //              handle join expressions, namely to handle a vector
1250 //              of lftas.
1251 //
1252 //              Return value is the HFTA se.
1253 //              Add lftas select_elements to the fta_select_list.
1254 //              set fta_forbidden if this node or any child cannot
1255 //              execute at the lfta.
1256
1257 #define SPLIT_FTAVEC_NOTBLVAR -1
1258 #define SPLIT_FTAVEC_MIXED -2
1259
1260 bool is_PROTOCOL_source(int colref_source,
1261                         vector< vector<select_element *> *> &lfta_select_list){
1262         if(colref_source>=0 && lfta_select_list[colref_source]!=NULL) return true;
1263         return false;
1264 }
1265
1266 int combine_colref_source(int s1, int s2){
1267         if(s1==s2) return(s1);
1268         if(s1==SPLIT_FTAVEC_NOTBLVAR) return s2;
1269         if(s2==SPLIT_FTAVEC_NOTBLVAR) return s1;
1270         return SPLIT_FTAVEC_MIXED;
1271 }
1272
1273 scalarexp_t *split_ftavec_se(
1274                                   scalarexp_t *se,      // the SE to split
1275                                   bool &fta_forbidden,  // return true if some part of se
1276                                                                                 // is fta-unsafe
1277                                   int &colref_source,   // the tblvar which sources the
1278                                                                                 // colref, or NOTBLVAR, or MIXED
1279                                   vector< vector<select_element *> *> &lfta_select_list,
1280                                                                                 // NULL if the tblvar is not PROTOCOL,
1281                                                                                 // else build the select list.
1282                                   ext_fcn_list *Ext_fcns // is the fcn lfta-safe?
1283                                  ){
1284 //              Return value is the HFTA SE, unless fta_forbidden is true and
1285 //              colref_source>=0 and the indicated source is PROTOCOL.
1286 //              In that case no split was done, the make_fta_se_ref must
1287 //              be done by the caller.
1288
1289   int p, fcn_id;
1290   vector<scalarexp_t *> operand_list;
1291   vector<data_type *> dt_signature;
1292   scalarexp_t *ret_se, *l_se, *r_se;
1293   bool l_forbid, r_forbid, this_forbid;
1294   int l_csource, r_csource, this_csource;
1295   colref_t *new_cr;
1296   scalarexp_t *new_se;
1297   data_type *dt = se->get_data_type();
1298
1299   switch(se->get_operator_type()){
1300     case SE_LITERAL:
1301                 fta_forbidden = ! se->get_data_type()->fta_legal_type();
1302                 colref_source = SPLIT_FTAVEC_NOTBLVAR;
1303                 ret_se = new scalarexp_t(se->get_literal());
1304                 ret_se->use_decorations_of(se);
1305                 return(ret_se);
1306
1307     case SE_PARAM:
1308                 fta_forbidden = ! se->get_data_type()->fta_legal_type();
1309                 colref_source = SPLIT_FTAVEC_NOTBLVAR;
1310                 ret_se = scalarexp_t::make_param_reference(se->get_op().c_str());
1311                 ret_se->use_decorations_of(se);
1312                 return(ret_se);
1313
1314         case SE_IFACE_PARAM:
1315                 fta_forbidden = false;
1316                 colref_source = se->get_ifpref()->get_tablevar_ref();
1317                 ret_se = scalarexp_t::make_iface_param_reference(se->get_ifpref());
1318                 ret_se->use_decorations_of(se);
1319                 return(ret_se);
1320
1321     case SE_COLREF:
1322 //                      No colref should be forbidden,
1323 //                      the schema is wrong, the fta_legal_type() fcn is wrong,
1324 //                      or the source table is actually a stream.
1325 //                      Issue a warning, but proceed with processing.
1326 //                      Also, should not be a ref to a gbvar.
1327 //                      (a gbvar ref only occurs in an aggregation node,
1328 //                      and these SEs are rehomed, not split.
1329                 fta_forbidden = ! se->get_data_type()->fta_legal_type();
1330                 colref_source = se->get_colref()->get_tablevar_ref();
1331
1332                 if(fta_forbidden && is_PROTOCOL_source(colref_source, lfta_select_list)){
1333                         fprintf(stderr,"WARNING, a PROTOCOL colref is a forbidden data type in split_ftavec_se,"
1334                                                         " colref is %s,"
1335                                                         " type is %s, line=%d, col=%d\n",
1336                                                         se->get_colref()->to_string().c_str(),
1337                                                         se->get_data_type()->to_string().c_str(),
1338                                                         se->lineno, se->charno
1339                                         );
1340                 }
1341
1342                 if(se->is_gb()){
1343                         fta_forbidden = true;   // eval in hfta.  ASSUME make copy as below.
1344                 }
1345
1346                 ret_se = new scalarexp_t(se->get_colref());
1347                 ret_se->use_decorations_of(se);
1348                 return(ret_se);
1349
1350     case SE_UNARY_OP:
1351                  l_se = split_ftavec_se(se->get_left_se(), l_forbid, colref_source, lfta_select_list, Ext_fcns);
1352
1353                  this_forbid = ! dt->fta_legal_operation(l_se->get_data_type(), se->get_op());
1354
1355 //                      If this operation is forbidden but the child SE is not,
1356 //                      AND the colref source in the se is a single PROTOCOL source
1357 //                      put the child se on the lfta_select_list, create a colref
1358 //                      which accesses this se, and make it the child of this op.
1359 //                      Exception : the child se is constant (only literal refs).
1360 //                      TODO: I think the exception is expressed by is_PROTOCOL_source
1361                  if(this_forbid && !l_forbid && is_PROTOCOL_source(colref_source, lfta_select_list)){
1362                          if(!is_literal_or_param_only(l_se)){
1363                                  new_se = make_fta_se_ref(lfta_select_list, l_se,colref_source);
1364                                  ret_se = new scalarexp_t(se->get_op().c_str(), new_se);
1365                          }
1366                  }else{
1367                          ret_se = new scalarexp_t(se->get_op().c_str(), l_se);
1368                  }
1369                  ret_se->use_decorations_of(se);
1370                  fta_forbidden = this_forbid | l_forbid;
1371                  return(ret_se);
1372
1373     case SE_BINARY_OP:
1374                  l_se = split_ftavec_se(se->get_left_se(), l_forbid, l_csource, lfta_select_list, Ext_fcns);
1375                  r_se = split_ftavec_se(se->get_right_se(), r_forbid, r_csource, lfta_select_list, Ext_fcns);
1376
1377                  this_forbid = ! dt->fta_legal_operation(l_se->get_data_type(), r_se->get_data_type(), se->get_op());
1378                  colref_source=combine_colref_source(l_csource, r_csource);
1379
1380 //                      Replace the left se if the parent must be hfta but the child can
1381 //                      be lfta. This translates to
1382 //                      a) result is PROTOCOL and forbidden, but left SE is not forbidden
1383 //                      OR b) if result is mixed but the left se is PROTOCOL, not forbidden
1384                  if( ((this_forbid || r_forbid) && !l_forbid && is_PROTOCOL_source(colref_source, lfta_select_list) ) ||
1385                                 (colref_source==SPLIT_FTAVEC_MIXED && !l_forbid &&
1386                                  is_PROTOCOL_source(l_csource, lfta_select_list)) ){
1387                          if(!is_literal_or_param_only(l_se)){
1388                                  new_se = make_fta_se_ref(lfta_select_list, l_se,l_csource);
1389                                  l_se = new_se;
1390                          }
1391                  }
1392
1393 //                      same logic as for right se.
1394                  if( ((this_forbid || l_forbid) && !r_forbid && is_PROTOCOL_source(colref_source, lfta_select_list) ) ||
1395                                 (colref_source==SPLIT_FTAVEC_MIXED && !r_forbid &&
1396                                  is_PROTOCOL_source(r_csource, lfta_select_list)) ){
1397                          if(!is_literal_or_param_only(r_se)){
1398                                  new_se = make_fta_se_ref(lfta_select_list, r_se,r_csource);
1399                                  r_se = new_se;
1400                          }
1401                  }
1402
1403                  ret_se = new scalarexp_t(se->get_op().c_str(), l_se, r_se);
1404                  ret_se->use_decorations_of(se);
1405                  fta_forbidden = this_forbid || r_forbid || l_forbid;
1406
1407                  return(ret_se);
1408
1409     case SE_AGGR_STAR:
1410     case SE_AGGR_SE:
1411
1412                 fprintf(stderr,"INTERNAL ERROR, aggregate ref (%s) in split_ftavec_se."
1413                                                 " line=%d, col=%d\n",
1414                                                 se->get_op().c_str(),
1415                                                 se->lineno, se->charno
1416                                 );
1417                 exit(1);
1418                 break;
1419
1420         case SE_FUNC:
1421                 {
1422                         operand_list = se->get_operands();
1423                         vector<scalarexp_t *> new_operands;
1424                         vector<bool> forbidden_op;
1425                         vector<int> csource;
1426
1427                         fta_forbidden = false;
1428                         colref_source = SPLIT_FTAVEC_NOTBLVAR;
1429                         for(p=0;p<operand_list.size();p++){
1430                                 l_se = split_ftavec_se(operand_list[p], l_forbid, l_csource, lfta_select_list, Ext_fcns);
1431
1432                                 fta_forbidden |= l_forbid;
1433                                 colref_source = combine_colref_source(colref_source, l_csource);
1434                                 new_operands.push_back(l_se);
1435                                 forbidden_op.push_back(l_forbid);
1436                                 csource.push_back(l_csource);
1437                                 dt_signature.push_back(operand_list[p]->get_data_type() );
1438                         }
1439
1440                         fcn_id = Ext_fcns->lookup_fcn(se->get_op(), dt_signature);
1441                         if( fcn_id < 0 ){
1442                                 fprintf(stderr,"ERROR, no external function %s(",se->get_op().c_str());
1443                                 int o;
1444                                 for(o=0;o<operand_list.size();o++){
1445                                         if(o>0) fprintf(stderr,", ");
1446                                         fprintf(stderr,"%s",operand_list[o]->get_data_type()->to_string().c_str());
1447                                 }
1448                                 fprintf(stderr,") is defined, line %d, char %d\n", se->get_lineno(), se->get_charno() );
1449                         if(fcn_id == -2) fprintf(stderr,"(multiple subsuming functions found)\n");
1450                                 return NULL;
1451                         }
1452
1453                         fta_forbidden |= (! Ext_fcns->fta_legal(fcn_id));
1454
1455 //                              Replace the non-forbidden operands.
1456 //                              the forbidden ones are already replaced.
1457                         if(fta_forbidden || colref_source == SPLIT_FTAVEC_MIXED){
1458                                 for(p=0;p<new_operands.size();p++){
1459                                         if(! forbidden_op[p] && is_PROTOCOL_source(csource[p], lfta_select_list)){
1460                                                 if(!is_literal_or_param_only(new_operands[p])){
1461                                                 new_se = make_fta_se_ref(lfta_select_list, new_operands[p],csource[p]);
1462                                                 new_operands[p] = new_se;
1463                                           }
1464                                         }
1465                                 }
1466                         }
1467
1468                         ret_se = new scalarexp_t(se->get_op().c_str(), new_operands);
1469                         ret_se->use_decorations_of(se);
1470
1471                         return(ret_se);
1472
1473                 }
1474         default:
1475                 printf("INTERNAL ERROR in split_ftavec_se: operator type %d\n",se->get_operator_type());
1476                 exit(1);
1477         break;
1478   }
1479   return(NULL);
1480
1481 }
1482
1483
1484 //              The predicates have already been
1485 //              broken into conjunctions.
1486 //              If any part of a conjunction is fta-forbidden,
1487 //              it must be executed in the stream operator.
1488 //              Else it is executed in the FTA.
1489 //              A pre-analysis should determine whether this
1490 //              predicate is fta-safe.  This procedure will
1491 //              assume that it is fta-forbidden and will
1492 //              prepare it for execution in the stream.
1493
1494 predicate_t *split_ftavec_pr(predicate_t *pr,
1495                                   vector< vector<select_element *> *> &lfta_select_list,
1496                                                  ext_fcn_list *Ext_fcns
1497                                                  ){
1498
1499   vector<literal_t *> llist;
1500   scalarexp_t *se_l, *se_r;
1501   bool l_forbid, r_forbid;
1502   int l_csource, r_csource;
1503   predicate_t *ret_pr, *pr_l, *pr_r;
1504   vector<scalarexp_t *> op_list, new_op_list;
1505   int o;
1506   vector<data_type *> dt_signature;
1507
1508
1509         switch(pr->get_operator_type()){
1510         case PRED_IN:
1511                 se_l = split_ftavec_se(pr->get_left_se(), l_forbid, l_csource, lfta_select_list, Ext_fcns);
1512
1513 //                              TODO: checking that the se is a PROTOCOL source should
1514 //                              take care of literal_or_param_only.
1515                 if(!l_forbid && is_PROTOCOL_source(l_csource, lfta_select_list)){
1516                   if(!is_literal_or_param_only(se_l)){
1517                         scalarexp_t *new_se = make_fta_se_ref(lfta_select_list, se_l,l_csource);
1518                         se_l = new_se;
1519                   }
1520                 }
1521                 ret_pr = new predicate_t(se_l, pr->get_lit_vec());
1522
1523                 return(ret_pr);
1524
1525         case PRED_COMPARE:
1526                 se_l = split_ftavec_se(pr->get_left_se(), l_forbid, l_csource, lfta_select_list, Ext_fcns);
1527                 if(!l_forbid  && is_PROTOCOL_source(l_csource, lfta_select_list)){
1528                   if(!is_literal_or_param_only(se_l)){
1529                         scalarexp_t *new_se = make_fta_se_ref(lfta_select_list, se_l,l_csource);
1530                         se_l = new_se;
1531                   }
1532                 }
1533
1534                 se_r = split_ftavec_se(pr->get_right_se(), r_forbid, r_csource, lfta_select_list, Ext_fcns);
1535                 if(!r_forbid  && is_PROTOCOL_source(r_csource, lfta_select_list)){
1536                   if(!is_literal_or_param_only(se_r)){
1537                         scalarexp_t *new_se = make_fta_se_ref(lfta_select_list, se_r,r_csource);
1538                         se_r = new_se;
1539                   }
1540                 }
1541
1542                 ret_pr = new predicate_t(se_l, pr->get_op().c_str(), se_r);
1543                 return(ret_pr);
1544
1545         case PRED_UNARY_OP:
1546                 pr_l = split_ftavec_pr(pr->get_left_pr(), lfta_select_list, Ext_fcns);
1547                 ret_pr = new predicate_t(pr->get_op().c_str(), pr_l);
1548                 return(ret_pr);
1549
1550         case PRED_BINARY_OP:
1551                 pr_l = split_ftavec_pr(pr->get_left_pr(), lfta_select_list, Ext_fcns);
1552                 pr_r = split_ftavec_pr(pr->get_right_pr(), lfta_select_list, Ext_fcns);
1553                 ret_pr = new predicate_t(pr->get_op().c_str(), pr_l, pr_r);
1554                 return(ret_pr);
1555
1556         case PRED_FUNC:
1557 //                      I can't push the predicate into the lfta, except by
1558 //                      returning a bool value, and that is not worth the trouble,
1559                 op_list = pr->get_op_list();
1560                 for(o=0;o<op_list.size();++o){
1561                         se_l = split_ftavec_se(op_list[o],l_forbid,l_csource,lfta_select_list,Ext_fcns);
1562                         if(!l_forbid && is_PROTOCOL_source(l_csource, lfta_select_list)){
1563                           if(!is_literal_or_param_only(se_l)){
1564                                 scalarexp_t *new_se = make_fta_se_ref(lfta_select_list, se_l,l_csource);
1565                                 se_l = new_se;
1566                           }
1567                         }
1568                         new_op_list.push_back(se_l);
1569                 }
1570
1571                 ret_pr =  new predicate_t(pr->get_op().c_str(), new_op_list);
1572                 ret_pr->set_fcn_id(pr->get_fcn_id());
1573                 return(ret_pr);
1574         default:
1575                 fprintf(stderr,"INTERNAL ERROR in split_fta_pr, line %d, character %d, unknown predicate operator type %d\n",
1576                         pr->get_lineno(), pr->get_charno(), pr->get_operator_type() );
1577                 exit(1);
1578         }
1579
1580         return(0);
1581
1582 }
1583
1584
1585
1586 ////////////////////////////////////////////////////////////////////////
1587 ///             rehome_hfta_se rehome_hfta_pr
1588 ///             This is use to split an sgah operator (aggregation),
1589 ///             I just need to make gb, aggr references point to the
1590 ///             new gb, aggr table entries.
1591
1592
1593 scalarexp_t *rehome_fta_se(scalarexp_t *se,
1594                                   map< int, scalarexp_t * > *aggr_map
1595                                  ){
1596
1597   int p, fcn_id;
1598   int agr_id;
1599   vector<scalarexp_t *> operand_list;
1600   scalarexp_t *ret_se, *l_se, *r_se;
1601   colref_t *new_cr;
1602   scalarexp_t *new_se;
1603   data_type *dt = se->get_data_type();
1604   vector<scalarexp_t *> new_operands;
1605
1606   switch(se->get_operator_type()){
1607     case SE_LITERAL:
1608                 ret_se = new scalarexp_t(se->get_literal());
1609                 ret_se->use_decorations_of(se);
1610                 return(ret_se);
1611
1612     case SE_PARAM:
1613                 ret_se = scalarexp_t::make_param_reference(se->get_op().c_str());
1614                 ret_se->use_decorations_of(se);
1615                 return(ret_se);
1616
1617         case SE_IFACE_PARAM:
1618                 ret_se = scalarexp_t::make_iface_param_reference(se->get_ifpref());
1619                 ret_se->use_decorations_of(se);
1620                 return(ret_se);
1621
1622
1623
1624     case SE_COLREF:
1625 //                      Must be a GB REF ...
1626 //                      I'm assuming that the hfta gbvar table has the
1627 //                      same sequence of entries as the input query's gbvar table.
1628 //                      Else I'll need some kind of translation table.
1629
1630                 if(! se->is_gb()){
1631                         fprintf(stderr,"WARNING, a colref is not a gbver ref in rehome_hfta_se"
1632                                                         " type is %s, line=%d, col=%d\n",
1633                                                         se->get_data_type()->to_string().c_str(),
1634                                                         se->lineno, se->charno
1635                                         );
1636                 }
1637
1638                 ret_se = new scalarexp_t(se->get_colref());
1639                 ret_se->use_decorations_of(se);         // just inherit the gbref
1640                 return(ret_se);
1641
1642     case SE_UNARY_OP:
1643                  l_se = rehome_fta_se(se->get_left_se(), aggr_map);
1644
1645                  ret_se = new scalarexp_t(se->get_op().c_str(), l_se);
1646                  ret_se->use_decorations_of(se);
1647                  return(ret_se);
1648
1649     case SE_BINARY_OP:
1650                  l_se = rehome_fta_se(se->get_left_se(), aggr_map);
1651                  r_se = rehome_fta_se(se->get_right_se(), aggr_map);
1652
1653                  ret_se = new scalarexp_t(se->get_op().c_str(), l_se, r_se);
1654                  ret_se->use_decorations_of(se);
1655
1656                  return(ret_se);
1657
1658     case SE_AGGR_STAR:
1659     case SE_AGGR_SE:
1660                 agr_id = se->get_aggr_ref();
1661                 return (*aggr_map)[agr_id];
1662                 break;
1663
1664         case SE_FUNC:
1665                 agr_id = se->get_aggr_ref();
1666                 if(agr_id >= 0) return (*aggr_map)[agr_id];
1667
1668                 operand_list = se->get_operands();
1669                 for(p=0;p<operand_list.size();p++){
1670                         l_se = rehome_fta_se(operand_list[p], aggr_map);
1671
1672                         new_operands.push_back(l_se);
1673                 }
1674
1675
1676                 ret_se = new scalarexp_t(se->get_op().c_str(), new_operands);
1677                 ret_se->use_decorations_of(se);
1678
1679                 return(ret_se);
1680
1681         default:
1682                 printf("INTERNAL ERROR in rehome_fta_se: operator type %d\n",se->get_operator_type());
1683                 exit(1);
1684         break;
1685   }
1686   return(NULL);
1687
1688 }
1689
1690
1691 //              The predicates have already been
1692 //              broken into conjunctions.
1693 //              If any part of a conjunction is fta-forbidden,
1694 //              it must be executed in the stream operator.
1695 //              Else it is executed in the FTA.
1696 //              A pre-analysis should determine whether this
1697 //              predicate is fta-safe.  This procedure will
1698 //              assume that it is fta-forbidden and will
1699 //              prepare it for execution in the stream.
1700
1701 predicate_t *rehome_fta_pr(predicate_t *pr,
1702                                                  map<int, scalarexp_t *> *aggr_map
1703                                                  ){
1704
1705   vector<literal_t *> llist;
1706   scalarexp_t *se_l, *se_r;
1707   predicate_t *ret_pr, *pr_l, *pr_r;
1708   vector<scalarexp_t *> op_list, new_op_list;
1709   int o;
1710
1711         switch(pr->get_operator_type()){
1712         case PRED_IN:
1713                 se_l = rehome_fta_se(pr->get_left_se(), aggr_map);
1714                 ret_pr = new predicate_t(se_l, pr->get_lit_vec());
1715                 return(ret_pr);
1716
1717         case PRED_COMPARE:
1718                 se_l = rehome_fta_se(pr->get_left_se(), aggr_map);
1719                 se_r = rehome_fta_se(pr->get_right_se(), aggr_map);
1720                 ret_pr = new predicate_t(se_l, pr->get_op().c_str(), se_r);
1721                 return(ret_pr);
1722
1723         case PRED_UNARY_OP:
1724                 pr_l = rehome_fta_pr(pr->get_left_pr(), aggr_map);
1725                 ret_pr = new predicate_t(pr->get_op().c_str(), pr_l);
1726                 return(ret_pr);
1727
1728         case PRED_BINARY_OP:
1729                 pr_l = rehome_fta_pr(pr->get_left_pr(), aggr_map);
1730                 pr_r = rehome_fta_pr(pr->get_right_pr(), aggr_map);
1731                 ret_pr = new predicate_t(pr->get_op().c_str(), pr_l, pr_r);
1732                 return(ret_pr);
1733
1734         case PRED_FUNC:
1735                 op_list = pr->get_op_list();
1736                 for(o=0;o<op_list.size();++o){
1737                         se_l = rehome_fta_se(op_list[o], aggr_map);
1738                         new_op_list.push_back(se_l);
1739                 }
1740                 ret_pr=  new predicate_t(pr->get_op().c_str(), new_op_list);
1741                 ret_pr->set_fcn_id(pr->get_fcn_id());
1742                 return(ret_pr);
1743
1744         default:
1745                 fprintf(stderr,"INTERNAL ERROR in rehome_fta_pr, line %d, character %d, unknown predicate operator type %d\n",
1746                         pr->get_lineno(), pr->get_charno(), pr->get_operator_type() );
1747                 exit(1);
1748         }
1749
1750         return(0);
1751
1752 }
1753
1754
1755 ////////////////////////////////////////////////////////////////////
1756 /////////////////               Create a STREAM table to represent the FTA output.
1757
1758 table_def *create_attributes(string tname, vector<select_element *> &select_list){
1759         int s;
1760
1761
1762 //                      Create a new STREAM schema for the output of the FTA.
1763
1764         field_entry_list *fel = new field_entry_list();
1765         set<string> ufcns;
1766         for(s=0;s<select_list.size();s++){
1767                 scalarexp_t *sel_se = select_list[s]->se;
1768                 data_type *dt = sel_se->get_data_type();
1769
1770 //                      Grab the annotations of the field.
1771 //                      As of this writing, the only meaningful annotations
1772 //                      are whether or not the attribute is temporal.
1773 //                      There can be an annotation of constant_t, but
1774 //                      I'll ignore this, it feels like an unsafe assumption
1775                 param_list *plist = new param_list();
1776 //              if(dt->is_temporal()){
1777                         vector<string> param_strings = dt->get_param_keys();
1778                         int p;
1779                         for(p=0;p<param_strings.size();++p){
1780                                 string v = dt->get_param_val(param_strings[p]);
1781                                 if(v != "")
1782                                         plist->append(param_strings[p].c_str(),v.c_str());
1783                                 else
1784                                         plist->append(param_strings[p].c_str());
1785                         }
1786 //              }
1787
1788 //              char access_fcn_name[500];
1789                 string colname = select_list[s]->name;
1790 //              sprintf(access_fcn_name,"get_field_%s",colname.c_str());
1791                 string access_fcn_name = "get_field_"+colname;
1792                 field_entry *fe = new field_entry(
1793                         dt->get_type_str(), colname, access_fcn_name, plist, ufcns
1794                 );
1795
1796                 fel->append_field(fe);
1797         }
1798
1799         table_def *fta_tbl = new table_def(
1800                 tname.c_str(), NULL, NULL, fel, STREAM_SCHEMA
1801         );
1802
1803         return(fta_tbl);
1804
1805 }
1806
1807 //------------------------------------------------------------------
1808 //              Textual representation of the query node.
1809
1810
1811
1812 string spx_qpn::to_query_string(){
1813
1814         string ret = "Select ";
1815         int s;
1816         for(s=0;s<select_list.size();s++){
1817                 if(s>0) ret+=", ";
1818                 ret += se_to_query_string(select_list[s]->se, NULL);
1819                 if(select_list[s]->name != "") ret += " AS "+select_list[s]->name;
1820         }
1821         ret += "\n";
1822
1823         ret += "From "+table_name->to_string()+"\n";
1824
1825         if(where.size() > 0){
1826                 ret += "Where ";
1827                 int w;
1828                 for(w=0;w<where.size();w++){
1829                         if(w>0) ret += " AND ";
1830                         ret += "(" + pred_to_query_str(where[w]->pr,NULL) + ")";
1831                 }
1832                 ret += "\n";
1833         }
1834
1835         return(ret);
1836 }
1837
1838
1839
1840
1841 string sgah_qpn::to_query_string(){
1842
1843         string ret = "Select ";
1844         int s;
1845         for(s=0;s<select_list.size();s++){
1846                 if(s>0) ret+=", ";
1847                 ret += se_to_query_string(select_list[s]->se, &aggr_tbl);
1848                 if(select_list[s]->name != "") ret += " AS "+select_list[s]->name;
1849         }
1850         ret += "\n";
1851
1852         ret += "From "+table_name->to_string()+"\n";
1853
1854         if(where.size() > 0){
1855                 ret += "Where ";
1856                 int w;
1857                 for(w=0;w<where.size();w++){
1858                         if(w>0) ret += " AND ";
1859                         ret += "(" + pred_to_query_str(where[w]->pr,&aggr_tbl) + ")";
1860                 }
1861                 ret += "\n";
1862         }
1863
1864         if(gb_tbl.size() > 0){
1865                 ret += "Group By ";
1866                 int g;
1867                 if(gb_tbl.gb_patterns.size() <= 1 || gb_tbl.gb_entry_type.size()==0){
1868                         for(g=0;g<gb_tbl.size();g++){
1869                                 if(g>0) ret += ", ";
1870 //                      if(gb_tbl.get_reftype(g) == GBVAR_SE){
1871                                         ret += se_to_query_string(gb_tbl.get_def(g), &aggr_tbl) + " AS ";
1872 //                      }
1873                                 ret += gb_tbl.get_name(g);
1874                         }
1875                 }else{
1876                         int gb_pos = 0;
1877                         for(g=0;g<gb_tbl.gb_entry_type.size();++g){
1878                                 if(g>0) ret += ", ";
1879                                 if(gb_tbl.gb_entry_type[g] == ""){
1880                                         ret += se_to_query_string(gb_tbl.get_def(gb_pos),&aggr_tbl)+
1881                                                 " AS "+ gb_tbl.get_name(gb_pos);
1882                                         gb_pos++;
1883                                 }
1884                                 if(gb_tbl.gb_entry_type[g] == "CUBE" ||
1885                                                 gb_tbl.gb_entry_type[g] == "ROLLUP"){
1886                                         ret += gb_tbl.gb_entry_type[g] + "(";
1887                                         int gg = 0;
1888                                         for(gg=0;gg<gb_tbl.gb_entry_count[g];++gg){
1889                                                 if(gg>0) ret += ", ";
1890                                                 ret += se_to_query_string(gb_tbl.get_def(gb_pos),&aggr_tbl)+ " AS "+ gb_tbl.get_name(gb_pos);
1891                                                 gb_pos++;
1892                                         }
1893                                         ret += ")";
1894                                 }
1895                                 if(gb_tbl.gb_entry_type[g] == "GROUPING_SETS"){
1896                                         ret += gb_tbl.gb_entry_type[g] + "(";
1897                                         int g1, g2;
1898                                         vector<vector<bool> > &local_components = gb_tbl.pattern_components[g];
1899                                         for(g1=0;g1<local_components.size();++g1){
1900                                                 if(g1>0) ret+=",";
1901                                                 bool first_field = true;
1902                                                 ret += "\n\t\t(";
1903                                                 for(g2=0;g2<=gb_tbl.gb_entry_count[g];g2++){
1904                                                         if(local_components[g1][g2]){
1905                                                                 if(!first_field) ret+=", ";
1906                                                                 else first_field = false;
1907                                                                 ret +=  gb_tbl.get_name(gb_pos+g2);
1908                                                         }
1909                                                 }
1910                                                 ret += ")";
1911                                         }
1912                                         ret += ") ";
1913                                         gb_pos += gb_tbl.gb_entry_count[g];
1914                                 }
1915                         }
1916                 }
1917                 ret += "\n";
1918         }
1919
1920         if(having.size() > 0){
1921                 ret += "Having ";
1922                 int h;
1923                 for(h=0;h<having.size();h++){
1924                         if(h>0) ret += " AND ";
1925                         ret += "(" + pred_to_query_str(having[h]->pr,&aggr_tbl) + ")";
1926                 }
1927                 ret += "\n";
1928         }
1929
1930         return(ret);
1931 }
1932
1933
1934 string rsgah_qpn::to_query_string(){
1935
1936         string ret = "Select ";
1937         int s;
1938         for(s=0;s<select_list.size();s++){
1939                 if(s>0) ret+=", ";
1940                 ret += se_to_query_string(select_list[s]->se, &aggr_tbl);
1941                 if(select_list[s]->name != "") ret += " AS "+select_list[s]->name;
1942         }
1943         ret += "\n";
1944
1945         ret += "From "+table_name->to_string()+"\n";
1946
1947         if(where.size() > 0){
1948                 ret += "Where ";
1949                 int w;
1950                 for(w=0;w<where.size();w++){
1951                         if(w>0) ret += " AND ";
1952                         ret += "(" + pred_to_query_str(where[w]->pr,&aggr_tbl) + ")";
1953                 }
1954                 ret += "\n";
1955         }
1956
1957         if(gb_tbl.size() > 0){
1958                 ret += "Group By ";
1959                 int g;
1960                 for(g=0;g<gb_tbl.size();g++){
1961                         if(g>0) ret += ", ";
1962 //                      if(gb_tbl.get_reftype(g) == GBVAR_SE){
1963                                 ret += se_to_query_string(gb_tbl.get_def(g), &aggr_tbl)+" AS ";
1964 //                      }
1965                         ret += gb_tbl.get_name(g);
1966                 }
1967                 ret += "\n";
1968         }
1969
1970         if(having.size() > 0){
1971                 ret += "Having ";
1972                 int h;
1973                 for(h=0;h<having.size();h++){
1974                         if(h>0) ret += " AND ";
1975                         ret += "(" + pred_to_query_str(having[h]->pr,&aggr_tbl) + ")";
1976                 }
1977                 ret += "\n";
1978         }
1979
1980         if(closing_when.size() > 0){
1981                 ret += "Closing_When ";
1982                 int h;
1983                 for(h=0;h<closing_when.size();h++){
1984                         if(h>0) ret += " AND ";
1985                         ret += "(" + pred_to_query_str(closing_when[h]->pr,&aggr_tbl) + ")";
1986                 }
1987                 ret += "\n";
1988         }
1989
1990         return(ret);
1991 }
1992
1993
1994 string sgahcwcb_qpn::to_query_string(){
1995
1996         string ret = "Select ";
1997         int s;
1998         for(s=0;s<select_list.size();s++){
1999                 if(s>0) ret+=", ";
2000                 ret += se_to_query_string(select_list[s]->se, &aggr_tbl);
2001                 if(select_list[s]->name != "") ret += " AS "+select_list[s]->name;
2002         }
2003         ret += "\n";
2004
2005         ret += "From "+table_name->to_string()+"\n";
2006
2007         if(where.size() > 0){
2008                 ret += "Where ";
2009                 int w;
2010                 for(w=0;w<where.size();w++){
2011                         if(w>0) ret += " AND ";
2012                         ret += "(" + pred_to_query_str(where[w]->pr,&aggr_tbl) + ")";
2013                 }
2014                 ret += "\n";
2015         }
2016
2017         if(gb_tbl.size() > 0){
2018                 ret += "Group By ";
2019                 int g;
2020                 for(g=0;g<gb_tbl.size();g++){
2021                         if(g>0) ret += ", ";
2022 //                      if(gb_tbl.get_reftype(g) == GBVAR_SE){
2023                                 ret += se_to_query_string(gb_tbl.get_def(g), &aggr_tbl) + " AS ";
2024 //                      }
2025                         ret += gb_tbl.get_name(g);
2026                 }
2027                 ret += "\n";
2028         }
2029
2030         if(sg_tbl.size() > 0){
2031                 ret += "Supergroup ";
2032                 int g;
2033                 bool first_elem = true;
2034                 for(g=0;g<gb_tbl.size();g++){
2035                         if(sg_tbl.count(g)){
2036                                 if(first_elem){
2037                                         ret += ", ";
2038                                         first_elem = false;
2039                                 }
2040                                 ret += gb_tbl.get_name(g);
2041                         }
2042                 }
2043                 ret += "\n";
2044         }
2045
2046         if(having.size() > 0){
2047                 ret += "Having ";
2048                 int h;
2049                 for(h=0;h<having.size();h++){
2050                         if(h>0) ret += " AND ";
2051                         ret += "(" + pred_to_query_str(having[h]->pr,&aggr_tbl) + ")";
2052                 }
2053                 ret += "\n";
2054         }
2055
2056
2057         if(cleanwhen.size() > 0){
2058                 ret += "Cleaning_When ";
2059                 int h;
2060                 for(h=0;h<cleanwhen.size();h++){
2061                         if(h>0) ret += " AND ";
2062                         ret += "(" + pred_to_query_str(cleanwhen[h]->pr,&aggr_tbl) + ")";
2063                 }
2064                 ret += "\n";
2065         }
2066
2067         if(cleanby.size() > 0){
2068                 ret += "Cleaning_By ";
2069                 int h;
2070                 for(h=0;h<cleanby.size();h++){
2071                         if(h>0) ret += " AND ";
2072                         ret += "(" + pred_to_query_str(cleanby[h]->pr,&aggr_tbl) + ")";
2073                 }
2074                 ret += "\n";
2075         }
2076
2077         return(ret);
2078 }
2079
2080
2081 string mrg_qpn::to_query_string(){
2082
2083         string ret="Merge ";
2084         ret += mvars[0]->to_query_string() + " : " + mvars[1]->to_query_string();
2085         if(slack != NULL){
2086                 ret += " SLACK "+se_to_query_string(slack, NULL);
2087         }
2088
2089         ret += "\nFrom ";
2090         int t;
2091         for(t=0;t<fm.size();++t){
2092                 if(t>0) ret += ", ";
2093                 ret += fm[t]->to_string();
2094         }
2095         ret += "\n";
2096
2097         return(ret);
2098 }
2099
2100 string join_eq_hash_qpn::to_query_string(){
2101
2102         string ret = "Select ";
2103         int s;
2104         for(s=0;s<select_list.size();s++){
2105                 if(s>0) ret+=", ";
2106                 ret += se_to_query_string(select_list[s]->se, NULL);
2107                 if(select_list[s]->name != "") ret += " AS "+select_list[s]->name;
2108         }
2109         ret += "\n";
2110
2111 //                      NOTE: assuming binary join.
2112         int properties = from[0]->get_property()+2*from[1]->get_property();
2113         switch(properties){
2114         case 0:
2115                 ret += "INNER_JOIN ";
2116                 break;
2117         case 1:
2118                 ret += "LEFT_OUTER_JOIN ";
2119                 break;
2120         case 2:
2121                 ret += "RIGHT_OUTER_JOIN ";
2122                 break;
2123         case 3:
2124                 ret += "OUTER_JOIN ";
2125                 break;
2126         }
2127
2128         ret += "From ";
2129         int f;
2130         for(f=0;f<from.size();++f){
2131                 if(f>0) ret+=", ";
2132                 ret += from[f]->to_string();
2133         }
2134         ret += "\n";
2135
2136         if(where.size() > 0){
2137                 ret += "Where ";
2138                 int w;
2139                 for(w=0;w<where.size();w++){
2140                         if(w>0) ret += " AND ";
2141                         ret += "(" + pred_to_query_str(where[w]->pr,NULL) + ")";
2142                 }
2143                 ret += "\n";
2144         }
2145
2146         return(ret);
2147 }
2148
2149 string filter_join_qpn::to_query_string(){
2150
2151         string ret = "Select ";
2152         int s;
2153         for(s=0;s<select_list.size();s++){
2154                 if(s>0) ret+=", ";
2155                 ret += se_to_query_string(select_list[s]->se, NULL);
2156                 if(select_list[s]->name != "") ret += " AS "+select_list[s]->name;
2157         }
2158         ret += "\n";
2159
2160 //                      NOTE: assuming binary join.
2161         ret += "FILTER_JOIN("+temporal_var->field+","+int_to_string(temporal_range)+") ";
2162
2163         ret += "From ";
2164         int f;
2165         for(f=0;f<from.size();++f){
2166                 if(f>0) ret+=", ";
2167                 ret += from[f]->to_string();
2168         }
2169         ret += "\n";
2170
2171         if(where.size() > 0){
2172                 ret += "Where ";
2173                 int w;
2174                 for(w=0;w<where.size();w++){
2175                         if(w>0) ret += " AND ";
2176                         ret += "(" + pred_to_query_str(where[w]->pr,NULL) + ")";
2177                 }
2178                 ret += "\n";
2179         }
2180
2181         return(ret);
2182 }
2183
2184
2185 // -----------------------------------------------------------------
2186 //              Query node subclass specific processing.
2187
2188
2189 vector<mrg_qpn *> mrg_qpn::split_sources(){
2190   vector<mrg_qpn *> ret;
2191   int i;
2192
2193 //                      sanity check
2194         if(fm.size() != mvars.size()){
2195                 fprintf(stderr,"INTERNAL ERROR in mrg_qpn::split_sources.  fm.size() = %lu, mvars.size() = %lu\n",fm.size(),mvars.size());
2196                 exit(1);
2197         }
2198         if(fm.size() == 1){
2199                 fprintf(stderr,"INTERNAL ERROR in mrg_qpn::split_sources, fm size is 1.\n");
2200                 exit(1);
2201         }
2202
2203 /*
2204 int ff;
2205 printf("spliting sources merge node, name = %s, %d sources.\n\t",node_name.c_str(), fm.size());
2206 for(ff=0;ff<fm.size();++ff){
2207 printf("%s ",fm[ff]->to_string().c_str());
2208 }
2209 printf("\n");
2210 */
2211
2212 //              Handle special cases.
2213         if(fm.size() == 2){
2214                 ret.push_back(this);
2215                 return ret;
2216         }
2217
2218         if(fm.size() == 3){
2219                 mrg_qpn *new_mrg = (mrg_qpn *)this->make_copy("_cH1");
2220                 new_mrg->fm.push_back(this->fm[0]);
2221                 new_mrg->fm.push_back(this->fm[1]);
2222                 new_mrg->mvars.push_back(this->mvars[0]);
2223                 new_mrg->mvars.push_back(this->mvars[1]);
2224
2225                 this->fm.erase(this->fm.begin());
2226                 this->mvars.erase(this->mvars.begin());
2227                 string vname = fm[0]->get_var_name();
2228                 this->fm[0] = new tablevar_t(new_mrg->node_name.c_str());
2229                 this->fm[0]->set_range_var(vname);
2230                 this->mvars[0]->set_field(table_layout->get_field_name(merge_fieldpos));
2231                 this->mvars[0]->set_tablevar_ref(0);
2232                 this->mvars[1]->set_tablevar_ref(1);
2233
2234                 ret.push_back(new_mrg);
2235                 ret.push_back(this);
2236
2237 /*
2238 printf("split sources %s (%s %s)\n",node_name.c_str(),new_mrg->node_name.c_str(),this->node_name.c_str());
2239 for(i=0;i<new_mrg->fm.size();++i)
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());
2241 for(i=0;i<this->fm.size();++i)
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());
2243 */
2244
2245                 return ret;
2246         }
2247
2248 //              General case.
2249 //              divide up the sources between two children.
2250 //              Then, recurse on the children.
2251
2252                 mrg_qpn *new_mrg1 = (mrg_qpn *)this->make_copy("_cH1");
2253                 mrg_qpn *new_mrg2 = (mrg_qpn *)this->make_copy("_cH2");
2254                 for(i=0;i<this->fm.size()/2;++i){
2255                         new_mrg1->fm.push_back(this->fm[i]);
2256                         new_mrg1->mvars.push_back(this->mvars[i]);
2257 //printf("Pushing %d (%s, %s) to new_mrg1\n",i,fm[i]->to_string().c_str(), mvars[i]->to_string().c_str());
2258                 }
2259                 for(;i<this->fm.size();++i){
2260                         new_mrg2->fm.push_back(this->fm[i]);
2261                         new_mrg2->mvars.push_back(this->mvars[i]);
2262 //printf("Pushing %d (%s, %s) to new_mrg2\n",i,fm[i]->to_string().c_str(), mvars[i]->to_string().c_str());
2263                 }
2264                 for(i=0;i<new_mrg1->mvars.size();++i)
2265                         new_mrg1->mvars[i]->set_tablevar_ref(i);
2266                 for(i=0;i<new_mrg2->mvars.size();++i)
2267                         new_mrg2->mvars[i]->set_tablevar_ref(i);
2268
2269 //                      Children created, make this merge them.
2270                 fm.clear();
2271                 mvars.clear();
2272 //                      var 1
2273                 tablevar_t *tmp_tblvar = new tablevar_t(new_mrg1->node_name.c_str());
2274                 tmp_tblvar->set_range_var("_mrg_var_1");
2275                 fm.push_back(tmp_tblvar);
2276                 colref_t *tmp_cref = new colref_t("_mrg_var_1",table_layout->get_field_name(merge_fieldpos).c_str());
2277                 tmp_cref->set_tablevar_ref(0);
2278                 mvars.push_back(tmp_cref);
2279 //                      var 2
2280                 tmp_tblvar = new tablevar_t(new_mrg2->node_name.c_str());
2281                 tmp_tblvar->set_range_var("_mrg_var_2");
2282                 fm.push_back(tmp_tblvar);
2283                 tmp_cref = new colref_t("_mrg_var_2",table_layout->get_field_name(merge_fieldpos).c_str());
2284                 tmp_cref->set_tablevar_ref(1);
2285                 mvars.push_back(tmp_cref);
2286
2287
2288 /*
2289 printf("split sources %s (%s %s)\n",node_name.c_str(),new_mrg1->node_name.c_str(),new_mrg2->node_name.c_str());
2290 for(i=0;i<new_mrg1->fm.size();++i)
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());
2292 for(i=0;i<new_mrg2->fm.size();++i)
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());
2294 */
2295
2296 //              Recurse and put them together
2297                 vector<mrg_qpn *> st1 = new_mrg1->split_sources();
2298                 ret.insert(ret.end(), st1.begin(), st1.end());
2299                 vector<mrg_qpn *> st2 = new_mrg2->split_sources();
2300                 ret.insert(ret.end(), st2.begin(), st2.end());
2301
2302                 ret.push_back(this);
2303
2304                 return(ret);
2305
2306 }
2307
2308
2309
2310 ////////        Split helper function : resolve interfaces
2311
2312 vector<pair<string,string> > get_ifaces(tablevar_t *table, ifq_t *ifdb, int n_virtual_ifaces, int hfta_parallelism, int hfta_idx){
2313         vector<pair<string,string> > basic_ifaces;
2314         int ierr;
2315         if(table->get_ifq()){
2316                 basic_ifaces= ifdb->eval(table->get_interface(),ierr);
2317                 if(ierr==1){
2318                 fprintf(stderr,"ERROR, Interface set %s not found.\n",table->get_interface().c_str());
2319                 }
2320                 if(ierr==2){
2321                         fprintf(stderr,"ERROR, interface definition file didn't parse.\n");
2322                 }
2323         }else{
2324                 basic_ifaces.push_back(make_pair(table->get_machine(), table->get_interface()));
2325         }
2326
2327         if(n_virtual_ifaces == 1)
2328                 return basic_ifaces;
2329
2330         int stride = n_virtual_ifaces / hfta_parallelism;
2331         int i,s;
2332         vector<pair<string,string> > ifaces;
2333
2334         for(i=0;i<basic_ifaces.size();++i){
2335                 string mach = basic_ifaces[i].first;
2336                 string iface = basic_ifaces[i].second;
2337                 for(s=hfta_idx*stride;s<(hfta_idx+1)*stride;++s){
2338                         ifaces.push_back(pair<string, string>(mach,iface+"X"+int_to_string(2*s)));
2339                 }
2340         }
2341
2342         return ifaces;
2343 }
2344
2345
2346 /////////       Split helper function : compute slack in a generated
2347 /////////       merge.
2348
2349 void mrg_qpn::resolve_slack(scalarexp_t *t_se, string fname, vector<pair<string, string> > &sources, ifq_t *ifdb, gb_table *gbt){
2350         int s,e,v;
2351         string es;
2352
2353 //              Find slack divisor, if any.
2354         string fnm;
2355         long long int slack_divisor = find_temporal_divisor(t_se,gbt, fnm);
2356         if(slack_divisor <= 0){
2357                 slack = NULL;
2358                 return;
2359         }
2360
2361 //              find max slack in the iface spec
2362         long long int max_slacker = 0, this_slacker;
2363         string rname = "Slack_"+fnm;
2364         for(s=0;s<sources.size();++s){
2365                 string src_machine = sources[s].first;
2366                 string src_iface = sources[s].second;
2367                 vector<string> slack_vec = ifdb->get_iface_vals(src_machine, src_iface,rname,e,es);
2368                 for(v=0;v<slack_vec.size();++v){
2369                         if(sscanf(slack_vec[v].c_str(),"%qd",&this_slacker)){
2370                                 if(this_slacker > max_slacker)
2371                                         max_slacker = this_slacker;
2372                         }
2373                 }
2374         }
2375
2376         if(max_slacker <= 0){
2377                 slack = NULL;
2378                 return;
2379         }
2380
2381 //              convert to SE
2382         long long int the_slack=(long long int)(ceil(((double)max_slacker)/((double)slack_divisor)));
2383         char tmps[256];
2384         sprintf(tmps,"%lld",the_slack);
2385         literal_t *slack_lit = new literal_t(tmps, LITERAL_LONGINT);
2386         slack = new scalarexp_t(slack_lit);
2387 }
2388
2389
2390 //------------------------------------------------------------------
2391 //              split a node to extract LFTA components.
2392
2393
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){
2395         // nothing to do, nothing to split, return copy of self.
2396
2397         hfta_returned = 1;
2398
2399         vector<qp_node *> ret_vec;
2400
2401         ret_vec.push_back(this);
2402         return(ret_vec);
2403
2404 }
2405
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){
2407         vector<qp_node *> ret_vec;
2408
2409 //              First check if the query can be pushed to the FTA.
2410         bool fta_ok = true;
2411         int s;
2412         for(s=0;s<select_list.size();s++){
2413                 fta_ok &= check_fta_forbidden_se(select_list[s]->se,NULL, Ext_fcns);
2414         }
2415         int p;
2416         for(p=0;p<where.size();p++){
2417                 fta_ok &= check_fta_forbidden_pr(where[p]->pr,NULL, Ext_fcns);
2418         }
2419
2420         if(!fta_ok){
2421                 fprintf(stderr,"ERROR, filter join %s is fta-unsafe.\n",node_name.c_str());
2422                 exit(1);
2423         }
2424
2425 //              Can it be done in a single lfta?
2426 //                      Get the set of interfaces it accesses.
2427         int ierr;
2428         int si;
2429         vector<string> sel_names;
2430         vector<pair<string,string> > ifaces = get_ifaces(from[0], ifdb, n_virtual_ifaces, hfta_parallelism, hfta_idx);
2431         if (ifaces.empty()) {
2432                 fprintf(stderr,"INTERNAL ERROR in filter_join_qpn::split_node_for_fta - empty interface set\n");
2433                 exit(1);
2434         }
2435
2436         if(ifaces.size() == 1){
2437 //                              Single interface, no need to merge.
2438                 hfta_returned = 0;
2439                 ret_vec.push_back(this);
2440                 int i;
2441                 for(i=0;i<from.size();i++){
2442                         from[i]->set_machine(ifaces[0].first);
2443                         from[i]->set_interface(ifaces[0].second);
2444                         from[i]->set_ifq(false);
2445                 }
2446                 return(ret_vec);
2447         }else{
2448 //                              Multiple interfaces, generate the interface-specific queries plus
2449 //                              the merge.
2450                 hfta_returned = 1;
2451
2452                 vector<string> sel_names;
2453                 for(si=0;si<ifaces.size();++si){
2454                         filter_join_qpn *fta_node = new filter_join_qpn();
2455
2456 //                      Name the fta
2457                         if(ifaces.size()==1)
2458                                 fta_node->set_node_name( node_name );
2459                         else{
2460                                 string new_name =  "_"+node_name+"_"+ifaces[si].first+"_"+ifaces[si].second;
2461                                 untaboo(new_name);
2462                                 fta_node->set_node_name(new_name);
2463                         }
2464                         sel_names.push_back(fta_node->get_node_name());
2465
2466 //                      Assign the table
2467                         int f;
2468                         for(f=0;f<from.size();f++){
2469                                 fta_node->from.push_back(from[f]->duplicate());
2470                                 fta_node->from[f]->set_machine(ifaces[si].first);
2471                                 fta_node->from[f]->set_interface(ifaces[si].second);
2472                                 fta_node->from[f]->set_ifq(false);
2473                         }
2474                         fta_node->temporal_var = temporal_var;
2475                         fta_node->temporal_range = temporal_range;
2476
2477                         fta_node->use_bloom = use_bloom;
2478
2479                         for(s=0;s<select_list.size();s++){
2480                                 fta_node->select_list.push_back( dup_select(select_list[s], NULL) );
2481                         }
2482
2483                         for(p=0;p<shared_pred.size();p++){
2484                                 predicate_t *new_pr = dup_pr(where[p]->pr, NULL);
2485                                 cnf_elem *new_cnf = new cnf_elem(new_pr);
2486                                 analyze_cnf(new_cnf);
2487                                 fta_node->shared_pred.push_back(new_cnf);
2488                                 fta_node->where.push_back(new_cnf);
2489                         }
2490                         for(p=0;p<pred_t0.size();p++){
2491                                 predicate_t *new_pr = dup_pr(where[p]->pr, NULL);
2492                                 cnf_elem *new_cnf = new cnf_elem(new_pr);
2493                                 analyze_cnf(new_cnf);
2494                                 fta_node->pred_t0.push_back(new_cnf);
2495                                 fta_node->where.push_back(new_cnf);
2496                         }
2497                         for(p=0;p<pred_t1.size();p++){
2498                                 predicate_t *new_pr = dup_pr(where[p]->pr, NULL);
2499                                 cnf_elem *new_cnf = new cnf_elem(new_pr);
2500                                 analyze_cnf(new_cnf);
2501                                 fta_node->pred_t1.push_back(new_cnf);
2502                                 fta_node->where.push_back(new_cnf);
2503                         }
2504                         for(p=0;p<hash_eq.size();p++){
2505                                 predicate_t *new_pr = dup_pr(where[p]->pr, NULL);
2506                                 cnf_elem *new_cnf = new cnf_elem(new_pr);
2507                                 analyze_cnf(new_cnf);
2508                                 fta_node->hash_eq.push_back(new_cnf);
2509                                 fta_node->where.push_back(new_cnf);
2510                         }
2511                         for(p=0;p<postfilter.size();p++){
2512                                 predicate_t *new_pr = dup_pr(where[p]->pr, NULL);
2513                                 cnf_elem *new_cnf = new cnf_elem(new_pr);
2514                                 analyze_cnf(new_cnf);
2515                                 fta_node->postfilter.push_back(new_cnf);
2516                                 fta_node->where.push_back(new_cnf);
2517                         }
2518
2519 //                      Xfer all of the parameters.
2520 //                      Use existing handle annotations.
2521                         vector<string> param_names = param_tbl->get_param_names();
2522                         int pi;
2523                         for(pi=0;pi<param_names.size();pi++){
2524                                 data_type *dt = param_tbl->get_data_type(param_names[pi]);
2525                                 fta_node->param_tbl->add_param(param_names[pi],dt->duplicate(),
2526                                                                         param_tbl->handle_access(param_names[pi]));
2527                         }
2528                         fta_node->definitions = definitions;
2529                         if(fta_node->resolve_if_params(ifdb, this->err_str)){
2530                                 this->error_code = 3;
2531                                 return ret_vec;
2532                         }
2533
2534                         ret_vec.push_back(fta_node);
2535                 }
2536
2537                 mrg_qpn *mrg_node = new mrg_qpn((filter_join_qpn *)ret_vec[0],
2538                          node_name,  sel_names,ifaces, ifdb);
2539                 ret_vec.push_back(mrg_node);
2540
2541                 return(ret_vec);
2542         }
2543
2544 }
2545
2546 //              Use to search for unresolved interface param refs in an hfta.
2547
2548 int spx_qpn::count_ifp_refs(set<string> &ifpnames){
2549         int ret = 0;
2550         int i;
2551         for(i=0;i<select_list.size();++i)
2552                 ret += count_se_ifp_refs(select_list[i]->se,ifpnames);
2553         for(i=0;i<where.size();++i)
2554                 ret += count_pr_ifp_refs(where[i]->pr,ifpnames);
2555         return ret;
2556 }
2557
2558 int sgah_qpn::count_ifp_refs(set<string> &ifpnames){
2559         int ret = 0;
2560         int i,j;
2561         for(i=0;i<select_list.size();++i)
2562                 ret += count_se_ifp_refs(select_list[i]->se,ifpnames);
2563         for(i=0;i<where.size();++i)
2564                 ret += count_pr_ifp_refs(where[i]->pr,ifpnames);
2565         for(i=0;i<having.size();++i)
2566                 ret += count_pr_ifp_refs(having[i]->pr,ifpnames);
2567         for(i=0;i<aggr_tbl.size();++i){
2568                 if(aggr_tbl.is_builtin(i) && !aggr_tbl.is_star_aggr(i)){
2569                         ret += count_se_ifp_refs(aggr_tbl.get_aggr_se(i),ifpnames);
2570                 }else{
2571                         vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(i);
2572                         for(j=0;j<opl.size();++j)
2573                                 ret += count_se_ifp_refs(opl[j],ifpnames);
2574                 }
2575         }
2576         for(i=0;i<gb_tbl.size();++i){
2577                 ret += count_se_ifp_refs(gb_tbl.get_def(i), ifpnames);
2578         }
2579         return ret;
2580 }
2581
2582
2583 int rsgah_qpn::count_ifp_refs(set<string> &ifpnames){
2584         int ret = 0;
2585         int i,j;
2586         for(i=0;i<select_list.size();++i)
2587                 ret += count_se_ifp_refs(select_list[i]->se,ifpnames);
2588         for(i=0;i<where.size();++i)
2589                 ret += count_pr_ifp_refs(where[i]->pr,ifpnames);
2590         for(i=0;i<having.size();++i)
2591                 ret += count_pr_ifp_refs(having[i]->pr,ifpnames);
2592         for(i=0;i<closing_when.size();++i)
2593                 ret += count_pr_ifp_refs(closing_when[i]->pr,ifpnames);
2594         for(i=0;i<aggr_tbl.size();++i){
2595                 if(aggr_tbl.is_builtin(i) && !aggr_tbl.is_star_aggr(i)){
2596                         ret += count_se_ifp_refs(aggr_tbl.get_aggr_se(i),ifpnames);
2597                 }else{
2598                         vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(i);
2599                         for(j=0;j<opl.size();++j)
2600                                 ret += count_se_ifp_refs(opl[j],ifpnames);
2601                 }
2602         }
2603         for(i=0;i<gb_tbl.size();++i){
2604                 ret += count_se_ifp_refs(gb_tbl.get_def(i), ifpnames);
2605         }
2606         return ret;
2607 }
2608
2609 int mrg_qpn::count_ifp_refs(set<string> &ifpnames){
2610         return 0;
2611 }
2612
2613 int join_eq_hash_qpn::count_ifp_refs(set<string> &ifpnames){
2614         int ret = 0;
2615         int i;
2616         for(i=0;i<select_list.size();++i)
2617                 ret += count_se_ifp_refs(select_list[i]->se,ifpnames);
2618         for(i=0;i<prefilter[0].size();++i)
2619                 ret += count_pr_ifp_refs(prefilter[0][i]->pr,ifpnames);
2620         for(i=0;i<prefilter[1].size();++i)
2621                 ret += count_pr_ifp_refs(prefilter[1][i]->pr,ifpnames);
2622         for(i=0;i<temporal_eq.size();++i)
2623                 ret += count_pr_ifp_refs(temporal_eq[i]->pr,ifpnames);
2624         for(i=0;i<hash_eq.size();++i)
2625                 ret += count_pr_ifp_refs(hash_eq[i]->pr,ifpnames);
2626         for(i=0;i<postfilter.size();++i)
2627                 ret += count_pr_ifp_refs(postfilter[i]->pr,ifpnames);
2628         return ret;
2629 }
2630
2631 int filter_join_qpn::count_ifp_refs(set<string> &ifpnames){
2632         int ret = 0;
2633         int i;
2634         for(i=0;i<select_list.size();++i)
2635                 ret += count_se_ifp_refs(select_list[i]->se,ifpnames);
2636         for(i=0;i<where.size();++i)
2637                 ret += count_pr_ifp_refs(where[i]->pr,ifpnames);
2638         return ret;
2639 }
2640
2641
2642 //              Resolve interface params to string literals
2643 int filter_join_qpn::resolve_if_params( ifq_t *ifdb, string &err){
2644         int ret = 0;
2645         int i;
2646         string ifname = from[0]->get_interface();
2647         string ifmach = from[0]->get_machine();
2648         for(i=0;i<select_list.size();++i)
2649                 if( resolve_se_ifp_refs(select_list[i]->se,ifmach, ifname, ifdb, err) )
2650                         ret = 1;
2651         for(i=0;i<where.size();++i)
2652                 if( resolve_pr_ifp_refs(where[i]->pr,ifmach, ifname, ifdb, err))
2653                         ret = 1;
2654         return ret;
2655 }
2656
2657
2658 int spx_qpn::resolve_if_params( ifq_t *ifdb, string &err){
2659         int ret = 0;
2660         int i;
2661         string ifname = table_name->get_interface();
2662         string ifmach = table_name->get_machine();
2663         for(i=0;i<select_list.size();++i)
2664                 if( resolve_se_ifp_refs(select_list[i]->se,ifmach, ifname, ifdb, err) )
2665                         ret = 1;
2666         for(i=0;i<where.size();++i)
2667                 if( resolve_pr_ifp_refs(where[i]->pr,ifmach, ifname, ifdb, err))
2668                         ret = 1;
2669         return ret;
2670 }
2671
2672 int sgah_qpn::resolve_if_params( ifq_t *ifdb, string &err){
2673         int ret = 0;
2674         int i,j;
2675         string ifname = table_name->get_interface();
2676         string ifmach = table_name->get_machine();
2677
2678 //printf("Select list has %d elements\n",select_list.size());
2679         for(i=0;i<select_list.size();++i){
2680 //printf("\tresolving elemet %d\n",i);
2681                 if( resolve_se_ifp_refs(select_list[i]->se,ifmach, ifname, ifdb, err) ){
2682                         ret = 1;
2683                 }
2684         }
2685         for(i=0;i<where.size();++i){
2686                 if( resolve_pr_ifp_refs(where[i]->pr,ifmach, ifname, ifdb, err) )
2687                         ret = 1;
2688         }
2689         for(i=0;i<having.size();++i){
2690                 if( resolve_pr_ifp_refs(having[i]->pr,ifmach, ifname, ifdb, err) )
2691                         ret = 1;
2692         }
2693 //printf("aggr list has %d elements\n",select_list.size());
2694         for(i=0;i<aggr_tbl.size();++i){
2695 //printf("\tresolving elemet %d\n",i);
2696                 if(aggr_tbl.is_builtin(i) && !aggr_tbl.is_star_aggr(i)){
2697 //printf("\t\t\tbuiltin\n");
2698                         if( resolve_se_ifp_refs(aggr_tbl.get_aggr_se(i),ifmach, ifname, ifdb, err) )
2699                                         ret = 1;
2700                 }else{
2701 //printf("\t\t\tudaf\n");
2702                         vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(i);
2703                         for(j=0;j<opl.size();++j)
2704                                 if( resolve_se_ifp_refs(opl[j],ifmach, ifname, ifdb, err) )
2705                                         ret = 1;
2706                 }
2707         }
2708         for(i=0;i<gb_tbl.size();++i){
2709                 if( resolve_se_ifp_refs(gb_tbl.get_def(i), ifmach, ifname, ifdb, err) )
2710                         ret = 1;
2711         }
2712         return ret;
2713 }
2714
2715
2716
2717 /*
2718         SPLITTING A SELECTION_PROJECTION OPERATOR
2719
2720         An SPX node may reference:
2721                 literals, parameters, colrefs, functions, operators
2722         An SPX node may not reference:
2723                 group-by variables, aggregates
2724
2725         An SPX node contains
2726                 selection list of SEs
2727                 where list of CNF predicates
2728
2729         Algorithm:
2730                 If each selection SE and each where predicate is fta-safe
2731                         execute entire operator as an LFTA.
2732                 Else
2733                         for each predicate in the where clause
2734                           if it is fta safe, execute it in the lfta
2735                           else, split each SE in the predicate, evaluate the
2736                                 top-level SEs in the hfta and eval the predicate on that.
2737                         For each SE in the se list
2738                           Split the SE, eval the high level part, push onto hfta
2739                                 selection list
2740
2741         Splitting an SE:
2742                 A SE represents a value which must be computed.  The LFTA
2743                 must provide sub-values from which the HFTA can compute the
2744                 desired value.
2745                 1) the SE is fta-safe
2746                         Create an entry in the selection list of the LFTA which is
2747                         the SE itself.  Reference this LFTA selection list entry in
2748                         the HFTA (via a field name assigned to the lfta selection
2749                         list entry).
2750                 2) The SE is not fta-safe
2751                         Determine the boundary between the fta-safe and the fta-unsafe
2752                         portions of the SE.  The result is a rooted tree (which is
2753                         evaluated at the HFTA) which references sub-SEs (which are
2754                         evaluated at the LFTA).  Each of the sub-SEs is placed on
2755                         the selection list of the LFTA and assigned field names,
2756                         the top part is evaluated at the HFTA and references the
2757                         sub-SEs through their assigned field names.
2758                 The only SEs on the LFTA selection list are those created by
2759                 the above mechanism.  The collection of assigned field names becomes
2760                 the schema of the LFTA.
2761
2762                 TODO: insert tablevar names into the colrefs.
2763
2764 */
2765
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){
2767
2768         int i;
2769         vector<qp_node *> ret_vec;
2770
2771 //                      If the node reads from a stream, don't split.
2772 //      int t = Schema->get_table_ref(table_name->get_schema_name());
2773         int t = table_name->get_schema_ref();
2774         if(Schema->get_schema_type(t) != PROTOCOL_SCHEMA){
2775                 hfta_returned = 1;
2776                 ret_vec.push_back(this);
2777                 return(ret_vec);
2778         }
2779
2780
2781 //                      Get the set of interfaces it accesses.
2782         int ierr;
2783         int si;
2784         vector<string> sel_names;
2785         vector<pair<string,string> > ifaces = get_ifaces(table_name, ifdb, n_virtual_ifaces, hfta_parallelism, hfta_idx);
2786         if (ifaces.empty()) {
2787                 fprintf(stderr,"INTERNAL ERROR in spx_qpn::split_node_for_fta - empty interface set\n");
2788                 exit(1);
2789         }
2790
2791
2792 //                      The FTA node, it is always returned.
2793
2794         spx_qpn *fta_node = new spx_qpn();
2795                 fta_node->table_name = table_name;
2796
2797 //                      for colname imputation
2798 //      vector<string> fta_flds, stream_flds;
2799
2800
2801 //              First check if the query can be pushed to the FTA.
2802         bool fta_ok = true;
2803         int s;
2804         for(s=0;s<select_list.size();s++){
2805                 fta_ok &= check_fta_forbidden_se(select_list[s]->se,NULL, Ext_fcns);
2806         }
2807         int p;
2808         for(p=0;p<where.size();p++){
2809                 fta_ok &= check_fta_forbidden_pr(where[p]->pr,NULL, Ext_fcns);
2810         }
2811
2812         if(fta_ok){
2813 ////////////////////////////////////////////////////////////
2814 //                      The query can be executed entirely in the FTA.
2815                 hfta_returned = 0;
2816
2817                 for(si=0;si<ifaces.size();++si){
2818                         fta_node = new spx_qpn();
2819
2820 //                      Name the fta
2821                         if(ifaces.size()==1)
2822                                 fta_node->set_node_name( node_name );
2823                         else{
2824                                 string new_name =  "_"+node_name+"_"+ifaces[si].first+"_"+ifaces[si].second;
2825                                 untaboo(new_name);
2826                                 fta_node->set_node_name(new_name);
2827                         }
2828                         sel_names.push_back(fta_node->get_node_name());
2829
2830 //                      Assign the table
2831                         fta_node->table_name = table_name->duplicate();
2832                         fta_node->table_name->set_machine(ifaces[si].first);
2833                         fta_node->table_name->set_interface(ifaces[si].second);
2834                         fta_node->table_name->set_ifq(false);
2835
2836                         for(s=0;s<select_list.size();s++){
2837                                 fta_node->select_list.push_back( dup_select(select_list[s], NULL) );
2838                         }
2839                         for(p=0;p<where.size();p++){
2840                                 predicate_t *new_pr = dup_pr(where[p]->pr, NULL);
2841                                 cnf_elem *new_cnf = new cnf_elem(new_pr);
2842                                 analyze_cnf(new_cnf);
2843
2844                                 fta_node->where.push_back(new_cnf);
2845                         }
2846
2847 //                      Xfer all of the parameters.
2848 //                      Use existing handle annotations.
2849                         vector<string> param_names = param_tbl->get_param_names();
2850                         int pi;
2851                         for(pi=0;pi<param_names.size();pi++){
2852                                 data_type *dt = param_tbl->get_data_type(param_names[pi]);
2853                                 fta_node->param_tbl->add_param(param_names[pi],dt->duplicate(),
2854                                                                         param_tbl->handle_access(param_names[pi]));
2855                         }
2856                         fta_node->definitions = definitions;
2857                         if(fta_node->resolve_if_params(ifdb, this->err_str)){
2858                                 this->error_code = 3;
2859                                 return ret_vec;
2860                         }
2861
2862                         ret_vec.push_back(fta_node);
2863                 }
2864
2865                 if(ifaces.size() > 1){
2866                 spx_qpn *tmp_spx = (spx_qpn *)(ret_vec[0]);
2867                         mrg_qpn *mrg_node = new mrg_qpn(tmp_spx,
2868                                  node_name,  sel_names,ifaces, ifdb);
2869                         /*
2870                         Do not split sources until we are done with optimizations
2871                         vector<mrg_qpn *> split_merge = mrg_node->split_sources();
2872                         for(i=0;i<split_merge.size();++i){
2873                                 ret_vec.push_back(split_merge[i]);
2874                         }
2875                         hfta_returned = split_merge.size();
2876                         */
2877                         ret_vec.push_back(mrg_node);
2878                         hfta_returned = 1;
2879                 }
2880
2881
2882 // printf("OK as FTA.\n");
2883 // printf("FTA node is:\n%s\n\n",fta_node->to_query_string().c_str() );
2884
2885                 return(ret_vec);
2886         }
2887
2888 ////////////////////////////////////////////////////
2889 //                      The fta must be split.  Create a stream node.
2890 //                      NOTE : I am counting on the single
2891 //                      table in the from list.  (Joins handled in a different operator).
2892
2893         hfta_returned = 1;
2894
2895         spx_qpn *stream_node = new spx_qpn();
2896         stream_node->set_node_name( node_name );
2897 //              Create the tablevar in the stream's FROM clause.
2898 //              set the schema name to the name of the LFTA,
2899 //              and use the same tablevar name.
2900         stream_node->table_name = new tablevar_t(
2901                          ("_fta_"+node_name).c_str()
2902          );
2903         stream_node->table_name->set_range_var(table_name->get_var_name());
2904
2905 //                      Name the fta
2906         fta_node->set_node_name( "_fta_"+node_name );
2907
2908 //                      table var names of fta, stream.
2909     string fta_var = fta_node->table_name->get_var_name();
2910     string stream_var = stream_node->table_name->get_var_name();
2911
2912 //                      Set up select list vector
2913         vector< vector<select_element *> *> select_vec;
2914         select_vec.push_back(&(fta_node->select_list)); // only one child
2915
2916
2917 //                      Split the select list into its FTA and stream parts.
2918 //                      If any part of the SE is fta-unsafe, it will return
2919 //                      a SE to execute at the stream ref'ing SE's evaluated
2920 //                      at the fta (which are put on the FTA's select list as a side effect).
2921 //                      If the SE is fta-safe, put it on the fta select list, make
2922 //                      a ref to it and put the ref on the stream select list.
2923         for(s=0;s<select_list.size();s++){
2924                 bool fta_forbidden = false;
2925                 int se_src = SPLIT_FTAVEC_NOTBLVAR;
2926 //              scalarexp_t *root_se = split_fta_se(
2927 //                      select_list[s]->se,fta_forbidden, fta_node->select_list, Ext_fcns
2928 //              );
2929                 scalarexp_t *root_se = split_ftavec_se( select_list[s]->se,
2930                                         fta_forbidden, se_src, select_vec, Ext_fcns
2931                 );
2932 //              if(fta_forbidden){
2933                 if(fta_forbidden || se_src == SPLIT_FTAVEC_NOTBLVAR){
2934                         stream_node->select_list.push_back(
2935                                 new select_element(root_se, select_list[s]->name)
2936                         );
2937                 }else{
2938                         scalarexp_t *new_se=make_fta_se_ref(fta_node->select_list,root_se,0);
2939                         stream_node->select_list.push_back(
2940                                 new select_element(new_se, select_list[s]->name)
2941                         );
2942                 }
2943         }
2944
2945
2946 //              The WHERE clause has already been split into a set of clauses
2947 //              that are ANDED together.  For each clause, check if its FTA-safe.
2948 //              If not, split its SE's into fta-safe and stream-executing parts,
2949 //              then put a clause which ref's the SEs into the stream.
2950 //              Else put it into the LFTA.
2951         predicate_t *pr_root;
2952         bool fta_forbidden;
2953         for(p=0;p<where.size();p++){
2954                 if(! check_fta_forbidden_pr(where[p]->pr, NULL, Ext_fcns) ){
2955                         pr_root = split_ftavec_pr(where[p]->pr,select_vec,Ext_fcns);
2956 //                      pr_root = split_fta_pr( where[p]->pr, fta_node->select_list, Ext_fcns);
2957                         fta_forbidden = true;
2958                 }else{
2959                         pr_root = dup_pr(where[p]->pr, NULL);
2960                         fta_forbidden = false;
2961                 }
2962                 cnf_elem *cnf_root = new cnf_elem(pr_root);
2963                 analyze_cnf(cnf_root);
2964
2965                 if(fta_forbidden){
2966                         stream_node->where.push_back(cnf_root);
2967                 }else{
2968                         fta_node->where.push_back(cnf_root);
2969                 }
2970         }
2971
2972
2973
2974 //                      Divide the parameters among the stream, FTA.
2975 //                      Currently : assume that the stream receives all parameters
2976 //                      and parameter updates, incorporates them, then passes
2977 //                      all of the parameters to the FTA.
2978 //                      This will need to change (tables, fta-unsafe types. etc.)
2979
2980 //                      I will pass on the use_handle_access marking, even
2981 //                      though the fcn call that requires handle access might
2982 //                      exist in only one of the parts of the query.
2983 //                      Parameter manipulation and handle access determination will
2984 //                      need to be revisited anyway.
2985         vector<string> param_names = param_tbl->get_param_names();
2986         int pi;
2987         for(pi=0;pi<param_names.size();pi++){
2988                 data_type *dt = param_tbl->get_data_type(param_names[pi]);
2989                 fta_node->param_tbl->add_param(param_names[pi],dt->duplicate(),
2990                                                                         param_tbl->handle_access(param_names[pi]));
2991                 stream_node->param_tbl->add_param(param_names[pi],dt->duplicate(),
2992                                                                         param_tbl->handle_access(param_names[pi]));
2993         }
2994
2995         fta_node->definitions = definitions; fta_node->definitions.erase("_referenced_ifaces");
2996         stream_node->definitions = definitions;
2997
2998 //              Now split by interfaces
2999         if(ifaces.size() > 1){
3000                 for(si=0;si<ifaces.size();++si){
3001                         spx_qpn *subq_node = new spx_qpn();
3002
3003 //                      Name the subquery
3004                         string new_name =  "_"+node_name+"_"+ifaces[si].first+"_"+ifaces[si].second;
3005                         untaboo(new_name);
3006                         subq_node->set_node_name( new_name) ;
3007                         sel_names.push_back(subq_node->get_node_name());
3008
3009 //                      Assign the table
3010                         subq_node->table_name = fta_node->table_name->duplicate();
3011                         subq_node->table_name->set_machine(ifaces[si].first);
3012                         subq_node->table_name->set_interface(ifaces[si].second);
3013                         subq_node->table_name->set_ifq(false);
3014
3015                         for(s=0;s<fta_node->select_list.size();s++){
3016                                 subq_node->select_list.push_back( dup_select(fta_node->select_list[s], NULL) );
3017                         }
3018                         for(p=0;p<fta_node->where.size();p++){
3019                                 predicate_t *new_pr = dup_pr(fta_node->where[p]->pr, NULL);
3020                                 cnf_elem *new_cnf = new cnf_elem(new_pr);
3021                                 analyze_cnf(new_cnf);
3022
3023                                 subq_node->where.push_back(new_cnf);
3024                         }
3025 //                      Xfer all of the parameters.
3026 //                      Use existing handle annotations.
3027                         vector<string> param_names = param_tbl->get_param_names();
3028                         int pi;
3029                         for(pi=0;pi<param_names.size();pi++){
3030                                 data_type *dt = param_tbl->get_data_type(param_names[pi]);
3031                                 subq_node->param_tbl->add_param(param_names[pi],dt->duplicate(),
3032                                                                         param_tbl->handle_access(param_names[pi]));
3033                         }
3034                         if(subq_node->resolve_if_params(ifdb, this->err_str)){
3035                                 this->error_code = 3;
3036                                 return ret_vec;
3037                         }
3038                         subq_node->definitions = definitions; subq_node->definitions.erase("_referenced_ifaces");
3039
3040                         ret_vec.push_back(subq_node);
3041                 }
3042
3043                 mrg_qpn *mrg_node = new mrg_qpn((spx_qpn *)(ret_vec[0]),
3044                          fta_node->node_name, sel_names, ifaces, ifdb);
3045                 /*
3046                 Do not split sources until we are done with optimizations
3047                 vector<mrg_qpn *> split_merge = mrg_node->split_sources();
3048                 for(i=0;i<split_merge.size();++i){
3049                         ret_vec.push_back(split_merge[i]);
3050                 }
3051                 */
3052                 ret_vec.push_back(mrg_node);
3053                 ret_vec.push_back(stream_node);
3054                 hfta_returned = 1/*split_merge.size()*/ + 1;
3055
3056         }else{
3057                 fta_node->table_name->set_machine(ifaces[0].first);
3058                 fta_node->table_name->set_interface(ifaces[0].second);
3059                 fta_node->table_name->set_ifq(false);
3060                 if(fta_node->resolve_if_params(ifdb, this->err_str)){
3061                         this->error_code = 3;
3062                         return ret_vec;
3063                 }
3064                 ret_vec.push_back(fta_node);
3065                 ret_vec.push_back(stream_node);
3066                 hfta_returned = 1;
3067         }
3068
3069 // printf("FTA node is:\n%s\n\n",fta_node->to_query_string().c_str() );
3070 // printf("Stream node is:\n%s\n\n",stream_node->to_query_string().c_str() );
3071
3072
3073         return(ret_vec);
3074 }
3075
3076
3077 /*
3078         Splitting a aggregation+sampling operator.
3079     right now, return an error if any splitting is required.
3080 */
3081
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){
3083
3084         hfta_returned = 1;
3085
3086         vector<qp_node *> ret_vec;
3087         int s, p, g, a, o, i;
3088         int si;
3089
3090         vector<string> fta_flds, stream_flds;
3091
3092 //                      If the node reads from a stream, don't split.
3093 //      int t = Schema->get_table_ref(table_name->get_schema_name());
3094         int t = table_name->get_schema_ref();
3095         if(Schema->get_schema_type(t) != PROTOCOL_SCHEMA){
3096                 ret_vec.push_back(this);
3097                 return(ret_vec);
3098         }
3099
3100         fprintf(stderr,"ERROR : cannot split a sampling operator (not yet implemented).\n");
3101         exit(1);
3102
3103         return ret_vec;
3104
3105
3106 }
3107
3108
3109 /*
3110         Splitting a running aggregation operator.
3111     The code is almost identical to that of the the sgah operator
3112     except that
3113        - there is no lfta-only option.
3114            - the stream node is rsagh_qpn (lfta is sgah or spx)
3115            - need to handle the closing when (similar to having)
3116 */
3117
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){
3119
3120         hfta_returned = 1;
3121
3122         vector<qp_node *> ret_vec;
3123         int s, p, g, a, o, i;
3124         int si;
3125
3126         vector<string> fta_flds, stream_flds;
3127
3128 //                      If the node reads from a stream, don't split.
3129 //      int t = Schema->get_table_ref(table_name->get_schema_name());
3130         int t = table_name->get_schema_ref();
3131         if(Schema->get_schema_type(t) != PROTOCOL_SCHEMA){
3132                 ret_vec.push_back(this);
3133                 return(ret_vec);
3134         }
3135
3136 //                      Get the set of interfaces it accesses.
3137         int ierr;
3138         vector<string> sel_names;
3139         vector<pair<string,string> > ifaces = get_ifaces(table_name, ifdb, n_virtual_ifaces, hfta_parallelism, hfta_idx);
3140         if (ifaces.empty()) {
3141                 fprintf(stderr,"INTERNAL ERROR in rsgah_qpn::split_node_for_fta - empty interface set\n");
3142                 exit(1);
3143         }
3144
3145
3146
3147
3148 //////////////////////////////////////////////////////////////
3149 ///                     Split into lfta, hfta.
3150
3151 //                      A rsgah node must always be split,
3152 //                      if for no other reason than to complete the
3153 //                      partial aggregation.
3154
3155 //                      First, determine if the query can be spit into aggr/aggr,
3156 //                      or if it must be selection/aggr.
3157 //                      Splitting into selection/aggr is allowed only
3158 //                      if select_lfta is set.
3159
3160
3161         bool select_allowed = definitions.count("select_lfta")>0;
3162         bool select_rqd = false;
3163
3164         set<int> unsafe_gbvars;         // for processing where clause
3165         for(g=0;g<gb_tbl.size();g++){
3166                 if(! check_fta_forbidden_se(gb_tbl.get_def(g), &aggr_tbl, Ext_fcns)){
3167                         if(!select_allowed){
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",
3169                                 gb_tbl.get_name(g).c_str(), se_to_query_string(gb_tbl.get_def(g), &aggr_tbl).c_str()
3170                           );
3171                           this->error_code = 1;
3172                           this->err_str = tmpstr;
3173                           return(ret_vec);
3174                         }else{
3175                           select_rqd = true;
3176                           unsafe_gbvars.insert(g);
3177                         }
3178                 }
3179         }
3180
3181 //                      Verify that the SEs in the aggregate definitions are fta-safe
3182         for(a=0;a<aggr_tbl.size();++a){
3183                 scalarexp_t *ase = aggr_tbl.get_aggr_se(a);
3184                 if(ase != NULL){        // COUNT(*) does not have a SE.
3185                   if(!select_allowed){
3186                     if(! check_fta_forbidden_se(aggr_tbl.get_aggr_se(a), &aggr_tbl, Ext_fcns)){
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",
3188                                 aggr_tbl.get_op(a).c_str(), se_to_query_string(aggr_tbl.get_aggr_se(a), &aggr_tbl).c_str()
3189                           );
3190                           this->error_code = 1;
3191                           this->err_str = tmpstr;
3192                           return(ret_vec);
3193                     }
3194                   }else{
3195                         select_rqd = true;
3196                   }
3197                 }
3198         }
3199
3200 //                      Verify that all of the ref'd UDAFs can be split.
3201
3202         for(a=0;a<aggr_tbl.size();++a){
3203                 if(! aggr_tbl.is_builtin(a)){
3204                         int afcn = aggr_tbl.get_fcn_id(a);
3205                         int super_id = Ext_fcns->get_superaggr_id(afcn);
3206                         int sub_id = Ext_fcns->get_subaggr_id(afcn);
3207                         if(super_id < 0 || sub_id < 0){
3208                           if(!select_allowed){
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";
3210                                 this->error_code = 1;
3211                                 return(ret_vec);
3212                           }else{
3213                                 select_rqd = true;
3214                           }
3215                         }
3216                 }
3217     }
3218
3219         for(p=0;p<where.size();p++){
3220                 if(! check_fta_forbidden_pr(where[p]->pr, &aggr_tbl, Ext_fcns) ){
3221                   if(!select_allowed){
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",
3223                                 pred_to_query_str(where[p]->pr,&aggr_tbl).c_str()
3224                         );
3225                         this->error_code = 1;
3226                         this->err_str = tmpstr;
3227                         return(ret_vec);
3228                   }else{
3229                         select_rqd = true;
3230                   }
3231                 }
3232         }
3233
3234
3235         if(! select_rqd){
3236
3237 /////////////////////////////////////////////////////
3238 //                      Split into  aggr/aggr.
3239
3240
3241
3242
3243
3244         sgah_qpn *fta_node = new sgah_qpn();
3245                 fta_node->table_name = table_name;
3246                 fta_node->set_node_name( "_fta_"+node_name );
3247                 fta_node->table_name->set_range_var(table_name->get_var_name());
3248
3249
3250         rsgah_qpn *stream_node = new rsgah_qpn();
3251                 stream_node->table_name = new tablevar_t(  ("_fta_"+node_name).c_str());
3252                 stream_node->set_node_name( node_name );
3253                 stream_node->table_name->set_range_var(table_name->get_var_name());
3254
3255 //                      First, process the group-by variables.
3256 //                      The fta must supply the values of all the gbvars.
3257 //                      If a gb is computed, the computation must be
3258 //                      performed at the FTA, so the SE must be FTA-safe.
3259 //                      Nice side effect : the gbvar table contains
3260 //                      matching entries for the original query, the lfta query,
3261 //                      and the hfta query.  So gbrefs in the new queries are set
3262 //                      correctly just by inheriting the gbrefs from the old query.
3263 //                      If this property changed, I'll need translation tables.
3264
3265
3266         for(g=0;g<gb_tbl.size();g++){
3267 //                      Insert the gbvar into the lfta.
3268                 scalarexp_t *gbvar_def = dup_se(gb_tbl.get_def(g), &aggr_tbl);
3269                 fta_node->gb_tbl.add_gb_var(
3270                         gb_tbl.get_name(g), gb_tbl.get_tblvar_ref(g), gbvar_def, gb_tbl.get_reftype(g)
3271                 );
3272
3273 //                      Insert a ref to the value of the gbvar into the lfta select list.
3274                 colref_t *new_cr = new colref_t(gb_tbl.get_name(g).c_str() );
3275                 scalarexp_t *gbvar_fta = new scalarexp_t(new_cr);
3276                 gbvar_fta->set_gb_ref(g);
3277                 gbvar_fta->set_data_type( gb_tbl.get_def(g)->get_data_type() );
3278                 scalarexp_t *gbvar_stream = make_fta_se_ref(fta_node->select_list, gbvar_fta,0);
3279
3280 //                      Insert the corresponding gbvar ref (gbvar_stream) into the stream.
3281                 gbvar_stream->set_gb_ref(-1);   // used as GBvar def
3282                 stream_node->gb_tbl.add_gb_var(
3283                         gbvar_stream->get_colref()->get_field(), -1, gbvar_stream,  gb_tbl.get_reftype(g)
3284                 );
3285
3286         }
3287
3288 //                      SEs in the aggregate definitions.
3289 //                      They are all safe, so split them up for later processing.
3290         map<int, scalarexp_t *> hfta_aggr_se;
3291         for(a=0;a<aggr_tbl.size();++a){
3292                 split_fta_aggr( &(aggr_tbl), a,
3293                                                 &(stream_node->aggr_tbl), &(fta_node->aggr_tbl)  ,
3294                                                 fta_node->select_list,
3295                                                 hfta_aggr_se,
3296                                                 Ext_fcns
3297                                         );
3298         }
3299
3300
3301 //                      Next, the select list.
3302
3303         for(s=0;s<select_list.size();s++){
3304                 bool fta_forbidden = false;
3305                 scalarexp_t *root_se = rehome_fta_se(select_list[s]->se, &hfta_aggr_se);
3306                 stream_node->select_list.push_back(
3307                         new select_element(root_se, select_list[s]->name));
3308         }
3309
3310
3311
3312 //                      All the predicates in the where clause must execute
3313 //                      in the fta.
3314
3315         for(p=0;p<where.size();p++){
3316                 predicate_t *new_pr = dup_pr(where[p]->pr, &aggr_tbl);
3317                 cnf_elem *new_cnf = new cnf_elem(new_pr);
3318                 analyze_cnf(new_cnf);
3319
3320                 fta_node->where.push_back(new_cnf);
3321         }
3322
3323 //                      All of the predicates in the having clause must
3324 //                      execute in the stream node.
3325
3326         for(p=0;p<having.size();p++){
3327                 predicate_t *pr_root = rehome_fta_pr( having[p]->pr,  &hfta_aggr_se);
3328                 cnf_elem *cnf_root = new cnf_elem(pr_root);
3329                 analyze_cnf(cnf_root);
3330
3331                 stream_node->having.push_back(cnf_root);
3332         }
3333
3334 //                      All of the predicates in the closing when clause must
3335 //                      execute in the stream node.
3336
3337         for(p=0;p<closing_when.size();p++){
3338                 predicate_t *pr_root=rehome_fta_pr(closing_when[p]->pr,&hfta_aggr_se);
3339                 cnf_elem *cnf_root = new cnf_elem(pr_root);
3340                 analyze_cnf(cnf_root);
3341
3342                 stream_node->closing_when.push_back(cnf_root);
3343         }
3344
3345
3346 //                      Divide the parameters among the stream, FTA.
3347 //                      Currently : assume that the stream receives all parameters
3348 //                      and parameter updates, incorporates them, then passes
3349 //                      all of the parameters to the FTA.
3350 //                      This will need to change (tables, fta-unsafe types. etc.)
3351
3352 //                      I will pass on the use_handle_access marking, even
3353 //                      though the fcn call that requires handle access might
3354 //                      exist in only one of the parts of the query.
3355 //                      Parameter manipulation and handle access determination will
3356 //                      need to be revisited anyway.
3357         vector<string> param_names = param_tbl->get_param_names();
3358         int pi;
3359         for(pi=0;pi<param_names.size();pi++){
3360                 data_type *dt = param_tbl->get_data_type(param_names[pi]);
3361                 fta_node->param_tbl->add_param(param_names[pi],dt->duplicate(),
3362                                                                         param_tbl->handle_access(param_names[pi]));
3363                 stream_node->param_tbl->add_param(param_names[pi],dt->duplicate(),
3364                                                                         param_tbl->handle_access(param_names[pi]));
3365         }
3366         fta_node->definitions = definitions; fta_node->definitions.erase("_referenced_ifaces");
3367         stream_node->definitions = definitions;
3368
3369 //              Now split by interfaces XXXX
3370         if(ifaces.size() > 1){
3371                 for(si=0;si<ifaces.size();++si){
3372                         sgah_qpn *subq_node = new sgah_qpn();
3373
3374 //                      Name the subquery
3375                         string new_name =  "_"+node_name+"_"+ifaces[si].first+"_"+ifaces[si].second;
3376                         untaboo(new_name);
3377                         subq_node->set_node_name( new_name) ;
3378                         sel_names.push_back(subq_node->get_node_name());
3379
3380 //                      Assign the table
3381                         subq_node->table_name = fta_node->table_name->duplicate();
3382                         subq_node->table_name->set_machine(ifaces[si].first);
3383                         subq_node->table_name->set_interface(ifaces[si].second);
3384                         subq_node->table_name->set_ifq(false);
3385
3386 //                      the GB vars.
3387                         for(g=0;g<fta_node->gb_tbl.size();g++){
3388 //                      Insert the gbvar into the lfta.
3389                                 scalarexp_t *gbvar_def = dup_se(fta_node->gb_tbl.get_def(g), NULL);
3390                                 subq_node->gb_tbl.add_gb_var(
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)
3392                                 );
3393                         }
3394
3395 //                      Insert the aggregates
3396                         for(a=0;a<fta_node->aggr_tbl.size();++a){
3397                                 subq_node->aggr_tbl.add_aggr(fta_node->aggr_tbl.duplicate(a));
3398                         }
3399
3400                         for(s=0;s<fta_node->select_list.size();s++){
3401                                 subq_node->select_list.push_back( dup_select(fta_node->select_list[s], NULL) );
3402                         }
3403                         for(p=0;p<fta_node->where.size();p++){
3404                                 predicate_t *new_pr = dup_pr(fta_node->where[p]->pr, NULL);
3405                                 cnf_elem *new_cnf = new cnf_elem(new_pr);
3406                                 analyze_cnf(new_cnf);
3407
3408                                 subq_node->where.push_back(new_cnf);
3409                         }
3410                         for(p=0;p<fta_node->having.size();p++){
3411                                 predicate_t *new_pr = dup_pr(fta_node->having[p]->pr, NULL);
3412                                 cnf_elem *new_cnf = new cnf_elem(new_pr);
3413                                 analyze_cnf(new_cnf);
3414
3415                                 subq_node->having.push_back(new_cnf);
3416                         }
3417 //                      Xfer all of the parameters.
3418 //                      Use existing handle annotations.
3419                         vector<string> param_names = param_tbl->get_param_names();
3420                         int pi;
3421                         for(pi=0;pi<param_names.size();pi++){
3422                                 data_type *dt = param_tbl->get_data_type(param_names[pi]);
3423                                 subq_node->param_tbl->add_param(param_names[pi],dt->duplicate(),
3424                                                                         param_tbl->handle_access(param_names[pi]));
3425                         }
3426                         subq_node->definitions = definitions; subq_node->definitions.erase("_referenced_ifaces");
3427                         if(subq_node->resolve_if_params(ifdb, this->err_str)){
3428                                 this->error_code = 3;
3429                                 return ret_vec;
3430                         }
3431
3432                         ret_vec.push_back(subq_node);
3433                 }
3434
3435                 mrg_qpn *mrg_node = new mrg_qpn((sgah_qpn *)(ret_vec[0]),
3436                          fta_node->node_name, sel_names, ifaces, ifdb);
3437
3438                 /*
3439                 Do not split sources until we are done with optimizations
3440                 vector<mrg_qpn *> split_merge = mrg_node->split_sources();
3441                 for(i=0;i<split_merge.size();++i){
3442                         ret_vec.push_back(split_merge[i]);
3443                 }
3444                 */
3445                 ret_vec.push_back(mrg_node);
3446                 ret_vec.push_back(stream_node);
3447                 hfta_returned = 1/*split_merge.size()*/+1;
3448
3449         }else{
3450                 fta_node->table_name->set_machine(ifaces[0].first);
3451                 fta_node->table_name->set_interface(ifaces[0].second);
3452                 fta_node->table_name->set_ifq(false);
3453                 if(fta_node->resolve_if_params(ifdb, this->err_str)){
3454                         this->error_code = 3;
3455                         return ret_vec;
3456                 }
3457                 ret_vec.push_back(fta_node);
3458                 ret_vec.push_back(stream_node);
3459                 hfta_returned = 1;
3460         }
3461
3462
3463 //      ret_vec.push_back(fta_node);
3464 //      ret_vec.push_back(stream_node);
3465
3466
3467         return(ret_vec);
3468
3469         }
3470
3471 /////////////////////////////////////////////////////////////////////
3472 ///             Split into selection LFTA, aggregation HFTA.
3473
3474         spx_qpn *fta_node = new spx_qpn();
3475                 fta_node->table_name = table_name;
3476                 fta_node->set_node_name( "_fta_"+node_name );
3477                 fta_node->table_name->set_range_var(table_name->get_var_name());
3478
3479
3480         rsgah_qpn *stream_node = new rsgah_qpn();
3481                 stream_node->table_name = new tablevar_t( ("_fta_"+node_name).c_str());
3482                 stream_node->set_node_name( node_name );
3483                 stream_node->table_name->set_range_var(table_name->get_var_name());
3484
3485
3486         vector< vector<select_element *> *> select_vec;
3487         select_vec.push_back(&(fta_node->select_list)); // only one child
3488
3489 //                      Process the gbvars.  Split their defining SEs.
3490         for(g=0;g<gb_tbl.size();g++){
3491                 bool fta_forbidden = false;
3492                 int se_src = SPLIT_FTAVEC_NOTBLVAR;
3493
3494                 scalarexp_t *gbvar_se = split_ftavec_se( gb_tbl.get_def(g),
3495                                         fta_forbidden, se_src, select_vec, Ext_fcns
3496                 );
3497 //              if(fta_forbidden) (
3498                 if(fta_forbidden || se_src == SPLIT_FTAVEC_NOTBLVAR){
3499                         stream_node->gb_tbl.add_gb_var(
3500                           gb_tbl.get_name(g),gb_tbl.get_tblvar_ref(g),gbvar_se,gb_tbl.get_reftype(g)
3501                         );
3502                 }else{
3503                         scalarexp_t *new_se=make_fta_se_ref(fta_node->select_list,gbvar_se,0);
3504                         stream_node->gb_tbl.add_gb_var(
3505                           gb_tbl.get_name(g),gb_tbl.get_tblvar_ref(g),new_se,gb_tbl.get_reftype(g)
3506                         );
3507                 }
3508         }
3509
3510 //              Process the aggregate table.
3511 //              Copy to stream, split the SEs.
3512         map<int, scalarexp_t *> hfta_aggr_se;   // for rehome
3513         for(a=0;a<aggr_tbl.size();++a){
3514                 scalarexp_t *hse;
3515                 if(aggr_tbl.is_builtin(a)){
3516                         if(aggr_tbl.is_star_aggr(a)){
3517                                 stream_node->aggr_tbl.add_aggr(aggr_tbl.get_op(a),NULL, false);
3518                                 hse=scalarexp_t::make_star_aggr(aggr_tbl.get_op(a).c_str());
3519                         }else{
3520                                 bool fta_forbidden = false;
3521                                 int se_src = SPLIT_FTAVEC_NOTBLVAR;
3522
3523                                 scalarexp_t *agg_se = split_ftavec_se( aggr_tbl.get_aggr_se(a),
3524                                         fta_forbidden, se_src, select_vec, Ext_fcns
3525                                 );
3526 //                              if(fta_forbidden) (
3527                                 if(fta_forbidden || se_src == SPLIT_FTAVEC_NOTBLVAR){
3528                                         stream_node->aggr_tbl.add_aggr(aggr_tbl.get_op(a), agg_se,false);
3529                                         hse=scalarexp_t::make_se_aggr(aggr_tbl.get_op(a).c_str(),agg_se);
3530                                 }else{
3531                                         scalarexp_t *new_se=make_fta_se_ref(fta_node->select_list,agg_se,0);
3532                                         stream_node->aggr_tbl.add_aggr(aggr_tbl.get_op(a), new_se,false);
3533                                         hse=scalarexp_t::make_se_aggr(aggr_tbl.get_op(a).c_str(),new_se);
3534                                 }
3535                         }
3536                         hse->set_data_type(aggr_tbl.get_data_type(a));
3537                         hse->set_aggr_id(a);
3538                         hfta_aggr_se[a]=hse;
3539                 }else{
3540                         vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(a);
3541                         vector<scalarexp_t *> new_opl;
3542                         for(o=0;o<opl.size();++o){
3543                                 bool fta_forbidden = false;
3544                                 int se_src = SPLIT_FTAVEC_NOTBLVAR;
3545                                 scalarexp_t *agg_se = split_ftavec_se( opl[o],
3546                                         fta_forbidden, se_src, select_vec, Ext_fcns
3547                                 );
3548 //                              scalarexp_t *agg_se = split_ftavec_se( aggr_tbl.get_aggr_se(a),
3549 //                                      fta_forbidden, se_src, select_vec, Ext_fcns
3550 //                              );
3551 //                              if(fta_forbidden) (
3552                                 if(fta_forbidden || se_src == SPLIT_FTAVEC_NOTBLVAR){
3553                                         new_opl.push_back(agg_se);
3554                                 }else{
3555                                         scalarexp_t *new_se=make_fta_se_ref(fta_node->select_list,agg_se,0);
3556                                         new_opl.push_back(new_se);
3557                                 }
3558                         }
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));
3560                         hse = new scalarexp_t(aggr_tbl.get_op(a).c_str(),new_opl);
3561                         hse->set_data_type(Ext_fcns->get_fcn_dt(aggr_tbl.get_fcn_id(a)));
3562                         hse->set_fcn_id(aggr_tbl.get_fcn_id(a));
3563                         hse->set_aggr_id(a);
3564                         hfta_aggr_se[a]=hse;
3565                 }
3566         }
3567
3568
3569 //              Process the WHERE clause.
3570 //              If it is fta-safe AND it refs only fta-safe gbvars,
3571 //              then expand the gbvars and put it into the lfta.
3572 //              Else, split it into an hfta predicate ref'ing
3573 //              se's computed partially in the lfta.
3574
3575         predicate_t *pr_root;
3576         bool fta_forbidden;
3577         for(p=0;p<where.size();p++){
3578                 if(! check_fta_forbidden_pr(where[p]->pr, NULL, Ext_fcns) || contains_gb_pr(where[p]->pr, unsafe_gbvars) ){
3579                         pr_root = split_ftavec_pr(where[p]->pr,select_vec,Ext_fcns);
3580                         fta_forbidden = true;
3581                 }else{
3582                         pr_root = dup_pr(where[p]->pr, NULL);
3583                         expand_gbvars_pr(pr_root, gb_tbl);
3584                         fta_forbidden = false;
3585                 }
3586                 cnf_elem *cnf_root = new cnf_elem(pr_root);
3587                 analyze_cnf(cnf_root);
3588
3589                 if(fta_forbidden){
3590                         stream_node->where.push_back(cnf_root);
3591                 }else{
3592                         fta_node->where.push_back(cnf_root);
3593                 }
3594         }
3595
3596
3597 //              Process the Select clause, rehome it on the
3598 //              new defs.
3599         for(s=0;s<select_list.size();s++){
3600                 bool fta_forbidden = false;
3601                 scalarexp_t *root_se = rehome_fta_se(select_list[s]->se, &hfta_aggr_se);
3602                 stream_node->select_list.push_back(
3603                         new select_element(root_se, select_list[s]->name));
3604         }
3605
3606
3607 // Process the Having clause
3608
3609 //                      All of the predicates in the having clause must
3610 //                      execute in the stream node.
3611
3612         for(p=0;p<having.size();p++){
3613                 predicate_t *pr_root = rehome_fta_pr( having[p]->pr,  &hfta_aggr_se);
3614                 cnf_elem *cnf_root = new cnf_elem(pr_root);
3615                 analyze_cnf(cnf_root);
3616
3617                 stream_node->having.push_back(cnf_root);
3618         }
3619 //                      Same for closing when
3620         for(p=0;p<closing_when.size();p++){
3621                 predicate_t *pr_root=rehome_fta_pr(closing_when[p]->pr,&hfta_aggr_se);
3622                 cnf_elem *cnf_root = new cnf_elem(pr_root);
3623                 analyze_cnf(cnf_root);
3624
3625                 stream_node->closing_when.push_back(cnf_root);
3626         }
3627
3628
3629 //              Handle parameters and a few last details.
3630         vector<string> param_names = param_tbl->get_param_names();
3631         int pi;
3632         for(pi=0;pi<param_names.size();pi++){
3633                 data_type *dt = param_tbl->get_data_type(param_names[pi]);
3634                 fta_node->param_tbl->add_param(param_names[pi],dt->duplicate(),
3635                                                                         param_tbl->handle_access(param_names[pi]));
3636                 stream_node->param_tbl->add_param(param_names[pi],dt->duplicate(),
3637                                                                         param_tbl->handle_access(param_names[pi]));
3638         }
3639
3640         fta_node->definitions = definitions; fta_node->definitions.erase("_referenced_ifaces");
3641         stream_node->definitions = definitions;
3642
3643 //              Now split by interfaces YYYY
3644         if(ifaces.size() > 1){
3645                 for(si=0;si<ifaces.size();++si){
3646                         spx_qpn *subq_node = new spx_qpn();
3647
3648 //                      Name the subquery
3649                         string new_name =  "_"+node_name+"_"+ifaces[si].first+"_"+ifaces[si].second;
3650                         untaboo(new_name);
3651                         subq_node->set_node_name( new_name) ;
3652                         sel_names.push_back(subq_node->get_node_name());
3653
3654 //                      Assign the table
3655                         subq_node->table_name = fta_node->table_name->duplicate();
3656                         subq_node->table_name->set_machine(ifaces[si].first);
3657                         subq_node->table_name->set_interface(ifaces[si].second);
3658                         subq_node->table_name->set_ifq(false);
3659
3660                         for(s=0;s<fta_node->select_list.size();s++){
3661                                 subq_node->select_list.push_back( dup_select(fta_node->select_list[s], NULL) );
3662                         }
3663                         for(p=0;p<fta_node->where.size();p++){
3664                                 predicate_t *new_pr = dup_pr(fta_node->where[p]->pr, NULL);
3665                                 cnf_elem *new_cnf = new cnf_elem(new_pr);
3666                                 analyze_cnf(new_cnf);
3667
3668                                 subq_node->where.push_back(new_cnf);
3669                         }
3670 //                      Xfer all of the parameters.
3671 //                      Use existing handle annotations.
3672                         vector<string> param_names = param_tbl->get_param_names();
3673                         int pi;
3674                         for(pi=0;pi<param_names.size();pi++){
3675                                 data_type *dt = param_tbl->get_data_type(param_names[pi]);
3676                                 subq_node->param_tbl->add_param(param_names[pi],dt->duplicate(),
3677                                                                         param_tbl->handle_access(param_names[pi]));
3678                         }
3679                         subq_node->definitions = definitions; subq_node->definitions.erase("_referenced_ifaces");
3680                         if(subq_node->resolve_if_params(ifdb, this->err_str)){
3681                                 this->error_code = 3;
3682                                 return ret_vec;
3683                         }
3684
3685                         ret_vec.push_back(subq_node);
3686                 }
3687
3688                 mrg_qpn *mrg_node = new mrg_qpn((spx_qpn *)(ret_vec[0]),
3689                          fta_node->node_name, sel_names, ifaces, ifdb);
3690                 /*
3691                 Do not split sources until we are done with optimizations
3692                 vector<mrg_qpn *> split_merge = mrg_node->split_sources();
3693                 for(i=0;i<split_merge.size();++i){
3694                         ret_vec.push_back(split_merge[i]);
3695                 }
3696                 */
3697                 ret_vec.push_back(mrg_node);
3698                 ret_vec.push_back(stream_node);
3699                 hfta_returned = 1/*split_merge.size()*/+1;
3700
3701         }else{
3702                 fta_node->table_name->set_machine(ifaces[0].first);
3703                 fta_node->table_name->set_interface(ifaces[0].second);
3704                 fta_node->table_name->set_ifq(false);
3705                 if(fta_node->resolve_if_params(ifdb, this->err_str)){
3706                         this->error_code = 3;
3707                         return ret_vec;
3708                 }
3709                 ret_vec.push_back(fta_node);
3710                 ret_vec.push_back(stream_node);
3711                 hfta_returned = 1;
3712         }
3713
3714         return(ret_vec);
3715
3716 }
3717
3718
3719 /*
3720                 Splitting an aggregation operator
3721
3722                 An aggregation operator can reference
3723                         literals, parameters, colrefs, group-by vars, aggregates,
3724                         operators, functions
3725
3726                 an aggregation contains
3727                         A selection list of SEs
3728                         A where list of predicates
3729                         A list group-by variable definition
3730                         A list of aggregates to be computed
3731                         A HAVING list of predicates.
3732
3733                 Aggregation involves two phases:
3734                         1) given an input tuple, determine if it satisfies all of
3735                                 the WHERE predicates.  If so, compute the group.
3736                                 Look up the group, update its aggregates.
3737                         2) given a closed group and its aggregates, determine
3738                                 if these values satisfy all of the HAVING predicates.
3739                                 If so, evaluate the SEs on the selection list from the
3740                                 group and its aggregates.
3741                 The two-phase nature of aggregation places restrictions on
3742                 what can be referenced by different components of the operator
3743                 (in addition to functions and operators).
3744                 - group-by variables : literals, parameters, colrefs
3745                 - WHERE predicates : group-by vars, literals, params, colrefs
3746                 - HAVING predicates : group-by vars, literals, params, aggregates
3747                 - Selection list SEs : group-by vars, literals, params, aggregates
3748
3749                 Splitting an aggregation operator into an LFTA/HFTA part
3750                 involves performing partial aggregation at the LFTA and
3751                 completing the aggregation at the HFTA.
3752                 - given a tuple, the LFTA part evaluates the WHERE clause,
3753                   and if it is satisfied, computes the group.  lookup the group
3754                   and update the aggregates.  output the group and its partial
3755                   aggregates
3756                 - Given a partial aggregate from the LFTA, look up the group and
3757                   update its aggregates.  When the group is closed, evalute
3758                   the HAVING clause and the SEs on the selection list.
3759                 THEREFORE the selection list of the LFTA must consist of the
3760                 group-by variables and the set of (bare) subaggregate values
3761                 necessary to compute the super aggregates.
3762                 Unlike the case with the SPX operator, the SE splitting point
3763                 is at the GBvar and the aggregate value level.
3764
3765                 ALGORITHM:
3766                 For each group-by variable
3767                         Put the GB variable definition in the LFTA GBVAR list.
3768                         Put the GBVAR in the LFTA selection list (as an SE).
3769                         Put a reference to that GBVAR in the HFTA GBVAR list.
3770                 For each aggregate
3771                         Split the aggregate into a superaggregate and a subaggregate.
3772                                 The SE of the superaggregate references the subaggregate value.
3773                                 (this will need modifications for MF aggregation)
3774                 For each SE in the selection list, HAVING predicate
3775                         Make GBVAR references point to the new GBVAR
3776                         make the aggregate value references point to the new aggregates.
3777
3778                 SEs are not so much split as their ref's are changed.
3779
3780                 TODO: insert tablevar names into the colrefs.
3781 */
3782
3783
3784
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){
3786
3787         hfta_returned = 1;
3788
3789         vector<qp_node *> ret_vec;
3790         int s, p, g, a, o, i;
3791         int si;
3792
3793         vector<string> fta_flds, stream_flds;
3794
3795 //                      If the node reads from a stream, don't split.
3796 //      int t = Schema->get_table_ref(table_name->get_schema_name());
3797         int t = table_name->get_schema_ref();
3798         if(Schema->get_schema_type(t) != PROTOCOL_SCHEMA){
3799                 ret_vec.push_back(this);
3800                 return(ret_vec);
3801         }
3802
3803 //                      Get the set of interfaces it accesses.
3804         int ierr;
3805         vector<string> sel_names;
3806         vector<pair<string,string> > ifaces = get_ifaces(table_name, ifdb, n_virtual_ifaces, hfta_parallelism, hfta_idx);
3807         if (ifaces.empty()) {
3808                 fprintf(stderr,"INTERNAL ERROR in sgah_qpn::split_node_for_fta - empty interface set\n");
3809                 exit(1);
3810         }
3811
3812
3813
3814 //////////////////////////////////////////////
3815 //              Is this LFTA-only?
3816         if(definitions.count("lfta_aggregation")>0){
3817 //                      Yes.  Ensure that everything is lfta-safe.
3818
3819 //                      Check only one interface is accessed.
3820                 if(ifaces.size()>1){
3821                         this->err_str = "ERROR, group-by query "+node_name+" is lfta-only, but it accesses more than one interface:\n";
3822                         for(si=0;si<ifaces.size();++si)
3823                                 this->err_str += "\t"+ifaces[si].first+"."+ifaces[si].second+"\n";
3824                         this->error_code = 2;
3825                         return(ret_vec);
3826                 }
3827
3828 //                      Check the group-by attributes
3829                 for(g=0;g<gb_tbl.size();g++){
3830                         if(! check_fta_forbidden_se(gb_tbl.get_def(g), &aggr_tbl, Ext_fcns)){
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",
3832                                         gb_tbl.get_name(g).c_str(), se_to_query_string(gb_tbl.get_def(g), &aggr_tbl).c_str()
3833                                 );
3834                                 this->error_code = 1;
3835                                 this->err_str = tmpstr;
3836                                 return(ret_vec);
3837                         }
3838                 }
3839
3840 //                      Verify that the SEs in the aggregate definitions are fta-safe
3841                 for(a=0;a<aggr_tbl.size();++a){
3842                         scalarexp_t *ase = aggr_tbl.get_aggr_se(a);
3843                         if(ase != NULL){        // COUNT(*) does not have a SE.
3844                                 if(! check_fta_forbidden_se(aggr_tbl.get_aggr_se(a), &aggr_tbl, Ext_fcns)){
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",
3846                                                 aggr_tbl.get_op(a).c_str(), se_to_query_string(aggr_tbl.get_aggr_se(a), &aggr_tbl).c_str()
3847                                         );
3848                                         this->error_code = 1;
3849                                         this->err_str = tmpstr;
3850                                         return(ret_vec);
3851                                 }
3852                         }
3853                         if(! aggr_tbl.fta_legal(a,Ext_fcns)){
3854                           if(! check_fta_forbidden_se(aggr_tbl.get_aggr_se(a), &aggr_tbl, Ext_fcns)){
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",
3856                                         aggr_tbl.get_op(a).c_str(), se_to_query_string(aggr_tbl.get_aggr_se(a), &aggr_tbl).c_str()
3857                                 );
3858                                 this->error_code = 1;
3859                                 this->err_str = tmpstr;
3860                                 return(ret_vec);
3861                                 }
3862                         }
3863                 }
3864
3865 //              Ensure that all the aggregates are fta-safe ....
3866
3867 //              select list
3868
3869                 for(s=0;s<select_list.size();s++){
3870                         if(! check_fta_forbidden_se(select_list[s]->se,NULL, Ext_fcns)){
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",
3872                                         pred_to_query_str(where[p]->pr,&aggr_tbl).c_str()
3873                                 );
3874                                 this->error_code = 1;
3875                                 this->err_str = tmpstr;
3876                                 return(ret_vec);
3877                         }
3878                 }
3879
3880 //              where predicate
3881
3882                 for(p=0;p<where.size();p++){
3883                         if(! check_fta_forbidden_pr(where[p]->pr, &aggr_tbl, Ext_fcns) ){
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",
3885                                         pred_to_query_str(where[p]->pr,&aggr_tbl).c_str()
3886                                 );
3887                                 this->error_code = 1;
3888                                 this->err_str = tmpstr;
3889                                 return(ret_vec);
3890                         }
3891                 }
3892
3893
3894 //              having predicate
3895                 if(having.size()>0){
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",
3897                                 pred_to_query_str(where[p]->pr,&aggr_tbl).c_str()
3898                         );
3899                         this->error_code = 1;
3900                         this->err_str = tmpstr;
3901                         return(ret_vec);
3902                 }
3903 //                      The query is lfta safe, return it.
3904
3905                 hfta_returned = 0;
3906                 ret_vec.push_back(this);
3907                 return(ret_vec);
3908         }
3909
3910 //////////////////////////////////////////////////////////////
3911 ///                     Split into lfta, hfta.
3912
3913 //                      A sgah node must always be split,
3914 //                      if for no other reason than to complete the
3915 //                      partial aggregation.
3916
3917 //                      First, determine if the query can be spit into aggr/aggr,
3918 //                      or if it must be selection/aggr.
3919 //                      Splitting into selection/aggr is allowed only
3920 //                      if select_lfta is set.
3921
3922
3923         bool select_allowed = definitions.count("select_lfta")>0;
3924         bool select_rqd = false;
3925
3926         set<int> unsafe_gbvars;         // for processing where clause
3927         for(g=0;g<gb_tbl.size();g++){
3928                 if(! check_fta_forbidden_se(gb_tbl.get_def(g), &aggr_tbl, Ext_fcns)){
3929                         if(!select_allowed){
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",
3931                                 gb_tbl.get_name(g).c_str(), se_to_query_string(gb_tbl.get_def(g), &aggr_tbl).c_str()
3932                           );
3933                           this->error_code = 1;
3934                           this->err_str = tmpstr;
3935                           return(ret_vec);
3936                         }else{
3937                           select_rqd = true;
3938                           unsafe_gbvars.insert(g);
3939                         }
3940                 }
3941         }
3942
3943 //                      Verify that the SEs in the aggregate definitions are fta-safe
3944         for(a=0;a<aggr_tbl.size();++a){
3945                 scalarexp_t *ase = aggr_tbl.get_aggr_se(a);
3946                 if(ase != NULL){        // COUNT(*) does not have a SE.
3947                   if(!select_allowed){
3948                     if(! check_fta_forbidden_se(aggr_tbl.get_aggr_se(a), &aggr_tbl, Ext_fcns)){
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",
3950                                 aggr_tbl.get_op(a).c_str(), se_to_query_string(aggr_tbl.get_aggr_se(a), &aggr_tbl).c_str()
3951                           );
3952                           this->error_code = 1;
3953                           this->err_str = tmpstr;
3954                           return(ret_vec);
3955                     }
3956                   }else{
3957                         select_rqd = true;
3958                   }
3959                 }
3960         }
3961
3962 //                      Verify that all of the ref'd UDAFs can be split.
3963
3964         for(a=0;a<aggr_tbl.size();++a){
3965                 if(! aggr_tbl.is_builtin(a)){
3966                         int afcn = aggr_tbl.get_fcn_id(a);
3967                         int super_id = Ext_fcns->get_superaggr_id(afcn);
3968                         int sub_id = Ext_fcns->get_subaggr_id(afcn);
3969                         if(super_id < 0 || sub_id < 0){
3970                           if(!select_allowed){
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";
3972                                 this->error_code = 1;
3973                                 return(ret_vec);
3974                           }else{
3975                                 select_rqd = true;
3976                           }
3977                         }
3978                 }
3979     }
3980
3981         for(p=0;p<where.size();p++){
3982                 if(! check_fta_forbidden_pr(where[p]->pr, &aggr_tbl, Ext_fcns) ){
3983                   if(!select_allowed){
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",
3985                                 pred_to_query_str(where[p]->pr,&aggr_tbl).c_str()
3986                         );
3987                         this->error_code = 1;
3988                         this->err_str = tmpstr;
3989                         return(ret_vec);
3990                   }else{
3991                         select_rqd = true;
3992                   }
3993                 }
3994         }
3995
3996
3997         if(! select_rqd){
3998
3999 /////////////////////////////////////////////////////
4000 //                      Split into  aggr/aggr.
4001
4002
4003
4004
4005
4006         sgah_qpn *fta_node = new sgah_qpn();
4007                 fta_node->table_name = table_name;
4008                 fta_node->set_node_name( "_fta_"+node_name );
4009                 fta_node->table_name->set_range_var(table_name->get_var_name());
4010
4011
4012         sgah_qpn *stream_node = new sgah_qpn();
4013                 stream_node->table_name = new tablevar_t(  ("_fta_"+node_name).c_str());
4014                 stream_node->set_node_name( node_name );
4015                 stream_node->table_name->set_range_var(table_name->get_var_name());
4016
4017 //                      allowed stream disorder.  Default is 2,
4018 //                      can override with max_lfta_disorder setting.
4019 //                      Also limit the hfta disorder, set to lfta disorder + 1.
4020 //                      can override with max_hfta_disorder.
4021
4022         fta_node->lfta_disorder = 2;
4023         if(this->get_val_of_def("max_lfta_disorder") != ""){
4024                 int d = atoi(this->get_val_of_def("max_lfta_disorder").c_str() );
4025                 if(d<1){
4026                         fprintf(stderr,"Warning, max_lfta_disorder in node %s is %d, must be at least 1, ignoring.\n",node_name.c_str(), d);
4027                 }else{
4028                         fta_node->lfta_disorder = d;
4029 printf("node %s setting lfta_disorder = %d\n",node_name.c_str(),fta_node->lfta_disorder);
4030                 }
4031         }
4032         if(fta_node->lfta_disorder > 1)
4033                 stream_node->hfta_disorder = fta_node->lfta_disorder + 1;
4034         else
4035                 stream_node->hfta_disorder =  1;
4036
4037         if(this->get_val_of_def("max_hfta_disorder") != ""){
4038                 int d = atoi(this->get_val_of_def("max_hfta_disorder").c_str() );
4039                 if(d<fta_node->lfta_disorder){
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);
4041                 }else{
4042                         fta_node->lfta_disorder = d;
4043                 }
4044                 if(fta_node->lfta_disorder < fta_node->hfta_disorder){
4045                         fta_node->hfta_disorder = fta_node->lfta_disorder + 1;
4046                 }
4047         }
4048
4049 //                      First, process the group-by variables.
4050 //                      The fta must supply the values of all the gbvars.
4051 //                      If a gb is computed, the computation must be
4052 //                      performed at the FTA, so the SE must be FTA-safe.
4053 //                      Nice side effect : the gbvar table contains
4054 //                      matching entries for the original query, the lfta query,
4055 //                      and the hfta query.  So gbrefs in the new queries are set
4056 //                      correctly just by inheriting the gbrefs from the old query.
4057 //                      If this property changed, I'll need translation tables.
4058
4059
4060         for(g=0;g<gb_tbl.size();g++){
4061 //                      Insert the gbvar into the lfta.
4062                 scalarexp_t *gbvar_def = dup_se(gb_tbl.get_def(g), &aggr_tbl);
4063                 fta_node->gb_tbl.add_gb_var(
4064                         gb_tbl.get_name(g), gb_tbl.get_tblvar_ref(g), gbvar_def, gb_tbl.get_reftype(g)
4065                 );
4066
4067 //                      Insert a ref to the value of the gbvar into the lfta select list.
4068                 colref_t *new_cr = new colref_t(gb_tbl.get_name(g).c_str() );
4069                 scalarexp_t *gbvar_fta = new scalarexp_t(new_cr);
4070                 gbvar_fta->set_gb_ref(g);
4071                 gbvar_fta->set_data_type( gb_tbl.get_def(g)->get_data_type() );
4072                 scalarexp_t *gbvar_stream = make_fta_se_ref(fta_node->select_list, gbvar_fta,0);
4073
4074 //                      Insert the corresponding gbvar ref (gbvar_stream) into the stream.
4075                 gbvar_stream->set_gb_ref(-1);   // used as GBvar def
4076                 stream_node->gb_tbl.add_gb_var(
4077                         gbvar_stream->get_colref()->get_field(), -1, gbvar_stream,  gb_tbl.get_reftype(g)
4078                 );
4079         }
4080 //                      multiple aggregation patterns, if any, go with the hfta
4081         stream_node->gb_tbl.set_pattern_info( &gb_tbl);
4082
4083 //                      SEs in the aggregate definitions.
4084 //                      They are all safe, so split them up for later processing.
4085         map<int, scalarexp_t *> hfta_aggr_se;
4086         for(a=0;a<aggr_tbl.size();++a){
4087                 split_fta_aggr( &(aggr_tbl), a,
4088                                                 &(stream_node->aggr_tbl), &(fta_node->aggr_tbl)  ,
4089                                                 fta_node->select_list,
4090                                                 hfta_aggr_se,
4091                                                 Ext_fcns
4092                                         );
4093 /*
4094 //              OLD TRACING CODE
4095
4096 int ii;
4097 for(ii=0;ii<fta_flds.size() || ii < fta_node->select_list.size();++ii){
4098         if(ii<fta_flds.size())
4099                 printf("\t%s : ",fta_flds[ii].c_str());
4100         else
4101                 printf("\t. : ");
4102         if(ii<fta_node->select_list.size())
4103                 printf("%s\n",fta_node->select_list[ii]->to_string().c_str());
4104         else
4105                 printf(".\n");
4106 }
4107 printf("hfta aggregates are:");
4108 for(ii=0;ii<stream_node->aggr_tbl.size();++ii){
4109         printf(" %s",stream_node->aggr_tbl.get_op(ii).c_str());
4110 }
4111 printf("\nlfta aggregates are:");
4112 for(ii=0;ii<fta_node->aggr_tbl.size();++ii){
4113         printf(" %s",fta_node->aggr_tbl.get_op(ii).c_str());
4114 }
4115 printf("\n\n");
4116 */
4117
4118         }
4119
4120
4121 //                      Next, the select list.
4122
4123         for(s=0;s<select_list.size();s++){
4124                 bool fta_forbidden = false;
4125                 scalarexp_t *root_se = rehome_fta_se(select_list[s]->se, &hfta_aggr_se);
4126                 stream_node->select_list.push_back(
4127                         new select_element(root_se, select_list[s]->name));
4128         }
4129
4130
4131
4132 //                      All the predicates in the where clause must execute
4133 //                      in the fta.
4134
4135         for(p=0;p<where.size();p++){
4136                 predicate_t *new_pr = dup_pr(where[p]->pr, &aggr_tbl);
4137                 cnf_elem *new_cnf = new cnf_elem(new_pr);
4138                 analyze_cnf(new_cnf);
4139
4140                 fta_node->where.push_back(new_cnf);
4141         }
4142
4143 //                      All of the predicates in the having clause must
4144 //                      execute in the stream node.
4145
4146         for(p=0;p<having.size();p++){
4147                 predicate_t *pr_root = rehome_fta_pr( having[p]->pr,  &hfta_aggr_se);
4148                 cnf_elem *cnf_root = new cnf_elem(pr_root);
4149                 analyze_cnf(cnf_root);
4150
4151                 stream_node->having.push_back(cnf_root);
4152         }
4153
4154
4155 //                      Divide the parameters among the stream, FTA.
4156 //                      Currently : assume that the stream receives all parameters
4157 //                      and parameter updates, incorporates them, then passes
4158 //                      all of the parameters to the FTA.
4159 //                      This will need to change (tables, fta-unsafe types. etc.)
4160
4161 //                      I will pass on the use_handle_access marking, even
4162 //                      though the fcn call that requires handle access might
4163 //                      exist in only one of the parts of the query.
4164 //                      Parameter manipulation and handle access determination will
4165 //                      need to be revisited anyway.
4166         vector<string> param_names = param_tbl->get_param_names();
4167         int pi;
4168         for(pi=0;pi<param_names.size();pi++){
4169                 data_type *dt = param_tbl->get_data_type(param_names[pi]);
4170                 fta_node->param_tbl->add_param(param_names[pi],dt->duplicate(),
4171                                                                         param_tbl->handle_access(param_names[pi]));
4172                 stream_node->param_tbl->add_param(param_names[pi],dt->duplicate(),
4173                                                                         param_tbl->handle_access(param_names[pi]));
4174         }
4175         fta_node->definitions = definitions; fta_node->definitions.erase("_referenced_ifaces");
4176         stream_node->definitions = definitions;
4177
4178 //              Now split by interfaces XXXX
4179         if(ifaces.size() > 1){
4180                 for(si=0;si<ifaces.size();++si){
4181                         sgah_qpn *subq_node = new sgah_qpn();
4182
4183 //                      Name the subquery
4184                         string new_name =  "_"+node_name+"_"+ifaces[si].first+"_"+ifaces[si].second;
4185                         untaboo(new_name);
4186                         subq_node->set_node_name( new_name) ;
4187                         sel_names.push_back(subq_node->get_node_name());
4188
4189 //                      Assign the table
4190                         subq_node->table_name = fta_node->table_name->duplicate();
4191                         subq_node->table_name->set_machine(ifaces[si].first);
4192                         subq_node->table_name->set_interface(ifaces[si].second);
4193                         subq_node->table_name->set_ifq(false);
4194
4195 //                      the GB vars.
4196                         for(g=0;g<fta_node->gb_tbl.size();g++){
4197 //                      Insert the gbvar into the lfta.
4198                                 scalarexp_t *gbvar_def = dup_se(fta_node->gb_tbl.get_def(g), NULL);
4199                                 subq_node->gb_tbl.add_gb_var(
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)
4201                                 );
4202                         }
4203
4204 //                      Insert the aggregates
4205                         for(a=0;a<fta_node->aggr_tbl.size();++a){
4206                                 subq_node->aggr_tbl.add_aggr(fta_node->aggr_tbl.duplicate(a));
4207                         }
4208
4209                         for(s=0;s<fta_node->select_list.size();s++){
4210                                 subq_node->select_list.push_back( dup_select(fta_node->select_list[s], NULL) );
4211                         }
4212                         for(p=0;p<fta_node->where.size();p++){
4213                                 predicate_t *new_pr = dup_pr(fta_node->where[p]->pr, NULL);
4214                                 cnf_elem *new_cnf = new cnf_elem(new_pr);
4215                                 analyze_cnf(new_cnf);
4216
4217                                 subq_node->where.push_back(new_cnf);
4218                         }
4219                         for(p=0;p<fta_node->having.size();p++){
4220                                 predicate_t *new_pr = dup_pr(fta_node->having[p]->pr, NULL);
4221                                 cnf_elem *new_cnf = new cnf_elem(new_pr);
4222                                 analyze_cnf(new_cnf);
4223
4224                                 subq_node->having.push_back(new_cnf);
4225                         }
4226 //                      Xfer all of the parameters.
4227 //                      Use existing handle annotations.
4228                         vector<string> param_names = param_tbl->get_param_names();
4229                         int pi;
4230                         for(pi=0;pi<param_names.size();pi++){
4231                                 data_type *dt = param_tbl->get_data_type(param_names[pi]);
4232                                 subq_node->param_tbl->add_param(param_names[pi],dt->duplicate(),
4233                                                                         param_tbl->handle_access(param_names[pi]));
4234                         }
4235                         subq_node->definitions = definitions; subq_node->definitions.erase("_referenced_ifaces");
4236                         if(subq_node->resolve_if_params(ifdb, this->err_str)){
4237                                 this->error_code = 3;
4238                                 return ret_vec;
4239                         }
4240
4241 //                      THe disorder
4242                         subq_node->lfta_disorder = fta_node->lfta_disorder;
4243
4244                         ret_vec.push_back(subq_node);
4245                 }
4246
4247                 mrg_qpn *mrg_node = new mrg_qpn((sgah_qpn *)(ret_vec[0]),
4248                          fta_node->node_name, sel_names, ifaces, ifdb);
4249                 mrg_node->set_disorder(fta_node->lfta_disorder);
4250
4251                 /*
4252                 Do not split sources until we are done with optimizations
4253                 vector<mrg_qpn *> split_merge = mrg_node->split_sources();
4254                 for(i=0;i<split_merge.size();++i){
4255                         ret_vec.push_back(split_merge[i]);
4256                 }
4257                 */
4258                 ret_vec.push_back(mrg_node);
4259                 ret_vec.push_back(stream_node);
4260                 hfta_returned = 1/*split_merge.size()*/+1;
4261
4262         }else{
4263                 fta_node->table_name->set_machine(ifaces[0].first);
4264                 fta_node->table_name->set_interface(ifaces[0].second);
4265                 fta_node->table_name->set_ifq(false);
4266                 if(fta_node->resolve_if_params(ifdb, this->err_str)){
4267                         this->error_code = 3;
4268                         return ret_vec;
4269                 }
4270                 ret_vec.push_back(fta_node);
4271                 ret_vec.push_back(stream_node);
4272                 hfta_returned = 1;
4273         }
4274
4275
4276 //      ret_vec.push_back(fta_node);
4277 //      ret_vec.push_back(stream_node);
4278
4279
4280         return(ret_vec);
4281
4282         }
4283
4284 /////////////////////////////////////////////////////////////////////
4285 ///             Split into selection LFTA, aggregation HFTA.
4286
4287         spx_qpn *fta_node = new spx_qpn();
4288                 fta_node->table_name = table_name;
4289                 fta_node->set_node_name( "_fta_"+node_name );
4290                 fta_node->table_name->set_range_var(table_name->get_var_name());
4291
4292
4293         sgah_qpn *stream_node = new sgah_qpn();
4294                 stream_node->table_name = new tablevar_t( ("_fta_"+node_name).c_str());
4295                 stream_node->set_node_name( node_name );
4296                 stream_node->table_name->set_range_var(table_name->get_var_name());
4297
4298
4299         vector< vector<select_element *> *> select_vec;
4300         select_vec.push_back(&(fta_node->select_list)); // only one child
4301
4302 //                      Process the gbvars.  Split their defining SEs.
4303         for(g=0;g<gb_tbl.size();g++){
4304                 bool fta_forbidden = false;
4305                 int se_src = SPLIT_FTAVEC_NOTBLVAR;
4306
4307                 scalarexp_t *gbvar_se = split_ftavec_se( gb_tbl.get_def(g),
4308                                         fta_forbidden, se_src, select_vec, Ext_fcns
4309                 );
4310 //              if(fta_forbidden) (
4311                 if(fta_forbidden || se_src == SPLIT_FTAVEC_NOTBLVAR){
4312                         stream_node->gb_tbl.add_gb_var(
4313                           gb_tbl.get_name(g),gb_tbl.get_tblvar_ref(g),gbvar_se,gb_tbl.get_reftype(g)
4314                         );
4315                 }else{
4316                         scalarexp_t *new_se=make_fta_se_ref(fta_node->select_list,gbvar_se,0);
4317                         stream_node->gb_tbl.add_gb_var(
4318                           gb_tbl.get_name(g),gb_tbl.get_tblvar_ref(g),new_se,gb_tbl.get_reftype(g)
4319                         );
4320                 }
4321         }
4322         stream_node->gb_tbl.set_pattern_info( &gb_tbl);
4323
4324 //              Process the aggregate table.
4325 //              Copy to stream, split the SEs.
4326         map<int, scalarexp_t *> hfta_aggr_se;   // for rehome
4327         for(a=0;a<aggr_tbl.size();++a){
4328                 scalarexp_t *hse;
4329                 if(aggr_tbl.is_builtin(a)){
4330                         if(aggr_tbl.is_star_aggr(a)){
4331                                 stream_node->aggr_tbl.add_aggr(aggr_tbl.get_op(a),NULL, false);
4332                                 hse=scalarexp_t::make_star_aggr(aggr_tbl.get_op(a).c_str());
4333                         }else{
4334                                 bool fta_forbidden = false;
4335                                 int se_src = SPLIT_FTAVEC_NOTBLVAR;
4336
4337                                 scalarexp_t *agg_se = split_ftavec_se( aggr_tbl.get_aggr_se(a),
4338                                         fta_forbidden, se_src, select_vec, Ext_fcns
4339                                 );
4340 //                              if(fta_forbidden) (
4341                                 if(fta_forbidden || se_src == SPLIT_FTAVEC_NOTBLVAR){
4342                                         stream_node->aggr_tbl.add_aggr(aggr_tbl.get_op(a), agg_se,false);
4343                                         hse=scalarexp_t::make_se_aggr(aggr_tbl.get_op(a).c_str(),agg_se);
4344                                 }else{
4345                                         scalarexp_t *new_se=make_fta_se_ref(fta_node->select_list,agg_se,0);
4346                                         stream_node->aggr_tbl.add_aggr(aggr_tbl.get_op(a), new_se,false);
4347                                         hse=scalarexp_t::make_se_aggr(aggr_tbl.get_op(a).c_str(),new_se);
4348                                 }
4349                         }
4350                         hse->set_data_type(aggr_tbl.get_data_type(a));
4351                         hse->set_aggr_id(a);
4352                         hfta_aggr_se[a]=hse;
4353                 }else{
4354                         vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(a);
4355                         vector<scalarexp_t *> new_opl;
4356                         for(o=0;o<opl.size();++o){
4357                                 bool fta_forbidden = false;
4358                                 int se_src = SPLIT_FTAVEC_NOTBLVAR;
4359                                 scalarexp_t *agg_se = split_ftavec_se( opl[o],
4360                                         fta_forbidden, se_src, select_vec, Ext_fcns
4361                                 );
4362 //                              scalarexp_t *agg_se = split_ftavec_se( aggr_tbl.get_aggr_se(a),
4363 //                                      fta_forbidden, se_src, select_vec, Ext_fcns
4364 //                              );
4365 //                              if(fta_forbidden) (
4366                                 if(fta_forbidden || se_src == SPLIT_FTAVEC_NOTBLVAR){
4367                                         new_opl.push_back(agg_se);
4368                                 }else{
4369                                         scalarexp_t *new_se=make_fta_se_ref(fta_node->select_list,agg_se,0);
4370                                         new_opl.push_back(new_se);
4371                                 }
4372                         }
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));
4374                         hse = new scalarexp_t(aggr_tbl.get_op(a).c_str(),new_opl);
4375                         hse->set_data_type(Ext_fcns->get_fcn_dt(aggr_tbl.get_fcn_id(a)));
4376                         hse->set_fcn_id(aggr_tbl.get_fcn_id(a));
4377                         hse->set_aggr_id(a);
4378                         hfta_aggr_se[a]=hse;
4379                 }
4380         }
4381
4382
4383 //              Process the WHERE clause.
4384 //              If it is fta-safe AND it refs only fta-safe gbvars,
4385 //              then expand the gbvars and put it into the lfta.
4386 //              Else, split it into an hfta predicate ref'ing
4387 //              se's computed partially in the lfta.
4388
4389         predicate_t *pr_root;
4390         bool fta_forbidden;
4391         for(p=0;p<where.size();p++){
4392                 if(! check_fta_forbidden_pr(where[p]->pr, NULL, Ext_fcns) || contains_gb_pr(where[p]->pr, unsafe_gbvars) ){
4393                         pr_root = split_ftavec_pr(where[p]->pr,select_vec,Ext_fcns);
4394                         fta_forbidden = true;
4395                 }else{
4396                         pr_root = dup_pr(where[p]->pr, NULL);
4397                         expand_gbvars_pr(pr_root, gb_tbl);
4398                         fta_forbidden = false;
4399                 }
4400                 cnf_elem *cnf_root = new cnf_elem(pr_root);
4401                 analyze_cnf(cnf_root);
4402
4403                 if(fta_forbidden){
4404                         stream_node->where.push_back(cnf_root);
4405                 }else{
4406                         fta_node->where.push_back(cnf_root);
4407                 }
4408         }
4409
4410
4411 //              Process the Select clause, rehome it on the
4412 //              new defs.
4413         for(s=0;s<select_list.size();s++){
4414                 bool fta_forbidden = false;
4415                 scalarexp_t *root_se = rehome_fta_se(select_list[s]->se, &hfta_aggr_se);
4416                 stream_node->select_list.push_back(
4417                         new select_element(root_se, select_list[s]->name));
4418         }
4419
4420
4421 // Process the Having clause
4422
4423 //                      All of the predicates in the having clause must
4424 //                      execute in the stream node.
4425
4426         for(p=0;p<having.size();p++){
4427                 predicate_t *pr_root = rehome_fta_pr( having[p]->pr,  &hfta_aggr_se);
4428                 cnf_elem *cnf_root = new cnf_elem(pr_root);
4429                 analyze_cnf(cnf_root);
4430
4431                 stream_node->having.push_back(cnf_root);
4432         }
4433
4434 //              Handle parameters and a few last details.
4435         vector<string> param_names = param_tbl->get_param_names();
4436         int pi;
4437         for(pi=0;pi<param_names.size();pi++){
4438                 data_type *dt = param_tbl->get_data_type(param_names[pi]);
4439                 fta_node->param_tbl->add_param(param_names[pi],dt->duplicate(),
4440                                                                         param_tbl->handle_access(param_names[pi]));
4441                 stream_node->param_tbl->add_param(param_names[pi],dt->duplicate(),
4442                                                                         param_tbl->handle_access(param_names[pi]));
4443         }
4444
4445         fta_node->definitions = definitions; fta_node->definitions.erase("_referenced_ifaces");
4446         stream_node->definitions = definitions;
4447
4448 //              Now split by interfaces YYYY
4449         if(ifaces.size() > 1){
4450                 for(si=0;si<ifaces.size();++si){
4451                         spx_qpn *subq_node = new spx_qpn();
4452
4453 //                      Name the subquery
4454                         string new_name =  "_"+node_name+"_"+ifaces[si].first+"_"+ifaces[si].second;
4455                         untaboo(new_name);
4456                         subq_node->set_node_name( new_name) ;
4457                         sel_names.push_back(subq_node->get_node_name());
4458
4459 //                      Assign the table
4460                         subq_node->table_name = fta_node->table_name->duplicate();
4461                         subq_node->table_name->set_machine(ifaces[si].first);
4462                         subq_node->table_name->set_interface(ifaces[si].second);
4463                         subq_node->table_name->set_ifq(false);
4464
4465                         for(s=0;s<fta_node->select_list.size();s++){
4466                                 subq_node->select_list.push_back( dup_select(fta_node->select_list[s], NULL) );
4467                         }
4468                         for(p=0;p<fta_node->where.size();p++){
4469                                 predicate_t *new_pr = dup_pr(fta_node->where[p]->pr, NULL);
4470                                 cnf_elem *new_cnf = new cnf_elem(new_pr);
4471                                 analyze_cnf(new_cnf);
4472
4473                                 subq_node->where.push_back(new_cnf);
4474                         }
4475 //                      Xfer all of the parameters.
4476 //                      Use existing handle annotations.
4477                         vector<string> param_names = param_tbl->get_param_names();
4478                         int pi;
4479                         for(pi=0;pi<param_names.size();pi++){
4480                                 data_type *dt = param_tbl->get_data_type(param_names[pi]);
4481                                 subq_node->param_tbl->add_param(param_names[pi],dt->duplicate(),
4482                                                                         param_tbl->handle_access(param_names[pi]));
4483                         }
4484                         subq_node->definitions = definitions; subq_node->definitions.erase("_referenced_ifaces");
4485                         if(subq_node->resolve_if_params(ifdb, this->err_str)){
4486                                 this->error_code = 3;
4487                                 return ret_vec;
4488                         }
4489
4490                         ret_vec.push_back(subq_node);
4491                 }
4492
4493                 mrg_qpn *mrg_node = new mrg_qpn((spx_qpn *)(ret_vec[0]),
4494                          fta_node->node_name, sel_names, ifaces, ifdb);
4495                 /*
4496                 Do not split sources until we are done with optimizations
4497                 vector<mrg_qpn *> split_merge = mrg_node->split_sources();
4498                 for(i=0;i<split_merge.size();++i){
4499                         ret_vec.push_back(split_merge[i]);
4500                 }
4501                 */
4502                 ret_vec.push_back(mrg_node);
4503                 ret_vec.push_back(stream_node);
4504                 hfta_returned = 1/*split_merge.size()*/+1;
4505
4506         }else{
4507                 fta_node->table_name->set_machine(ifaces[0].first);
4508                 fta_node->table_name->set_interface(ifaces[0].second);
4509                 fta_node->table_name->set_ifq(false);
4510                 if(fta_node->resolve_if_params(ifdb, this->err_str)){
4511                         this->error_code = 3;
4512                         return ret_vec;
4513                 }
4514                 ret_vec.push_back(fta_node);
4515                 ret_vec.push_back(stream_node);
4516                 hfta_returned = 1;
4517         }
4518
4519
4520 //      ret_vec.push_back(fta_node);
4521 //      ret_vec.push_back(stream_node);
4522
4523
4524         return(ret_vec);
4525
4526 }
4527
4528
4529 /*
4530         SPLITTING A EQ-TEMPORAL, HASH JOIN OPERATOR
4531
4532         An JOIN_EQ_HASH_QPN node may reference:
4533                 literals, parameters, colrefs, functions, operators
4534         An JOIN_EQ_HASH_QPN node may not reference:
4535                 group-by variables, aggregates
4536
4537         An JOIN_EQ_HASH_QPN node contains
4538                 selection list of SEs
4539                 where list of CNF predicates, broken into:
4540                         prefilter[2]
4541                         temporal_eq
4542                         hash_eq
4543                         postfilter
4544
4545         Algorithm:
4546                 For each tablevar whose source is a PROTOCOL
4547                         Create a LFTA for that tablevar
4548                         Push as many prefilter[..] predicates to that tablevar as is
4549                                 possible.
4550                         Split the SEs in the select list, and the predicates not
4551                                 pushed to the LFTA.
4552
4553 */
4554
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){
4556
4557         vector<qp_node *> ret_vec;
4558         int f,p,s;
4559
4560 //                      If the node reads from streams only, don't split.
4561         bool stream_only = true;
4562         for(f=0;f<from.size();++f){
4563 //              int t = Schema->get_table_ref(from[f]->get_schema_name());
4564                 int t = from[f]->get_schema_ref();
4565                 if(Schema->get_schema_type(t) == PROTOCOL_SCHEMA) stream_only = false;
4566         }
4567         if(stream_only){
4568                 hfta_returned = 1;
4569                 ret_vec.push_back(this);
4570                 return(ret_vec);
4571         }
4572
4573
4574 //                      The HFTA node, it is always returned.
4575
4576         join_eq_hash_qpn *stream_node = new join_eq_hash_qpn();
4577         for(f=0;f<from.size();++f){
4578 //              tablevar_t *tmp_tblvar = new tablevar_t( from[f]->get_interface().c_str(), from[f]->get_schema_name().c_str());
4579                 tablevar_t *tmp_tblvar =  from[f]->duplicate();
4580 //              tmp_tblvar->set_range_var(from[f]->get_var_name());
4581
4582                 stream_node->from.push_back(tmp_tblvar);
4583         }
4584         stream_node->set_node_name(node_name);
4585
4586 //                      Create spx (selection) children for each PROTOCOL source.
4587         vector<spx_qpn *> child_vec;
4588         vector< vector<select_element *> *> select_vec;
4589         for(f=0;f<from.size();++f){
4590 //              int t = Schema->get_table_ref(from[f]->get_schema_name());
4591                 int t = from[f]->get_schema_ref();
4592                 if(Schema->get_schema_type(t) == PROTOCOL_SCHEMA){
4593                         spx_qpn *child_qpn = new spx_qpn();
4594                         sprintf(tmpstr,"_fta_%d_%s",f,node_name.c_str());
4595                         child_qpn->set_node_name(string(tmpstr));
4596                         child_qpn->table_name = new tablevar_t(
4597                            from[f]->get_interface().c_str(), from[f]->get_schema_name().c_str(), from[f]->get_ifq());
4598                         child_qpn->table_name->set_range_var(from[f]->get_var_name());
4599
4600                         child_vec.push_back(child_qpn);
4601                         select_vec.push_back(&(child_qpn->select_list));
4602
4603 //                      Update the stream's FROM clause to read from this child
4604                         stream_node->from[f]->set_interface("");
4605                         stream_node->from[f]->set_schema(tmpstr);
4606                 }else{
4607                         child_vec.push_back(NULL);
4608                         select_vec.push_back(NULL);
4609                 }
4610         }
4611
4612 //              Push lfta-safe prefilter to the lfta
4613 //              TODO: I'm not copying the preds, I dont *think* it will be a problem.
4614         predicate_t *pr_root;
4615
4616         for(f=0;f<from.size();++f){
4617           vector<cnf_elem *> pred_vec = prefilter[f];
4618           if(child_vec[f] != NULL){
4619                 for(p=0;p<pred_vec.size();++p){
4620                         if(check_fta_forbidden_pr(pred_vec[p]->pr,NULL, Ext_fcns)){
4621                                 child_vec[f]->where.push_back(pred_vec[p]);
4622                         }else{
4623                                 pr_root = split_ftavec_pr(pred_vec[p]->pr,select_vec,Ext_fcns);
4624                                 cnf_elem *cnf_root = new cnf_elem(pr_root);
4625                                 analyze_cnf(cnf_root);
4626                                 stream_node->prefilter[f].push_back(cnf_root);
4627                         }
4628                 }
4629           }else{
4630                 for(p=0;p<pred_vec.size();++p){
4631                         stream_node->prefilter[f].push_back(pred_vec[p]);
4632                 }
4633           }
4634
4635         }
4636
4637 //              Process the other predicates
4638         for(p=0;p<temporal_eq.size();++p){
4639                 pr_root = split_ftavec_pr(temporal_eq[p]->pr,select_vec,Ext_fcns);
4640                 cnf_elem *cnf_root = new cnf_elem(pr_root);
4641                 analyze_cnf(cnf_root);
4642                 stream_node->temporal_eq.push_back(cnf_root);
4643         }
4644         for(p=0;p<hash_eq.size();++p){
4645                 pr_root = split_ftavec_pr(hash_eq[p]->pr,select_vec,Ext_fcns);
4646                 cnf_elem *cnf_root = new cnf_elem(pr_root);
4647                 analyze_cnf(cnf_root);
4648                 stream_node->hash_eq.push_back(cnf_root);
4649         }
4650         for(p=0;p<postfilter.size();++p){
4651                 pr_root = split_ftavec_pr(postfilter[p]->pr,select_vec,Ext_fcns);
4652                 cnf_elem *cnf_root = new cnf_elem(pr_root);
4653                 analyze_cnf(cnf_root);
4654                 stream_node->postfilter.push_back(cnf_root);
4655         }
4656
4657 //              Process the SEs
4658         for(s=0;s<select_list.size();s++){
4659                 bool fta_forbidden = false;
4660                 int se_src = SPLIT_FTAVEC_NOTBLVAR;
4661                 scalarexp_t *root_se = split_ftavec_se( select_list[s]->se,
4662                                         fta_forbidden, se_src, select_vec, Ext_fcns
4663                 );
4664                 if(fta_forbidden || !is_PROTOCOL_source(se_src, select_vec)){
4665                         stream_node->select_list.push_back(
4666                                 new select_element(root_se, select_list[s]->name) );
4667                 }else{
4668                         scalarexp_t *new_se=make_fta_se_ref(select_vec,root_se,se_src);
4669                         stream_node->select_list.push_back(
4670                                 new select_element(new_se, select_list[s]->name)
4671                         );
4672                 }
4673         }
4674
4675
4676 //              I need to "rehome" the colrefs -- make the annotations in the colrefs
4677 //              agree with their tablevars.
4678         for(f=0;f<child_vec.size();++f){
4679           if(child_vec[f]!=NULL){
4680                 vector<tablevar_t *> fm; fm.push_back(child_vec[f]->table_name);
4681
4682                 for(s=0;s<child_vec[f]->select_list.size();++s)
4683                         bind_colref_se(child_vec[f]->select_list[s]->se, fm,0,0);
4684                 for(p=0;p<child_vec[f]->where.size();++p)
4685 //                      bind_colref_pr(child_vec[f]->where[p]->pr, fm,f,0);
4686                         bind_colref_pr(child_vec[f]->where[p]->pr, fm,0,0);
4687           }
4688         }
4689
4690 //              rehome the colrefs in the hfta node.
4691         for(f=0;f<stream_node->from.size();++f){
4692           stream_node->where.clear();
4693           for(s=0;s<stream_node->from.size();++s){
4694                 for(p=0;p<stream_node->prefilter[s].size();++p){
4695                   bind_colref_pr((stream_node->prefilter[s])[p]->pr,stream_node->from,f,f);
4696                 }
4697           }
4698           for(p=0;p<stream_node->temporal_eq.size();++p){
4699                 bind_colref_pr(stream_node->temporal_eq[p]->pr,stream_node->from,f,f);
4700           }
4701           for(p=0;p<stream_node->hash_eq.size();++p){
4702                 bind_colref_pr(stream_node->hash_eq[p]->pr,stream_node->from,f,f);
4703           }
4704           for(p=0;p<stream_node->postfilter.size();++p){
4705                 bind_colref_pr(stream_node->postfilter[p]->pr,stream_node->from,f,f);
4706           }
4707           for(s=0;s<stream_node->select_list.size();++s){
4708                 bind_colref_se(stream_node->select_list[s]->se,stream_node->from,f,f);
4709           }
4710         }
4711
4712 //                      Rebuild the WHERE clause
4713         stream_node->where.clear();
4714         for(s=0;s<stream_node->from.size();++s){
4715                 for(p=0;p<stream_node->prefilter[s].size();++p){
4716                   stream_node->where.push_back((stream_node->prefilter[s])[p]);
4717                 }
4718         }
4719         for(p=0;p<stream_node->temporal_eq.size();++p){
4720                 stream_node->where.push_back(stream_node->temporal_eq[p]);
4721         }
4722         for(p=0;p<stream_node->hash_eq.size();++p){
4723                 stream_node->where.push_back(stream_node->hash_eq[p]);
4724         }
4725         for(p=0;p<stream_node->postfilter.size();++p){
4726                 stream_node->where.push_back(stream_node->postfilter[p]);
4727         }
4728
4729
4730 //              Build the return list
4731         vector<qp_node *> hfta_nodes;
4732         hfta_returned = 1;
4733         for(f=0;f<from.size();++f){
4734                 if(child_vec[f] != NULL){
4735                         spx_qpn *c_node = child_vec[f];
4736                         vector<pair<string, string> > ifaces = get_ifaces(c_node->table_name, ifdb, n_virtual_ifaces, hfta_parallelism, hfta_idx);
4737                         if (ifaces.empty()) {
4738                                 fprintf(stderr,"INTERNAL ERROR in join_eq_hash_qpn::split_node_for_fta - empty interface set\n");
4739                                 exit(1);
4740                         }
4741
4742                         if(ifaces.size() == 1){
4743                                 c_node->table_name->set_machine(ifaces[0].first);
4744                                 c_node->table_name->set_interface(ifaces[0].second);
4745                                 c_node->table_name->set_ifq(false);
4746                                 if(c_node->resolve_if_params(ifdb, this->err_str)){
4747                                         this->error_code = 3;
4748                                         return ret_vec;
4749                                 }
4750                                 ret_vec.push_back(c_node);
4751                         }else{
4752                                 vector<string> sel_names;
4753                                 int si;
4754                                 for(si=0;si<ifaces.size();++si){
4755                                         spx_qpn *subq_node = new spx_qpn();
4756
4757 //                      Name the subquery
4758                                         string new_name =  "_"+c_node->node_name+"_"+ifaces[si].first+"_"+ifaces[si].second;
4759                                         untaboo(new_name);
4760                                         subq_node->set_node_name( new_name) ;
4761                                         sel_names.push_back(subq_node->get_node_name());
4762
4763 //                      Assign the table
4764                                         subq_node->table_name = c_node->table_name->duplicate();
4765                                         subq_node->table_name->set_machine(ifaces[si].first);
4766                                         subq_node->table_name->set_interface(ifaces[si].second);
4767                                         subq_node->table_name->set_ifq(false);
4768
4769                                         for(s=0;s<c_node->select_list.size();s++){
4770                                           subq_node->select_list.push_back(dup_select(c_node->select_list[s], NULL));
4771                                         }
4772                                         for(p=0;p<c_node->where.size();p++){
4773                                           predicate_t *new_pr = dup_pr(c_node->where[p]->pr, NULL);
4774                                           cnf_elem *new_cnf = new cnf_elem(new_pr);
4775                                           analyze_cnf(new_cnf);
4776
4777 printf("table name is %s\n",subq_node->table_name->to_string().c_str());
4778                                           subq_node->where.push_back(new_cnf);
4779                                         }
4780 //                      Xfer all of the parameters.
4781 //                      Use existing handle annotations.
4782 //                                      vector<string> param_names = param_tbl->get_param_names();
4783 //                                      int pi;
4784 //                                      for(pi=0;pi<param_names.size();pi++){
4785 //                                              data_type *dt = param_tbl->get_data_type(param_names[pi]);
4786 //                                              subq_node->param_tbl->add_param(param_names[pi],dt->duplicate(),
4787 //                                                                      param_tbl->handle_access(param_names[pi]));
4788 //                                      }
4789 //                                      subq_node->definitions = definitions;
4790
4791                                 if(subq_node->resolve_if_params(ifdb, this->err_str)){
4792                                         this->error_code = 3;
4793                                         return ret_vec;
4794                                 }
4795
4796                                         ret_vec.push_back(subq_node);
4797                                 }
4798                                 int lpos = ret_vec.size()-1     ;
4799                                 mrg_qpn *mrg_node = new mrg_qpn((spx_qpn *)(ret_vec[lpos]),c_node->node_name,sel_names, ifaces, ifdb);
4800                                 /*
4801                                 Do not split sources until we are done with optimizations
4802                                 vector<mrg_qpn *> split_merge = mrg_node->split_sources();
4803                                 int i;
4804                                 for(i=0;i<split_merge.size();++i){
4805                                         hfta_nodes.push_back(split_merge[i]);
4806                                 }
4807                                 */
4808                                 hfta_nodes.push_back(mrg_node);
4809                         }
4810                 }
4811         }
4812         int i;
4813         for(i=0;i<hfta_nodes.size();++i) ret_vec.push_back(hfta_nodes[i]);
4814         ret_vec.push_back(stream_node);
4815         hfta_returned = hfta_nodes.size()+1;
4816
4817 //                      Currently : assume that the stream receives all parameters
4818 //                      and parameter updates, incorporates them, then passes
4819 //                      all of the parameters to the FTA.
4820 //                      This will need to change (tables, fta-unsafe types. etc.)
4821
4822 //                      I will pass on the use_handle_access marking, even
4823 //                      though the fcn call that requires handle access might
4824 //                      exist in only one of the parts of the query.
4825 //                      Parameter manipulation and handle access determination will
4826 //                      need to be revisited anyway.
4827         vector<string> param_names = param_tbl->get_param_names();
4828         int pi;
4829         for(pi=0;pi<param_names.size();pi++){
4830                 int ri;
4831                 data_type *dt = param_tbl->get_data_type(param_names[pi]);
4832                 for(ri=0;ri<ret_vec.size();++ri){
4833                         ret_vec[ri]->param_tbl->add_param(param_names[pi],dt->duplicate(),
4834                                                                         param_tbl->handle_access(param_names[pi]));
4835                         ret_vec[ri]->definitions = definitions; ret_vec[ri]->definitions.erase("_referenced_ifaces");
4836                 }
4837         }
4838
4839
4840
4841         return(ret_vec);
4842
4843 }
4844
4845
4846 /////////////////////////////////////////////////////////////
4847 ////                    extract_opview
4848
4849 //              Common processing
4850 int process_opview(tablevar_t *fmtbl, int pos, string node_name,
4851                                  table_list *Schema,
4852                                 vector<query_node *> &qnodes,
4853                                 opview_set &opviews,
4854                                 vector<table_exp_t *> &ret, string rootnm, string silo_nm){
4855
4856         int s,f,q,m;
4857
4858         int schref = fmtbl->get_schema_ref();
4859         if(schref <= 0)
4860                 return 0;
4861
4862         if(Schema->get_schema_type(schref) == OPERATOR_VIEW_SCHEMA){
4863                 opview_entry *opv = new opview_entry();
4864                 opv->parent_qname = node_name;
4865                 opv->root_name = rootnm;
4866                 opv->view_name = fmtbl->get_schema_name();
4867                 opv->pos = pos;
4868                 sprintf(tmpstr,"%s_UDOP%d_%s",node_name.c_str(),pos,opv->view_name.c_str());
4869                 opv->udop_alias = tmpstr;
4870                 fmtbl->set_udop_alias(opv->udop_alias);
4871
4872                 opv->exec_fl = Schema->get_op_prop(schref, string("file"));
4873                 opv->liveness_timeout = atoi(Schema->get_op_prop(schref, string("liveness_timeout")).c_str());
4874
4875                 vector<subquery_spec *> subq = Schema->get_subqueryspecs(schref);
4876                 for(s=0;s<subq.size();++s){
4877 //                              Validate that the fields match.
4878                         subquery_spec *sqs = subq[s];
4879                         vector<field_entry *> flds = Schema->get_fields(sqs->name+silo_nm);
4880                         if(flds.size() == 0){
4881                                 fprintf(stderr,"INTERNAL ERROR: subquery %s of view %s not found in Schema.\n",sqs->name.c_str(), opv->view_name.c_str());
4882                                 return(1);
4883                         }
4884                         if(flds.size() < sqs->types.size()){
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());
4886                                 return(1);
4887                         }
4888                         bool failed = false;
4889                         for(f=0;f<sqs->types.size();++f){
4890                                 data_type dte(sqs->types[f],sqs->modifiers[f]);
4891                                 data_type dtf(flds[f]->get_type(),flds[f]->get_modifier_list());
4892                                 if(! dte.subsumes_type(&dtf) ){
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());
4894                                         failed = true;
4895                                 }
4896 /*
4897                                 if(dte.is_temporal() && (dte.get_temporal() != dtf.get_temporal()) ){
4898                                         string pstr = dte.get_temporal_string();
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);
4900                                         failed = true;
4901                                 }
4902 */
4903                         }
4904                         if(failed)
4905                                 return(1);
4906 ///                             Validation done, find the subquery, make a copy of the
4907 ///                             parse tree, and add it to the return list.
4908                         for(q=0;q<qnodes.size();++q)
4909                                 if(qnodes[q]->name == sqs->name)
4910                                         break;
4911                         if(q==qnodes.size()){
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());
4913                                 return(1);
4914                         }
4915
4916                         table_exp_t *newq = dup_table_exp(qnodes[q]->parse_tree);
4917                         sprintf(tmpstr,"%s_OP%d_%s_SUBQ%d",node_name.c_str(),pos,opv->view_name.c_str(),s);
4918                         string newq_name = tmpstr;
4919                         newq->nmap["query_name"] = newq_name;
4920                         ret.push_back(newq);
4921                         opv->subq_names.push_back(newq_name);
4922                 }
4923                 fmtbl->set_opview_idx(opviews.append(opv));
4924         }
4925
4926         return 0;
4927 }
4928
4929 vector<table_exp_t *> spx_qpn::extract_opview(table_list *Schema, vector<query_node *> &qnodes, opview_set &opviews, string rootnm, string silo_name){
4930         vector<table_exp_t *> ret;
4931
4932         int retval = process_opview(table_name,0,node_name,
4933                                                                 Schema,qnodes,opviews,ret, rootnm, silo_name);
4934         if(retval) exit(1);
4935     return(ret);
4936 }
4937
4938
4939 vector<table_exp_t *> sgah_qpn::extract_opview(table_list *Schema,  vector<query_node *> &qnodes, opview_set &opviews, string rootnm, string silo_name){
4940         vector<table_exp_t *> ret;
4941
4942         int retval = process_opview(table_name,0,node_name,
4943                                                                 Schema,qnodes,opviews,ret, rootnm, silo_name);
4944         if(retval) exit(1);
4945     return(ret);
4946 }
4947
4948 vector<table_exp_t *> rsgah_qpn::extract_opview(table_list *Schema,  vector<query_node *> &qnodes, opview_set &opviews, string rootnm, string silo_name){
4949         vector<table_exp_t *> ret;
4950
4951         int retval = process_opview(table_name,0,node_name,
4952                                                                 Schema,qnodes,opviews,ret, rootnm, silo_name);
4953         if(retval) exit(1);
4954     return(ret);
4955 }
4956
4957
4958 vector<table_exp_t *> sgahcwcb_qpn::extract_opview(table_list *Schema,  vector<query_node *> &qnodes, opview_set &opviews, string rootnm, string silo_name){
4959         vector<table_exp_t *> ret;
4960
4961         int retval = process_opview(table_name,0,node_name,
4962                                                                 Schema,qnodes,opviews,ret, rootnm, silo_name);
4963         if(retval) exit(1);
4964     return(ret);
4965 }
4966
4967
4968
4969 vector<table_exp_t *> mrg_qpn::extract_opview(table_list *Schema,  vector<query_node *> &qnodes, opview_set &opviews, string rootnm, string silo_name){
4970         vector<table_exp_t *> ret;
4971         int f;
4972         for(f=0;f<fm.size();++f){
4973                 int retval = process_opview(fm[f],f,node_name,
4974                                                                 Schema,qnodes,opviews,ret, rootnm, silo_name);
4975                 if(retval) exit(1);
4976         }
4977     return(ret);
4978 }
4979
4980
4981
4982
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){
4984         vector<table_exp_t *> ret;
4985         int f;
4986         for(f=0;f<from.size();++f){
4987                 int retval = process_opview(from[f],f,node_name,
4988                                                                 Schema,qnodes,opviews,ret, rootnm, silo_name);
4989                 if(retval) exit(1);
4990         }
4991     return(ret);
4992 }
4993
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){
4995         vector<table_exp_t *> ret;
4996         int f;
4997         for(f=0;f<from.size();++f){
4998                 int retval = process_opview(from[f],f,node_name,
4999                                                                 Schema,qnodes,opviews,ret, rootnm, silo_name);
5000                 if(retval) exit(1);
5001         }
5002     return(ret);
5003 }
5004
5005
5006
5007 //////////////////////////////////////////////////////////////////
5008 //////////////////////////////////////////////////////////////////
5009 ///////                 Additional methods
5010
5011
5012
5013 //////////////////////////////////////////////////////////////////
5014 //              Get schema of operator output
5015
5016 table_def *mrg_qpn::get_fields(){
5017         return(table_layout);
5018 }
5019
5020
5021 table_def *spx_qpn::get_fields(){
5022         return(create_attributes(node_name, select_list));
5023 }
5024
5025 table_def *sgah_qpn::get_fields(){
5026         return(create_attributes(node_name, select_list));
5027 }
5028
5029 table_def *rsgah_qpn::get_fields(){
5030         return(create_attributes(node_name, select_list));
5031 }
5032
5033 table_def *sgahcwcb_qpn::get_fields(){
5034         return(create_attributes(node_name, select_list));
5035 }
5036
5037 table_def *filter_join_qpn::get_fields(){
5038         return(create_attributes(node_name, select_list));
5039 }
5040
5041
5042 table_def *join_eq_hash_qpn::get_fields(){
5043         int i, h, s, t;
5044
5045 //                      First, gather temporal colrefs and SEs.
5046         map<col_id, temporal_type> temporal_cids;
5047         vector<scalarexp_t *> temporal_se;
5048         for(h=0;h<temporal_eq.size();++h){
5049                 scalarexp_t *sel = temporal_eq[h]->pr->get_left_se();
5050                 scalarexp_t *ser = temporal_eq[h]->pr->get_right_se();
5051
5052                 if(sel->get_operator_type() == SE_COLREF){
5053                         col_id tcol(sel->get_colref());
5054                         if(temporal_cids.count(tcol) == 0){
5055                                 temporal_cids[tcol] = sel->get_data_type()->get_temporal();
5056                         }
5057                 }else{
5058                         temporal_se.push_back(sel);
5059                 }
5060
5061                 if(ser->get_operator_type() == SE_COLREF){
5062                         col_id tcol(ser->get_colref());
5063                         if(temporal_cids.count(tcol) == 0){
5064                                 temporal_cids[tcol] = ser->get_data_type()->get_temporal();
5065                         }
5066                 }else{
5067                         temporal_se.push_back(ser);
5068                 }
5069         }
5070
5071 //              Mark select elements as nontemporal, then deduce which
5072 //              ones are temporal.
5073         for(s=0;s<select_list.size();++s){
5074                 select_list[s]->se->get_data_type()->set_temporal(
5075                         compute_se_temporal(select_list[s]->se, temporal_cids)
5076                 );
5077 //                              Second chance if it is an exact match to an SE.
5078 //      for(s=0;s<select_list.size();++s){
5079                 if(! select_list[s]->se->get_data_type()->is_temporal() ){
5080                         for(t=0;t<temporal_se.size();++t){
5081                                 if(is_equivalent_se(temporal_se[t], select_list[s]->se)){
5082                                         select_list[s]->se->get_data_type()->set_temporal(
5083                                                 temporal_se[t]->get_data_type()->get_temporal()
5084                                         );
5085                                 }
5086                         }
5087                 }
5088 //      }
5089         }
5090
5091 //                      If there is an outer join, verify that
5092 //                      the temporal attributes are actually temporal.
5093 //                      NOTE: this code must be synchronized with the
5094 //                      equivalence finding in join_eq_hash_qpn::generate_functor
5095 //                      (and also, the join_eq_hash_qpn constructor)
5096   if(from[0]->get_property() || from[1]->get_property()){
5097         set<string> l_equiv, r_equiv;
5098         for(i=0;i<temporal_eq.size();i++){
5099                 scalarexp_t *lse =      temporal_eq[i]->pr->get_left_se();
5100                 scalarexp_t *rse =      temporal_eq[i]->pr->get_right_se();
5101                 if(lse->get_operator_type()==SE_COLREF){
5102                         l_equiv.insert(lse->get_colref()->get_field());
5103                 }
5104                 if(rse->get_operator_type()==SE_COLREF){
5105                         r_equiv.insert(rse->get_colref()->get_field());
5106                 }
5107         }
5108
5109         for(s=0;s<select_list.size();++s){
5110                 if(select_list[s]->se->get_data_type()->is_temporal()){
5111                         col_id_set cid_set;
5112                         col_id_set::iterator ci;
5113                         bool failed = false;
5114                         gather_se_col_ids(select_list[s]->se,cid_set, NULL);
5115                         for(ci=cid_set.begin();ci!=cid_set.end();++ci){
5116                                 if((*ci).tblvar_ref == 0){
5117                                          if(from[0]->get_property()){
5118                                                 if(l_equiv.count((*ci).field) == 0){
5119                                                         failed = true;
5120                                                 }
5121                                         }
5122                                 }else{
5123                                          if(from[1]->get_property()){
5124                                                 if(r_equiv.count((*ci).field) == 0){
5125                                                         failed = true;
5126                                                 }
5127                                         }
5128                                 }
5129                         }
5130                         if(failed){
5131                                 select_list[s]->se->get_data_type()->reset_temporal();
5132                         }
5133                 }
5134         }
5135   }
5136
5137
5138         return create_attributes(node_name, select_list);
5139 }
5140
5141
5142
5143 //-----------------------------------------------------------------
5144 //                      get output tables
5145
5146
5147 //                      Get tablevar_t names of input and output tables
5148
5149 //      output_file_qpn::output_file_qpn(){source_op_name = ""; }
5150         vector<tablevar_t *> output_file_qpn::get_input_tbls(){
5151                 return(fm);
5152         }
5153
5154         vector<tablevar_t *> mrg_qpn::get_input_tbls(){
5155                 return(fm);
5156         }
5157
5158         vector<tablevar_t *> spx_qpn::get_input_tbls(){
5159                 vector<tablevar_t *> retval(1,table_name);
5160                 return(retval);
5161         }
5162
5163         vector<tablevar_t *> sgah_qpn::get_input_tbls(){
5164                 vector<tablevar_t *> retval(1,table_name);
5165                 return(retval);
5166         }
5167
5168         vector<tablevar_t *> rsgah_qpn::get_input_tbls(){
5169                 vector<tablevar_t *> retval(1,table_name);
5170                 return(retval);
5171         }
5172
5173         vector<tablevar_t *> sgahcwcb_qpn::get_input_tbls(){
5174                 vector<tablevar_t *> retval(1,table_name);
5175                 return(retval);
5176         }
5177
5178         vector<tablevar_t *> join_eq_hash_qpn::get_input_tbls(){
5179                 return(from);
5180         }
5181
5182         vector<tablevar_t *> filter_join_qpn::get_input_tbls(){
5183                 return(from);
5184         }
5185
5186 //-----------------------------------------------------------------
5187 //                      get output tables
5188
5189
5190 //              This does not make sense, this fcn returns the output table *name*,
5191 //              not its schema, and then there is another fcn to rturn the schema.
5192         vector<tablevar_t *> output_file_qpn::get_output_tbls(){
5193                 vector<tablevar_t *> retval(1,new tablevar_t(node_name.c_str()));
5194                 return(retval);
5195         }
5196
5197         vector<tablevar_t *> mrg_qpn::get_output_tbls(){
5198                 vector<tablevar_t *> retval(1,new tablevar_t(node_name.c_str()));
5199                 return(retval);
5200         }
5201
5202         vector<tablevar_t *> spx_qpn::get_output_tbls(){
5203                 vector<tablevar_t *> retval(1,new tablevar_t(node_name.c_str()));
5204                 return(retval);
5205         }
5206
5207         vector<tablevar_t *> sgah_qpn::get_output_tbls(){
5208                 vector<tablevar_t *> retval(1,new tablevar_t(node_name.c_str()));
5209                 return(retval);
5210         }
5211
5212         vector<tablevar_t *> rsgah_qpn::get_output_tbls(){
5213                 vector<tablevar_t *> retval(1,new tablevar_t(node_name.c_str()));
5214                 return(retval);
5215         }
5216
5217         vector<tablevar_t *> sgahcwcb_qpn::get_output_tbls(){
5218                 vector<tablevar_t *> retval(1,new tablevar_t(node_name.c_str()));
5219                 return(retval);
5220         }
5221
5222         vector<tablevar_t *> join_eq_hash_qpn::get_output_tbls(){
5223                 vector<tablevar_t *> retval(1,new tablevar_t(node_name.c_str()));
5224                 return(retval);
5225         }
5226
5227         vector<tablevar_t *> filter_join_qpn::get_output_tbls(){
5228                 vector<tablevar_t *> retval(1,new tablevar_t(node_name.c_str()));
5229                 return(retval);
5230         }
5231
5232
5233
5234 //-----------------------------------------------------------------
5235 //                      Bind to schema
5236
5237 //              Associate colrefs with this schema.
5238 //              Also, use this opportunity to create table_layout (the output schema).
5239 //              If the output schema is ever needed before
5240 void mrg_qpn::bind_to_schema(table_list *Schema){
5241         int t;
5242         for(t=0;t<fm.size();++t){
5243                 int tblref = Schema->get_table_ref(fm[t]->get_schema_name());
5244                 if(tblref>=0)
5245                 fm[t]->set_schema_ref(tblref );
5246         }
5247
5248 //              Here I assume that the colrefs have been reorderd
5249 //              during analysis so that mvars line up with fm.
5250         mvars[0]->set_schema_ref(fm[0]->get_schema_ref());
5251         mvars[1]->set_schema_ref(fm[1]->get_schema_ref());
5252
5253
5254 }
5255
5256
5257
5258 //              Associate colrefs in SEs with this schema.
5259 void spx_qpn::bind_to_schema(table_list *Schema){
5260 //                      Bind the tablevars in the From clause to the Schema
5261 //                      (it might have changed from analysis time)
5262         int t = Schema->get_table_ref(table_name->get_schema_name() );
5263         if(t>=0)
5264         table_name->set_schema_ref(t );
5265
5266 //                      Get the "from" clause
5267         tablevar_list_t fm(table_name);
5268
5269 //                      Bind all SEs to this schema
5270         int p;
5271         for(p=0;p<where.size();++p){
5272                 bind_to_schema_pr(where[p]->pr, &fm, Schema);
5273         }
5274         int s;
5275         for(s=0;s<select_list.size();++s){
5276                 bind_to_schema_se(select_list[s]->se, &fm, Schema);
5277         }
5278
5279 //              Collect set of tuples referenced in this HFTA
5280 //              input, internal, or output.
5281
5282 }
5283
5284 col_id_set spx_qpn::get_colrefs(bool ext_fcns_only,table_list *Schema){
5285         col_id_set retval, tmp_cset;
5286         int p;
5287         for(p=0;p<where.size();++p){
5288                 gather_pr_col_ids(where[p]->pr, tmp_cset, NULL);
5289         }
5290         int s;
5291         for(s=0;s<select_list.size();++s){
5292                 gather_se_col_ids(select_list[s]->se, tmp_cset, NULL);
5293         }
5294         col_id_set::iterator  cisi;
5295         if(ext_fcns_only){
5296                 for(cisi=tmp_cset.begin();cisi!=tmp_cset.end();++cisi){
5297                         field_entry *fe = Schema->get_field((*cisi).schema_ref, (*cisi).field);
5298                         if(fe->get_unpack_fcns().size()>0)
5299                                 retval.insert((*cisi));
5300                 }
5301                 return retval;
5302         }
5303
5304         return tmp_cset;
5305 }
5306
5307 col_id_set filter_join_qpn::get_colrefs(bool ext_fcns_only,table_list *Schema){
5308         col_id_set retval, tmp_cset;
5309         int p;
5310         for(p=0;p<where.size();++p){
5311                 gather_pr_col_ids(where[p]->pr, tmp_cset, NULL);
5312         }
5313         int s;
5314         for(s=0;s<select_list.size();++s){
5315                 gather_se_col_ids(select_list[s]->se, tmp_cset, NULL);
5316         }
5317         col_id_set::iterator  cisi;
5318         if(ext_fcns_only){
5319                 for(cisi=tmp_cset.begin();cisi!=tmp_cset.end();++cisi){
5320                         field_entry *fe = Schema->get_field((*cisi).schema_ref, (*cisi).field);
5321                         if(fe->get_unpack_fcns().size()>0)
5322                                 retval.insert((*cisi));
5323                 }
5324                 return retval;
5325         }
5326
5327         return tmp_cset;
5328 }
5329
5330
5331
5332 //              Associate colrefs in SEs with this schema.
5333 void join_eq_hash_qpn::bind_to_schema(table_list *Schema){
5334 //                      Bind the tablevars in the From clause to the Schema
5335 //                      (it might have changed from analysis time)
5336         int f;
5337         for(f=0;f<from.size();++f){
5338                 string snm = from[f]->get_schema_name();
5339                 int tbl_ref = Schema->get_table_ref(snm);
5340                 if(tbl_ref >= 0)
5341                 from[f]->set_schema_ref(tbl_ref);
5342         }
5343
5344 //                      Bind all SEs to this schema
5345         tablevar_list_t fm(from);
5346
5347         int p;
5348         for(p=0;p<where.size();++p){
5349                 bind_to_schema_pr(where[p]->pr, &fm, Schema);
5350         }
5351         int s;
5352         for(s=0;s<select_list.size();++s){
5353                 bind_to_schema_se(select_list[s]->se, &fm, Schema);
5354         }
5355
5356 //              Collect set of tuples referenced in this HFTA
5357 //              input, internal, or output.
5358
5359 }
5360
5361 void filter_join_qpn::bind_to_schema(table_list *Schema){
5362 //                      Bind the tablevars in the From clause to the Schema
5363 //                      (it might have changed from analysis time)
5364         int f;
5365         for(f=0;f<from.size();++f){
5366                 string snm = from[f]->get_schema_name();
5367                 int tbl_ref = Schema->get_table_ref(snm);
5368                 if(tbl_ref >= 0)
5369                 from[f]->set_schema_ref(tbl_ref);
5370         }
5371
5372 //                      Bind all SEs to this schema
5373         tablevar_list_t fm(from);
5374
5375         int p;
5376         for(p=0;p<where.size();++p){
5377                 bind_to_schema_pr(where[p]->pr, &fm, Schema);
5378         }
5379         int s;
5380         for(s=0;s<select_list.size();++s){
5381                 bind_to_schema_se(select_list[s]->se, &fm, Schema);
5382         }
5383
5384 //              Collect set of tuples referenced in this HFTA
5385 //              input, internal, or output.
5386
5387 }
5388
5389
5390
5391
5392 void sgah_qpn::bind_to_schema(table_list *Schema){
5393 //                      Bind the tablevars in the From clause to the Schema
5394 //                      (it might have changed from analysis time)
5395
5396
5397         int t = Schema->get_table_ref(table_name->get_schema_name() );
5398         if(t>=0)
5399         table_name->set_schema_ref(t );
5400
5401 //                      Get the "from" clause
5402         tablevar_list_t fm(table_name);
5403
5404
5405
5406 //                      Bind all SEs to this schema
5407         int p;
5408         for(p=0;p<where.size();++p){
5409                 bind_to_schema_pr(where[p]->pr, &fm, Schema);
5410         }
5411         for(p=0;p<having.size();++p){
5412                 bind_to_schema_pr(having[p]->pr, &fm, Schema);
5413         }
5414         int s;
5415         for(s=0;s<select_list.size();++s){
5416                 bind_to_schema_se(select_list[s]->se, &fm, Schema);
5417         }
5418         int g;
5419         for(g=0;g<gb_tbl.size();++g){
5420                 bind_to_schema_se(gb_tbl.get_def(g), &fm, Schema);
5421         }
5422         int a;
5423         for(a=0;a<aggr_tbl.size();++a){
5424                 if(aggr_tbl.is_builtin(a)){
5425                         bind_to_schema_se(aggr_tbl.get_aggr_se(a), &fm, Schema);
5426                 }else{
5427                         vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(a);
5428                         int o;
5429                         for(o=0;o<opl.size();++o){
5430                                 bind_to_schema_se(opl[o],&fm,Schema);
5431                         }
5432                 }
5433         }
5434 }
5435
5436 col_id_set sgah_qpn::get_colrefs(bool ext_fcns_only,table_list *Schema){
5437         col_id_set retval, tmp_cset;
5438         int p;
5439         for(p=0;p<where.size();++p){
5440                 gather_pr_col_ids(where[p]->pr, tmp_cset, &gb_tbl);
5441         }
5442         int g;
5443         for(g=0;g<gb_tbl.size();++g){
5444                 gather_se_col_ids(gb_tbl.get_def(g), tmp_cset, &gb_tbl);
5445         }
5446         int a;
5447         for(a=0;a<aggr_tbl.size();++a){
5448                 if(aggr_tbl.is_builtin(a)){
5449                         gather_se_col_ids(aggr_tbl.get_aggr_se(a), tmp_cset, &gb_tbl);
5450                 }else{
5451                         vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(a);
5452                         int o;
5453                         for(o=0;o<opl.size();++o){
5454                                 gather_se_col_ids(opl[o], tmp_cset, &gb_tbl);
5455                         }
5456                 }
5457         }
5458
5459         col_id_set::iterator  cisi;
5460         if(ext_fcns_only){
5461                 for(cisi=tmp_cset.begin();cisi!=tmp_cset.end();++cisi){
5462                         field_entry *fe = Schema->get_field((*cisi).schema_ref, (*cisi).field);
5463                         if(fe->get_unpack_fcns().size()>0)
5464                                 retval.insert((*cisi));
5465                 }
5466                 return retval;
5467         }
5468
5469         return tmp_cset;
5470 }
5471
5472
5473 void rsgah_qpn::bind_to_schema(table_list *Schema){
5474 //                      Bind the tablevars in the From clause to the Schema
5475 //                      (it might have changed from analysis time)
5476         int t = Schema->get_table_ref(table_name->get_schema_name() );
5477         if(t>=0)
5478         table_name->set_schema_ref(t );
5479
5480 //                      Get the "from" clause
5481         tablevar_list_t fm(table_name);
5482
5483 //                      Bind all SEs to this schema
5484         int p;
5485         for(p=0;p<where.size();++p){
5486                 bind_to_schema_pr(where[p]->pr, &fm, Schema);
5487         }
5488         for(p=0;p<having.size();++p){
5489                 bind_to_schema_pr(having[p]->pr, &fm, Schema);
5490         }
5491         for(p=0;p<closing_when.size();++p){
5492                 bind_to_schema_pr(closing_when[p]->pr, &fm, Schema);
5493         }
5494         int s;
5495         for(s=0;s<select_list.size();++s){
5496                 bind_to_schema_se(select_list[s]->se, &fm, Schema);
5497         }
5498         int g;
5499         for(g=0;g<gb_tbl.size();++g){
5500                 bind_to_schema_se(gb_tbl.get_def(g), &fm, Schema);
5501         }
5502         int a;
5503         for(a=0;a<aggr_tbl.size();++a){
5504                 if(aggr_tbl.is_builtin(a)){
5505                         bind_to_schema_se(aggr_tbl.get_aggr_se(a), &fm, Schema);
5506                 }else{
5507                         vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(a);
5508                         int o;
5509                         for(o=0;o<opl.size();++o){
5510                                 bind_to_schema_se(opl[o],&fm,Schema);
5511                         }
5512                 }
5513         }
5514 }
5515
5516
5517 void sgahcwcb_qpn::bind_to_schema(table_list *Schema){
5518 //                      Bind the tablevars in the From clause to the Schema
5519 //                      (it might have changed from analysis time)
5520         int t = Schema->get_table_ref(table_name->get_schema_name() );
5521         if(t>=0)
5522         table_name->set_schema_ref(t );
5523
5524 //                      Get the "from" clause
5525         tablevar_list_t fm(table_name);
5526
5527 //                      Bind all SEs to this schema
5528         int p;
5529         for(p=0;p<where.size();++p){
5530                 bind_to_schema_pr(where[p]->pr, &fm, Schema);
5531         }
5532         for(p=0;p<having.size();++p){
5533                 bind_to_schema_pr(having[p]->pr, &fm, Schema);
5534         }
5535         for(p=0;p<having.size();++p){
5536                 bind_to_schema_pr(cleanby[p]->pr, &fm, Schema);
5537         }
5538         for(p=0;p<having.size();++p){
5539                 bind_to_schema_pr(cleanwhen[p]->pr, &fm, Schema);
5540         }
5541         int s;
5542         for(s=0;s<select_list.size();++s){
5543                 bind_to_schema_se(select_list[s]->se, &fm, Schema);
5544         }
5545         int g;
5546         for(g=0;g<gb_tbl.size();++g){
5547                 bind_to_schema_se(gb_tbl.get_def(g), &fm, Schema);
5548         }
5549         int a;
5550         for(a=0;a<aggr_tbl.size();++a){
5551                 if(aggr_tbl.is_builtin(a)){
5552                         bind_to_schema_se(aggr_tbl.get_aggr_se(a), &fm, Schema);
5553                 }else{
5554                         vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(a);
5555                         int o;
5556                         for(o=0;o<opl.size();++o){
5557                                 bind_to_schema_se(opl[o],&fm,Schema);
5558                         }
5559                 }
5560         }
5561 }
5562
5563
5564
5565
5566
5567
5568 ///////////////////////////////////////////////////////////////
5569 ///////////////////////////////////////////////////////////////
5570 ///             Functions for code generation.
5571
5572
5573 //-----------------------------------------------------------------
5574 //              get_cplx_lit_tbl
5575
5576 cplx_lit_table *mrg_qpn::get_cplx_lit_tbl(ext_fcn_list *Ext_fcns){
5577         return(new cplx_lit_table());
5578 }
5579
5580 cplx_lit_table *spx_qpn::get_cplx_lit_tbl(ext_fcn_list *Ext_fcns){
5581         int i;
5582         cplx_lit_table *complex_literals = new cplx_lit_table();
5583
5584         for(i=0;i<select_list.size();i++){
5585                 find_complex_literal_se(select_list[i]->se, Ext_fcns, complex_literals);
5586         }
5587         for(i=0;i<where.size();++i){
5588                 find_complex_literal_pr(where[i]->pr,Ext_fcns, complex_literals);
5589         }
5590
5591         return(complex_literals);
5592 }
5593
5594 cplx_lit_table *sgah_qpn::get_cplx_lit_tbl(ext_fcn_list *Ext_fcns){
5595         int i,j;
5596         cplx_lit_table *complex_literals = new cplx_lit_table();
5597
5598         for(i=0;i<aggr_tbl.size();++i){
5599                 if(aggr_tbl.is_builtin(i) && !aggr_tbl.is_star_aggr(i)){
5600                         find_complex_literal_se(aggr_tbl.get_aggr_se(i), Ext_fcns, complex_literals);
5601                 }else{
5602                         vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(i);
5603                         for(j=0;j<opl.size();++j)
5604                                 find_complex_literal_se(opl[j], Ext_fcns, complex_literals);
5605                 }
5606         }
5607
5608         for(i=0;i<select_list.size();i++){
5609                 find_complex_literal_se(select_list[i]->se, Ext_fcns, complex_literals);
5610         }
5611     for(i=0;i<gb_tbl.size();i++){
5612         find_complex_literal_se(gb_tbl.get_def(i), Ext_fcns, complex_literals);
5613     }
5614         for(i=0;i<where.size();++i){
5615                 find_complex_literal_pr(where[i]->pr,Ext_fcns, complex_literals);
5616         }
5617         for(i=0;i<having.size();++i){
5618                         find_complex_literal_pr(having[i]->pr,Ext_fcns, complex_literals);
5619         }
5620
5621         return(complex_literals);
5622 }
5623
5624
5625 cplx_lit_table *rsgah_qpn::get_cplx_lit_tbl(ext_fcn_list *Ext_fcns){
5626         int i,j;
5627         cplx_lit_table *complex_literals = new cplx_lit_table();
5628
5629         for(i=0;i<aggr_tbl.size();++i){
5630                 if(aggr_tbl.is_builtin(i) && !aggr_tbl.is_star_aggr(i)){
5631                         find_complex_literal_se(aggr_tbl.get_aggr_se(i), Ext_fcns, complex_literals);
5632                 }else{
5633                         vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(i);
5634                         for(j=0;j<opl.size();++j)
5635                                 find_complex_literal_se(opl[j], Ext_fcns, complex_literals);
5636                 }
5637         }
5638
5639         for(i=0;i<select_list.size();i++){
5640                 find_complex_literal_se(select_list[i]->se, Ext_fcns, complex_literals);
5641         }
5642     for(i=0;i<gb_tbl.size();i++){
5643         find_complex_literal_se(gb_tbl.get_def(i), Ext_fcns, complex_literals);
5644     }
5645         for(i=0;i<where.size();++i){
5646                 find_complex_literal_pr(where[i]->pr,Ext_fcns, complex_literals);
5647         }
5648         for(i=0;i<having.size();++i){
5649                         find_complex_literal_pr(having[i]->pr,Ext_fcns, complex_literals);
5650         }
5651         for(i=0;i<closing_when.size();++i){
5652                         find_complex_literal_pr(closing_when[i]->pr,Ext_fcns, complex_literals);
5653         }
5654
5655         return(complex_literals);
5656 }
5657
5658
5659 cplx_lit_table *sgahcwcb_qpn::get_cplx_lit_tbl(ext_fcn_list *Ext_fcns){
5660         int i,j;
5661         cplx_lit_table *complex_literals = new cplx_lit_table();
5662
5663         for(i=0;i<aggr_tbl.size();++i){
5664                 if(aggr_tbl.is_builtin(i) && !aggr_tbl.is_star_aggr(i)){
5665                         find_complex_literal_se(aggr_tbl.get_aggr_se(i), Ext_fcns, complex_literals);
5666                 }else{
5667                         vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(i);
5668                         for(j=0;j<opl.size();++j)
5669                                 find_complex_literal_se(opl[j], Ext_fcns, complex_literals);
5670                 }
5671         }
5672
5673         for(i=0;i<select_list.size();i++){
5674                 find_complex_literal_se(select_list[i]->se, Ext_fcns, complex_literals);
5675         }
5676     for(i=0;i<gb_tbl.size();i++){
5677         find_complex_literal_se(gb_tbl.get_def(i), Ext_fcns, complex_literals);
5678     }
5679         for(i=0;i<where.size();++i){
5680                 find_complex_literal_pr(where[i]->pr,Ext_fcns, complex_literals);
5681         }
5682         for(i=0;i<having.size();++i){
5683                         find_complex_literal_pr(having[i]->pr,Ext_fcns, complex_literals);
5684         }
5685         for(i=0;i<cleanwhen.size();++i){
5686                         find_complex_literal_pr(cleanwhen[i]->pr,Ext_fcns, complex_literals);
5687         }
5688         for(i=0;i<cleanby.size();++i){
5689                         find_complex_literal_pr(cleanby[i]->pr,Ext_fcns, complex_literals);
5690         }
5691
5692         return(complex_literals);
5693 }
5694
5695 cplx_lit_table *join_eq_hash_qpn::get_cplx_lit_tbl(ext_fcn_list *Ext_fcns){
5696         int i;
5697         cplx_lit_table *complex_literals = new cplx_lit_table();
5698
5699         for(i=0;i<select_list.size();i++){
5700                 find_complex_literal_se(select_list[i]->se, Ext_fcns, complex_literals);
5701         }
5702         for(i=0;i<where.size();++i){
5703                 find_complex_literal_pr(where[i]->pr,Ext_fcns, complex_literals);
5704         }
5705
5706         return(complex_literals);
5707 }
5708
5709 cplx_lit_table *filter_join_qpn::get_cplx_lit_tbl(ext_fcn_list *Ext_fcns){
5710         int i;
5711         cplx_lit_table *complex_literals = new cplx_lit_table();
5712
5713         for(i=0;i<select_list.size();i++){
5714                 find_complex_literal_se(select_list[i]->se, Ext_fcns, complex_literals);
5715         }
5716         for(i=0;i<where.size();++i){
5717                 find_complex_literal_pr(where[i]->pr,Ext_fcns, complex_literals);
5718         }
5719
5720         return(complex_literals);
5721 }
5722
5723
5724
5725
5726 //-----------------------------------------------------------------
5727 //              get_handle_param_tbl
5728
5729 vector<handle_param_tbl_entry *> mrg_qpn::get_handle_param_tbl(ext_fcn_list *Ext_fcns){
5730     vector<handle_param_tbl_entry *> retval;
5731         return(retval);
5732 }
5733
5734
5735 vector<handle_param_tbl_entry *> spx_qpn::get_handle_param_tbl(ext_fcn_list *Ext_fcns){
5736         int i;
5737     vector<handle_param_tbl_entry *> retval;
5738
5739         for(i=0;i<select_list.size();i++){
5740                 find_param_handles_se(select_list[i]->se, Ext_fcns, retval);
5741         }
5742         for(i=0;i<where.size();++i){
5743                 find_param_handles_pr(where[i]->pr,Ext_fcns, retval);
5744         }
5745
5746         return(retval);
5747 }
5748
5749
5750 vector<handle_param_tbl_entry *> sgah_qpn::get_handle_param_tbl(ext_fcn_list *Ext_fcns){
5751         int i,j;
5752     vector<handle_param_tbl_entry *> retval;
5753
5754
5755         for(i=0;i<aggr_tbl.size();++i){
5756                 if(aggr_tbl.is_builtin(i) && !aggr_tbl.is_star_aggr(i)){
5757                         find_param_handles_se(aggr_tbl.get_aggr_se(i), Ext_fcns, retval);
5758                 }else{
5759                         vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(i);
5760                         for(j=0;j<opl.size();++j)
5761                                 find_param_handles_se(opl[j], Ext_fcns, retval);
5762                 }
5763         }
5764         for(i=0;i<select_list.size();i++){
5765                 find_param_handles_se(select_list[i]->se, Ext_fcns, retval);
5766         }
5767     for(i=0;i<gb_tbl.size();i++){
5768         find_param_handles_se(gb_tbl.get_def(i), Ext_fcns, retval);
5769     }
5770         for(i=0;i<where.size();++i){
5771                 find_param_handles_pr(where[i]->pr,Ext_fcns, retval);
5772         }
5773         for(i=0;i<having.size();++i){
5774                         find_param_handles_pr(having[i]->pr,Ext_fcns, retval);
5775         }
5776
5777         return(retval);
5778 }
5779
5780
5781 vector<handle_param_tbl_entry *> rsgah_qpn::get_handle_param_tbl(ext_fcn_list *Ext_fcns){
5782         int i,j;
5783     vector<handle_param_tbl_entry *> retval;
5784
5785
5786         for(i=0;i<aggr_tbl.size();++i){
5787                 if(aggr_tbl.is_builtin(i) && !aggr_tbl.is_star_aggr(i)){
5788                         find_param_handles_se(aggr_tbl.get_aggr_se(i), Ext_fcns, retval);
5789                 }else{
5790                         vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(i);
5791                         for(j=0;j<opl.size();++j)
5792                                 find_param_handles_se(opl[j], Ext_fcns, retval);
5793                 }
5794         }
5795         for(i=0;i<select_list.size();i++){
5796                 find_param_handles_se(select_list[i]->se, Ext_fcns, retval);
5797         }
5798     for(i=0;i<gb_tbl.size();i++){
5799         find_param_handles_se(gb_tbl.get_def(i), Ext_fcns, retval);
5800     }
5801         for(i=0;i<where.size();++i){
5802                 find_param_handles_pr(where[i]->pr,Ext_fcns, retval);
5803         }
5804         for(i=0;i<having.size();++i){
5805                         find_param_handles_pr(having[i]->pr,Ext_fcns, retval);
5806         }
5807         for(i=0;i<closing_when.size();++i){
5808                         find_param_handles_pr(closing_when[i]->pr,Ext_fcns, retval);
5809         }
5810
5811         return(retval);
5812 }
5813
5814
5815 vector<handle_param_tbl_entry *> sgahcwcb_qpn::get_handle_param_tbl(ext_fcn_list *Ext_fcns){
5816         int i,j;
5817     vector<handle_param_tbl_entry *> retval;
5818
5819
5820         for(i=0;i<aggr_tbl.size();++i){
5821                 if(aggr_tbl.is_builtin(i) && !aggr_tbl.is_star_aggr(i)){
5822                         find_param_handles_se(aggr_tbl.get_aggr_se(i), Ext_fcns, retval);
5823                 }else{
5824                         vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(i);
5825                         for(j=0;j<opl.size();++j)
5826                                 find_param_handles_se(opl[j], Ext_fcns, retval);
5827                 }
5828         }
5829         for(i=0;i<select_list.size();i++){
5830                 find_param_handles_se(select_list[i]->se, Ext_fcns, retval);
5831         }
5832     for(i=0;i<gb_tbl.size();i++){
5833         find_param_handles_se(gb_tbl.get_def(i), Ext_fcns, retval);
5834     }
5835         for(i=0;i<where.size();++i){
5836                 find_param_handles_pr(where[i]->pr,Ext_fcns, retval);
5837         }
5838         for(i=0;i<having.size();++i){
5839                         find_param_handles_pr(having[i]->pr,Ext_fcns, retval);
5840         }
5841         for(i=0;i<cleanwhen.size();++i){
5842                         find_param_handles_pr(cleanwhen[i]->pr,Ext_fcns, retval);
5843         }
5844         for(i=0;i<cleanby.size();++i){
5845                         find_param_handles_pr(cleanby[i]->pr,Ext_fcns, retval);
5846         }
5847
5848         return(retval);
5849 }
5850
5851 vector<handle_param_tbl_entry *> join_eq_hash_qpn::get_handle_param_tbl(ext_fcn_list *Ext_fcns){
5852         int i;
5853     vector<handle_param_tbl_entry *> retval;
5854
5855         for(i=0;i<select_list.size();i++){
5856                 find_param_handles_se(select_list[i]->se, Ext_fcns, retval);
5857         }
5858         for(i=0;i<where.size();++i){
5859                 find_param_handles_pr(where[i]->pr,Ext_fcns, retval);
5860         }
5861
5862         return(retval);
5863 }
5864
5865
5866 vector<handle_param_tbl_entry *> filter_join_qpn::get_handle_param_tbl(ext_fcn_list *Ext_fcns){
5867         int i;
5868     vector<handle_param_tbl_entry *> retval;
5869
5870         for(i=0;i<select_list.size();i++){
5871                 find_param_handles_se(select_list[i]->se, Ext_fcns, retval);
5872         }
5873         for(i=0;i<where.size();++i){
5874                 find_param_handles_pr(where[i]->pr,Ext_fcns, retval);
5875         }
5876
5877         return(retval);
5878 }
5879
5880 ///////////////////////////////////////////////////////////////
5881 ///////////////////////////////////////////////////////////////
5882 ///             Functions for operator output rates estimations
5883
5884
5885 //-----------------------------------------------------------------
5886 //              get_rate_estimate
5887
5888 double spx_qpn::get_rate_estimate() {
5889
5890         // dummy method for now
5891         return SPX_SELECTIVITY * DEFAULT_INTERFACE_RATE;
5892 }
5893
5894 double sgah_qpn::get_rate_estimate() {
5895
5896         // dummy method for now
5897         return SGAH_SELECTIVITY * DEFAULT_INTERFACE_RATE;
5898 }
5899
5900 double rsgah_qpn::get_rate_estimate() {
5901
5902         // dummy method for now
5903         return RSGAH_SELECTIVITY * DEFAULT_INTERFACE_RATE;
5904 }
5905
5906 double sgahcwcb_qpn::get_rate_estimate() {
5907
5908         // dummy method for now
5909         return SGAHCWCB_SELECTIVITY * DEFAULT_INTERFACE_RATE;
5910 }
5911
5912 double mrg_qpn::get_rate_estimate() {
5913
5914         // dummy method for now
5915         return MRG_SELECTIVITY * DEFAULT_INTERFACE_RATE;
5916 }
5917
5918 double join_eq_hash_qpn::get_rate_estimate() {
5919
5920         // dummy method for now
5921         return JOIN_EQ_HASH_SELECTIVITY * DEFAULT_INTERFACE_RATE;
5922 }
5923
5924
5925 //////////////////////////////////////////////////////////////////////////////
5926 //////////////////////////////////////////////////////////////////////////////
5927 /////           Generate functors
5928
5929
5930
5931
5932 //-------------------------------------------------------------------------
5933 //                      Code generation utilities.
5934 //-------------------------------------------------------------------------
5935
5936 //              Globals referenced by generate utilities
5937
5938 static gb_table *segen_gb_tbl;            // Table of all group-by attributes.
5939
5940
5941
5942 //                      Generate code that makes reference
5943 //                      to the tuple, and not to any aggregates.
5944 //                              NEW : it might reference a stateful function.
5945 static string generate_se_code(scalarexp_t *se,table_list *schema){
5946         string ret;
5947     data_type *ldt, *rdt;
5948         int o;
5949         vector<scalarexp_t *> operands;
5950
5951
5952         switch(se->get_operator_type()){
5953         case SE_LITERAL:
5954                 if(se->is_handle_ref()){
5955                         sprintf(tmpstr,"handle_param_%d",se->get_handle_ref() );
5956                         ret = tmpstr;
5957                         return(ret);
5958                 }
5959                 if(se->get_literal()->is_cpx_lit()){
5960                         sprintf(tmpstr,"complex_literal_%d",se->get_literal()->get_cpx_lit_ref() );
5961                         ret = tmpstr;
5962                         return(ret);
5963                 }
5964                 return(se->get_literal()->to_hfta_C_code("")); // not complex no constr.
5965         case SE_PARAM:
5966                 if(se->is_handle_ref()){
5967                         sprintf(tmpstr,"handle_param_%d",se->get_handle_ref() );
5968                         ret = tmpstr;
5969                         return(ret);
5970                 }
5971                 ret.append("param_");
5972                 ret.append(se->get_param_name());
5973                 return(ret);
5974         case SE_UNARY_OP:
5975         ldt = se->get_left_se()->get_data_type();
5976         if(ldt->complex_operator(se->get_op()) ){
5977                         ret.append( ldt->get_complex_operator(se->get_op()) );
5978                         ret.append("(");
5979                         ret.append(generate_se_code(se->get_left_se(),schema));
5980             ret.append(")");
5981                 }else{
5982                         ret.append("(");
5983                         ret.append(se->get_op());
5984                         ret.append(generate_se_code(se->get_left_se(),schema));
5985                         ret.append(")");
5986                 }
5987                 return(ret);
5988         case SE_BINARY_OP:
5989         ldt = se->get_left_se()->get_data_type();
5990         rdt = se->get_right_se()->get_data_type();
5991
5992         if(ldt->complex_operator(rdt, se->get_op()) ){
5993                         ret.append( ldt->get_complex_operator(rdt, se->get_op()) );
5994                         ret.append("(");
5995                         ret.append(generate_se_code(se->get_left_se(),schema));
5996                         ret.append(", ");
5997                         ret.append(generate_se_code(se->get_right_se(),schema));
5998                         ret.append(")");
5999                 }else{
6000                         ret.append("(");
6001                         ret.append(generate_se_code(se->get_left_se(),schema));
6002                         ret.append(se->get_op());
6003                         ret.append(generate_se_code(se->get_right_se(),schema));
6004                         ret.append(")");
6005                 }
6006                 return(ret);
6007         case SE_COLREF:
6008                 if(se->is_gb()){                // OK to ref gb attrs, but they're not yet unpacked ...
6009                                                         // so return the defining code.
6010                         int gref = se->get_gb_ref();
6011                         scalarexp_t *gdef_se = segen_gb_tbl->get_def(gref);
6012                         ret = generate_se_code(gdef_se, schema );
6013
6014                 }else{
6015                 sprintf(tmpstr,"unpack_var_%s_%d",
6016                   se->get_colref()->get_field().c_str(), se->get_colref()->get_tablevar_ref() );
6017                 ret = tmpstr;
6018                 }
6019                 return(ret);
6020         case SE_FUNC:
6021                 if(se->is_partial()){
6022                         sprintf(tmpstr,"partial_fcn_result_%d",se->get_partial_ref());
6023                         ret = tmpstr;
6024                 }else{
6025                         ret += se->op + "(";
6026                         operands = se->get_operands();
6027                         bool first_elem = true;
6028                         if(se->get_storage_state() != ""){
6029                                 ret += "&(stval->state_var_"+se->get_storage_state()+"),cd";
6030                                 first_elem = false;
6031                         }
6032                         for(o=0;o<operands.size();o++){
6033                                 if(first_elem) first_elem=false; else ret += ", ";
6034                                 if(operands[o]->get_data_type()->is_buffer_type() &&
6035                                         (! (operands[o]->is_handle_ref()) ) )
6036                                         ret.append("&");
6037                                 ret += generate_se_code(operands[o], schema);
6038                         }
6039                         ret += ")";
6040                 }
6041                 return(ret);
6042         default:
6043                 fprintf(stderr,"INTERNAL ERROR in generate_se_code (hfta), line %d, character %d: unknown operator type %d\n",
6044                                 se->get_lineno(), se->get_charno(),se->get_operator_type());
6045                 return("ERROR in generate_se_code");
6046         }
6047 }
6048
6049 //              generate code that refers only to aggregate data and constants.
6050 //                      NEW : modified to handle superaggregates and stateful fcn refs.
6051 //                      Assume that the state is in *stval
6052 static string generate_se_code_fm_aggr(scalarexp_t *se, string gbvar, string aggvar, table_list *schema){
6053
6054         string ret;
6055     data_type *ldt, *rdt;
6056         int o;
6057         vector<scalarexp_t *> operands;
6058
6059
6060         switch(se->get_operator_type()){
6061         case SE_LITERAL:
6062                 if(se->is_handle_ref()){
6063                         sprintf(tmpstr,"handle_param_%d",se->get_handle_ref() );
6064                         ret = tmpstr;
6065                         return(ret);
6066                 }
6067                 if(se->get_literal()->is_cpx_lit()){
6068                         sprintf(tmpstr,"complex_literal_%d",se->get_literal()->get_cpx_lit_ref() );
6069                         ret = tmpstr;
6070                         return(ret);
6071                 }
6072                 return(se->get_literal()->to_hfta_C_code("")); // not complex no constr.
6073         case SE_PARAM:
6074                 if(se->is_handle_ref()){
6075                         sprintf(tmpstr,"handle_param_%d",se->get_handle_ref() );
6076                         ret = tmpstr;
6077                         return(ret);
6078                 }
6079                 ret.append("param_");
6080                 ret.append(se->get_param_name());
6081                 return(ret);
6082         case SE_UNARY_OP:
6083         ldt = se->get_left_se()->get_data_type();
6084         if(ldt->complex_operator(se->get_op()) ){
6085                         ret.append( ldt->get_complex_operator(se->get_op()) );
6086                         ret.append("(");
6087                         ret.append(generate_se_code_fm_aggr(se->get_left_se(),gbvar,aggvar,schema));
6088             ret.append(")");
6089                 }else{
6090                         ret.append("(");
6091                         ret.append(se->get_op());
6092                         ret.append(generate_se_code_fm_aggr(se->get_left_se(),gbvar,aggvar,schema));
6093                         ret.append(")");
6094                 }
6095                 return(ret);
6096         case SE_BINARY_OP:
6097         ldt = se->get_left_se()->get_data_type();
6098         rdt = se->get_right_se()->get_data_type();
6099
6100         if(ldt->complex_operator(rdt, se->get_op()) ){
6101                         ret.append( ldt->get_complex_operator(rdt, se->get_op()) );
6102                         ret.append("(");
6103                         ret.append(generate_se_code_fm_aggr(se->get_left_se(),gbvar,aggvar,schema));
6104                         ret.append(", ");
6105                         ret.append(generate_se_code_fm_aggr(se->get_right_se(),gbvar,aggvar,schema));
6106                         ret.append(")");
6107                 }else{
6108                         ret.append("(");
6109                         ret.append(generate_se_code_fm_aggr(se->get_left_se(),gbvar,aggvar,schema));
6110                         ret.append(se->get_op());
6111                         ret.append(generate_se_code_fm_aggr(se->get_right_se(),gbvar,aggvar,schema));
6112                         ret.append(")");
6113                 }
6114                 return(ret);
6115         case SE_COLREF:
6116                 if(se->is_gb()){                // OK to ref gb attrs, but they're not yet unpacked ...
6117                                                         // so return the defining code.
6118                         sprintf(tmpstr,"%s%d",gbvar.c_str(),se->get_gb_ref());
6119                         ret = tmpstr;
6120
6121                 }else{
6122                 fprintf(stderr,"ERROR reference to non-GB column ref not permitted here,"
6123                                 "error in query_plan.cc:generate_se_code_fm_aggr, line %d, character %d.\n",
6124                                 se->get_lineno(), se->get_charno());
6125                 ret = tmpstr;
6126                 }
6127                 return(ret);
6128         case SE_AGGR_STAR:
6129         case SE_AGGR_SE:
6130                 if(se->is_superaggr()){
6131                         sprintf(tmpstr,"stval->aggr_var%d",se->get_aggr_ref());
6132                 }else{
6133                         sprintf(tmpstr,"%saggr_var%d",aggvar.c_str(),se->get_aggr_ref());
6134                 }
6135                 ret = tmpstr;
6136                 return(ret);
6137         case SE_FUNC:
6138 //                              Is it a UDAF?
6139                 if(se->get_aggr_ref() >= 0){
6140                         sprintf(tmpstr,"udaf_ret_%d",se->get_aggr_ref());
6141                         ret = tmpstr;
6142                         return(ret);
6143                 }
6144
6145                 if(se->is_partial()){
6146                         sprintf(tmpstr,"partial_fcn_result_%d",se->get_partial_ref());
6147                         ret = tmpstr;
6148                 }else{
6149                         ret += se->op + "(";
6150                         bool first_elem = true;
6151                         if(se->get_storage_state() != ""){
6152                                 ret += "&(stval->state_var_"+se->get_storage_state()+"),cd";
6153                                 first_elem = false;
6154                         }
6155                         operands = se->get_operands();
6156                         for(o=0;o<operands.size();o++){
6157                                 if(first_elem) first_elem=false; else ret += ", ";
6158                                 if(operands[o]->get_data_type()->is_buffer_type() &&
6159                                         (! (operands[o]->is_handle_ref()) ) )
6160                                         ret.append("&");
6161                                 ret += generate_se_code_fm_aggr(operands[o], gbvar,aggvar, schema);
6162                         }
6163                         ret += ")";
6164                 }
6165                 return(ret);
6166         default:
6167                 fprintf(stderr,"INTERNAL ERROR in query_plan.cc::generate_se_code_fm_aggr, line %d, character %d: unknown operator type %d\n",
6168                                 se->get_lineno(), se->get_charno(),se->get_operator_type());
6169                 return("ERROR in generate_se_code_fm_aggr");
6170         }
6171
6172 }
6173
6174
6175 static string unpack_partial_fcn_fm_aggr(scalarexp_t *se, int pfn_id, string gbvar, string aggvar, table_list *schema){
6176         string ret;
6177         int o;
6178         vector<scalarexp_t *> operands;
6179
6180
6181         if(se->get_operator_type() != SE_FUNC){
6182                 fprintf(stderr,"INTERNAL ERROR, non-function SE passed to unpack_partial_fcn_fm_aggr. line %d, character %d\n",
6183                                 se->get_lineno(), se->get_charno());
6184                 return("ERROR in unpack_partial_fcn_fm_aggr");
6185         }
6186
6187         ret = "\tretval = " + se->get_op() + "( ",
6188         sprintf(tmpstr, "&partial_fcn_result_%d",pfn_id);
6189         ret += tmpstr;
6190
6191         if(se->get_storage_state() != ""){
6192                 ret += ",&(stval->state_var_"+se->get_storage_state()+"),cd";
6193         }
6194
6195         operands = se->get_operands();
6196         for(o=0;o<operands.size();o++){
6197                 ret += ", ";
6198                 if(operands[o]->get_data_type()->is_buffer_type() &&
6199                                         (! (operands[o]->is_handle_ref()) ) )
6200                         ret.append("&");
6201                 ret += generate_se_code_fm_aggr(operands[o], gbvar,aggvar, schema);
6202         }
6203         ret += ");\n";
6204
6205         return(ret);
6206 }
6207
6208
6209 static string unpack_partial_fcn(scalarexp_t *se, int pfn_id, table_list *schema){
6210         string ret;
6211         int o;
6212         vector<scalarexp_t *> operands;
6213
6214         if(se->get_operator_type() != SE_FUNC){
6215                 fprintf(stderr,"INTERNAL ERROR, non-function SE passed to unpack_partial_fcn. line %d, character %d\n",
6216                                 se->get_lineno(), se->get_charno());
6217                 return("ERROR in unpack_partial_fcn");
6218         }
6219
6220         ret = "\tretval = " + se->get_op() + "( ",
6221         sprintf(tmpstr, "&partial_fcn_result_%d",pfn_id);
6222         ret += tmpstr;
6223
6224         if(se->get_storage_state() != ""){
6225                 ret += ",&(stval->state_var_"+se->get_storage_state()+"),cd";
6226         }
6227
6228         operands = se->get_operands();
6229         for(o=0;o<operands.size();o++){
6230                 ret += ", ";
6231                 if(operands[o]->get_data_type()->is_buffer_type() &&
6232                                         (! (operands[o]->is_handle_ref()) ) )
6233                         ret.append("&");
6234                 ret += generate_se_code(operands[o], schema);
6235         }
6236         ret += ");\n";
6237
6238         return(ret);
6239 }
6240
6241 static string generate_cached_fcn(scalarexp_t *se, int pfn_id, table_list *schema){
6242         string ret;
6243         int o;
6244         vector<scalarexp_t *> operands;
6245
6246         if(se->get_operator_type() != SE_FUNC){
6247                 fprintf(stderr,"INTERNAL ERROR, non-function SE passed to generate_cached_fcn. line %d, character %d\n",
6248                                 se->get_lineno(), se->get_charno());
6249                 return("ERROR in generate_cached_fcn");
6250         }
6251
6252         ret = se->get_op()+"(";
6253
6254         if(se->get_storage_state() != ""){
6255                 ret += "&(stval->state_var_"+se->get_storage_state()+"),cd,";
6256         }
6257
6258         operands = se->get_operands();
6259         for(o=0;o<operands.size();o++){
6260                 if(o) ret += ", ";
6261                 if(operands[o]->get_data_type()->is_buffer_type() &&
6262                                         (! (operands[o]->is_handle_ref()) ) )
6263                         ret.append("&");
6264                 ret += generate_se_code(operands[o], schema);
6265         }
6266         ret += ");\n";
6267
6268         return(ret);
6269 }
6270
6271
6272
6273
6274
6275 static string generate_C_comparison_op(string op){
6276   if(op == "=") return("==");
6277   if(op == "<>") return("!=");
6278   return(op);
6279 }
6280
6281 static string generate_C_boolean_op(string op){
6282         if( (op == "AND") || (op == "And") || (op == "and") ){
6283                 return("&&");
6284         }
6285         if( (op == "OR") || (op == "Or") || (op == "or") ){
6286                 return("||");
6287         }
6288         if( (op == "NOT") || (op == "Not") || (op == "not") ){
6289                 return("!");
6290         }
6291
6292         return("ERROR UNKNOWN BOOLEAN OPERATOR");
6293 }
6294
6295
6296 static string generate_predicate_code(predicate_t *pr,table_list *schema){
6297         string ret;
6298         vector<literal_t *>  litv;
6299         int i;
6300     data_type *ldt, *rdt;
6301         vector<scalarexp_t *> op_list;
6302         int o;
6303
6304         switch(pr->get_operator_type()){
6305         case PRED_IN:
6306         ldt = pr->get_left_se()->get_data_type();
6307
6308                 ret.append("( ");
6309                 litv = pr->get_lit_vec();
6310                 for(i=0;i<litv.size();i++){
6311                         if(i>0) ret.append(" || ");
6312                         ret.append("( ");
6313
6314                 if(ldt->complex_comparison(ldt) ){
6315                                 ret.append( ldt->get_hfta_comparison_fcn(ldt) );
6316                                 ret.append("( ");
6317                                 if(ldt->is_buffer_type() )
6318                                         ret.append("&");
6319                                 ret.append(generate_se_code(pr->get_left_se(), schema));
6320                                 ret.append(", ");
6321                                 if(ldt->is_buffer_type() )
6322                                         ret.append("&");
6323                                 if(litv[i]->is_cpx_lit()){
6324                                         sprintf(tmpstr,"complex_literal_%d",litv[i]->get_cpx_lit_ref() );
6325                                         ret += tmpstr;
6326                                 }else{
6327                                         ret.append(litv[i]->to_C_code(""));
6328                                 }
6329                                 ret.append(") == 0");
6330                         }else{
6331                                 ret.append(generate_se_code(pr->get_left_se(), schema));
6332                                 ret.append(" == ");
6333                                 ret.append(litv[i]->to_hfta_C_code(""));
6334                         }
6335
6336                         ret.append(" )");
6337                 }
6338                 ret.append(" )");
6339                 return(ret);
6340
6341         case PRED_COMPARE:
6342         ldt = pr->get_left_se()->get_data_type();
6343         rdt = pr->get_right_se()->get_data_type();
6344
6345                 ret.append("( ");
6346         if(ldt->complex_comparison(rdt) ){
6347                         ret.append(ldt->get_hfta_comparison_fcn(rdt));
6348                         ret.append("(");
6349                         if(ldt->is_buffer_type() )
6350                                 ret.append("&");
6351                         ret.append(generate_se_code(pr->get_left_se(),schema) );
6352                         ret.append(", ");
6353                         if(rdt->is_buffer_type() )
6354                                 ret.append("&");
6355                         ret.append(generate_se_code(pr->get_right_se(),schema) );
6356                         ret.append(") ");
6357                         ret.append( generate_C_comparison_op(pr->get_op()));
6358                         ret.append("0");
6359                 }else{
6360                         ret.append(generate_se_code(pr->get_left_se(),schema) );
6361                         ret.append( generate_C_comparison_op(pr->get_op()));
6362                         ret.append(generate_se_code(pr->get_right_se(),schema) );
6363                 }
6364                 ret.append(" )");
6365                 return(ret);
6366         case PRED_UNARY_OP:
6367                 ret.append("( ");
6368                 ret.append( generate_C_boolean_op(pr->get_op()) );
6369                 ret.append(generate_predicate_code(pr->get_left_pr(),schema) );
6370                 ret.append(" )");
6371                 return(ret);
6372         case PRED_BINARY_OP:
6373                 ret.append("( ");
6374                 ret.append(generate_predicate_code(pr->get_left_pr(),schema) );
6375                 ret.append( generate_C_boolean_op(pr->get_op()) );
6376                 ret.append(generate_predicate_code(pr->get_right_pr(),schema) );
6377                 ret.append(" )");
6378                 return(ret);
6379         case PRED_FUNC:
6380                 ret += pr->get_op() + "( ";
6381                 op_list = pr->get_op_list();
6382                 for(o=0;o<op_list.size();++o){
6383                         if(o>0) ret += ", ";
6384                         if(op_list[o]->get_data_type()->is_buffer_type() && (! (op_list[o]->is_handle_ref()) ) )
6385                                         ret.append("&");
6386                         ret += generate_se_code(op_list[o], schema);
6387                 }
6388                 ret += " )";
6389                 return(ret);
6390         default:
6391                 fprintf(stderr,"INTERNAL ERROR in generate_predicate_code, line %d, character %d, unknown predicate operator type %d\n",
6392                         pr->get_lineno(), pr->get_charno(), pr->get_operator_type() );
6393                 return("ERROR in generate_predicate_code");
6394         }
6395 }
6396
6397 static string generate_predicate_code_fm_aggr(predicate_t *pr, string gbvar, string aggvar,table_list *schema){
6398         string ret;
6399         vector<literal_t *>  litv;
6400         int i;
6401     data_type *ldt, *rdt;
6402         vector<scalarexp_t *> op_list;
6403         int o;
6404
6405         switch(pr->get_operator_type()){
6406         case PRED_IN:
6407         ldt = pr->get_left_se()->get_data_type();
6408
6409                 ret.append("( ");
6410                 litv = pr->get_lit_vec();
6411                 for(i=0;i<litv.size();i++){
6412                         if(i>0) ret.append(" || ");
6413                         ret.append("( ");
6414
6415                 if(ldt->complex_comparison(ldt) ){
6416                                 ret.append( ldt->get_hfta_comparison_fcn(ldt) );
6417                                 ret.append("( ");
6418                                 if(ldt->is_buffer_type() )
6419                                         ret.append("&");
6420                                 ret.append(generate_se_code_fm_aggr(pr->get_left_se(), gbvar, aggvar, schema));
6421                                 ret.append(", ");
6422                                 if(ldt->is_buffer_type() )
6423                                         ret.append("&");
6424                                 if(litv[i]->is_cpx_lit()){
6425                                         sprintf(tmpstr,"complex_literal_%d",litv[i]->get_cpx_lit_ref() );
6426                                         ret += tmpstr;
6427                                 }else{
6428                                         ret.append(litv[i]->to_C_code(""));
6429                                 }
6430                                 ret.append(") == 0");
6431                         }else{
6432                                 ret.append(generate_se_code_fm_aggr(pr->get_left_se(), gbvar, aggvar, schema));
6433                                 ret.append(" == ");
6434                                 ret.append(litv[i]->to_hfta_C_code(""));
6435                         }
6436
6437                         ret.append(" )");
6438                 }
6439                 ret.append(" )");
6440                 return(ret);
6441
6442         case PRED_COMPARE:
6443         ldt = pr->get_left_se()->get_data_type();
6444         rdt = pr->get_right_se()->get_data_type();
6445
6446                 ret.append("( ");
6447         if(ldt->complex_comparison(rdt) ){
6448                         ret.append(ldt->get_hfta_comparison_fcn(rdt));
6449                         ret.append("(");
6450                         if(ldt->is_buffer_type() )
6451                                 ret.append("&");
6452                         ret.append(generate_se_code_fm_aggr(pr->get_left_se(), gbvar, aggvar,schema) );
6453                         ret.append(", ");
6454                         if(rdt->is_buffer_type() )
6455                                 ret.append("&");
6456                         ret.append(generate_se_code_fm_aggr(pr->get_right_se(), gbvar, aggvar,schema) );
6457                         ret.append(") ");
6458                         ret.append( generate_C_comparison_op(pr->get_op()));
6459                         ret.append("0");
6460                 }else{
6461                         ret.append(generate_se_code_fm_aggr(pr->get_left_se(), gbvar, aggvar,schema) );
6462                         ret.append( generate_C_comparison_op(pr->get_op()));
6463                         ret.append(generate_se_code_fm_aggr(pr->get_right_se(), gbvar, aggvar,schema) );
6464                 }
6465                 ret.append(" )");
6466                 return(ret);
6467         case PRED_UNARY_OP:
6468                 ret.append("( ");
6469                 ret.append( generate_C_boolean_op(pr->get_op()) );
6470                 ret.append(generate_predicate_code_fm_aggr(pr->get_left_pr(), gbvar, aggvar,schema) );
6471                 ret.append(" )");
6472                 return(ret);
6473         case PRED_BINARY_OP:
6474                 ret.append("( ");
6475                 ret.append(generate_predicate_code_fm_aggr(pr->get_left_pr(), gbvar, aggvar,schema) );
6476                 ret.append( generate_C_boolean_op(pr->get_op()) );
6477                 ret.append(generate_predicate_code_fm_aggr(pr->get_right_pr(), gbvar, aggvar,schema) );
6478                 ret.append(" )");
6479                 return(ret);
6480         case PRED_FUNC:
6481                 ret += pr->get_op() + "( ";
6482                 op_list = pr->get_op_list();
6483                 for(o=0;o<op_list.size();++o){
6484                         if(o>0) ret += ", ";
6485                         if(op_list[o]->get_data_type()->is_buffer_type() && (! (op_list[o]->is_handle_ref()) ) )
6486                                         ret.append("&");
6487                         ret += generate_se_code_fm_aggr(op_list[o], gbvar, aggvar, schema);
6488                 }
6489                 ret += " )";
6490                 return(ret);
6491         default:
6492                 fprintf(stderr,"INTERNAL ERROR in generate_predicate_code, line %d, character %d, unknown predicate operator type %d\n",
6493                         pr->get_lineno(), pr->get_charno(), pr->get_operator_type() );
6494                 return("ERROR in generate_predicate_code");
6495         }
6496 }
6497
6498
6499 //                              Aggregation code
6500
6501
6502 static string generate_equality_test(string &lhs_op, string &rhs_op, data_type *dt){
6503         string ret;
6504
6505     if(dt->complex_comparison(dt) ){
6506                 ret.append(dt->get_hfta_comparison_fcn(dt));
6507                 ret.append("(");
6508                         if(dt->is_buffer_type() )
6509                                 ret.append("&");
6510                 ret.append(lhs_op);
6511                 ret.append(", ");
6512                         if(dt->is_buffer_type() )
6513                                 ret.append("&");
6514                 ret.append(rhs_op );
6515                 ret.append(") == 0");
6516         }else{
6517                 ret.append(lhs_op );
6518                 ret.append(" == ");
6519                 ret.append(rhs_op );
6520         }
6521
6522         return(ret);
6523 }
6524
6525 static string generate_comparison(string &lhs_op, string &rhs_op, data_type *dt){
6526         string ret;
6527
6528     if(dt->complex_comparison(dt) ){
6529                 ret.append(dt->get_hfta_comparison_fcn(dt));
6530                 ret.append("(");
6531                         if(dt->is_buffer_type() )
6532                                 ret.append("&");
6533                 ret.append(lhs_op);
6534                 ret.append(", ");
6535                         if(dt->is_buffer_type() )
6536                                 ret.append("&");
6537                 ret.append(rhs_op );
6538                 ret.append(") == 0");
6539         }else{
6540                 ret.append(lhs_op );
6541                 ret.append(" == ");
6542                 ret.append(rhs_op );
6543         }
6544
6545         return(ret);
6546 }
6547
6548
6549 //              Here I assume that only MIN and MAX aggregates can be computed
6550 //              over BUFFER data types.
6551
6552 static string generate_aggr_update(string var, aggregate_table *atbl,int aidx, table_list *schema){
6553         string retval = "\t\t";
6554         string op = atbl->get_op(aidx);
6555
6556 //              Is it a UDAF
6557         if(! atbl->is_builtin(aidx)) {
6558                 int o;
6559                 retval += op+"_HFTA_AGGR_UPDATE_(";
6560                 if(atbl->get_storage_type(aidx)->get_type() != fstring_t) retval+="&";
6561                 retval+="("+var+")";
6562                 vector<scalarexp_t *> opl = atbl->get_operand_list(aidx);
6563                 for(o=0;o<opl.size();++o){{
6564                         retval += ",";
6565                         if(opl[o]->get_data_type()->is_buffer_type() && (! (opl[o]->is_handle_ref()) ) )
6566                                         retval.append("&");
6567                                 retval += generate_se_code(opl[o], schema);
6568                         }
6569                 }
6570                 retval += ");\n";
6571
6572                 return retval;
6573         }
6574
6575
6576 //                      builtin processing
6577         data_type *dt = atbl->get_data_type(aidx);
6578
6579         if(op == "COUNT"){
6580                 retval.append(var);
6581                 retval.append("++;\n");
6582                 return(retval);
6583         }
6584         if(op == "SUM"){
6585                 retval.append(var);
6586                 retval.append(" += ");
6587                 retval.append(generate_se_code(atbl->get_aggr_se(aidx), schema) );
6588                 retval.append(";\n");
6589                 return(retval);
6590         }
6591         if(op == "MIN"){
6592                 sprintf(tmpstr,"aggr_tmp_%d",aidx);
6593                 retval += dt->make_host_cvar(tmpstr);
6594                 retval += " = ";
6595                 retval += generate_se_code(atbl->get_aggr_se(aidx), schema )+";\n";
6596                 if(dt->complex_comparison(dt)){
6597                         if(dt->is_buffer_type())
6598                           sprintf(tmpstr,"\t\tif(%s(&aggr_tmp_%d,&(%s)) < 0)\n",dt->get_hfta_comparison_fcn(dt).c_str(), aidx, var.c_str());
6599                         else
6600                           sprintf(tmpstr,"\t\tif(%s(aggr_tmp_%d,%s) < 0)\n",dt->get_hfta_comparison_fcn(dt).c_str(), aidx, var.c_str());
6601                 }else{
6602                         sprintf(tmpstr,"\t\tif(aggr_tmp_%d < %s)\n",aidx,var.c_str());
6603                 }
6604                 retval.append(tmpstr);
6605                 if(dt->is_buffer_type()){
6606                         sprintf(tmpstr,"\t\t\t%s(&(%s),&aggr_tmp_%d);\n",dt->get_hfta_buffer_replace().c_str(),var.c_str(),aidx);
6607                 }else{
6608                         sprintf(tmpstr,"\t\t\t%s = aggr_tmp_%d;\n",var.c_str(),aidx);
6609                 }
6610                 retval.append(tmpstr);
6611
6612                 return(retval);
6613         }
6614         if(op == "MAX"){
6615                 sprintf(tmpstr,"aggr_tmp_%d",aidx);
6616                 retval+=dt->make_host_cvar(tmpstr);
6617                 retval+=" = ";
6618                 retval+=generate_se_code(atbl->get_aggr_se(aidx), schema )+";\n";
6619                 if(dt->complex_comparison(dt)){
6620                         if(dt->is_buffer_type())
6621                          sprintf(tmpstr,"\t\tif(%s(&aggr_tmp_%d,&(%s)) > 0)\n",dt->get_hfta_comparison_fcn(dt).c_str(), aidx, var.c_str());
6622                         else
6623                          sprintf(tmpstr,"\t\tif(%s(aggr_tmp_%d,%s) > 0)\n",dt->get_hfta_comparison_fcn(dt).c_str(), aidx, var.c_str());
6624                 }else{
6625                         sprintf(tmpstr,"\t\tif(aggr_tmp_%d > %s)\n",aidx,var.c_str());
6626                 }
6627                 retval.append(tmpstr);
6628                 if(dt->is_buffer_type()){
6629                         sprintf(tmpstr,"\t\t\t%s(&(%s),&aggr_tmp_%d);\n",dt->get_hfta_buffer_replace().c_str(),var.c_str(),aidx);
6630                 }else{
6631                         sprintf(tmpstr,"\t\t\t%s = aggr_tmp_%d;\n",var.c_str(),aidx);
6632                 }
6633                 retval.append(tmpstr);
6634
6635                 return(retval);
6636
6637         }
6638         if(op == "AND_AGGR"){
6639                 retval.append(var);
6640                 retval.append(" &= ");
6641                 retval.append(generate_se_code(atbl->get_aggr_se(aidx), schema) );
6642                 retval.append(";\n");
6643                 return(retval);
6644         }
6645         if(op == "OR_AGGR"){
6646                 retval.append(var);
6647                 retval.append(" |= ");
6648                 retval.append(generate_se_code(atbl->get_aggr_se(aidx), schema) );
6649                 retval.append(";\n");
6650                 return(retval);
6651         }
6652         if(op == "XOR_AGGR"){
6653                 retval.append(var);
6654                 retval.append(" ^= ");
6655                 retval.append(generate_se_code(atbl->get_aggr_se(aidx), schema) );
6656                 retval.append(";\n");
6657                 return(retval);
6658         }
6659         if(op=="AVG"){
6660                 retval += var+"_sum += "+generate_se_code(atbl->get_aggr_se(aidx), schema)+";\n";
6661                 retval += "\t\t"+var+"_cnt += 1;\n";
6662                 retval += "\t\t"+var+" = "+var+"_sum / "+var+"_cnt;\n";
6663                 return retval;
6664         }
6665
6666         fprintf(stderr,"INTERNAL ERROR : aggregate %s not recognized in query_plan::generate_aggr_update.\n",op.c_str());
6667         exit(1);
6668         return(retval);
6669
6670 }
6671
6672
6673 //              superaggr minus.
6674
6675 static string generate_superaggr_minus(string var, string supervar, aggregate_table *atbl,int aidx, table_list *schema){
6676         string retval = "\t\t";
6677         string op = atbl->get_op(aidx);
6678
6679 //              Is it a UDAF
6680         if(! atbl->is_builtin(aidx)) {
6681                 int o;
6682                 retval += op+"_HFTA_AGGR_MINUS_(";
6683                 if(atbl->get_storage_type(aidx)->get_type() != fstring_t) retval+="&";
6684                 retval+="("+supervar+"),";
6685                 if(atbl->get_storage_type(aidx)->get_type() != fstring_t) retval+="&";
6686                 retval+="("+var+");\n";
6687
6688                 return retval;
6689         }
6690
6691
6692         if(op == "COUNT" || op == "SUM"){
6693                 retval += supervar + "-=" +var + ";\n";
6694                 return(retval);
6695         }
6696
6697         if(op == "XOR_AGGR"){
6698                 retval += supervar + "^=" +var + ";\n";
6699                 return(retval);
6700         }
6701
6702         if(op=="MIN" || op == "MAX")
6703                 return "";
6704
6705         fprintf(stderr,"INTERNAL ERROR : aggregate %s not recognized in generate_superaggr_minus.\n",op.c_str());
6706         exit(1);
6707         return(retval);
6708
6709 }
6710
6711
6712
6713
6714 static string generate_aggr_init(string var, aggregate_table *atbl,int aidx, table_list *schema){
6715         string retval;
6716         string op = atbl->get_op(aidx);
6717
6718 //                      UDAF processing
6719         if(! atbl->is_builtin(aidx)){
6720 //                      initialize
6721                 retval += "\t"+atbl->get_op(aidx)+"_HFTA_AGGR_INIT_(";
6722                 if(atbl->get_storage_type(aidx)->get_type() != fstring_t) retval+="&";
6723                 retval+="("+var+"));\n";
6724 //                      Add 1st tupl
6725                 retval += "\t"+atbl->get_op(aidx)+"_HFTA_AGGR_UPDATE_(";
6726                 if(atbl->get_storage_type(aidx)->get_type() != fstring_t) retval+="&";
6727                 retval+="("+var+")";
6728                 vector<scalarexp_t *> opl = atbl->get_operand_list(aidx);
6729                 int o;
6730                 for(o=0;o<opl.size();++o){
6731                         retval += ",";
6732                         if(opl[o]->get_data_type()->is_buffer_type() && (! (opl[o]->is_handle_ref()) ) )
6733                                         retval.append("&");
6734                                 retval += generate_se_code(opl[o],schema);
6735                         }
6736                 retval += ");\n";
6737                 return(retval);
6738         }
6739
6740 //                      builtin aggregate processing
6741         data_type *dt = atbl->get_data_type(aidx);
6742
6743         if(op == "COUNT"){
6744                 retval = var;
6745                 retval.append(" = 1;\n");
6746                 return(retval);
6747         }
6748
6749         if(op == "SUM" || op == "MIN" || op == "MAX" || op == "AND_AGGR" ||
6750                                         op=="AVG" || op == "OR_AGGR" || op == "XOR_AGGR"){
6751                 if(dt->is_buffer_type()){
6752                         sprintf(tmpstr,"\t\taggr_tmp_%d = %s;\n",aidx,generate_se_code(atbl->get_aggr_se(aidx), schema ).c_str() );
6753                         retval.append(tmpstr);
6754                         sprintf(tmpstr,"\t\t%s(&(%s),&aggr_tmp_%d);\n",dt->get_hfta_buffer_assign_copy().c_str(),var.c_str(),aidx);
6755                         retval.append(tmpstr);
6756                 }else{
6757                         if(op=="AVG"){
6758                                 retval += var+"_sum = "+generate_se_code(atbl->get_aggr_se(aidx), schema)+";\n";
6759                                 retval += "\t"+var+"_cnt = 1;\n";
6760                                 retval += "\t"+var+" = "+var+"_sum;\n";
6761                         }else{
6762                                 retval = var;
6763                                 retval += " = ";
6764                                 retval.append(generate_se_code(atbl->get_aggr_se(aidx), schema));
6765                                 retval.append(";\n");
6766                         }
6767                 }
6768                 return(retval);
6769         }
6770
6771         fprintf(stderr,"INTERNAL ERROR : aggregate %s not recognized in query_plan::generate_aggr_init.\n",op.c_str());
6772         exit(1);
6773         return(retval);
6774
6775 }
6776
6777
6778
6779 static string generate_aggr_reinitialize(string var, aggregate_table *atbl,int aidx, table_list *schema){
6780         string retval;
6781         string op = atbl->get_op(aidx);
6782
6783 //                      UDAF processing
6784         if(! atbl->is_builtin(aidx)){
6785 //                      initialize
6786                 retval +=  "\t"+atbl->get_op(aidx);
6787                 if(atbl->is_running_aggr(aidx)){
6788                         retval += "_HFTA_AGGR_REINIT_(";
6789                 }else{
6790                         retval += "_HFTA_AGGR_INIT_(";
6791                 }
6792                 if(atbl->get_storage_type(aidx)->get_type() != fstring_t) retval+="&";
6793                 retval+="("+var+"));\n";
6794                 return(retval);
6795         }
6796
6797 //                      builtin aggregate processing
6798         data_type *dt = atbl->get_data_type(aidx);
6799
6800         if(op == "COUNT"){
6801                 retval = var;
6802                 retval.append(" = 0;\n");
6803                 return(retval);
6804         }
6805
6806         if(op == "SUM" ||  op == "AND_AGGR" ||
6807                                                                         op == "OR_AGGR" || op == "XOR_AGGR"){
6808                 if(dt->is_buffer_type()){
6809                         return("ERROR, cannot yet handle reinitialization of builtin aggregates over strings.");
6810                 }else{
6811                         retval = var;
6812                         retval += " = ";
6813                         literal_t l(dt->type_indicator());
6814                         retval.append(l.to_string());
6815                         retval.append(";\n");
6816                 }
6817                 return(retval);
6818         }
6819
6820         if(op == "MIN"){
6821                 if(dt->is_buffer_type()){
6822                         return("ERROR, cannot yet handle reinitialization of builtin aggregates over strings.");
6823                 }else{
6824                         retval = var;
6825                         retval += " = ";
6826                         retval.append(dt->get_max_literal());
6827                         retval.append(";\n");
6828                 }
6829                 return(retval);
6830         }
6831
6832         if(op == "MAX"){
6833                 if(dt->is_buffer_type()){
6834                         return("ERROR, cannot yet handle reinitialization of builtin aggregates over strings.");
6835                 }else{
6836                         retval = var;
6837                         retval += " = ";
6838                         retval.append(dt->get_min_literal());
6839                         retval.append(";\n");
6840                 }
6841                 return(retval);
6842         }
6843
6844         fprintf(stderr,"INTERNAL ERROR : aggregate %s not recognized in generate_aggr_reinitialize.\n",op.c_str());
6845         exit(1);
6846         return(retval);
6847
6848 }
6849
6850
6851 //                      Generate parameter holding vars from a param table.
6852 static string generate_param_vars(param_table *param_tbl){
6853         string ret;
6854         int p;
6855         vector<string> param_vec = param_tbl->get_param_names();
6856         for(p=0;p<param_vec.size();p++){
6857                 data_type *dt = param_tbl->get_data_type(param_vec[p]);
6858                 sprintf(tmpstr,"param_%s;\n", param_vec[p].c_str());
6859                 ret += "\t"+dt->make_host_cvar(tmpstr)+";\n";
6860                 if(param_tbl->handle_access(param_vec[p])){
6861                         ret += "\tstruct search_handle *param_handle_"+param_vec[p]+";\n";
6862                 }
6863         }
6864         return(ret);
6865 }
6866
6867 //                      Parameter manipulation routines
6868 static string generate_load_param_block(string functor_name,
6869                                                         param_table *param_tbl,
6870                                                         vector<handle_param_tbl_entry *> param_handle_table
6871                                                         ){
6872         int p;
6873         vector<string> param_names = param_tbl->get_param_names();
6874
6875         string ret = "int load_params_"+functor_name+"(gs_int32_t sz, void *value){\n";
6876     ret.append("\tint pos=0;\n");
6877     ret.append("\tint data_pos;\n");
6878
6879         for(p=0;p<param_names.size();p++){
6880                 data_type *dt = param_tbl->get_data_type(param_names[p]);
6881                 if(dt->is_buffer_type()){
6882                         sprintf(tmpstr,"tmp_var_%s;\n", param_names[p].c_str());
6883                         ret += "\t"+dt->make_host_cvar(tmpstr)+";\n";
6884                 }
6885         }
6886
6887
6888 //              Verify that the block is of minimum size
6889         if(param_names.size() > 0){
6890                 ret += "//\tVerify that the value block is large enough */\n";
6891                 ret.append("\n\tdata_pos = ");
6892                 for(p=0;p<param_names.size();p++){
6893                         if(p>0) ret.append(" + ");
6894                         data_type *dt = param_tbl->get_data_type(param_names[p]);
6895                         ret.append("sizeof( ");
6896                         ret.append( dt->get_host_cvar_type() );
6897                         ret.append(" )");
6898                 }
6899                 ret.append(";\n");
6900                 ret.append("\tif(data_pos > sz) return 1;\n\n");
6901         }
6902
6903 ///////////////////////
6904 ///             Verify that all strings can be unpacked.
6905
6906         ret += "//\tVerify that the strings can be unpacked */\n";
6907         for(p=0;p<param_names.size();p++){
6908                 data_type *dt = param_tbl->get_data_type(param_names[p]);
6909                 if(dt->is_buffer_type()){
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() );
6911                         ret.append(tmpstr);
6912                         switch( dt->get_type() ){
6913                         case v_str_t:
6914 //                              ret += "\ttmp_var_"+param_names[p]+".offset = ntohl( tmp_var_"+param_names[p]+".offset );\n";           // ntoh conversion
6915 //                              ret += "\ttmp_var_"+param_names[p]+".length = ntohl( tmp_var_"+param_names[p]+".length );\n";   // ntoh conversion
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() );
6917                                 ret.append(tmpstr);
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() );
6919                                 ret.append(tmpstr);
6920                         break;
6921                         default:
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() );
6923                                 exit(1);
6924                         break;
6925                         }
6926                 }
6927                 ret += "\tpos += sizeof( "+dt->get_host_cvar_type()+" );\n";
6928         }
6929
6930
6931 /////////////////////////
6932
6933         ret += "/*\tThe block is OK, do the unpacking.  */\n";
6934         ret += "\tpos = 0;\n";
6935
6936         for(p=0;p<param_names.size();p++){
6937                 data_type *dt = param_tbl->get_data_type(param_names[p]);
6938                 if(dt->is_buffer_type()){
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() );
6940             ret.append(tmpstr);
6941                 }else{
6942 //                      if(dt->needs_hn_translation()){
6943 //                              sprintf(tmpstr,"\tparam_%s =  %s( *( (%s *)( (gs_sp_t )value+pos) ) );\n",
6944 //                                param_names[p].c_str(), dt->ntoh_translation().c_str(), dt->get_host_cvar_type().c_str() );
6945 //                      }else{
6946                                 sprintf(tmpstr,"\tparam_%s =  *( (%s *)( (gs_sp_t )value+pos) );\n",
6947                                   param_names[p].c_str(), dt->get_host_cvar_type().c_str() );
6948 //                      }
6949                         ret.append(tmpstr);
6950                 }
6951                 ret += "\tpos += sizeof( "+dt->get_host_cvar_type()+" );\n";
6952         }
6953
6954 //                      TODO: I think this method of handle registration is obsolete
6955 //                      and should be deleted.
6956 //                         some examination reveals that handle_access is always false.
6957         for(p=0;p<param_names.size();p++){
6958                 if(param_tbl->handle_access(param_names[p]) ){
6959                         data_type *pdt = param_tbl->get_data_type(param_names[p]);
6960 //                                      create the new.
6961                         ret += "\tt->param_handle_"+param_names[p]+" = " +
6962                                 pdt->handle_registration_name() +
6963                                 "((struct FTA *)t, &(t->param_"+param_names[p]+"));\n";
6964                 }
6965         }
6966 //                      Register the pass-by-handle parameters
6967
6968         ret += "/* register the pass-by-handle parameters */\n";
6969
6970     int ph;
6971     for(ph=0;ph<param_handle_table.size();++ph){
6972                 data_type pdt(param_handle_table[ph]->type_name);
6973                 switch(param_handle_table[ph]->val_type){
6974                 case cplx_lit_e:
6975                         break;
6976                 case litval_e:
6977                         break;
6978                 case param_e:
6979                         sprintf(tmpstr,"\thandle_param_%d = %s(",ph,param_handle_table[ph]->lfta_registration_fcn().c_str());
6980                         ret += tmpstr;
6981                         if(pdt.is_buffer_type()) ret += "&(";
6982                         ret += "param_"+param_handle_table[ph]->param_name;
6983                         if(pdt.is_buffer_type()) ret += ")";
6984                     ret += ");\n";
6985                         break;
6986                 default:
6987                         fprintf(stderr, "INTERNAL ERROR unknown case found when processing pass-by-handle parameter table.\n");
6988                         exit(1);
6989                 }
6990         }
6991
6992
6993         ret += "\treturn(0);\n";
6994         ret.append("}\n\n");
6995
6996         return(ret);
6997
6998 }
6999
7000 static string generate_delete_param_block(string functor_name,
7001                                                 param_table *param_tbl,
7002                                                 vector<handle_param_tbl_entry *> param_handle_table
7003                                 ){
7004
7005         int p;
7006         vector<string> param_names = param_tbl->get_param_names();
7007
7008         string ret = "void destroy_params_"+functor_name+"(){\n";
7009
7010         for(p=0;p<param_names.size();p++){
7011                 data_type *dt = param_tbl->get_data_type(param_names[p]);
7012                 if(dt->is_buffer_type()){
7013                         sprintf(tmpstr,"\t\t%s(&param_%s);\n",dt->get_hfta_buffer_destroy().c_str(),param_names[p].c_str());
7014                         ret.append(tmpstr);
7015                 }
7016                 if(param_tbl->handle_access(param_names[p]) ){
7017                         ret += "\t\t" + dt->get_handle_destructor() +
7018                                 "(t->param_handle_" + param_names[p] + ");\n";
7019                 }
7020         }
7021
7022         ret += "//\t\tDeregister handles.\n";
7023     int ph;
7024     for(ph=0;ph<param_handle_table.size();++ph){
7025                 if(param_handle_table[ph]->val_type == param_e){
7026                   sprintf(tmpstr, "\t\t%s(handle_param_%d);\n",
7027                         param_handle_table[ph]->lfta_deregistration_fcn().c_str(),ph);
7028                   ret += tmpstr;
7029                 }
7030         }
7031
7032         ret += "}\n\n";
7033         return ret;
7034 }
7035
7036 // ---------------------------------------------------------------------
7037 //              functions for creating functor variables.
7038
7039 static string generate_access_vars(col_id_set &cid_set, table_list *schema){
7040         string ret;
7041         col_id_set::iterator csi;
7042
7043         for(csi=cid_set.begin(); csi!=cid_set.end();++csi){
7044         int schref = (*csi).schema_ref;
7045                 int tblref = (*csi).tblvar_ref;
7046                 string field = (*csi).field;
7047                 data_type dt(schema->get_type_name(schref,field));
7048                 sprintf(tmpstr,"unpack_var_%s_%d", field.c_str(), tblref);
7049                 ret+="\t"+dt.make_host_cvar(tmpstr)+";\n";
7050                 sprintf(tmpstr,"\tgs_int32_t unpack_offset_%s_%d;\n", field.c_str(), tblref);
7051                 ret.append(tmpstr);
7052         }
7053         return(ret);
7054 }
7055
7056 static string generate_partial_fcn_vars(vector<scalarexp_t *> &partial_fcns,
7057         vector<int> &ref_cnt, vector<bool> &is_partial, bool gen_fcn_cache){
7058         string ret;
7059         int p;
7060
7061
7062         for(p=0;p<partial_fcns.size();++p){
7063                 if(!gen_fcn_cache || is_partial[p] ||  ref_cnt[p]>1){
7064                         sprintf(tmpstr,"partial_fcn_result_%d", p);
7065                         ret+="\t"+partial_fcns[p]->get_data_type()->make_host_cvar(tmpstr)+";\n";
7066                         if(gen_fcn_cache && ref_cnt[p]>1){
7067                                 ret+="\tint fcn_ref_cnt_"+int_to_string(p)+";\n";
7068                         }
7069                 }
7070         }
7071         return(ret);
7072 }
7073
7074
7075 static string generate_complex_lit_vars(cplx_lit_table *complex_literals){
7076         string ret;
7077     int cl;
7078     for(cl=0;cl<complex_literals->size();cl++){
7079         literal_t *l = complex_literals->get_literal(cl);
7080         data_type *dtl = new data_type( l->get_type() );
7081         sprintf(tmpstr,"complex_literal_%d",cl);
7082                 ret += "\t"+dtl->make_host_cvar(tmpstr)+";\n";
7083         if(complex_literals->is_handle_ref(cl)){
7084             sprintf(tmpstr,"\tstruct search_handle *lit_handle_%d;\n",cl);
7085             ret.append(tmpstr);
7086         }
7087     }
7088         return(ret);
7089 }
7090
7091
7092 static string generate_pass_by_handle_vars(
7093                                 vector<handle_param_tbl_entry *> &param_handle_table){
7094         string ret;
7095         int p;
7096
7097         for(p=0;p<param_handle_table.size();++p){
7098                 sprintf(tmpstr,"\tgs_param_handle_t handle_param_%d;\n",p);
7099                 ret += tmpstr;
7100         }
7101
7102         return(ret);
7103 }
7104
7105
7106 // ------------------------------------------------------------
7107 //              functions for generating initialization code.
7108
7109 static string gen_access_var_init(col_id_set &cid_set){
7110         string ret;
7111         col_id_set::iterator csi;
7112
7113     for(csi=cid_set.begin(); csi!=cid_set.end();++csi){
7114         int tblref = (*csi).tblvar_ref;
7115         string field = (*csi).field;
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());
7117         ret.append(tmpstr);
7118     }
7119         return ret;
7120 }
7121
7122
7123 static string gen_complex_lit_init(cplx_lit_table *complex_literals){
7124         string ret;
7125
7126         int cl;
7127     for(cl=0;cl<complex_literals->size();cl++){
7128         literal_t *l = complex_literals->get_literal(cl);
7129 //        sprintf(tmpstr,"\tcomplex_literal_%d = ",cl);
7130 //        ret += tmpstr + l->to_hfta_C_code() + ";\n";
7131         sprintf(tmpstr,"&(complex_literal_%d)",cl);
7132         ret += "\t" + l->to_hfta_C_code(tmpstr) + ";\n";
7133 //                      I think that the code below is obsolete
7134 //                      TODO: it is obsolete.  add_cpx_lit is always
7135 //                      called with the handle indicator being false.
7136 //                      This entire structure should be cleansed.
7137         if(complex_literals->is_handle_ref(cl)){
7138             data_type *dt = new data_type( l->get_type() );
7139             sprintf(tmpstr,"\tlit_handle_%d = %s(&(f->complex_literal_%d));\n",
7140                 cl, dt->hfta_handle_registration_name().c_str(), cl);
7141             ret += tmpstr;
7142             delete dt;
7143        }
7144     }
7145         return(ret);
7146 }
7147
7148
7149 static string gen_partial_fcn_init(vector<scalarexp_t *> &partial_fcns){
7150         string ret;
7151
7152         int p;
7153         for(p=0;p<partial_fcns.size();++p){
7154                 data_type *pdt =partial_fcns[p]->get_data_type();
7155                 literal_t empty_lit(pdt->type_indicator());
7156                 if(pdt->is_buffer_type()){
7157 //                      sprintf(tmpstr,"\tpartial_fcn_result_%d = %s;\n",
7158 //                               p, empty_lit.to_hfta_C_code().c_str());
7159                         sprintf(tmpstr,"&(partial_fcn_result_%d)",p);
7160                         ret += "\t"+empty_lit.to_hfta_C_code(tmpstr)+";\n";
7161                 }
7162         }
7163         return(ret);
7164 }
7165
7166 static string gen_pass_by_handle_init(
7167                                 vector<handle_param_tbl_entry *> &param_handle_table){
7168         string ret;
7169
7170     int ph;
7171     for(ph=0;ph<param_handle_table.size();++ph){
7172                 data_type pdt(param_handle_table[ph]->type_name);
7173                 sprintf(tmpstr,"\thandle_param_%d = %s(",ph,param_handle_table[ph]->lfta_registration_fcn().c_str());
7174                 switch(param_handle_table[ph]->val_type){
7175                 case cplx_lit_e:
7176                         ret += tmpstr;
7177                         if(pdt.is_buffer_type()) ret += "&(";
7178                         sprintf(tmpstr,"complex_literal_%d",param_handle_table[ph]->complex_literal_idx);
7179                         ret += tmpstr;
7180                         if(pdt.is_buffer_type()) ret += ")";
7181                         ret += ");\n";
7182                         break;
7183                 case litval_e:
7184                         ret += tmpstr;
7185                         ret += param_handle_table[ph]->litval->to_hfta_C_code("") + ");\n";
7186 //                      ret += ");\n";
7187                         break;
7188                 case param_e:
7189 //                              query parameter handles are regstered/deregistered in the
7190 //                              load_params function.
7191 //                      ret += "t->param_"+param_handle_table[ph]->param_name;
7192                         break;
7193                 default:
7194                         fprintf(stderr, "INTERNAL ERROR unknown case found when processing pass-by-handle parameter table.\n");
7195                         exit(1);
7196                 }
7197         }
7198         return(ret);
7199 }
7200
7201 //------------------------------------------------------------
7202 //                      functions for destructor and deregistration code
7203
7204 static string gen_complex_lit_dtr(cplx_lit_table *complex_literals){
7205         string ret;
7206
7207         int cl;
7208     for(cl=0;cl<complex_literals->size();cl++){
7209         literal_t *l = complex_literals->get_literal(cl);
7210                 data_type ldt(  l->get_type() );
7211         if(ldt.is_buffer_type()){
7212                         sprintf(tmpstr,"\t\t%s(&complex_literal_%d);\n",
7213                           ldt.get_hfta_buffer_destroy().c_str(), cl );
7214             ret += tmpstr;
7215         }
7216     }
7217         return(ret);
7218 }
7219
7220
7221 static string gen_pass_by_handle_dtr(
7222                                 vector<handle_param_tbl_entry *> &param_handle_table){
7223         string ret;
7224
7225         int ph;
7226     for(ph=0;ph<param_handle_table.size();++ph){
7227                 sprintf(tmpstr, "\t\t%s(handle_param_%d);\n",
7228                         param_handle_table[ph]->lfta_deregistration_fcn().c_str(),ph);
7229                 ret += tmpstr;
7230         }
7231         return(ret);
7232 }
7233
7234 //                      Destroy all previous results
7235 static string gen_partial_fcn_dtr(vector<scalarexp_t *> &partial_fcns){
7236         string ret;
7237
7238         int p;
7239         for(p=0;p<partial_fcns.size();++p){
7240                 data_type *pdt =partial_fcns[p]->get_data_type();
7241                 if(pdt->is_buffer_type()){
7242                         sprintf(tmpstr,"\t\t%s(&partial_fcn_result_%d);\n",
7243                           pdt->get_hfta_buffer_destroy().c_str(), p );
7244                         ret += tmpstr;
7245                 }
7246         }
7247         return(ret);
7248 }
7249
7250 //              Destroy previsou results of fcns in pfcn_set
7251 static string gen_partial_fcn_dtr(vector<scalarexp_t *> &partial_fcns, set<int> &pfcn_set){
7252         string ret;
7253         set<int>::iterator si;
7254
7255         for(si=pfcn_set.begin(); si!=pfcn_set.end(); ++si){
7256                 data_type *pdt =partial_fcns[(*si)]->get_data_type();
7257                 if(pdt->is_buffer_type()){
7258                         sprintf(tmpstr,"\t\t%s(&partial_fcn_result_%d);\n",
7259                           pdt->get_hfta_buffer_destroy().c_str(), (*si) );
7260                         ret += tmpstr;
7261                 }
7262         }
7263         return(ret);
7264 }
7265
7266
7267 //-------------------------------------------------------------------------
7268 //                      Functions related to se generation bookkeeping.
7269
7270 static void get_new_pred_cids(predicate_t *pr, col_id_set &found_cids,
7271                                                                 col_id_set &new_cids, gb_table *gtbl){
7272         col_id_set this_pred_cids;
7273         col_id_set::iterator csi;
7274
7275 //                              get colrefs in predicate not already found.
7276         gather_pr_col_ids(pr,this_pred_cids,gtbl);
7277         set_difference(this_pred_cids.begin(), this_pred_cids.end(),
7278                                            found_cids.begin(), found_cids.end(),
7279                                                 inserter(new_cids,new_cids.begin()) );
7280
7281 //                              We've found these cids, so update found_cids
7282         for(csi=new_cids.begin(); csi!=new_cids.end(); ++csi)
7283                 found_cids.insert((*csi));
7284
7285 }
7286
7287 //              after the call, new_cids will have the colrefs in se but not found_cids.
7288 //              update found_cids with the new cids.
7289 static void get_new_se_cids(scalarexp_t *se, col_id_set &found_cids,
7290                                                                 col_id_set &new_cids, gb_table *gtbl){
7291         col_id_set this_se_cids;
7292         col_id_set::iterator csi;
7293
7294 //                              get colrefs in se not already found.
7295         gather_se_col_ids(se,this_se_cids,gtbl);
7296         set_difference(this_se_cids.begin(), this_se_cids.end(),
7297                                            found_cids.begin(), found_cids.end(),
7298                                                 inserter(new_cids,new_cids.begin()) );
7299
7300 //                              We've found these cids, so update found_cids
7301         for(csi=new_cids.begin(); csi!=new_cids.end(); ++csi)
7302                 found_cids.insert((*csi));
7303
7304 }
7305
7306 static string gen_unpack_cids(table_list *schema, col_id_set &new_cids, string on_problem, vector<bool> &needs_xform){
7307         string ret;
7308         col_id_set::iterator csi;
7309
7310         for(csi=new_cids.begin(); csi!=new_cids.end(); ++csi){
7311         int schref = (*csi).schema_ref;
7312             int tblref = (*csi).tblvar_ref;
7313         string field = (*csi).field;
7314                 data_type dt(schema->get_type_name(schref,field));
7315                 string unpack_fcn;
7316                 if(needs_xform[tblref]){
7317                         unpack_fcn = dt.get_hfta_unpack_fcn();
7318                 }else{
7319                         unpack_fcn = dt.get_hfta_unpack_fcn_noxf();
7320                 }
7321                 if(dt.is_buffer_type()){
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);
7323                 }else{
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);
7325                 }
7326                 ret += tmpstr;
7327                 if(dt.is_buffer_type()){
7328                         ret += "\tif(problem) return "+on_problem+" ;\n";
7329                 }
7330         }
7331         return(ret);
7332 }
7333
7334 // generates the declaration of all the variables related to
7335 // temp tuples generation
7336 static string gen_decl_temp_vars(){
7337         string ret;
7338
7339         ret += "\t// variables related to temp tuple generation\n";
7340         ret += "\tbool temp_tuple_received;\n";
7341
7342         return(ret);
7343 }
7344
7345 // generates initialization code for variables related to temp tuple processing
7346 static string gen_init_temp_vars(table_list *schema, vector<select_element *>& select_list, gb_table *gtbl){
7347         string ret;
7348         col_id_set::iterator csi;
7349         int s;
7350
7351 //              Initialize internal state
7352         ret += "\ttemp_tuple_received = false;\n";
7353
7354         col_id_set temp_cids;   // colrefs unpacked thus far.
7355
7356         for(s=0;s<select_list.size();s++){
7357                 if (select_list[s]->se->get_data_type()->is_temporal()) {
7358 //                      Find the set of attributes accessed in this SE
7359                         col_id_set new_cids;
7360                         get_new_se_cids(select_list[s]->se,temp_cids, new_cids, gtbl);
7361
7362                         // init these vars
7363                         for(csi=new_cids.begin(); csi!=new_cids.end(); ++csi){
7364                                 int schref = (*csi).schema_ref;
7365                                 int tblref = (*csi).tblvar_ref;
7366                                 string field = (*csi).field;
7367                                 data_type dt(schema->get_type_name(schref,field), schema->get_modifier_list(schref,field));
7368
7369                                 sprintf(tmpstr,"\t unpack_var_%s_%d = %s;\n", field.c_str(), tblref,
7370                                         dt.is_increasing() ? dt.get_min_literal().c_str() : dt.get_max_literal().c_str());
7371                                 ret += tmpstr;
7372                         }
7373                 }
7374         }
7375         return(ret);
7376 }
7377
7378
7379
7380 // generates a check if tuple is temporal
7381 static string gen_temp_tuple_check(string node_name, int channel) {
7382         string ret;
7383
7384         char tmpstr[256];
7385         sprintf(tmpstr, "tup%d", channel);
7386         string tup_name = tmpstr;
7387         sprintf(tmpstr, "schema_handle%d", channel);
7388         string schema_handle_name = tmpstr;
7389         string tuple_offset_name = "tuple_metadata_offset"+int_to_string(channel);
7390
7391 //                      check if it is a temporary status tuple
7392         ret += "\t// check if tuple is temp status tuple\n";
7393 //              ret += "\tif (ftaschema_is_temporal_tuple(" + schema_handle_name + ", " + tup_name + ".data)) {\n";
7394         ret += "\tif (ftaschema_is_temporal_tuple_offset(" + tuple_offset_name + ", " + tup_name + ".data)) {\n";
7395         ret += "\t\ttemp_tuple_received = true;\n";
7396         ret += "\t}\n";
7397         ret += "\telse\n\t\ttemp_tuple_received = false;\n\n";
7398
7399         return(ret);
7400 }
7401
7402 // generates unpacking code for all temporal attributes referenced in select
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) {
7404         string ret;
7405         int s;
7406
7407 //              Unpack all the temporal attributes references in select list
7408 //              we need it to be able to generate temp status tuples
7409         for(s=0;s<select_list.size();s++){
7410                 if (select_list[s]->se->get_data_type()->is_temporal()) {
7411 //                      Find the set of attributes accessed in this SE
7412                         col_id_set new_cids;
7413                         get_new_se_cids(select_list[s]->se,found_cids, new_cids, gtbl);
7414 //                      Unpack these values.
7415                         ret += gen_unpack_cids(schema, new_cids, "false", needs_xform);
7416                 }
7417         }
7418
7419         return(ret);
7420 }
7421
7422
7423 //              Generates temporal tuple generation code (except attribute packing)
7424 static string gen_init_temp_status_tuple(string node_name) {
7425         string ret;
7426
7427         ret += "\t// create temp status tuple\n";
7428         ret += "\tresult.tuple_size = sizeof("+generate_tuple_name( node_name)+") + sizeof(gs_uint8_t);\n";
7429         ret += "\tresult.data = (gs_sp_t )malloc(result.tuple_size);\n";
7430         ret += "\tresult.heap_resident = true;\n";
7431         ret += "\t//            Mark tuple as temporal\n";
7432         ret += "\t*((gs_sp_t )result.data + sizeof("+generate_tuple_name( node_name)+")) = TEMPORAL_TUPLE;\n";
7433
7434         ret += "\t"+generate_tuple_name( node_name)+" *tuple = ("+
7435                 generate_tuple_name( node_name) +" *)(result.data);\n";
7436
7437         return(ret);
7438 }
7439
7440
7441 //              Assume that all colrefs unpacked already ...
7442 static string gen_unpack_partial_fcn(table_list *schema,
7443                                         vector<scalarexp_t *> &partial_fcns,set<int> &pfcn_refs,
7444                                         string on_problem){
7445         string ret;
7446         set<int>::iterator si;
7447
7448 //                      Since set<..> is a "Sorted Associative Container",
7449 //                      we can walk through it in sorted order by walking from
7450 //                      begin() to end().  (and the partial fcns must be
7451 //                      evaluated in this order).
7452         for(si=pfcn_refs.begin();si!=pfcn_refs.end();++si){
7453                 ret += unpack_partial_fcn(partial_fcns[(*si)], (*si), schema);
7454                 ret += "\tif(retval) return "+on_problem+" ;\n";
7455         }
7456         return(ret);
7457 }
7458
7459 //              Assume that all colrefs unpacked already ...
7460 //              this time with cached functions.
7461 static string gen_unpack_partial_fcn(table_list *schema,
7462                                         vector<scalarexp_t *> &partial_fcns,set<int> &pfcn_refs,
7463                                         vector<int> &fcn_ref_cnt, vector<bool> &is_partial_fcn,
7464                                         string on_problem){
7465         string ret;
7466         set<int>::iterator si;
7467
7468 //                      Since set<..> is a "Sorted Associative Container",
7469 //                      we can walk through it in sorted order by walking from
7470 //                      begin() to end().  (and the partial fcns must be
7471 //                      evaluated in this order).
7472         for(si=pfcn_refs.begin();si!=pfcn_refs.end();++si){
7473                 if(fcn_ref_cnt[(*si)] > 1){
7474                         ret += "\tif(fcn_ref_cnt_"+int_to_string((*si))+"==0){\n";
7475                 }
7476                 if(is_partial_fcn[(*si)]){
7477                         ret += unpack_partial_fcn(partial_fcns[(*si)], (*si), schema);
7478                         ret += "\tif(retval) return "+on_problem+" ;\n";
7479                 }
7480                 if(fcn_ref_cnt[(*si)] > 1){
7481                         if(!is_partial_fcn[(*si)]){
7482                                 ret += "\t\tpartial_fcn_result_"+int_to_string((*si))+"="+generate_cached_fcn(partial_fcns[(*si)],(*si),schema)+";\n";
7483                         }
7484                         ret += "\t\tfcn_ref_cnt_"+int_to_string((*si))+"=1;\n";
7485                         ret += "\t}\n";
7486                 }
7487         }
7488
7489         return(ret);
7490 }
7491
7492
7493 //              This version finds and unpacks new colrefs.
7494 //              found_cids gets updated with the newly unpacked cids.
7495 static string gen_full_unpack_partial_fcn(table_list *schema,
7496                                         vector<scalarexp_t *> &partial_fcns,set<int> &pfcn_refs,
7497                                         col_id_set &found_cids, gb_table *gtbl, string on_problem,
7498                                         vector<bool> &needs_xform){
7499         string ret;
7500         set<int>::iterator slsi;
7501
7502         for(slsi=pfcn_refs.begin(); slsi!=pfcn_refs.end(); ++slsi){
7503 //                      find all new fields ref'd by this partial fcn.
7504                 col_id_set new_cids;
7505                 get_new_se_cids(partial_fcns[(*slsi)], found_cids, new_cids, gtbl);
7506 //                      Unpack these values.
7507                 ret += gen_unpack_cids(schema, new_cids, on_problem, needs_xform);
7508
7509 //                      Now evaluate the partial fcn.
7510                 ret += unpack_partial_fcn(partial_fcns[(*slsi)], (*slsi), schema);
7511                 ret += "\tif(retval) return "+on_problem+" ;\n";
7512         }
7513         return(ret);
7514 }
7515
7516 //              This version finds and unpacks new colrefs.
7517 //              found_cids gets updated with the newly unpacked cids.
7518 //                      BUT : only for the partial functions.
7519 static string gen_full_unpack_partial_fcn(table_list *schema,
7520                                         vector<scalarexp_t *> &partial_fcns,set<int> &pfcn_refs,
7521                                         vector<int> &fcn_ref_cnt, vector<bool> &is_partial_fcn,
7522                                         col_id_set &found_cids, gb_table *gtbl, string on_problem,
7523                                         vector<bool> &needs_xform){
7524         string ret;
7525         set<int>::iterator slsi;
7526
7527         for(slsi=pfcn_refs.begin(); slsi!=pfcn_refs.end(); ++slsi){
7528           if(is_partial_fcn[(*slsi)]){
7529 //                      find all new fields ref'd by this partial fcn.
7530                 col_id_set new_cids;
7531                 get_new_se_cids(partial_fcns[(*slsi)], found_cids, new_cids, gtbl);
7532 //                      Unpack these values.
7533                 ret += gen_unpack_cids(schema, new_cids, on_problem, needs_xform);
7534
7535 //                      Now evaluate the partial fcn.
7536                 if(fcn_ref_cnt[(*slsi)] > 1){
7537                         ret += "\tif(fcn_ref_cnt_"+int_to_string((*slsi))+"==0){\n";
7538                 }
7539                 if(is_partial_fcn[(*slsi)]){
7540                         ret += unpack_partial_fcn(partial_fcns[(*slsi)], (*slsi), schema);
7541                         ret += "\tif(retval) return "+on_problem+" ;\n";
7542                 }
7543                 if(fcn_ref_cnt[(*slsi)] > 1){
7544                         ret += "\t\tfcn_ref_cnt_"+int_to_string((*slsi))+"=1;\n";
7545                         ret += "\t}\n";
7546                 }
7547
7548           }
7549         }
7550         return(ret);
7551 }
7552
7553 static string gen_remaining_cached_fcns(table_list *schema,
7554                                         vector<scalarexp_t *> &partial_fcns,set<int> &pfcn_refs,
7555                                         vector<int> &fcn_ref_cnt, vector<bool> &is_partial_fcn){
7556         string ret;
7557         set<int>::iterator slsi;
7558
7559         for(slsi=pfcn_refs.begin(); slsi!=pfcn_refs.end(); ++slsi){
7560           if(!is_partial_fcn[(*slsi)] && fcn_ref_cnt[(*slsi)] > 1){
7561
7562                 if(fcn_ref_cnt[(*slsi)] > 1){
7563                         ret += "\tif(fcn_ref_cnt_"+int_to_string((*slsi))+"==0){\n";
7564                         ret += "\t\tpartial_fcn_result_"+int_to_string((*slsi))+"="+generate_cached_fcn(partial_fcns[(*slsi)],(*slsi),schema)+";\n";
7565                         ret += "\t\tfcn_ref_cnt_"+int_to_string((*slsi))+"=1;\n";
7566                         ret += "\t}\n";
7567                 }
7568           }
7569         }
7570         return(ret);
7571 }
7572
7573
7574 //              unpack the colrefs in cid_set not in found_cids
7575 static string gen_remaining_colrefs(table_list *schema,
7576                         col_id_set &cid_set, col_id_set &found_cids, string on_problem,
7577                         vector<bool> &needs_xform){
7578         string ret;
7579         col_id_set::iterator csi;
7580
7581         for(csi=cid_set.begin(); csi!=cid_set.end();csi++){
7582                 if(found_cids.count( (*csi) ) == 0){
7583                 int schref = (*csi).schema_ref;
7584                     int tblref = (*csi).tblvar_ref;
7585                 string field = (*csi).field;
7586                         data_type dt(schema->get_type_name(schref,field));
7587                         string unpack_fcn;
7588                         if(needs_xform[tblref]){
7589                                 unpack_fcn = dt.get_hfta_unpack_fcn();
7590                         }else{
7591                                 unpack_fcn = dt.get_hfta_unpack_fcn_noxf();
7592                         }
7593                         if(dt.is_buffer_type()){
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);
7595                         }else{
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);
7597                         }
7598                         ret += tmpstr;
7599                         if(dt.is_buffer_type()){
7600                                 ret.append("\tif(problem) return "+on_problem+" ;\n");
7601                         }
7602                 }
7603         }
7604         return(ret);
7605 }
7606
7607 static string gen_buffer_selvars(table_list *schema,
7608                                                                 vector<select_element *> &select_list){
7609         string ret;
7610         int s;
7611
7612     for(s=0;s<select_list.size();s++){
7613                 scalarexp_t *se = select_list[s]->se;
7614         data_type *sdt = se->get_data_type();
7615         if(sdt->is_buffer_type() &&
7616                         !( (se->get_operator_type() == SE_COLREF) ||
7617                            (se->get_operator_type() == SE_FUNC && se->is_partial()) ||
7618                            (se->get_operator_type() == SE_FUNC && se->get_aggr_ref() >= 0))
7619                 ){
7620             sprintf(tmpstr,"selvar_%d",s);
7621                         ret+="\t"+sdt->make_host_cvar(tmpstr)+" = ";
7622                         ret += generate_se_code(se,schema) +";\n";
7623         }
7624     }
7625         return(ret);
7626 }
7627
7628 static string gen_buffer_selvars_size(vector<select_element *> &select_list,table_list *schema){
7629         string ret;
7630         int s;
7631
7632     for(s=0;s<select_list.size();s++){
7633                 scalarexp_t *se = select_list[s]->se;
7634         data_type *sdt = se->get_data_type();
7635         if(sdt->is_buffer_type()){
7636                   if( !( (se->get_operator_type() == SE_COLREF) ||
7637                            (se->get_operator_type() == SE_FUNC && se->is_partial()) ||
7638                            (se->get_operator_type() == SE_FUNC && se->get_aggr_ref() >= 0))
7639                   ){
7640             sprintf(tmpstr," + %s(&selvar_%d)", sdt->get_hfta_buffer_size().c_str(),s);
7641             ret.append(tmpstr);
7642                   }else{
7643             sprintf(tmpstr," + %s(&%s)", sdt->get_hfta_buffer_size().c_str(),
7644                                 generate_se_code(se,schema).c_str());
7645             ret.append(tmpstr);
7646                   }
7647         }
7648     }
7649         return(ret);
7650 }
7651
7652 static string gen_buffer_selvars_dtr(vector<select_element *> &select_list){
7653         string ret;
7654         int s;
7655
7656     for(s=0;s<select_list.size();s++){
7657                 scalarexp_t *se = select_list[s]->se;
7658         data_type *sdt = se->get_data_type();
7659         if(sdt->is_buffer_type() &&
7660                         !( (se->get_operator_type() == SE_COLREF) ||
7661                                 (se->get_operator_type() == SE_AGGR_STAR) ||
7662                                 (se->get_operator_type() == SE_AGGR_SE) ||
7663                            (se->get_operator_type() == SE_FUNC && se->is_partial()) ||
7664                            (se->get_operator_type() == SE_FUNC && se->get_aggr_ref() >= 0))
7665                         ){
7666                                 sprintf(tmpstr,"\t\t%s(&selvar_%d);\n",
7667                                   sdt->get_hfta_buffer_destroy().c_str(), s );
7668                 ret += tmpstr;
7669         }
7670     }
7671         return(ret);
7672 }
7673
7674
7675 static string gen_pack_tuple(table_list *schema, vector<select_element *> &select_list, string node_name, bool temporal_only){
7676         string ret;
7677         int s;
7678
7679         ret += "\tint tuple_pos = sizeof("+generate_tuple_name(node_name)+") + sizeof(gs_uint8_t);\n";
7680     for(s=0;s<select_list.size();s++){
7681                 scalarexp_t *se  = select_list[s]->se;
7682         data_type *sdt = se->get_data_type();
7683
7684         if(!temporal_only && sdt->is_buffer_type()){
7685                   if( !( (se->get_operator_type() == SE_COLREF) ||
7686                            (se->get_operator_type() == SE_FUNC && se->is_partial()))
7687                         ){
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);
7689                 ret.append(tmpstr);
7690                 sprintf(tmpstr,"\ttuple_pos += %s(&selvar_%d);\n", sdt->get_hfta_buffer_size().c_str(), s);
7691                 ret.append(tmpstr);
7692                         }else{
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());
7694                 ret.append(tmpstr);
7695                 sprintf(tmpstr,"\ttuple_pos += %s(&%s);\n", sdt->get_hfta_buffer_size().c_str(), generate_se_code(se,schema).c_str());
7696                 ret.append(tmpstr);
7697                         }
7698         }else if (!temporal_only || sdt->is_temporal()) {
7699             sprintf(tmpstr,"\ttuple->tuple_var%d = ",s);
7700             ret.append(tmpstr);
7701             ret.append(generate_se_code(se,schema) );
7702             ret.append(";\n");
7703         }
7704     }
7705         return(ret);
7706 }
7707
7708
7709 //-------------------------------------------------------------------------
7710 //                      functor generation methods
7711 //-------------------------------------------------------------------------
7712
7713 /////////////////////////////////////////////////////////
7714 ////                    File Output Operator
7715 string output_file_qpn::generate_functor_name(){
7716         return("output_file_functor_" + normalize_name(get_node_name()));
7717 }
7718
7719
7720 string output_file_qpn::generate_functor(table_list *schema, ext_fcn_list *Ext_fcns, vector<bool> &needs_xform){
7721         string ret = "class " + this->generate_functor_name() + "{\n";
7722
7723 //              Find the temporal field
7724         int temporal_field_idx;
7725         data_type *tdt = NULL;
7726         for(temporal_field_idx=0;temporal_field_idx<fields.size();temporal_field_idx++){
7727                 tdt = new data_type(fields[temporal_field_idx]->get_type(), fields[temporal_field_idx]->get_modifier_list());
7728                 if(tdt->is_temporal()){
7729                         break;
7730                 }else{
7731                         delete tdt;
7732                 }
7733         }
7734
7735         if(temporal_field_idx == fields.size()){
7736                 fprintf(stderr,"ERROR, no temporal field for file output operator %s\n",node_name.c_str());
7737                 exit(1);
7738         }
7739
7740         ret += "private:\n";
7741
7742         // var to save the schema handle
7743         ret += "\tint schema_handle0;\n";
7744 //                      tuple metadata offset
7745         ret += "\tint tuple_metadata_offset0;\n";
7746         sprintf(tmpstr,"\tgs_int32_t unpack_offset_%s_0;\n",  fields[temporal_field_idx]->get_name().c_str());
7747         ret.append(tmpstr);
7748
7749 //              For unpacking the hashing fields, if any
7750         int h;
7751         for(h=0;h<hash_flds.size();++h){
7752                 sprintf(tmpstr,"unpack_var_%s", fields[hash_flds[h]]->get_name().c_str());
7753                 data_type *hdt = new data_type(fields[hash_flds[h]]->get_type(), fields[hash_flds[h]]->get_modifier_list());
7754                 ret+="\t"+hdt->make_host_cvar(tmpstr)+";\n";
7755                 if(hash_flds[h]!=temporal_field_idx){
7756                         sprintf(tmpstr,"\tgs_int32_t unpack_offset_%s_0;\n",  fields[hash_flds[h]]->get_name().c_str());
7757                         ret.append(tmpstr);
7758                 }
7759         }
7760 //              Specail case for output file hashing
7761         if(n_streams>1 && hash_flds.size()==0){
7762                 ret+="\tgs_uint32_t outfl_cnt;\n";
7763         }
7764
7765         ret += "//\t\tRemember the last posted timestamp.\n";
7766         ret+="\t"+tdt->make_host_cvar("timestamp")+";\n";
7767         ret+="\t"+tdt->make_host_cvar("last_bucket")+";\n";
7768         ret+="\t"+tdt->make_host_cvar("slack")+";\n";
7769         ret += "\tbool first_execution;\n";
7770         ret += "\tbool temp_tuple_received;\n";
7771         ret += "\tbool is_eof;\n";
7772
7773         ret += "\tgs_int32_t bucketwidth;\n";
7774
7775         ret += "public:\n";
7776 //-------------------
7777 //                      The functor constructor
7778 //                      pass in a schema handle (e.g. for the 1st input stream),
7779 //                      use it to determine how to unpack the merge variable.
7780 //                      ASSUME that both streams have the same layout,
7781 //                      just duplicate it.
7782
7783 //              unpack vars
7784         ret += "//\t\tFunctor constructor.\n";
7785         ret +=  this->generate_functor_name()+"(int schema_hndl){\n";
7786
7787         ret += "\tschema_handle0 = schema_hndl;\n";
7788 //              tuple metadata offset
7789         ret += "\ttuple_metadata_offset0 = ftaschema_get_tuple_metadata_offset(schema_handle0);\n";
7790
7791         if(output_spec->bucketwidth == 0)
7792                 ret += "\tbucketwidth = 60;\n";
7793         else
7794                 ret += "\tbucketwidth = "+int_to_string(output_spec->bucketwidth)+";\n";
7795         ret += "//\t\tGet offsets for unpacking fields from input tuple.\n";
7796
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());
7798    ret.append(tmpstr);
7799 //              Hashing field unpacking, if any
7800         for(h=0;h<hash_flds.size();++h){
7801                 if(hash_flds[h]!=temporal_field_idx){
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());
7803                         ret.append(tmpstr);
7804                 }
7805         }
7806
7807         ret+="\tfirst_execution = true;\n";
7808
7809 //              Initialize internal state
7810         ret += "\ttemp_tuple_received = false;\n";
7811
7812         //              Init last timestamp values to minimum value for their type
7813         if (tdt->is_increasing()){
7814                 ret+="\ttimestamp = " + tdt->get_min_literal() + ";\n";
7815                 ret+="\tlast_bucket = " + tdt->get_min_literal() + ";\n";
7816         }else{
7817                 ret+="\ttimestamp = " + tdt->get_max_literal() + ";\n";
7818                 ret+="\tlast_bucket = " + tdt->get_max_literal() + ";\n";
7819         }
7820
7821
7822         ret += "};\n\n";
7823
7824         ret += "//\t\tFunctor destructor.\n";
7825         ret +=  "~"+this->generate_functor_name()+"(){\n";
7826         ret+="};\n\n";
7827
7828
7829         ret += "int load_params_"+this->generate_functor_name()+"(gs_int32_t sz, void *value){return 0;}\n";
7830         ret += "void destroy_params_"+this->generate_functor_name()+"(){}\n";
7831
7832 //                      Register new parameter block
7833         ret += "int set_param_block(gs_int32_t sz, void* value){\n";
7834           ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";
7835           ret += "\treturn this->load_params_"+this->generate_functor_name()+
7836                                 "(sz, value);\n";
7837         ret += "};\n\n";
7838
7839         ret+="\nbool temp_status_received(const host_tuple& tup0)/* const*/   {\n";
7840         ret+="\tgs_int32_t problem;\n";
7841
7842         ret += "\tvoid *tup_ptr = (void *)(&tup0);\n";
7843         ret += "\tis_eof = ftaschema_is_eof_tuple(schema_handle0,tup_ptr);\n";
7844
7845         ret += gen_temp_tuple_check(this->node_name, 0);
7846
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);
7848         ret += tmpstr;
7849
7850         for(h=0;h<hash_flds.size();++h){
7851                 data_type *hdt = new data_type(fields[hash_flds[h]]->get_type(), fields[hash_flds[h]]->get_modifier_list());
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);
7853         ret += tmpstr;
7854         }
7855         ret +=
7856 "       return temp_tuple_received;\n"
7857 "}\n"
7858 "\n"
7859 ;
7860
7861         ret +=
7862 "bool new_epoch(){\n"
7863 "       if(first_execution || (last_bucket + 1) * bucketwidth <= timestamp){\n"
7864 "               last_bucket = timestamp / bucketwidth;\n"
7865 "               first_execution = false;\n"
7866 "               return true;\n"
7867 "       }\n"
7868 "       return false;\n"
7869 "}\n"
7870 "\n"
7871 ;
7872
7873         if(n_streams <= 1){
7874                 ret+=
7875 "inline gs_uint32_t output_hash(){return 0;}\n\n";
7876         }else{
7877                 if(hash_flds.size()==0){
7878                         ret +=
7879 "gs_uint32_t output_hash(){\n"
7880 "       outfl_cnt++;\n"
7881 "       if(outfl_cnt >= "+int_to_string(n_streams)+")\n"
7882 "               outfl_cnt = 0;\n"
7883 "       return outfl_cnt;\n"
7884 "}\n"
7885 "\n"
7886 ;
7887                 }else{
7888                         ret +=
7889 "gs_uint32_t output_hash(){\n"
7890 "       gs_uint32_t ret = "
7891 ;
7892                         for(h=0;h<hash_flds.size();++h){
7893                                 if(h>0) ret += "^";
7894                                 data_type *hdt = new data_type(fields[hash_flds[h]]->get_type(), fields[hash_flds[h]]->get_modifier_list());
7895                                 if(hdt->use_hashfunc()){
7896                                         sprintf(tmpstr,"%s(&(unpack_var_%s))",hdt->get_hfta_hashfunc().c_str(),fields[hash_flds[h]]->get_name().c_str());
7897                                 }else{
7898                                         sprintf(tmpstr,"unpack_var_%s",fields[hash_flds[h]]->get_name().c_str());
7899                                 }
7900                                 ret += tmpstr;
7901                         }
7902                         ret +=
7903 ";\n"
7904 "       return  ret % "+int_to_string(hash_flds.size())+";\n"
7905 "}\n\n"
7906 ;
7907                 }
7908         }
7909
7910 ret +=
7911 "gs_uint32_t num_file_streams(){\n"
7912 "       return("+int_to_string(n_streams)+");\n"
7913 "}\n\n"
7914 ;
7915
7916         ret +=
7917 "string get_filename_base(){\n"
7918 "       char tmp_fname[500];\n";
7919
7920         string output_filename_base = hfta_query_name+filestream_id;
7921 /*
7922         if(n_hfta_clones > 1){
7923                 output_filename_base += "_"+int_to_string(parallel_idx);
7924         }
7925 */
7926
7927
7928
7929         if(output_spec->output_directory == "")
7930                 ret +=
7931 "       sprintf(tmp_fname,\""+output_filename_base+"_%lld\",(gs_int64_t)(last_bucket*bucketwidth));\n";
7932                 else ret +=
7933 "       sprintf(tmp_fname,\""+output_spec->output_directory+"/"+output_filename_base+"_%lld\",(gs_int64_t)(last_bucket*bucketwidth));\n";
7934 ret +=
7935 "       return (string)(tmp_fname);\n"
7936 "}\n"
7937 "\n";
7938
7939
7940 ret+=
7941 "bool do_compression(){\n";
7942         if(do_gzip)
7943                 ret += "        return true;\n";
7944         else
7945                 ret += "        return false;\n";
7946 ret+=
7947 "}\n"
7948 "\n"
7949 "bool is_eof_tuple(){\n"
7950 "       return is_eof;\n"
7951 "}\n"
7952 "\n"
7953 "bool propagate_tuple(){\n"
7954 ;
7955 if(eat_input)
7956         ret+="\treturn false;\n";
7957 else
7958         ret+="\treturn true;\n";
7959 ret+="}\n\n";
7960 //              create a temp status tuple
7961         ret += "int create_temp_status_tuple(host_tuple& result) {\n\n";
7962
7963         ret += gen_init_temp_status_tuple(this->hfta_query_name);
7964
7965         sprintf(tmpstr,"\ttuple->tuple_var%d = timestamp;\n",temporal_field_idx);
7966
7967
7968         ret += tmpstr;
7969
7970         ret += "\treturn 0;\n";
7971         ret += "}\n\n";
7972         ret += "};\n\n";
7973
7974         return ret;
7975 }
7976
7977
7978 string output_file_qpn::generate_operator(int i, string params){
7979         string optype = "file_output_operator";
7980         switch(compression_type){
7981         case regular:
7982                 optype = "file_output_operator";
7983         break;
7984         case gzip:
7985                 optype = "zfile_output_operator";
7986         break;
7987         case bzip:
7988                 optype = "bfile_output_operator";
7989         break;
7990         }
7991
7992                 return("        "+optype+"<" +
7993                 generate_functor_name() +
7994                 "> *op"+int_to_string(i)+" = new "+optype+"<"+
7995                 generate_functor_name() +">("+params+", \"" + hfta_query_name + "\""
7996                 + "," + hfta_query_name + "_schema_definition);\n");
7997 }
7998
7999 /////////////////////////////////////////////////////////
8000 //////                  SPX functor
8001
8002
8003 string spx_qpn::generate_functor_name(){
8004         return("spx_functor_" + normalize_name(normalize_name(this->get_node_name())));
8005 }
8006
8007 string spx_qpn::generate_functor(table_list *schema, ext_fcn_list *Ext_fcns, vector<bool> &needs_xform){
8008 //                      Initialize generate utility globals
8009         segen_gb_tbl = NULL;
8010
8011         string ret = "class " + this->generate_functor_name() + "{\n";
8012
8013 //                      Find variables referenced in this query node.
8014
8015   col_id_set cid_set;
8016   col_id_set::iterator csi;
8017
8018         int w, s, p;
8019     for(w=0;w<where.size();++w)
8020         gather_pr_col_ids(where[w]->pr,cid_set,NULL);
8021     for(s=0;s<select_list.size();s++){
8022         gather_se_col_ids(select_list[s]->se,cid_set,NULL);
8023     }
8024
8025
8026 //                      Private variables : store the state of the functor.
8027 //                      1) variables for unpacked attributes
8028 //                      2) offsets of the upacked attributes
8029 //                      3) storage of partial functions
8030 //                      4) storage of complex literals (i.e., require a constructor)
8031
8032         ret += "private:\n";
8033         ret += "\tbool first_execution;\t// internal processing state \n";
8034         ret += "\tint schema_handle0;\n";
8035
8036         // generate the declaration of all the variables related to
8037         // temp tuples generation
8038         ret += gen_decl_temp_vars();
8039
8040
8041 //                      unpacked attribute storage, offsets
8042         ret += "//\t\tstorage and offsets of accessed fields.\n";
8043         ret += generate_access_vars(cid_set,schema);
8044 //                      tuple metadata management
8045         ret += "\tint tuple_metadata_offset0;\n";
8046
8047 //                      Variables to store results of partial functions.
8048 //                      WARNING find_partial_functions modifies the SE
8049 //                      (it marks the partial function id).
8050         ret += "//\t\tParital function result storage\n";
8051         vector<scalarexp_t *> partial_fcns;
8052         vector<int> fcn_ref_cnt;
8053         vector<bool> is_partial_fcn;
8054         for(s=0;s<select_list.size();s++){
8055                 find_partial_fcns(select_list[s]->se, &partial_fcns,&fcn_ref_cnt,&is_partial_fcn, Ext_fcns);
8056         }
8057         for(w=0;w<where.size();w++){
8058                 find_partial_fcns_pr(where[w]->pr, &partial_fcns, &fcn_ref_cnt,&is_partial_fcn,Ext_fcns);
8059         }
8060 //              Unmark non-partial expensive functions referenced only once.
8061         for(p=0; p<partial_fcns.size();p++){
8062                 if(!is_partial_fcn[p] && fcn_ref_cnt[p] <= 1){
8063                         partial_fcns[p]->set_partial_ref(-1);
8064                 }
8065         }
8066         if(partial_fcns.size()>0){
8067           ret += generate_partial_fcn_vars(partial_fcns,fcn_ref_cnt,is_partial_fcn,true);
8068         }
8069
8070 //                      Complex literals (i.e., they need constructors)
8071         ret += "//\t\tComplex literal storage.\n";
8072         cplx_lit_table *complex_literals = this->get_cplx_lit_tbl(Ext_fcns);
8073         ret += generate_complex_lit_vars(complex_literals);
8074
8075 //                      Pass-by-handle parameters
8076         ret += "//\t\tPass-by-handle storage.\n";
8077         vector<handle_param_tbl_entry *> param_handle_table = this->get_handle_param_tbl(Ext_fcns);
8078         ret += generate_pass_by_handle_vars(param_handle_table);
8079
8080 //                      Variables to hold parameters
8081         ret += "//\tfor query parameters\n";
8082         ret += generate_param_vars(param_tbl);
8083
8084
8085 //                      The publicly exposed functions
8086
8087         ret += "\npublic:\n";
8088
8089
8090 //-------------------
8091 //                      The functor constructor
8092 //                      pass in the schema handle.
8093 //                      1) make assignments to the unpack offset variables
8094 //                      2) initialize the complex literals
8095 //                      3) Set the initial values of the temporal attributes
8096 //                              referenced in select clause (in case we need to emit
8097 //                              temporal tuple before receiving first tuple )
8098
8099         ret += "//\t\tFunctor constructor.\n";
8100         ret +=  this->generate_functor_name()+"(int schema_handle0){\n";
8101
8102 //              save schema handle
8103         ret += "this->schema_handle0 = schema_handle0;\n";
8104
8105 //              unpack vars
8106         ret += "//\t\tGet offsets for unpacking fields from input tuple.\n";
8107         ret += gen_access_var_init(cid_set);
8108 //              tuple metadata
8109         ret += "\ttuple_metadata_offset0 = ftaschema_get_tuple_metadata_offset(schema_handle0);\n";
8110
8111 //              complex literals
8112         ret += "//\t\tInitialize complex literals.\n";
8113         ret += gen_complex_lit_init(complex_literals);
8114
8115 //              Initialize partial function results so they can be safely GC'd
8116         ret += gen_partial_fcn_init(partial_fcns);
8117
8118 //              Initialize non-query-parameter parameter handles
8119         ret += gen_pass_by_handle_init(param_handle_table);
8120
8121 //              Init temporal attributes referenced in select list
8122         ret += gen_init_temp_vars(schema, select_list, NULL);
8123
8124         ret += "};\n\n";
8125
8126
8127 //-------------------
8128 //                      Functor destructor
8129         ret += "//\t\tFunctor destructor.\n";
8130         ret +=  "~"+this->generate_functor_name()+"(){\n";
8131
8132 //              clean up buffer-type complex literals.
8133         ret += gen_complex_lit_dtr(complex_literals);
8134
8135 //                      Deregister the pass-by-handle parameters
8136         ret += "/* register and de-register the pass-by-handle parameters */\n";
8137         ret += gen_pass_by_handle_dtr(param_handle_table);
8138
8139 //                      Reclaim buffer space for partial fucntion results
8140         ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";
8141         ret += gen_partial_fcn_dtr(partial_fcns);
8142
8143
8144 //                      Destroy the parameters, if any need to be destroyed
8145         ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";
8146
8147         ret += "};\n\n";
8148
8149
8150 //-------------------
8151 //                      Parameter manipulation routines
8152         ret += generate_load_param_block(this->generate_functor_name(),
8153                                                                         this->param_tbl,param_handle_table );
8154         ret += generate_delete_param_block(this->generate_functor_name(),
8155                                                                         this->param_tbl,param_handle_table);
8156
8157
8158 //-------------------
8159 //                      Register new parameter block
8160         ret += "int set_param_block(gs_int32_t sz, void* value){\n";
8161           ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";
8162           ret += "\treturn this->load_params_"+this->generate_functor_name()+
8163                                 "(sz, value);\n";
8164         ret += "};\n\n";
8165
8166
8167 //-------------------
8168 //                      The selection predicate.
8169 //                      Unpack variables for 1 cnf element
8170 //                      at a time, return false immediately if the
8171 //                      predicate fails.
8172 //                      optimization : evaluate the cheap cnf elements
8173 //                      first, the expensive ones last.
8174
8175         ret += "bool predicate(host_tuple &tup0){\n";
8176         //              Variables for execution of the function.
8177         ret += "\tgs_int32_t problem = 0;\n";   // return unpack failure
8178 //              Initialize cached function indicators.
8179         for(p=0;p<partial_fcns.size();++p){
8180                 if(fcn_ref_cnt[p]>1){
8181                         ret+="\tfcn_ref_cnt_"+int_to_string(p)+"=0;\n";
8182                 }
8183         }
8184
8185
8186         ret += gen_temp_tuple_check(this->node_name, 0);
8187
8188         if(partial_fcns.size()>0){              // partial fcn access failure
8189           ret += "\tgs_retval_t retval = 0;\n";
8190           ret += "\n";
8191         }
8192
8193 //                      Reclaim buffer space for partial fucntion results
8194         ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";
8195         ret += gen_partial_fcn_dtr(partial_fcns);
8196
8197         col_id_set found_cids;  // colrefs unpacked thus far.
8198         ret += gen_unpack_temp_vars(schema, found_cids, select_list, NULL, needs_xform);
8199
8200 //              For temporal status tuple we don't need to do anything else
8201         ret += "\tif (temp_tuple_received) return false;\n\n";
8202
8203
8204         for(w=0;w<where.size();++w){
8205                 sprintf(tmpstr,"//\t\tPredicate clause %d.\n",w);
8206                 ret += tmpstr;
8207 //                      Find the set of variables accessed in this CNF elem,
8208 //                      but in no previous element.
8209                 col_id_set new_cids;
8210                 get_new_pred_cids(where[w]->pr,found_cids, new_cids, NULL);
8211 //                      Unpack these values.
8212                 ret += gen_unpack_cids(schema, new_cids, "false", needs_xform);
8213 //                      Find partial fcns ref'd in this cnf element
8214                 set<int> pfcn_refs;
8215                 collect_partial_fcns_pr(where[w]->pr, pfcn_refs);
8216                 ret += gen_unpack_partial_fcn(schema,partial_fcns,pfcn_refs,fcn_ref_cnt, is_partial_fcn, "false");
8217
8218                 ret += "\tif( !("+generate_predicate_code(where[w]->pr,schema)+
8219                                 +") ) return(false);\n";
8220         }
8221
8222 //              The partial functions ref'd in the select list
8223 //              must also be evaluated.  If one returns false,
8224 //              then implicitly the predicate is false.
8225         set<int> sl_pfcns;
8226         for(s=0;s<select_list.size();s++){
8227                 collect_partial_fcns(select_list[s]->se, sl_pfcns);
8228         }
8229         if(sl_pfcns.size() > 0)
8230                 ret += "//\t\tUnpack remaining partial fcns.\n";
8231         ret += gen_full_unpack_partial_fcn(schema, partial_fcns, sl_pfcns,
8232                                         fcn_ref_cnt, is_partial_fcn,
8233                                         found_cids, NULL, "false", needs_xform);
8234
8235 //                      Unpack remaining fields
8236         ret += "//\t\tunpack any remaining fields from the input tuple.\n";
8237         ret += gen_remaining_colrefs(schema, cid_set, found_cids, "false", needs_xform);
8238
8239
8240         ret += "\treturn(true);\n";
8241         ret += "};\n\n";
8242
8243
8244 //-------------------
8245 //                      The output tuple function.
8246 //                      Unpack the remaining attributes into
8247 //                      the placeholder variables, unpack the
8248 //                      partial fcn refs, then pack up the tuple.
8249
8250         ret += "host_tuple create_output_tuple() {\n";
8251         ret += "\thost_tuple tup;\n";
8252         ret += "\tgs_retval_t retval = 0;\n";
8253
8254 //                      Unpack any remaining cached functions.
8255         ret += gen_remaining_cached_fcns(schema, partial_fcns, sl_pfcns,
8256                                         fcn_ref_cnt, is_partial_fcn);
8257
8258
8259 //          Now, compute the size of the tuple.
8260
8261 //          Unpack any BUFFER type selections into temporaries
8262 //          so that I can compute their size and not have
8263 //          to recompute their value during tuple packing.
8264 //          I can use regular assignment here because
8265 //          these temporaries are non-persistent.
8266
8267         ret += "//\t\tCompute the size of the tuple.\n";
8268         ret += "//\t\t\tNote: buffer storage packed at the end of the tuple.\n";
8269
8270 //                      Unpack all buffer type selections, to be able to compute their size
8271         ret += gen_buffer_selvars(schema, select_list);
8272
8273 //      The size of the tuple is the size of the tuple struct plus the
8274 //      size of the buffers to be copied in.
8275
8276
8277       ret+="\ttup.tuple_size = sizeof(" + generate_tuple_name( this->get_node_name()) +") + sizeof(gs_uint8_t)";
8278         ret += gen_buffer_selvars_size(select_list,schema);
8279         ret.append(";\n");
8280
8281 //              Allocate tuple data block.
8282         ret += "//\t\tCreate the tuple block.\n";
8283           ret += "\ttup.data = malloc(tup.tuple_size);\n";
8284           ret += "\ttup.heap_resident = true;\n";
8285 //              Mark tuple as regular
8286           ret += "\t*((gs_sp_t )tup.data + sizeof(" + generate_tuple_name( this->get_node_name()) +")) = REGULAR_TUPLE;\n";
8287
8288 //        ret += "\ttup.channel = 0;\n";
8289           ret += "\t"+generate_tuple_name( this->get_node_name())+" *tuple = ("+
8290                                 generate_tuple_name( this->get_node_name())+" *)(tup.data);\n";
8291
8292 //              Start packing.
8293 //                      (Here, offsets are hard-wired.  is this a problem?)
8294
8295         ret += "//\t\tPack the fields into the tuple.\n";
8296         ret += gen_pack_tuple(schema,select_list,this->get_node_name(), false );
8297
8298 //                      Delete string temporaries
8299         ret += gen_buffer_selvars_dtr(select_list);
8300
8301         ret += "\treturn tup;\n";
8302         ret += "};\n";
8303
8304 //-------------------------------------------------------------------
8305 //              Temporal update functions
8306
8307         ret += "bool temp_status_received(){return temp_tuple_received;};\n\n";
8308
8309
8310 //              create a temp status tuple
8311         ret += "int create_temp_status_tuple(host_tuple& result) {\n\n";
8312
8313         ret += gen_init_temp_status_tuple(this->get_node_name());
8314
8315 //              Start packing.
8316 //                      (Here, offsets are hard-wired.  is this a problem?)
8317
8318         ret += "//\t\tPack the fields into the tuple.\n";
8319         ret += gen_pack_tuple(schema,select_list,this->get_node_name(), true );
8320
8321         ret += "\treturn 0;\n";
8322         ret += "};};\n\n";
8323
8324         return(ret);
8325 }
8326
8327
8328 string spx_qpn::generate_operator(int i, string params){
8329
8330                 return("        select_project_operator<" +
8331                 generate_functor_name() +
8332                 "> *op"+int_to_string(i)+" = new select_project_operator<"+
8333                 generate_functor_name() +">("+params+", \"" + get_node_name() + "\");\n");
8334 }
8335
8336
8337 ////////////////////////////////////////////////////////////////
8338 ////    SGAH functor
8339
8340
8341
8342 string sgah_qpn::generate_functor_name(){
8343         return("sgah_functor_" + normalize_name(this->get_node_name()));
8344 }
8345
8346
8347 string sgah_qpn::generate_functor(table_list *schema, ext_fcn_list *Ext_fcns, vector<bool> &needs_xform){
8348         int a,g,w,s;
8349
8350
8351 //                      Initialize generate utility globals
8352         segen_gb_tbl = &(gb_tbl);
8353
8354 //              Might need to generate empty values for cube processing.
8355         map<int, string> structured_types;
8356         for(g=0;g<gb_tbl.size();++g){
8357                 if(gb_tbl.get_data_type(g)->is_structured_type()){
8358                         structured_types[gb_tbl.get_data_type(g)->type_indicator()] = gb_tbl.get_data_type(g)->get_type_str();
8359                 }
8360         }
8361
8362 //--------------------------------
8363 //                      group definition class
8364         string ret = "class " + generate_functor_name() + "_groupdef{\n";
8365         ret += "public:\n";
8366         for(g=0;g<this->gb_tbl.size();g++){
8367                 sprintf(tmpstr,"gb_var%d",g);
8368                 ret+="\t"+this->gb_tbl.get_data_type(g)->make_host_cvar(tmpstr)+";\n";
8369         }
8370 //              empty strucutred literals
8371         map<int, string>::iterator sii;
8372         for(sii=structured_types.begin();sii!=structured_types.end();++sii){
8373                 data_type dt(sii->second);
8374                 literal_t empty_lit(sii->first);
8375                 ret += "\t"+dt.make_host_cvar(empty_lit.hfta_empty_literal_name())+";\n";
8376         }
8377 //              Constructors
8378         if(structured_types.size()==0){
8379                 ret += "\t"+generate_functor_name() + "_groupdef(){};\n";
8380         }else{
8381                 ret += "\t"+generate_functor_name() + "_groupdef(){}\n";
8382         }
8383
8384
8385         ret += "\t"+generate_functor_name() + "_groupdef("+
8386                 this->generate_functor_name() + "_groupdef *gd){\n";
8387         for(g=0;g<gb_tbl.size();g++){
8388                 data_type *gdt = gb_tbl.get_data_type(g);
8389                 if(gdt->is_buffer_type()){
8390                         sprintf(tmpstr,"\t\t%s(&gb_var%d, &(gd->gb_var%d));\n",
8391                           gdt->get_hfta_buffer_assign_copy().c_str(),g,g );
8392                         ret += tmpstr;
8393                 }else{
8394                         sprintf(tmpstr,"\t\tgb_var%d = gd->gb_var%d;\n",g,g);
8395                         ret += tmpstr;
8396                 }
8397         }
8398         ret += "\t}\n";
8399         ret += "\t"+generate_functor_name() + "_groupdef("+
8400                 this->generate_functor_name() + "_groupdef *gd, bool *pattern){\n";
8401         for(sii=structured_types.begin();sii!=structured_types.end();++sii){
8402                 literal_t empty_lit(sii->first);
8403                 ret += "\t\t"+empty_lit.to_hfta_C_code("&"+empty_lit.hfta_empty_literal_name())+";\n";
8404         }
8405         for(g=0;g<gb_tbl.size();g++){
8406                 data_type *gdt = gb_tbl.get_data_type(g);
8407                 ret += "\t\tif(pattern["+int_to_string(g)+"]){\n";
8408                 if(gdt->is_buffer_type()){
8409                         sprintf(tmpstr,"\t\t\t%s(&gb_var%d, &(gd->gb_var%d));\n",
8410                           gdt->get_hfta_buffer_assign_copy().c_str(),g,g );
8411                         ret += tmpstr;
8412                 }else{
8413                         sprintf(tmpstr,"\t\t\tgb_var%d = gd->gb_var%d;\n",g,g);
8414                         ret += tmpstr;
8415                 }
8416                 ret += "\t\t}else{\n";
8417                 literal_t empty_lit(gdt->type_indicator());
8418                 if(empty_lit.is_cpx_lit()){
8419                         ret +="\t\t\tgb_var"+int_to_string(g)+"= "+empty_lit.hfta_empty_literal_name()+";\n";
8420                 }else{
8421                         ret +="\t\t\tgb_var"+int_to_string(g)+"="+empty_lit.to_hfta_C_code("")+";\n";
8422                 }
8423                 ret += "\t\t}\n";
8424         }
8425         ret += "\t};\n";
8426 //              destructor
8427         ret += "\t~"+ generate_functor_name() + "_groupdef(){\n";
8428         for(g=0;g<gb_tbl.size();g++){
8429                 data_type *gdt = gb_tbl.get_data_type(g);
8430                 if(gdt->is_buffer_type()){
8431                         sprintf(tmpstr,"\t\t%s(&gb_var%d);\n",
8432                           gdt->get_hfta_buffer_destroy().c_str(), g );
8433                         ret += tmpstr;
8434                 }
8435         }
8436         ret += "\t};\n";
8437
8438         data_type *tgdt;
8439         for(g=0;g<gb_tbl.size();g++){
8440                 data_type *gdt = gb_tbl.get_data_type(g);
8441                 if(gdt->is_temporal()){
8442                         tgdt = gdt;
8443                         break;
8444                 }
8445         }
8446         ret += tgdt->get_host_cvar_type()+" get_curr_gb(){\n";
8447         ret+="\treturn gb_var"+int_to_string(g)+";\n";
8448         ret+="}\n";
8449
8450         ret +="};\n\n";
8451
8452 //--------------------------------
8453 //                      aggr definition class
8454         ret += "class " + this->generate_functor_name() + "_aggrdef{\n";
8455         ret += "public:\n";
8456         for(a=0;a<aggr_tbl.size();a++){
8457                 aggr_table_entry *ate = aggr_tbl.agr_tbl[a];
8458                 sprintf(tmpstr,"aggr_var%d",a);
8459                 if(aggr_tbl.is_builtin(a)){
8460                   ret+="\t"+ aggr_tbl.get_data_type(a)->make_host_cvar(tmpstr)+";\n";
8461                   if(aggr_tbl.get_op(a) == "AVG"){      // HACK!
8462                         data_type cnt_type = data_type("ullong");
8463                         ret+="\t"+cnt_type.make_host_cvar(string(tmpstr)+"_cnt")+";\n";
8464                         ret+="\t"+ aggr_tbl.get_data_type(a)->make_host_cvar(string(tmpstr)+"_sum")+";\n";
8465                   }
8466                 }else{
8467                   ret+="\t"+ aggr_tbl.get_storage_type(a)->make_host_cvar(tmpstr)+";\n";
8468                 }
8469         }
8470 //              Constructors
8471         ret += "\t"+this->generate_functor_name() + "_aggrdef(){};\n";
8472 //              destructor
8473         ret += "\t~"+this->generate_functor_name() + "_aggrdef(){\n";
8474         for(a=0;a<aggr_tbl.size();a++){
8475                 if(aggr_tbl.is_builtin(a)){
8476                         data_type *adt = aggr_tbl.get_data_type(a);
8477                         if(adt->is_buffer_type()){
8478                                 sprintf(tmpstr,"\t\t%s(&aggr_var%d);\n",
8479                                 adt->get_hfta_buffer_destroy().c_str(), a );
8480                                 ret += tmpstr;
8481                         }
8482                 }else{
8483                         ret+="\t\t"+aggr_tbl.get_op(a)+"_HFTA_AGGR_DESTROY_(";
8484                         if(aggr_tbl.get_storage_type(a)->get_type() != fstring_t) ret+="&";
8485                         ret+="(aggr_var"+int_to_string(a)+"));\n";
8486                 }
8487         }
8488         ret += "\t};\n";
8489         ret +="};\n\n";
8490
8491 //-------------------------------------------
8492 //              group-by patterns for the functor,
8493 //              initialization within the class is cumbersome.
8494         int n_patterns = gb_tbl.gb_patterns.size();
8495         int i,j;
8496         ret += "bool "+this->generate_functor_name()+"_gb_patterns["+int_to_string(n_patterns)+
8497                         "]["+int_to_string(gb_tbl.size())+"] = {\n";
8498         if(n_patterns == 0){
8499                 for(i=0;i<gb_tbl.size();++i){
8500                         if(i>0) ret += ",";
8501                         ret += "true";
8502                 }
8503         }else{
8504                 for(i=0;i<n_patterns;++i){
8505                         if(i>0) ret += ",\n";
8506                         ret += "\t{";
8507                         for(j=0;j<gb_tbl.size();j++){
8508                                 if(j>0) ret += ", ";
8509                                 if(gb_tbl.gb_patterns[i][j]){
8510                                         ret += "true";
8511                                 }else{
8512                                         ret += "false";
8513                                 }
8514                         }
8515                         ret += "}";
8516                 }
8517                 ret += "\n";
8518         }
8519         ret += "};\n";
8520
8521
8522 //--------------------------------
8523 //                      gb functor class
8524         ret += "class " + this->generate_functor_name() + "{\n";
8525
8526 //                      Find variables referenced in this query node.
8527
8528   col_id_set cid_set;
8529   col_id_set::iterator csi;
8530
8531     for(w=0;w<where.size();++w)
8532         gather_pr_col_ids(where[w]->pr,cid_set,segen_gb_tbl);
8533     for(w=0;w<having.size();++w)
8534         gather_pr_col_ids(having[w]->pr,cid_set,segen_gb_tbl);
8535         for(g=0;g<gb_tbl.size();g++)
8536                 gather_se_col_ids(gb_tbl.get_def(g),cid_set,segen_gb_tbl);
8537
8538     for(s=0;s<select_list.size();s++){
8539         gather_se_col_ids(select_list[s]->se,cid_set,segen_gb_tbl);     // descends into aggregates
8540     }
8541
8542
8543 //                      Private variables : store the state of the functor.
8544 //                      1) variables for unpacked attributes
8545 //                      2) offsets of the upacked attributes
8546 //                      3) storage of partial functions
8547 //                      4) storage of complex literals (i.e., require a constructor)
8548
8549         ret += "private:\n";
8550
8551         // var to save the schema handle
8552         ret += "\tint schema_handle0;\n";
8553         // metadata from schema handle
8554         ret += "\tint tuple_metadata_offset0;\n";
8555
8556         // generate the declaration of all the variables related to
8557         // temp tuples generation
8558         ret += gen_decl_temp_vars();
8559
8560 //                      unpacked attribute storage, offsets
8561         ret += "//\t\tstorage and offsets of accessed fields.\n";
8562         ret += generate_access_vars(cid_set, schema);
8563
8564 //                      Variables to store results of partial functions.
8565 //                      WARNING find_partial_functions modifies the SE
8566 //                      (it marks the partial function id).
8567         ret += "//\t\tParital function result storage\n";
8568         vector<scalarexp_t *> partial_fcns;
8569         vector<int> fcn_ref_cnt;
8570         vector<bool> is_partial_fcn;
8571         for(s=0;s<select_list.size();s++){
8572                 find_partial_fcns(select_list[s]->se, &partial_fcns,NULL,NULL,  Ext_fcns);
8573         }
8574         for(w=0;w<where.size();w++){
8575                 find_partial_fcns_pr(where[w]->pr, &partial_fcns,NULL,NULL,  Ext_fcns);
8576         }
8577         for(w=0;w<having.size();w++){
8578                 find_partial_fcns_pr(having[w]->pr, &partial_fcns,NULL,NULL,  Ext_fcns);
8579         }
8580         for(g=0;g<gb_tbl.size();g++){
8581                 find_partial_fcns(gb_tbl.get_def(g), &partial_fcns,NULL,NULL,  Ext_fcns);
8582         }
8583         for(a=0;a<aggr_tbl.size();a++){
8584                 find_partial_fcns(aggr_tbl.get_aggr_se(a), &partial_fcns,NULL,NULL,  Ext_fcns);
8585         }
8586         if(partial_fcns.size()>0){
8587           ret += "/*\t\tVariables for storing results of partial functions. \t*/\n";
8588           ret += generate_partial_fcn_vars(partial_fcns,fcn_ref_cnt,is_partial_fcn,false);
8589         }
8590
8591 //                      Complex literals (i.e., they need constructors)
8592         ret += "//\t\tComplex literal storage.\n";
8593         cplx_lit_table *complex_literals = this->get_cplx_lit_tbl(Ext_fcns);
8594         ret += generate_complex_lit_vars(complex_literals);
8595
8596 //                      Pass-by-handle parameters
8597         ret += "//\t\tPass-by-handle storage.\n";
8598         vector<handle_param_tbl_entry *> param_handle_table = this->get_handle_param_tbl(Ext_fcns);
8599         ret += generate_pass_by_handle_vars(param_handle_table);
8600
8601
8602 //                      variables to hold parameters.
8603         ret += "//\tfor query parameters\n";
8604         ret += generate_param_vars(param_tbl);
8605
8606 //              Is there a temporal flush?  If so create flush temporaries,
8607 //              create flush indicator.
8608         bool uses_temporal_flush = false;
8609         for(g=0;g<gb_tbl.size();g++){
8610                 data_type *gdt = gb_tbl.get_data_type(g);
8611                 if(gdt->is_temporal())
8612                         uses_temporal_flush = true;
8613         }
8614
8615         if(uses_temporal_flush){
8616                 ret += "//\t\tFor temporal flush\n";
8617                 for(g=0;g<gb_tbl.size();g++){
8618                         data_type *gdt = gb_tbl.get_data_type(g);
8619                         if(gdt->is_temporal()){
8620                           sprintf(tmpstr,"last_gb%d",g);
8621                           ret+="\t"+gb_tbl.get_data_type(g)->make_host_cvar(tmpstr)+";\n";
8622                           sprintf(tmpstr,"last_flushed_gb%d",g);
8623                           ret+="\t"+gb_tbl.get_data_type(g)->make_host_cvar(tmpstr)+";\n";
8624                         }
8625                 }
8626                 ret += "\tbool needs_temporal_flush;\n";
8627         }
8628
8629
8630 //                      The publicly exposed functions
8631
8632         ret += "\npublic:\n";
8633
8634
8635 //-------------------
8636 //                      The functor constructor
8637 //                      pass in the schema handle.
8638 //                      1) make assignments to the unpack offset variables
8639 //                      2) initialize the complex literals
8640
8641         ret += "//\t\tFunctor constructor.\n";
8642         ret +=  this->generate_functor_name()+"(int schema_handle0){\n";
8643
8644         // save the schema handle
8645         ret += "\t\tthis->schema_handle0 = schema_handle0;\n";
8646
8647 //              unpack vars
8648         ret += "//\t\tGet offsets for unpacking fields from input tuple.\n";
8649         ret += gen_access_var_init(cid_set);
8650 //              tuple metadata
8651         ret += "tuple_metadata_offset0 = ftaschema_get_tuple_metadata_offset(schema_handle0);\n";
8652
8653 //              complex literals
8654         ret += "//\t\tInitialize complex literals.\n";
8655         ret += gen_complex_lit_init(complex_literals);
8656
8657 //              Initialize partial function results so they can be safely GC'd
8658         ret += gen_partial_fcn_init(partial_fcns);
8659
8660 //              Initialize non-query-parameter parameter handles
8661         ret += gen_pass_by_handle_init(param_handle_table);
8662
8663 //              temporal flush variables
8664 //              ASSUME that structured values won't be temporal.
8665         if(uses_temporal_flush){
8666                 ret += "//\t\tInitialize temporal flush variables.\n";
8667                 for(g=0;g<gb_tbl.size();g++){
8668                         data_type *gdt = gb_tbl.get_data_type(g);
8669                         if(gdt->is_temporal()){
8670                                 literal_t gl(gdt->type_indicator());
8671                                 sprintf(tmpstr,"\tlast_gb%d = %s;\n",g, gl.to_hfta_C_code("").c_str());
8672                                 ret.append(tmpstr);
8673                                 sprintf(tmpstr,"\tlast_flushed_gb%d = %s;\n",g, gl.to_hfta_C_code("").c_str());
8674                                 ret.append(tmpstr);
8675                         }
8676                 }
8677                 ret += "\tneeds_temporal_flush = false;\n";
8678         }
8679
8680         //              Init temporal attributes referenced in select list
8681         ret += gen_init_temp_vars(schema, select_list, segen_gb_tbl);
8682
8683         ret += "}\n\n";
8684
8685 //-------------------
8686 //                      Functor destructor
8687         ret += "//\t\tFunctor destructor.\n";
8688         ret +=  "~"+this->generate_functor_name()+"(){\n";
8689
8690 //                      clean up buffer type complex literals
8691         ret += gen_complex_lit_dtr(complex_literals);
8692
8693 //                      Deregister the pass-by-handle parameters
8694         ret += "/* register and de-register the pass-by-handle parameters */\n";
8695         ret += gen_pass_by_handle_dtr(param_handle_table);
8696
8697 //                      clean up partial function results.
8698         ret += "/* clean up partial function storage    */\n";
8699         ret += gen_partial_fcn_dtr(partial_fcns);
8700
8701 //                      Destroy the parameters, if any need to be destroyed
8702         ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";
8703
8704         ret += "};\n\n";
8705
8706
8707 //-------------------
8708 //                      Parameter manipulation routines
8709         ret += generate_load_param_block(this->generate_functor_name(),
8710                                                                         this->param_tbl,param_handle_table);
8711         ret += generate_delete_param_block(this->generate_functor_name(),
8712                                                                         this->param_tbl,param_handle_table);
8713
8714 //-------------------
8715 //                      Register new parameter block
8716
8717         ret += "int set_param_block(gs_int32_t sz, void* value){\n";
8718           ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";
8719           ret += "\treturn this->load_params_"+this->generate_functor_name()+
8720                                 "(sz, value);\n";
8721         ret += "};\n\n";
8722
8723 // -----------------------------------
8724 //                      group-by pattern support
8725
8726         ret +=
8727 "int n_groupby_patterns(){\n"
8728 "       return "+int_to_string(gb_tbl.gb_patterns.size())+";\n"
8729 "}\n"
8730 "bool *get_pattern(int p){\n"
8731 "       return "+this->generate_functor_name()+"_gb_patterns[p];\n"
8732 "}\n\n"
8733 ;
8734
8735
8736
8737
8738 //-------------------
8739 //              the create_group method.
8740 //              This method creates a group in a buffer passed in
8741 //              (to allow for creation on the stack).
8742 //              There are also a couple of side effects:
8743 //              1) evaluate the WHERE clause (and therefore, unpack all partial fcns)
8744 //              2) determine if a temporal flush is required.
8745
8746         ret += this->generate_functor_name()+"_groupdef *create_group(host_tuple &tup0, gs_sp_t buffer){\n";
8747         //              Variables for execution of the function.
8748         ret += "\tgs_int32_t problem = 0;\n";   // return unpack failure
8749
8750         if(partial_fcns.size()>0){              // partial fcn access failure
8751           ret += "\tgs_retval_t retval = 0;\n";
8752           ret += "\n";
8753         }
8754 //              return value
8755         ret += "\t"+generate_functor_name()+"_groupdef *gbval = ("+generate_functor_name()+
8756                         "_groupdef *) buffer;\n";
8757
8758 //              Start by cleaning up partial function results
8759         ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";
8760         set<int> w_pfcns;       // partial fcns in where clause
8761         for(w=0;w<where.size();++w)
8762                 collect_partial_fcns_pr(where[w]->pr, w_pfcns);
8763
8764         set<int> ag_gb_pfcns;   // partial fcns in gbdefs, aggr se's
8765         for(g=0;g<gb_tbl.size();g++){
8766                 collect_partial_fcns(gb_tbl.get_def(g), ag_gb_pfcns);
8767         }
8768         for(a=0;a<aggr_tbl.size();a++){
8769                 collect_partial_fcns(aggr_tbl.get_aggr_se(a), ag_gb_pfcns);
8770         }
8771         ret += gen_partial_fcn_dtr(partial_fcns,w_pfcns);
8772         ret += gen_partial_fcn_dtr(partial_fcns,ag_gb_pfcns);
8773 //      ret += gen_partial_fcn_dtr(partial_fcns);
8774
8775
8776         ret += gen_temp_tuple_check(this->node_name, 0);
8777         col_id_set found_cids;  // colrefs unpacked thus far.
8778         ret += gen_unpack_temp_vars(schema, found_cids, select_list, segen_gb_tbl, needs_xform);
8779
8780
8781 //                      Save temporal group-by variables
8782
8783
8784         ret.append("\n\t//\t\tCompute temporal groupby attributes\n\n");
8785
8786           for(g=0;g<gb_tbl.size();g++){
8787
8788                         data_type *gdt = gb_tbl.get_data_type(g);
8789
8790                         if(gdt->is_temporal()){
8791                                 sprintf(tmpstr,"\tgbval->gb_var%d = %s;\n",
8792                                         g, generate_se_code(gb_tbl.get_def(g),schema).c_str() );
8793                                 ret.append(tmpstr);
8794                         }
8795                 }
8796                 ret.append("\n");
8797
8798
8799
8800 //                      Compare the temporal GB vars with the stored ones,
8801 //                      set flush indicator and update stored GB vars if there is any change.
8802
8803 ret += "// hfta_disorder = "+int_to_string(hfta_disorder)+"\n";
8804         if(hfta_disorder < 2){
8805                 if(uses_temporal_flush){
8806                         ret+= "\tif( !( (";
8807                         bool first_one = true;
8808                         for(g=0;g<gb_tbl.size();g++){
8809                                 data_type *gdt = gb_tbl.get_data_type(g);
8810
8811                                 if(gdt->is_temporal()){
8812                                 sprintf(tmpstr,"last_gb%d",g);   string lhs_op = tmpstr;
8813                                 sprintf(tmpstr,"gbval->gb_var%d",g);   string rhs_op = tmpstr;
8814                                 if(first_one){first_one = false;} else {ret += ") && (";}
8815                                 ret += generate_equality_test(lhs_op, rhs_op, gdt);
8816                                 }
8817                         }
8818                         ret += ") ) ){\n";
8819                         for(g=0;g<gb_tbl.size();g++){
8820                         data_type *gdt = gb_tbl.get_data_type(g);
8821                         if(gdt->is_temporal()){
8822                                 if(gdt->is_buffer_type()){
8823                                         sprintf(tmpstr,"\t\t%s(&(gbval->gb_var%d),&last_gb%d);\n",gdt->get_hfta_buffer_replace().c_str(),g,g);
8824                                 }else{
8825                                         sprintf(tmpstr,"\t\tlast_flushed_gb%d = last_gb%d;\n",g,g);
8826                                         ret += tmpstr;
8827                                         sprintf(tmpstr,"\t\tlast_gb%d = gbval->gb_var%d;\n",g,g);
8828                                 }
8829                                 ret += tmpstr;
8830                                 }
8831                         }
8832                         ret += "\t\tneeds_temporal_flush=true;\n";
8833                         ret += "\t\t}else{\n"
8834                                 "\t\t\tneeds_temporal_flush=false;\n"
8835                                 "\t\t}\n";
8836                 }
8837         }else{
8838                 ret+= "\tif(temp_tuple_received && !( (";
8839                 bool first_one = true;
8840                 for(g=0;g<gb_tbl.size();g++){
8841                         data_type *gdt = gb_tbl.get_data_type(g);
8842
8843                         if(gdt->is_temporal()){
8844                                 sprintf(tmpstr,"last_gb%d",g);   string lhs_op = tmpstr;
8845                                 sprintf(tmpstr,"gbval->gb_var%d",g);   string rhs_op = tmpstr;
8846                                 if(first_one){first_one = false;} else {ret += ") && (";}
8847                                 ret += generate_equality_test(lhs_op, rhs_op, gdt);
8848                                 break;
8849                         }
8850                 }
8851                 ret += ") ) ){\n";
8852                 int temporal_g = 0;
8853                 for(g=0;g<gb_tbl.size();g++){
8854                         data_type *gdt = gb_tbl.get_data_type(g);
8855                         if(gdt->is_temporal()){
8856                                 temporal_g = g;
8857                                 if(gdt->is_buffer_type()){
8858                                         sprintf(tmpstr,"\t\t%s(&(gbval->gb_var%d),&last_gb%d);\n",gdt->get_hfta_buffer_replace().c_str(),g,g);
8859                                 }else{
8860                                         sprintf(tmpstr,"\t\tlast_flushed_gb%d = last_gb%d;\n",g,g);
8861                                         ret += tmpstr;
8862                                         sprintf(tmpstr,"\t\tlast_gb%d = gbval->gb_var%d;\n",g,g);
8863                                 }
8864                                 ret += tmpstr;
8865                                 break;
8866                         }
8867                 }
8868                 data_type *tgdt = gb_tbl.get_data_type(temporal_g);
8869                 literal_t gl(tgdt->type_indicator());
8870                 ret += "\t\tif(last_flushed_gb"+int_to_string(temporal_g)+">"+gl.to_hfta_C_code("")+")\n";
8871                 ret += "\t\t\tneeds_temporal_flush=true;\n";
8872                 ret += "\t\t}else{\n"
8873                         "\t\t\tneeds_temporal_flush=false;\n"
8874                         "\t\t}\n";
8875         }
8876
8877
8878 //              For temporal status tuple we don't need to do anything else
8879         ret += "\tif (temp_tuple_received) return NULL;\n\n";
8880
8881         for(w=0;w<where.size();++w){
8882                 sprintf(tmpstr,"//\t\tPredicate clause %d.\n",w);
8883                 ret += tmpstr;
8884 //                      Find the set of variables accessed in this CNF elem,
8885 //                      but in no previous element.
8886                 col_id_set new_cids;
8887                 get_new_pred_cids(where[w]->pr, found_cids, new_cids, segen_gb_tbl);
8888
8889 //                      Unpack these values.
8890                 ret += gen_unpack_cids(schema, new_cids, "NULL", needs_xform);
8891 //                      Find partial fcns ref'd in this cnf element
8892                 set<int> pfcn_refs;
8893                 collect_partial_fcns_pr(where[w]->pr, pfcn_refs);
8894                 ret += gen_unpack_partial_fcn(schema, partial_fcns, pfcn_refs,"NULL");
8895
8896                 ret += "\tif( !("+generate_predicate_code(where[w]->pr,schema)+
8897                                 +") ) return(NULL);\n";
8898         }
8899
8900 //              The partial functions ref'd in the group-by var and aggregate
8901 //              definitions must also be evaluated.  If one returns false,
8902 //              then implicitly the predicate is false.
8903         set<int>::iterator pfsi;
8904
8905         if(ag_gb_pfcns.size() > 0)
8906                 ret += "//\t\tUnpack remaining partial fcns.\n";
8907         ret += gen_full_unpack_partial_fcn(schema, partial_fcns, ag_gb_pfcns,
8908                                                                                 found_cids, segen_gb_tbl, "NULL", needs_xform);
8909
8910 //                      Unpack the group-by variables
8911
8912           for(g=0;g<gb_tbl.size();g++){
8913                 data_type *gdt = gb_tbl.get_data_type(g);
8914
8915                 if(!gdt->is_temporal()){
8916 //                      Find the new fields ref'd by this GBvar def.
8917                         col_id_set new_cids;
8918                         get_new_se_cids(gb_tbl.get_def(g), found_cids, new_cids, segen_gb_tbl);
8919 //                      Unpack these values.
8920                         ret += gen_unpack_cids(schema, new_cids, "NULL", needs_xform);
8921
8922                         sprintf(tmpstr,"\tgbval->gb_var%d = %s;\n",
8923                                 g, generate_se_code(gb_tbl.get_def(g),schema).c_str() );
8924 /*
8925 //                              There seems to be no difference between the two
8926 //                              branches of the IF statement.
8927                 data_type *gdt = gb_tbl.get_data_type(g);
8928                   if(gdt->is_buffer_type()){
8929 //                              Create temporary copy.
8930                         sprintf(tmpstr,"\tgbval->gb_var%d = %s;\n",
8931                                 g, generate_se_code(gb_tbl.get_def(g),schema).c_str() );
8932                   }else{
8933                         scalarexp_t *gse = gb_tbl.get_def(g);
8934                         sprintf(tmpstr,"\tgbval->gb_var%d = %s;\n",
8935                                         g,generate_se_code(gse,schema).c_str());
8936                   }
8937 */
8938
8939                         ret.append(tmpstr);
8940                 }
8941           }
8942           ret.append("\n");
8943
8944         ret+= "\treturn gbval;\n";
8945         ret += "};\n\n\n";
8946
8947 //--------------------------------------------------------
8948 //                      Create and initialize an aggregate object
8949
8950         ret += this->generate_functor_name()+"_aggrdef *create_aggregate(host_tuple &tup0, gs_sp_t buffer){\n";
8951         //              Variables for execution of the function.
8952         ret += "\tgs_int32_t problem = 0;\n";   // return unpack failure
8953
8954 //              return value
8955         ret += "\t"+generate_functor_name()+"_aggrdef *aggval = ("+generate_functor_name()+
8956                         "_aggrdef *)buffer;\n";
8957
8958         for(a=0;a<aggr_tbl.size();a++){
8959                 if(aggr_tbl.is_builtin(a)){
8960 //                      Create temporaries for buffer return values
8961                   data_type *adt = aggr_tbl.get_data_type(a);
8962                   if(adt->is_buffer_type()){
8963                         sprintf(tmpstr,"aggr_tmp_%d", a);
8964                         ret+=adt->make_host_cvar(tmpstr)+";\n";
8965                   }
8966                 }
8967         }
8968
8969 //              Unpack all remaining attributes
8970         ret += gen_remaining_colrefs(schema, cid_set, found_cids, "NULL", needs_xform);
8971         for(a=0;a<aggr_tbl.size();a++){
8972           sprintf(tmpstr,"aggval->aggr_var%d",a);
8973           string assignto_var = tmpstr;
8974           ret += "\t"+generate_aggr_init(assignto_var,&aggr_tbl,a, schema);
8975         }
8976
8977         ret += "\treturn aggval;\n";
8978         ret += "};\n\n";
8979
8980 //--------------------------------------------------------
8981 //                      update an aggregate object
8982
8983         ret += "void update_aggregate(host_tuple &tup0, "
8984                 +generate_functor_name()+"_groupdef *gbval, "+
8985                 generate_functor_name()+"_aggrdef *aggval){\n";
8986         //              Variables for execution of the function.
8987         ret += "\tgs_int32_t problem = 0;\n";   // return unpack failure
8988
8989 //                      use of temporaries depends on the aggregate,
8990 //                      generate them in generate_aggr_update
8991
8992
8993 //              Unpack all remaining attributes
8994         ret += gen_remaining_colrefs(schema, cid_set, found_cids, "", needs_xform);
8995         for(a=0;a<aggr_tbl.size();a++){
8996           sprintf(tmpstr,"aggval->aggr_var%d",a);
8997           string varname = tmpstr;
8998           ret.append(generate_aggr_update(varname,&aggr_tbl,a, schema));
8999         }
9000
9001         ret += "\treturn;\n";
9002         ret += "};\n";
9003
9004 //---------------------------------------------------
9005 //                      Flush test
9006
9007         ret += "\tbool flush_needed(){\n";
9008         if(uses_temporal_flush){
9009                 ret += "\t\treturn needs_temporal_flush;\n";
9010         }else{
9011                 ret += "\t\treturn false;\n";
9012         }
9013         ret += "\t};\n";
9014
9015 //---------------------------------------------------
9016 //                      create output tuple
9017 //                      Unpack the partial functions ref'd in the where clause,
9018 //                      select clause.  Evaluate the where clause.
9019 //                      Finally, pack the tuple.
9020
9021 //                      I need to use special code generation here,
9022 //                      so I'll leave it in longhand.
9023
9024         ret += "host_tuple create_output_tuple("
9025                 +generate_functor_name()+"_groupdef *gbval, "+
9026                 generate_functor_name()+"_aggrdef *aggval, bool &failed){\n";
9027
9028         ret += "\thost_tuple tup;\n";
9029         ret += "\tfailed = false;\n";
9030         ret += "\tgs_retval_t retval = 0;\n";
9031
9032         string gbvar = "gbval->gb_var";
9033         string aggvar = "aggval->";
9034
9035 //                      Create cached temporaries for UDAF return values.
9036         for(a=0;a<aggr_tbl.size();a++){
9037                 if(! aggr_tbl.is_builtin(a)){
9038                         int afcn_id = aggr_tbl.get_fcn_id(a);
9039                         data_type *adt = Ext_fcns->get_fcn_dt(afcn_id);
9040                         sprintf(tmpstr,"udaf_ret_%d", a);
9041                         ret+="\t"+adt->make_host_cvar(tmpstr)+";\n";
9042                 }
9043         }
9044
9045
9046 //                      First, get the return values from the UDAFS
9047         for(a=0;a<aggr_tbl.size();a++){
9048                 if(! aggr_tbl.is_builtin(a)){
9049                         ret += "\t"+aggr_tbl.get_op(a)+"_HFTA_AGGR_OUTPUT_(&(udaf_ret_"+int_to_string(a)+"),";
9050                         if(aggr_tbl.get_storage_type(a)->get_type() != fstring_t) ret+="&";
9051                         ret+="("+aggvar+"aggr_var"+int_to_string(a)+"));\n";
9052                 }
9053         }
9054
9055         set<int> hv_sl_pfcns;
9056         for(w=0;w<having.size();w++){
9057                 collect_partial_fcns_pr(having[w]->pr, hv_sl_pfcns);
9058         }
9059         for(s=0;s<select_list.size();s++){
9060                 collect_partial_fcns(select_list[s]->se, hv_sl_pfcns);
9061         }
9062
9063 //              clean up the partial fcn results from any previous execution
9064         ret += gen_partial_fcn_dtr(partial_fcns,hv_sl_pfcns);
9065
9066 //              Unpack them now
9067         for(pfsi=hv_sl_pfcns.begin();pfsi!=hv_sl_pfcns.end();++pfsi){
9068                 ret += unpack_partial_fcn_fm_aggr(partial_fcns[(*pfsi)], (*pfsi), gbvar, aggvar, schema);
9069                 ret += "\tif(retval){ failed = true; return(tup);}\n";
9070         }
9071
9072 //              Evalaute the HAVING clause
9073 //              TODO: this seems to have a ++ operator rather than a + operator.
9074         for(w=0;w<having.size();++w){
9075                 ret += "\tif( !("+generate_predicate_code_fm_aggr(having[w]->pr,gbvar, aggvar, schema) +") ) { failed = true; return(tup);}\n";
9076         }
9077
9078 //          Now, compute the size of the tuple.
9079
9080 //          Unpack any BUFFER type selections into temporaries
9081 //          so that I can compute their size and not have
9082 //          to recompute their value during tuple packing.
9083 //          I can use regular assignment here because
9084 //          these temporaries are non-persistent.
9085 //                      TODO: should I be using the selvar generation routine?
9086
9087         ret += "//\t\tCompute the size of the tuple.\n";
9088         ret += "//\t\t\tNote: buffer storage packed at the end of the tuple.\n";
9089       for(s=0;s<select_list.size();s++){
9090                 scalarexp_t *se = select_list[s]->se;
9091         data_type *sdt = se->get_data_type();
9092         if(sdt->is_buffer_type() &&
9093                          !( (se->get_operator_type() == SE_COLREF) ||
9094                                 (se->get_operator_type() == SE_AGGR_STAR) ||
9095                                 (se->get_operator_type() == SE_AGGR_SE) ||
9096                            (se->get_operator_type() == SE_FUNC && se->is_partial()) ||
9097                            (se->get_operator_type() == SE_FUNC && se->get_aggr_ref() >= 0))
9098                 ){
9099             sprintf(tmpstr,"selvar_%d",s);
9100                         ret+="\t"+sdt->make_host_cvar(tmpstr)+" = ";
9101                         ret += generate_se_code_fm_aggr(se,gbvar, aggvar, schema) +";\n";
9102         }
9103       }
9104
9105 //      The size of the tuple is the size of the tuple struct plus the
9106 //      size of the buffers to be copied in.
9107
9108       ret+="\ttup.tuple_size = sizeof(" + generate_tuple_name( this->get_node_name()) +") + sizeof(gs_uint8_t)";
9109       for(s=0;s<select_list.size();s++){
9110 //              if(s>0) ret += "+";
9111                 scalarexp_t *se = select_list[s]->se;
9112         data_type *sdt = select_list[s]->se->get_data_type();
9113         if(sdt->is_buffer_type()){
9114                   if(!( (se->get_operator_type() == SE_COLREF) ||
9115                                 (se->get_operator_type() == SE_AGGR_STAR) ||
9116                                 (se->get_operator_type() == SE_AGGR_SE) ||
9117                            (se->get_operator_type() == SE_FUNC && se->is_partial()) ||
9118                            (se->get_operator_type() == SE_FUNC && se->get_aggr_ref() >= 0))
9119                   ){
9120             sprintf(tmpstr," + %s(&selvar_%d)", sdt->get_hfta_buffer_size().c_str(),s);
9121             ret.append(tmpstr);
9122                   }else{
9123             sprintf(tmpstr," + %s(&%s)", sdt->get_hfta_buffer_size().c_str(),generate_se_code_fm_aggr(se,gbvar, aggvar, schema).c_str());
9124             ret.append(tmpstr);
9125                   }
9126         }
9127       }
9128       ret.append(";\n");
9129
9130 //              Allocate tuple data block.
9131         ret += "//\t\tCreate the tuple block.\n";
9132           ret += "\ttup.data = malloc(tup.tuple_size);\n";
9133           ret += "\ttup.heap_resident = true;\n";
9134
9135 //              Mark tuple as regular
9136           ret += "\t*((gs_sp_t )tup.data + sizeof(" + generate_tuple_name( this->get_node_name()) +")) = REGULAR_TUPLE;\n";
9137
9138 //        ret += "\ttup.channel = 0;\n";
9139           ret += "\t"+generate_tuple_name( this->get_node_name())+" *tuple = ("+
9140                                 generate_tuple_name( this->get_node_name())+" *)(tup.data);\n";
9141
9142 //              Start packing.
9143 //                      (Here, offsets are hard-wired.  is this a problem?)
9144
9145         ret += "//\t\tPack the fields into the tuple.\n";
9146           ret += "\tint tuple_pos = sizeof("+generate_tuple_name( this->get_node_name()) +") + sizeof(gs_uint8_t);\n";
9147       for(s=0;s<select_list.size();s++){
9148                 scalarexp_t *se = select_list[s]->se;
9149         data_type *sdt = se->get_data_type();
9150         if(sdt->is_buffer_type()){
9151                   if(!( (se->get_operator_type() == SE_COLREF) ||
9152                                 (se->get_operator_type() == SE_AGGR_STAR) ||
9153                                 (se->get_operator_type() == SE_AGGR_SE) ||
9154                            (se->get_operator_type() == SE_FUNC && se->is_partial()) ||
9155                            (se->get_operator_type() == SE_FUNC && se->get_aggr_ref() >= 0))
9156                   ){
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);
9158             ret.append(tmpstr);
9159             sprintf(tmpstr,"\ttuple_pos += %s(&selvar_%d);\n", sdt->get_hfta_buffer_size().c_str(), s);
9160             ret.append(tmpstr);
9161                   }else{
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());
9163             ret.append(tmpstr);
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());
9165             ret.append(tmpstr);
9166                   }
9167         }else{
9168             sprintf(tmpstr,"\ttuple->tuple_var%d = ",s);
9169             ret.append(tmpstr);
9170             ret.append(generate_se_code_fm_aggr(se,gbvar, aggvar, schema) );
9171             ret.append(";\n");
9172         }
9173       }
9174
9175 //                      Destroy string temporaries
9176           ret += gen_buffer_selvars_dtr(select_list);
9177 //                      Destroy string return vals of UDAFs
9178         for(a=0;a<aggr_tbl.size();a++){
9179                 if(! aggr_tbl.is_builtin(a)){
9180                         int afcn_id = aggr_tbl.get_fcn_id(a);
9181                         data_type *adt = Ext_fcns->get_fcn_dt(afcn_id);
9182                         if(adt->is_buffer_type()){
9183                                 sprintf(tmpstr,"\t%s(&udaf_ret_%d);\n",
9184                                 adt->get_hfta_buffer_destroy().c_str(), a );
9185                                 ret += tmpstr;
9186                         }
9187                 }
9188         }
9189
9190
9191           ret += "\treturn tup;\n";
9192           ret += "};\n";
9193
9194
9195 //-------------------------------------------------------------------
9196 //              Temporal update functions
9197
9198         ret+="bool temp_status_received(){return temp_tuple_received;};\n\n";
9199
9200         for(g=0;g<gb_tbl.size();g++){
9201                 data_type *gdt = gb_tbl.get_data_type(g);
9202                 if(gdt->is_temporal()){
9203                         tgdt = gdt;
9204                         break;
9205                 }
9206         }
9207         ret += tgdt->get_host_cvar_type()+" get_last_flushed_gb(){\n";
9208         ret+="\treturn last_flushed_gb"+int_to_string(g)+";\n";
9209         ret+="}\n";
9210         ret += tgdt->get_host_cvar_type()+" get_last_gb(){\n";
9211         ret+="\treturn last_gb"+int_to_string(g)+";\n";
9212         ret+="}\n";
9213
9214
9215
9216
9217 //              create a temp status tuple
9218         ret += "int create_temp_status_tuple(host_tuple& result, bool flush_finished) {\n\n";
9219
9220         ret += gen_init_temp_status_tuple(this->get_node_name());
9221
9222 //              Start packing.
9223 //                      (Here, offsets are hard-wired.  is this a problem?)
9224
9225         ret += "//\t\tPack the fields into the tuple.\n";
9226         for(s=0;s<select_list.size();s++){
9227                 data_type *sdt = select_list[s]->se->get_data_type();
9228                 if(sdt->is_temporal()){
9229                         sprintf(tmpstr,"\ttuple->tuple_var%d = ",s);
9230                         ret += tmpstr;
9231
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());
9233                         ret += tmpstr;
9234                         ret += ";\n";
9235                 }
9236         }
9237
9238
9239         ret += "\treturn 0;\n";
9240         ret += "};};\n\n\n";
9241
9242
9243 //----------------------------------------------------------
9244 //                      The hash function
9245
9246         ret += "struct "+generate_functor_name()+"_hash_func{\n";
9247         ret += "\tgs_uint32_t operator()(const "+generate_functor_name()+
9248                                 "_groupdef *grp) const{\n";
9249         ret += "\t\treturn( (";
9250         for(g=0;g<gb_tbl.size();g++){
9251                 if(g>0) ret += "^";
9252                 data_type *gdt = gb_tbl.get_data_type(g);
9253                 if(gdt->use_hashfunc()){
9254                         if(gdt->is_buffer_type())
9255                                 sprintf(tmpstr,"(%s*%s(&(grp->gb_var%d)))",hash_nums[g%NRANDS].c_str(),gdt->get_hfta_hashfunc().c_str(),g);
9256                         else
9257                                 sprintf(tmpstr,"(%s*%s(grp->gb_var%d))",hash_nums[g%NRANDS].c_str(),gdt->get_hfta_hashfunc().c_str(),g);
9258                 }else{
9259                         sprintf(tmpstr,"(%s*grp->gb_var%d)",hash_nums[g%NRANDS].c_str(),g);
9260                 }
9261                 ret += tmpstr;
9262         }
9263         ret += ") >> 32);\n";
9264         ret += "\t}\n";
9265         ret += "};\n\n";
9266
9267 //----------------------------------------------------------
9268 //                      The comparison function
9269
9270         ret += "struct "+generate_functor_name()+"_equal_func{\n";
9271         ret += "\tbool operator()(const "+generate_functor_name()+"_groupdef *grp1, "+
9272                         generate_functor_name()+"_groupdef *grp2) const{\n";
9273         ret += "\t\treturn( (";
9274
9275         for(g=0;g<gb_tbl.size();g++){
9276                 if(g>0) ret += ") && (";
9277                 data_type *gdt = gb_tbl.get_data_type(g);
9278                 if(gdt->complex_comparison(gdt)){
9279                 if(gdt->is_buffer_type())
9280                         sprintf(tmpstr,"(%s(&(grp1->gb_var%d), &(grp2->gb_var%d))==0)",
9281                                 gdt->get_hfta_comparison_fcn(gdt).c_str(),g,g);
9282                 else
9283                         sprintf(tmpstr,"(%s((grp1->gb_var%d), (grp2->gb_var%d))==0)",
9284                                 gdt->get_hfta_comparison_fcn(gdt).c_str(),g,g);
9285                 }else{
9286                         sprintf(tmpstr,"grp1->gb_var%d == grp2->gb_var%d",g,g);
9287                 }
9288                 ret += tmpstr;
9289         }
9290         ret += ") );\n";
9291         ret += "\t}\n";
9292         ret += "};\n\n";
9293
9294
9295         return(ret);
9296 }
9297
9298 string sgah_qpn::generate_operator(int i, string params){
9299
9300         if(hfta_disorder < 2){
9301                 return(
9302                         "       groupby_operator<" +
9303                         generate_functor_name()+","+
9304                         generate_functor_name() + "_groupdef, " +
9305                         generate_functor_name() + "_aggrdef, " +
9306                         generate_functor_name()+"_hash_func, "+
9307                         generate_functor_name()+"_equal_func "
9308                         "> *op"+int_to_string(i)+" = new groupby_operator<"+
9309                         generate_functor_name()+","+
9310                         generate_functor_name() + "_groupdef, " +
9311                         generate_functor_name() + "_aggrdef, " +
9312                         generate_functor_name()+"_hash_func, "+
9313                         generate_functor_name()+"_equal_func "
9314                         ">("+params+", \"" + get_node_name() +
9315 "\");\n"
9316                 );
9317         }
9318         data_type *tgdt;
9319         for(int g=0;g<gb_tbl.size();g++){
9320                 data_type *gdt = gb_tbl.get_data_type(g);
9321                 if(gdt->is_temporal()){
9322                         tgdt = gdt;
9323                         break;
9324                 }
9325         }
9326
9327         return(
9328                         "       groupby_operator_oop<" +
9329                         generate_functor_name()+","+
9330                         generate_functor_name() + "_groupdef, " +
9331                         generate_functor_name() + "_aggrdef, " +
9332                         generate_functor_name()+"_hash_func, "+
9333                         generate_functor_name()+"_equal_func, " +
9334             tgdt->get_host_cvar_type() +
9335                         "> *op"+int_to_string(i)+" = new groupby_operator_oop<"+
9336                         generate_functor_name()+","+
9337                         generate_functor_name() + "_groupdef, " +
9338                         generate_functor_name() + "_aggrdef, " +
9339                         generate_functor_name()+"_hash_func, "+
9340                         generate_functor_name()+"_equal_func, " +
9341             tgdt->get_host_cvar_type() +
9342                         ">("+params+", \"" + get_node_name() +
9343 "\");\n"
9344                 );
9345 }
9346
9347
9348 ////////////////////////////////////////////////
9349 ///             MERGE operator
9350 ///             MRG functor
9351 ////////////////////////////////////////////
9352
9353 string mrg_qpn::generate_functor_name(){
9354         return("mrg_functor_" + normalize_name(this->get_node_name()));
9355 }
9356
9357 string mrg_qpn::generate_functor(table_list *schema, ext_fcn_list *Ext_fcns, vector<bool> &needs_xform){
9358         int tblref;
9359
9360
9361 //              Sanity check
9362         if(fm.size() != mvars.size()){
9363                 fprintf(stderr,"INTERNAL ERROR in mrg_qpn::generate_functor fm.size=%lu, mvars.size=%lu\n",fm.size(),mvars.size());
9364                 exit(1);
9365         }
9366         if(fm.size() != 2){
9367                 fprintf(stderr,"INTERNAL ERROR in mrg_qpn::generate_functor fm.size=mvars.size=%lu\n",fm.size());
9368                 exit(1);
9369         }
9370
9371
9372 //                      Initialize generate utility globals
9373         segen_gb_tbl = NULL;
9374
9375         string ret = "class " + this->generate_functor_name() + "{\n";
9376
9377 //              Private variable:
9378 //              1) Vars for unpacked attrs.
9379 //              2) offsets ofthe unpakced attrs
9380 //              3) last_posted_timestamp
9381
9382         data_type dta(
9383                 schema->get_type_name(mvars[0]->get_schema_ref(), mvars[0]->get_field()),
9384                 schema->get_modifier_list(mvars[0]->get_schema_ref(), mvars[0]->get_field())
9385         );
9386         data_type dtb(
9387                 schema->get_type_name(mvars[1]->get_schema_ref(), mvars[1]->get_field()),
9388                 schema->get_modifier_list(mvars[1]->get_schema_ref(), mvars[1]->get_field())
9389         );
9390
9391         ret += "private:\n";
9392
9393         // var to save the schema handle
9394         ret += "\tint schema_handle0;\n";
9395
9396         // generate the declaration of all the variables related to
9397         // temp tuples generation
9398         ret += gen_decl_temp_vars();
9399
9400 //                      unpacked attribute storage, offsets
9401         ret += "//\t\tstorage and offsets of accessed fields.\n";
9402         ret += "\tint tuple_metadata_offset0, tuple_metadata_offset1;\n";
9403         tblref = 0;
9404         sprintf(tmpstr,"unpack_var_%s_%d", mvars[0]->get_field().c_str(), tblref);
9405         ret+="\t"+dta.make_host_cvar(tmpstr)+";\n";
9406         sprintf(tmpstr,"\tgs_int32_t unpack_offset_%s_%d;\n", mvars[0]->get_field().c_str(), tblref);
9407         ret.append(tmpstr);
9408         tblref = 1;
9409         sprintf(tmpstr,"unpack_var_%s_%d", mvars[1]->get_field().c_str(), tblref);
9410         ret+="\t"+dtb.make_host_cvar(tmpstr)+";\n";
9411         sprintf(tmpstr,"\tgs_int32_t unpack_offset_%s_%d;\n", mvars[1]->get_field().c_str(), tblref);
9412         ret.append(tmpstr);
9413
9414         ret += "//\t\tRemember the last posted timestamp.\n";
9415         ret+="\t"+dta.make_host_cvar("last_posted_timestamp_0")+";\n";
9416         ret+="\t"+dta.make_host_cvar("last_posted_timestamp_1")+";\n";
9417         ret+="\t"+dta.make_host_cvar("timestamp")+";\n";
9418         ret+="\t"+dta.make_host_cvar("slack")+";\n";
9419 //      ret += "\t bool first_execution_0, first_execution_1;\n";
9420
9421 //                      variables to hold parameters.
9422         ret += "//\tfor query parameters\n";
9423         ret += generate_param_vars(param_tbl);
9424
9425         ret += "public:\n";
9426 //-------------------
9427 //                      The functor constructor
9428 //                      pass in a schema handle (e.g. for the 1st input stream),
9429 //                      use it to determine how to unpack the merge variable.
9430 //                      ASSUME that both streams have the same layout,
9431 //                      just duplicate it.
9432
9433 //              unpack vars
9434         ret += "//\t\tFunctor constructor.\n";
9435         ret +=  this->generate_functor_name()+"(int schema_handle0){\n";
9436
9437         // var to save the schema handle
9438         ret += "\tthis->schema_handle0 = schema_handle0;\n";
9439         ret += "\ttuple_metadata_offset0=ftaschema_get_tuple_metadata_offset(schema_handle0);\n";
9440         ret += "\ttuple_metadata_offset1=ftaschema_get_tuple_metadata_offset(schema_handle0);\n";
9441
9442         ret += "//\t\tGet offsets for unpacking fields from input tuple.\n";
9443
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());
9445    ret.append(tmpstr);
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);
9447         ret.append(tmpstr);
9448 //      ret+="\tfirst_execution_0 = first_execution_1 = true;\n";
9449         if(slack)
9450                 ret+="\tslack = "+generate_se_code(slack,schema)+";\n";
9451         else
9452                 ret+="\tslack = 0;\n";
9453
9454 //              Initialize internal state
9455         ret += "\ttemp_tuple_received = false;\n";
9456
9457         //              Init last timestamp values to minimum value for their type
9458         if (dta.is_increasing())
9459                 ret+="\tlast_posted_timestamp_0 = last_posted_timestamp_1 = " + dta.get_min_literal() + ";\n";
9460         else
9461                 ret+="\tlast_posted_timestamp_0 = last_posted_timestamp_1 = " + dta.get_max_literal() + ";\n";
9462
9463
9464         ret += "};\n\n";
9465
9466         ret += "//\t\tFunctor destructor.\n";
9467         ret +=  "~"+this->generate_functor_name()+"(){\n";
9468
9469 //                      Destroy the parameters, if any need to be destroyed
9470         ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";
9471
9472         ret+="};\n\n";
9473
9474
9475 //                      no pass-by-handle params.
9476         vector<handle_param_tbl_entry *> param_handle_table;
9477
9478 //                      Parameter manipulation routines
9479         ret += generate_load_param_block(this->generate_functor_name(),
9480                                                                         this->param_tbl,param_handle_table);
9481         ret += generate_delete_param_block(this->generate_functor_name(),
9482                                                                         this->param_tbl,param_handle_table);
9483
9484 //                      Register new parameter block
9485
9486         ret += "int set_param_block(gs_int32_t sz, void* value){\n";
9487           ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";
9488           ret += "\treturn this->load_params_"+this->generate_functor_name()+
9489                                 "(sz, value);\n";
9490         ret += "};\n\n";
9491
9492
9493 //      -----------------------------------
9494 //                      Compare method
9495
9496         string unpack_fcna;
9497         if(needs_xform[0]) unpack_fcna = dta.get_hfta_unpack_fcn();
9498         else unpack_fcna = dta.get_hfta_unpack_fcn_noxf();
9499         string unpack_fcnb;
9500         if(needs_xform[1]) unpack_fcnb = dtb.get_hfta_unpack_fcn();
9501         else unpack_fcnb = dtb.get_hfta_unpack_fcn_noxf();
9502
9503 /*
9504         ret+="\tint compare(const host_tuple& tup1, const host_tuple& tup2) const{ \n";
9505         ret+="\t"+dta.make_host_cvar("timestamp1")+";\n";
9506         ret+="\t"+dta.make_host_cvar("timestamp2")+";\n";
9507         ret+="\tgs_int32_t problem;\n";
9508         ret+="\tif (tup1.channel == 0)  {\n";
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);
9510         ret += tmpstr;
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);
9512         ret += tmpstr;
9513         ret+="\t}else{\n";
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);
9515         ret += tmpstr;
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);
9517         ret += tmpstr;
9518         ret+="\t}\n";
9519         ret+=
9520 "        if (timestamp1 > timestamp2+slack)\n"
9521 "            return 1;\n"
9522 "        else if (timestamp1 < timestamp2)\n"
9523 "            return -1;\n"
9524 "        else\n"
9525 "            return 0;\n"
9526 "\n"
9527 "    }\n\n";
9528 */
9529
9530 ret +=
9531 "       void get_timestamp(const host_tuple& tup0){\n"
9532 "               gs_int32_t problem;\n"
9533 ;
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);
9535         ret += tmpstr;
9536 ret +=
9537 "       }\n"
9538 "\n"
9539 ;
9540
9541
9542
9543 //                      Compare to temp status.
9544         ret+=
9545 "       int compare_with_temp_status(int channel)   {\n"
9546 "       // check if tuple is temp status tuple\n"
9547 "\n"
9548 "       if (channel == 0)  {\n"
9549 //"     if(first_execution_0) return 1;\n"
9550 "        if (timestamp == last_posted_timestamp_0)\n"
9551 "            return 0;\n"
9552 "        else if (timestamp < last_posted_timestamp_0)\n"
9553 "            return -1;\n"
9554 "        else\n"
9555 "            return 1;\n"
9556 "       }\n"
9557 //"     if(first_execution_1) return 1;\n"
9558 "        if (timestamp == last_posted_timestamp_1)\n"
9559 "            return 0;\n"
9560 "        else if (timestamp < last_posted_timestamp_1)\n"
9561 "            return -1;\n"
9562 "        else\n"
9563 "            return 1;\n"
9564 "\n"
9565 "    }\n"
9566 ;
9567
9568         ret +=
9569 "       int compare_stored_with_temp_status(const host_tuple& tup0, int channel)/* const*/   {\n"
9570 ;
9571         ret+="\t"+dta.make_host_cvar("l_timestamp")+";\n";
9572         ret+="\tgs_int32_t problem;\n";
9573
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);
9575         ret += tmpstr;
9576         ret+="\tif (channel == 0)  {\n";
9577 //              ret+="\tif(first_execution_0) return 1;\n";
9578         ret+=
9579 "        if (l_timestamp == last_posted_timestamp_0)\n"
9580 "            return 0;\n"
9581 "        else if (l_timestamp < last_posted_timestamp_0)\n"
9582 "            return -1;\n"
9583 "        else\n"
9584 "            return 1;\n"
9585 "       }\n";
9586 //              ret+="\tif(first_execution_1) return 1;\n";
9587         ret+=
9588 "        if (l_timestamp == last_posted_timestamp_1)\n"
9589 "            return 0;\n"
9590 "        else if (l_timestamp < last_posted_timestamp_1)\n"
9591 "            return -1;\n"
9592 "        else\n"
9593 "            return 1;\n"
9594 "\n"
9595 "    }\n\n";
9596
9597
9598 //                      update temp status.
9599         ret+=
9600 "       int update_temp_status(const host_tuple& tup) {\n"
9601 "               if (tup.channel == 0)  {\n"
9602 "                       last_posted_timestamp_0=timestamp;\n"
9603 //"                     first_execution_0 = false;\n"
9604 "               }else{\n"
9605 "                       last_posted_timestamp_1=timestamp;\n"
9606 //"                     first_execution_1 = false;\n"
9607 "               }\n"
9608 "               return 0;\n"
9609 "   }\n"
9610 ;
9611         ret+=
9612 "       int update_stored_temp_status(const host_tuple& tup, int channel) {\n"
9613 ;
9614         ret+="\t"+dta.make_host_cvar("l_timestamp")+";\n";
9615         ret+="\tgs_int32_t problem;\n";
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);
9617         ret += tmpstr;
9618 ret+=
9619 "               if (tup.channel == 0)  {\n"
9620 "                       last_posted_timestamp_0=l_timestamp;\n"
9621 //"                     first_execution_0 = false;\n"
9622 "               }else{\n"
9623 "                       last_posted_timestamp_1=l_timestamp;\n"
9624 //"                     first_execution_1 = false;\n"
9625 "               }\n"
9626 "               return 0;\n"
9627 "   }\n"
9628 ;
9629 /*
9630         ret+="\t"+dta.make_host_cvar("timestamp")+";\n";
9631         ret+="\tgs_int32_t problem;\n";
9632         ret+="\tif (tup.channel == 0)  {\n";
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);
9634         ret += tmpstr;
9635         ret+="\t}else{\n";
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);
9637         ret += tmpstr;
9638         ret+="\t}\n";
9639         ret+="\tif (tup.channel == 0)  {\n";
9640         ret+="\tlast_posted_timestamp_0=timestamp;\n";
9641         ret +="\tfirst_execution_0 = false;\n";
9642         ret+="\t}else{\n";
9643         ret+="\tlast_posted_timestamp_1=timestamp;\n";
9644         ret +="\tfirst_execution_1 = false;\n";
9645         ret+="\t}\n";
9646         ret+=
9647 "    }\n\n";
9648 */
9649
9650
9651 //                      update temp status modulo slack.
9652         ret+="\tint update_temp_status_by_slack(const host_tuple& tup, int channel) {\n";
9653     if(slack){
9654         ret+="\t"+dta.make_host_cvar("timestamp")+";\n";
9655         ret+="\tgs_int32_t problem;\n";
9656         ret+="\tif (tup.channel == 0)  {\n";
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);
9658         ret += tmpstr;
9659         ret+="\t}else{\n";
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);
9661         ret += tmpstr;
9662         ret+="\t}\n";
9663 ret +=
9664 "       if (channel == 0)  {\n"
9665 "               if(first_execution_0){\n"
9666 "                       last_posted_timestamp_0=timestamp - slack;\n"
9667 "                       first_execution_0 = false;\n"
9668 "               }else{\n"
9669 "                       if(last_posted_timestamp_0 < timestamp-slack)\n"
9670 "                               last_posted_timestamp_0 = timestamp-slack;\n"
9671 "               }\n"
9672 "       }else{\n"
9673 "               if(first_execution_1){\n"
9674 "                       last_posted_timestamp_1=timestamp - slack;\n"
9675 "                       first_execution_1 = false;\n"
9676 "               }else{\n"
9677 "                       if(last_posted_timestamp_1 < timestamp-slack)\n"
9678 "                               last_posted_timestamp_1 = timestamp-slack;\n"
9679 "               }\n"
9680 "       }\n"
9681 "       return 0;\n"
9682 "    }\n\n";
9683         }else{
9684         ret +=
9685 "       return 0;\n"
9686 "       }\n\n";
9687         }
9688
9689
9690 //
9691         ret+=
9692 "bool temp_status_received(const host_tuple& tup0){\n"
9693 "       return ftaschema_is_temporal_tuple_offset(tuple_metadata_offset0, tup0.data);\n"
9694 "};\n"
9695 ;
9696 //"bool temp_status_received(){return temp_tuple_received;};\n\n";
9697
9698
9699 //              create a temp status tuple
9700         ret += "int create_temp_status_tuple(host_tuple& result) {\n\n";
9701
9702         ret += gen_init_temp_status_tuple(this->get_node_name());
9703
9704 //              Start packing.
9705         ret += "//\t\tPack the fields into the tuple.\n";
9706
9707         string fld_name = mvars[0]->get_field();
9708         int idx = table_layout->get_field_idx(fld_name);
9709         field_entry* fld = table_layout->get_field(idx);
9710         data_type dt(fld->get_type());
9711
9712 //      if (needs_xform[0] && needs_xform[1] && dt.needs_hn_translation())
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());
9714 //      else
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);
9716
9717         ret += tmpstr;
9718
9719         ret += "\treturn 0;\n";
9720         ret += "}\n\n";
9721
9722 //                      Transform tuple (before output)
9723
9724
9725  ret += "void xform_tuple(host_tuple &tup){\n";
9726  if((needs_xform[0] && !needs_xform[1]) || (needs_xform[1] && !needs_xform[0])){
9727   ret += "\tstruct "+generate_tuple_name(this->get_node_name())+" *tuple = ("+
9728                 generate_tuple_name(this->get_node_name())+" *)(tup.data);\n";
9729
9730   vector<field_entry *> flds = table_layout->get_fields();
9731
9732   ret+="\tif(tup.channel == 0){\n";
9733   if(needs_xform[0] && !needs_xform[1]){
9734         int f;
9735         for(f=0;f<flds.size();f++){
9736                 ret.append("\t");
9737                 data_type dt(flds[f]->get_type());
9738                 if(dt.get_type() == v_str_t){
9739 //                      sprintf(tmpstr,"\ttuple->tuple_var%d.offset = htonl(tuple->tuple_var%d.offset);\n",f,f);
9740 //                      ret += tmpstr;
9741 //                      sprintf(tmpstr,"\ttuple->tuple_var%d.length = htonl(tuple->tuple_var%d.length);\n",f,f);
9742 //                      ret += tmpstr;
9743 //                      sprintf(tmpstr,"\ttuple->tuple_var%d.reserved = htonl(tuple->tuple_var%d.reserved);\n",f,f);
9744 //                      ret += tmpstr;
9745                 }else{
9746                         if(dt.needs_hn_translation()){
9747 //                              sprintf(tmpstr,"\ttuple->tuple_var%d = %s(tuple->tuple_var%d);\n",
9748 //                                      f, dt.hton_translation().c_str(), f);
9749 //                              ret += tmpstr;
9750                         }
9751                 }
9752         }
9753   }else{
9754         ret += "\t\treturn;\n";
9755   }
9756   ret.append("\t}\n");
9757
9758
9759   ret+="\tif(tup.channel == 1){\n";
9760   if(needs_xform[1] && !needs_xform[0]){
9761         int f;
9762         for(f=0;f<flds.size();f++){
9763                 ret.append("\t");
9764                 data_type dt(flds[f]->get_type());
9765                 if(dt.get_type() == v_str_t){
9766 //                      sprintf(tmpstr,"\ttuple->tuple_var%d.offset = htonl(tuple->tuple_var%d.offset);\n",f,f);
9767 //                      ret += tmpstr;
9768 //                      sprintf(tmpstr,"\ttuple->tuple_var%d.length = htonl(tuple->tuple_var%d.length);\n",f,f);
9769 //                      ret += tmpstr;
9770 //                      sprintf(tmpstr,"\ttuple->tuple_var%d.reserved = htonl(tuple->tuple_var%d.reserved);\n",f,f);
9771 //                      ret += tmpstr;
9772                 }else{
9773                         if(dt.needs_hn_translation()){
9774 //                              sprintf(tmpstr,"\ttuple->tuple_var%d = %s(tuple->tuple_var%d);\n",
9775 //                                      f, dt.hton_translation().c_str(), f);
9776 //                              ret += tmpstr;
9777                         }
9778                 }
9779         }
9780   }else{
9781         ret += "\t\treturn;\n";
9782   }
9783   ret.append("\t}\n");
9784  }
9785
9786   ret.append("};\n\n");
9787
9788 //              print_warnings() : tell the functor if the user wants to print warnings.
9789   ret += "bool print_warnings(){\n";
9790   if(definitions.count("print_warnings") && (
9791                 definitions["print_warnings"] == "yes" ||
9792                 definitions["print_warnings"] == "Yes" ||
9793                 definitions["print_warnings"] == "YES" )) {
9794         ret += "return true;\n";
9795   }else{
9796         ret += "return false;\n";
9797   }
9798   ret.append("};\n\n");
9799
9800
9801 //              Done with methods.
9802         ret+="\n};\n\n";
9803
9804
9805         return(ret);
9806 }
9807
9808 string mrg_qpn::generate_operator(int i, string params){
9809
9810         if(disorder < 2){
9811                 return(
9812                         "       merge_operator<" +
9813                         generate_functor_name()+
9814                         "> *op"+int_to_string(i)+" = new merge_operator<"+
9815                         generate_functor_name()+
9816                         ">("+params+",10000,\"" + get_node_name() + "\");\n"
9817                 );
9818         }
9819         return(
9820                         "       merge_operator_oop<" +
9821                         generate_functor_name()+
9822                         "> *op"+int_to_string(i)+" = new merge_operator_oop<"+
9823                         generate_functor_name()+
9824                         ">("+params+",10000,\"" + get_node_name() + "\");\n"
9825         );
9826 }
9827
9828
9829 /////////////////////////////////////////////////////////
9830 //////                  JOIN_EQ_HASH functor
9831
9832
9833 string join_eq_hash_qpn::generate_functor_name(){
9834         return("join_eq_hash_functor_" + normalize_name(this->get_node_name()));
9835 }
9836
9837 string join_eq_hash_qpn::generate_functor(table_list *schema, ext_fcn_list *Ext_fcns, vector<bool> &needs_xform){
9838         int p,s;
9839         vector<data_type *> hashkey_dt;         // data types in the hash key
9840         vector<data_type *> temporal_dt;        // data types in the temporal key
9841         map<string,scalarexp_t *> l_equiv, r_equiv;     // field equivalences
9842         set<int> pfcn_refs;
9843         col_id_set new_cids, local_cids;
9844
9845 //--------------------------------
9846 //              Global init
9847
9848         string plus_op = "+";
9849
9850 //--------------------------------
9851 //                      key definition class
9852         string ret = "class " + generate_functor_name() + "_keydef{\n";
9853         ret += "public:\n";
9854 //                      Collect attributes from hash join predicates.
9855 //                      ASSUME equality predicate.
9856 //                      Use the upwardly compatible data type
9857 //                      (infer from '+' operator if possible, else use left type)
9858         for(p=0;p<this->hash_eq.size();++p){
9859                 scalarexp_t *lse =      hash_eq[p]->pr->get_left_se();
9860                 scalarexp_t *rse =      hash_eq[p]->pr->get_right_se();
9861                 data_type *hdt = new data_type(
9862                         lse->get_data_type(), rse->get_data_type(), plus_op );
9863                 if(hdt->get_type() == undefined_t){
9864                         hashkey_dt.push_back(lse->get_data_type()->duplicate());
9865                         delete hdt;
9866                 }else{
9867                         hashkey_dt.push_back(hdt);
9868                 }
9869                 sprintf(tmpstr,"hashkey_var%d",p);
9870                 ret+="\t"+hashkey_dt[p]->make_host_cvar(tmpstr)+";\n";
9871
9872 //                      find equivalences
9873 //                      NOTE: this code needs to be synched with the temporality
9874 //                      checking done at join_eq_hash_qpn::get_fields
9875                 if(lse->get_operator_type()==SE_COLREF){
9876                         l_equiv[lse->get_colref()->get_field()] = rse;
9877                 }
9878                 if(rse->get_operator_type()==SE_COLREF){
9879                         r_equiv[rse->get_colref()->get_field()] = lse;
9880                 }
9881         }
9882         ret += "\tbool touched;\n";
9883
9884 //              Constructors
9885         ret += "\t"+generate_functor_name() + "_keydef(){touched=false;};\n";
9886 //              destructor
9887         ret += "\t~"+ generate_functor_name() + "_keydef(){\n";
9888         for(p=0;p<hashkey_dt.size();p++){
9889                 if(hashkey_dt[p]->is_buffer_type()){
9890                         sprintf(tmpstr,"\t\t%s(&hashkey_var%d);\n",
9891                           hashkey_dt[p]->get_hfta_buffer_destroy().c_str(), p );
9892                         ret += tmpstr;
9893                 }
9894         }
9895         ret += "\t};\n";
9896         ret+="\tvoid touch(){touched = true;};\n";
9897         ret+="\tbool is_touched(){return touched;};\n";
9898         ret +="};\n\n";
9899
9900
9901 //--------------------------------
9902 //              temporal equality definition class
9903         ret += "class " + generate_functor_name() + "_tempeqdef{\n";
9904         ret += "public:\n";
9905 //                      Collect attributes from hash join predicates.
9906 //                      ASSUME equality predicate.
9907 //                      Use the upwardly compatible date type
9908 //                      (infer from '+' operator if possible, else use left type)
9909         for(p=0;p<this->temporal_eq.size();++p){
9910                 scalarexp_t *lse =      temporal_eq[p]->pr->get_left_se();
9911                 scalarexp_t *rse =      temporal_eq[p]->pr->get_right_se();
9912                 data_type *hdt = new data_type(
9913                         lse->get_data_type(), rse->get_data_type(), plus_op );
9914                 if(hdt->get_type() == undefined_t){
9915                         temporal_dt.push_back(hash_eq[p]->pr->get_left_se()->get_data_type()->duplicate());
9916                         delete hdt;
9917                 }else{
9918                         temporal_dt.push_back(hdt);
9919                 }
9920                 sprintf(tmpstr,"tempeq_var%d",p);
9921                 ret+="\t"+temporal_dt[p]->make_host_cvar(tmpstr)+";\n";
9922 //                      find equivalences
9923                 if(lse->get_operator_type()==SE_COLREF){
9924                         l_equiv[lse->get_colref()->get_field()] = rse;
9925                 }
9926                 if(rse->get_operator_type()==SE_COLREF){
9927                         r_equiv[rse->get_colref()->get_field()] = lse;
9928                 }
9929         }
9930
9931 //              Constructors
9932         ret += "\t"+generate_functor_name() + "_tempeqdef(){};\n";
9933 //              destructor
9934         ret += "\t~"+ generate_functor_name() + "_tempeqdef(){\n";
9935         for(p=0;p<temporal_dt.size();p++){
9936                 if(temporal_dt[p]->is_buffer_type()){
9937                         sprintf(tmpstr,"\t\t%s(&tempeq_var%d);\n",
9938                           temporal_dt[p]->get_hfta_buffer_destroy().c_str(), p );
9939                         ret += tmpstr;
9940                 }
9941         }
9942         ret += "\t};\n";
9943         ret +="};\n\n";
9944
9945
9946 //--------------------------------
9947 //                      temporal eq, hash join functor class
9948         ret += "class " + this->generate_functor_name() + "{\n";
9949
9950 //                      Find variables referenced in this query node.
9951
9952         col_id_set cid_set;
9953         col_id_set::iterator csi;
9954
9955     for(p=0;p<where.size();++p)
9956         gather_pr_col_ids(where[p]->pr,cid_set,NULL);
9957     for(s=0;s<select_list.size();s++)
9958         gather_se_col_ids(select_list[s]->se,cid_set,NULL);
9959
9960 //                      Private variables : store the state of the functor.
9961 //                      1) variables for unpacked attributes
9962 //                      2) offsets of the upacked attributes
9963 //                      3) storage of partial functions
9964 //                      4) storage of complex literals (i.e., require a constructor)
9965
9966         ret += "private:\n";
9967
9968         // var to save the schema handles
9969         ret += "\tint schema_handle0;\n";
9970         ret += "\tint schema_handle1;\n";
9971
9972         // generate the declaration of all the variables related to
9973         // temp tuples generation
9974         ret += gen_decl_temp_vars();
9975         // tuple metadata offsets
9976         ret += "\tint tuple_metadata_offset0, tuple_metadata_offset1;\n";
9977
9978 //                      unpacked attribute storage, offsets
9979         ret += "//\t\tstorage and offsets of accessed fields.\n";
9980         ret += generate_access_vars(cid_set, schema);
9981
9982
9983 //                      Variables to store results of partial functions.
9984 //                      WARNING find_partial_functions modifies the SE
9985 //                      (it marks the partial function id).
9986         ret += "//\t\tParital function result storage\n";
9987         vector<scalarexp_t *> partial_fcns;
9988         vector<int> fcn_ref_cnt;
9989         vector<bool> is_partial_fcn;
9990         for(s=0;s<select_list.size();s++){
9991                 find_partial_fcns(select_list[s]->se, &partial_fcns,NULL,NULL,  Ext_fcns);
9992         }
9993         for(p=0;p<where.size();p++){
9994                 find_partial_fcns_pr(where[p]->pr, &partial_fcns,NULL,NULL,  Ext_fcns);
9995         }
9996         if(partial_fcns.size()>0){
9997           ret += "/*\t\tVariables for storing results of partial functions. \t*/\n";
9998           ret += generate_partial_fcn_vars(partial_fcns,fcn_ref_cnt,is_partial_fcn,false);
9999         }
10000
10001 //                      Complex literals (i.e., they need constructors)
10002         ret += "//\t\tComplex literal storage.\n";
10003         cplx_lit_table *complex_literals = this->get_cplx_lit_tbl(Ext_fcns);
10004         ret += generate_complex_lit_vars(complex_literals);
10005 //                      We need the following to handle strings in outer joins.
10006 //                              NEED AN EMPTY LITERAL FOR EAcH STRUCTURED LITERAL
10007         ret += "\tstruct vstring EmptyString;\n";
10008         ret += "\tstruct hfta_ipv6_str EmptyIp6;\n";
10009
10010 //                      Pass-by-handle parameters
10011         ret += "//\t\tPass-by-handle storage.\n";
10012         vector<handle_param_tbl_entry *> param_handle_table = this->get_handle_param_tbl(Ext_fcns);
10013         ret += generate_pass_by_handle_vars(param_handle_table);
10014
10015
10016 //                      variables to hold parameters.
10017         ret += "//\tfor query parameters\n";
10018         ret += generate_param_vars(param_tbl);
10019
10020
10021         ret += "\npublic:\n";
10022 //-------------------
10023 //                      The functor constructor
10024 //                      pass in the schema handle.
10025 //                      1) make assignments to the unpack offset variables
10026 //                      2) initialize the complex literals
10027
10028         ret += "//\t\tFunctor constructor.\n";
10029         ret +=  this->generate_functor_name()+"(int schema_handle0, int schema_handle1){\n";
10030
10031         ret += "\t\tthis->schema_handle0 = schema_handle0;\n";
10032         ret += "\t\tthis->schema_handle1 = schema_handle1;\n";
10033 //              metadata offsets
10034         ret += "\ttuple_metadata_offset0 = ftaschema_get_tuple_metadata_offset(schema_handle0);\n";
10035         ret += "\ttuple_metadata_offset1 = ftaschema_get_tuple_metadata_offset(schema_handle1);\n";
10036
10037 //              unpack vars
10038         ret += "//\t\tGet offsets for unpacking fields from input tuple.\n";
10039         ret += gen_access_var_init(cid_set);
10040
10041 //              complex literals
10042         ret += "//\t\tInitialize complex literals.\n";
10043         ret += gen_complex_lit_init(complex_literals);
10044 //              Initialize EmptyString to the ... empty string
10045 //                              NEED AN EMPTY LITERAL FOR EAcH STRUCTURED LITERAL
10046         literal_t mtstr_lit("");
10047         ret += "\t" + mtstr_lit.to_hfta_C_code("&EmptyString")+";\n";
10048         literal_t mip6_lit("0:0:0:0:0:0:0:0",LITERAL_IPV6);
10049         ret += "\t" + mip6_lit.to_hfta_C_code("&EmptyIp6")+";\n";
10050
10051 //              Initialize partial function results so they can be safely GC'd
10052         ret += gen_partial_fcn_init(partial_fcns);
10053
10054 //              Initialize non-query-parameter parameter handles
10055         ret += gen_pass_by_handle_init(param_handle_table);
10056
10057 //              Init temporal attributes referenced in select list
10058         ret += gen_init_temp_vars(schema, select_list, NULL);
10059
10060
10061         ret += "};\n";
10062
10063
10064
10065 //-------------------
10066 //                      Functor destructor
10067         ret += "//\t\tFunctor destructor.\n";
10068         ret +=  "~"+this->generate_functor_name()+"(){\n";
10069
10070 //                      clean up buffer type complex literals
10071         ret += gen_complex_lit_dtr(complex_literals);
10072
10073 //                      Deregister the pass-by-handle parameters
10074         ret += "/* register and de-register the pass-by-handle parameters */\n";
10075         ret += gen_pass_by_handle_dtr(param_handle_table);
10076
10077 //                      clean up partial function results.
10078         ret += "/* clean up partial function storage    */\n";
10079         ret += gen_partial_fcn_dtr(partial_fcns);
10080
10081 //                      Destroy the parameters, if any need to be destroyed
10082         ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";
10083
10084         ret += "};\n\n";
10085
10086
10087 //-------------------
10088 //                      Parameter manipulation routines
10089         ret += generate_load_param_block(this->generate_functor_name(),
10090                                                                         this->param_tbl,param_handle_table);
10091         ret += generate_delete_param_block(this->generate_functor_name(),
10092                                                                         this->param_tbl,param_handle_table);
10093
10094 //-------------------
10095 //                      Register new parameter block
10096
10097         ret += "int set_param_block(gs_int32_t sz, void* value){\n";
10098           ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";
10099           ret += "\treturn this->load_params_"+this->generate_functor_name()+
10100                                 "(sz, value);\n";
10101         ret += "};\n\n";
10102
10103
10104 //-------------------
10105 //                      The create_key method.
10106 //                      Perform heap allocation.
10107 //                      ASSUME : the LHS of the preds reference channel 0 attributes
10108 //                      NOTE : it may fail if a partial function fails.
10109
10110         ret += this->generate_functor_name()+"_keydef *create_key(host_tuple &tup, bool &failed){\n";
10111 //              Variables for execution of the function.
10112         ret+="\t"+this->generate_functor_name()+"_keydef *retval = NULL;\n";
10113         ret+="\tgs_int32_t problem = 0;\n";
10114
10115 //              Assume unsuccessful completion
10116         ret+= "\tfailed = true;\n";
10117
10118 //              Switch the processing based on the channel
10119         ret+="\tif(tup.channel == 0){\n";
10120         ret+="// ------------ processing for channel 0\n";
10121         ret+="\t\thost_tuple &tup0 = tup;\n";
10122 //              Gather partial fcns and colids ref'd by this branch
10123         pfcn_refs.clear();
10124         new_cids.clear(); local_cids.clear();
10125         for(p=0;p<hash_eq.size();p++){
10126                 collect_partial_fcns(hash_eq[p]->pr->get_left_se(), pfcn_refs);
10127                 gather_se_col_ids(hash_eq[p]->pr->get_left_se(),local_cids,NULL);
10128         }
10129
10130 //              Start by cleaning up partial function results
10131         ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";
10132         ret += gen_partial_fcn_dtr(partial_fcns,pfcn_refs);
10133
10134 //                      Evaluate the partial functions
10135         ret += gen_full_unpack_partial_fcn(schema, partial_fcns, pfcn_refs,
10136                                 new_cids, NULL, "NULL", needs_xform);
10137 //                      test passed -- unpack remaining cids.
10138         ret += gen_remaining_colrefs(schema, local_cids, new_cids, "NULL", needs_xform);
10139
10140 //                      Alloc and load a key object
10141         ret += "\t\tretval = new "+this->generate_functor_name()+"_keydef();\n";
10142         for(p=0;p<hash_eq.size();p++){
10143                 data_type *hdt = hash_eq[p]->pr->get_left_se()->get_data_type();
10144                 if(hdt->is_buffer_type()){
10145                         string vname = "tmp_keyvar"+int_to_string(p);
10146                         ret += "\t\t"+hdt->make_host_cvar(vname)+" = "+generate_se_code(hash_eq[p]->pr->get_left_se(),schema)+";\n";
10147                         ret += "\t\t"+hdt->get_hfta_buffer_assign_copy()+"(&(retval->hashkey_var"+int_to_string(p)+"),&"+vname+");\n";
10148                 }else{
10149                   sprintf(tmpstr,"\t\tretval->hashkey_var%d = %s;\n",
10150                         p,generate_se_code(hash_eq[p]->pr->get_left_se(),schema).c_str() );
10151                   ret += tmpstr;
10152                 }
10153         }
10154         ret += "\t}else{\n";
10155
10156         ret+="// ------------ processing for channel 1\n";
10157         ret+="\t\thost_tuple &tup1 = tup;\n";
10158 //              Gather partial fcns and colids ref'd by this branch
10159         pfcn_refs.clear();
10160         new_cids.clear(); local_cids.clear();
10161         for(p=0;p<hash_eq.size();p++){
10162                 collect_partial_fcns(hash_eq[p]->pr->get_right_se(), pfcn_refs);
10163                 gather_se_col_ids(hash_eq[p]->pr->get_right_se(),local_cids,NULL);
10164         }
10165
10166 //              Start by cleaning up partial function results
10167         ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";
10168         ret += gen_partial_fcn_dtr(partial_fcns,pfcn_refs);
10169
10170 //                      Evaluate the partial functions
10171         ret += gen_full_unpack_partial_fcn(schema, partial_fcns, pfcn_refs,
10172                                 new_cids, NULL, "NULL", needs_xform);
10173
10174 //                      test passed -- unpack remaining cids.
10175         ret += gen_remaining_colrefs(schema, local_cids, new_cids, "NULL", needs_xform);
10176
10177 //                      Alloc and load a key object
10178         ret += "\t\tretval = new "+this->generate_functor_name()+"_keydef();\n";
10179         for(p=0;p<hash_eq.size();p++){
10180                 data_type *hdt = hash_eq[p]->pr->get_right_se()->get_data_type();
10181                 if(hdt->is_buffer_type()){
10182                         string vname = "tmp_keyvar"+int_to_string(p);
10183                         ret += "\t\t"+hdt->make_host_cvar(vname)+" = "+generate_se_code(hash_eq[p]->pr->get_right_se(),schema)+";\n";
10184                         ret += "\t\t"+hdt->get_hfta_buffer_assign_copy()+"(&(retval->hashkey_var"+int_to_string(p)+"),&"+vname+");\n";
10185                 }else{
10186                   sprintf(tmpstr,"\t\tretval->hashkey_var%d = %s;\n",
10187                         p,generate_se_code(hash_eq[p]->pr->get_right_se(),schema).c_str() );
10188                   ret += tmpstr;
10189                 }
10190         }
10191         ret += "\t}\n";
10192
10193         ret += "\tfailed = false;\n";
10194         ret += "\t return retval;\n";
10195         ret += "}\n";
10196
10197
10198 //-------------------
10199 //                      The load_ts method.
10200 //                      load into an allocated buffer.
10201 //                      ASSUME : the LHS of the preds reference channel 0 attributes
10202 //                      NOTE : it may fail if a partial function fails.
10203 //                      NOTE : cann't handle buffer attributes
10204
10205         ret += "bool load_ts_from_tup("+this->generate_functor_name()+"_tempeqdef *ts, host_tuple &tup){\n";
10206 //              Variables for execution of the function.
10207         ret+="\tgs_int32_t problem = 0;\n";
10208
10209 //              Switch the processing based on the channel
10210         ret+="\tif(tup.channel == 0){\n";
10211         ret+="// ------------ processing for channel 0\n";
10212         ret+="\t\thost_tuple &tup0 = tup;\n";
10213
10214 //              Gather partial fcns and colids ref'd by this branch
10215         pfcn_refs.clear();
10216         new_cids.clear(); local_cids.clear();
10217         for(p=0;p<temporal_eq.size();p++){
10218                 collect_partial_fcns(temporal_eq[p]->pr->get_left_se(), pfcn_refs);
10219                 gather_se_col_ids(temporal_eq[p]->pr->get_left_se(),local_cids,NULL);
10220         }
10221
10222 //              Start by cleaning up partial function results
10223         ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";
10224         ret += gen_partial_fcn_dtr(partial_fcns,pfcn_refs);
10225
10226 //                      Evaluate the partial functions
10227         ret += gen_full_unpack_partial_fcn(schema, partial_fcns, pfcn_refs,
10228                                 new_cids, NULL, "false", needs_xform);
10229
10230 //                      test passed -- unpack remaining cids.
10231         ret += gen_remaining_colrefs(schema, local_cids, new_cids, "false", needs_xform);
10232
10233 //                      load the temporal key object
10234         for(p=0;p<temporal_eq.size();p++){
10235                 sprintf(tmpstr,"\t\tts->tempeq_var%d = %s;\n",
10236                         p,generate_se_code(temporal_eq[p]->pr->get_left_se(),schema).c_str() );
10237                 ret += tmpstr;
10238         }
10239
10240         ret += "\t}else{\n";
10241
10242         ret+="// ------------ processing for channel 1\n";
10243         ret+="\t\thost_tuple &tup1 = tup;\n";
10244
10245 //              Gather partial fcns and colids ref'd by this branch
10246         pfcn_refs.clear();
10247         new_cids.clear(); local_cids.clear();
10248         for(p=0;p<temporal_eq.size();p++){
10249                 collect_partial_fcns(temporal_eq[p]->pr->get_right_se(), pfcn_refs);
10250                 gather_se_col_ids(temporal_eq[p]->pr->get_right_se(),local_cids,NULL);
10251         }
10252
10253 //              Start by cleaning up partial function results
10254         ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";
10255         ret += gen_partial_fcn_dtr(partial_fcns,pfcn_refs);
10256
10257 //                      Evaluate the partial functions
10258         ret += gen_full_unpack_partial_fcn(schema, partial_fcns, pfcn_refs,
10259                                 new_cids, NULL, "false", needs_xform);
10260
10261 //                      test passed -- unpack remaining cids.
10262         ret += gen_remaining_colrefs(schema, local_cids, new_cids, "false", needs_xform);
10263
10264 //                      load the key object
10265         for(p=0;p<temporal_eq.size();p++){
10266                 sprintf(tmpstr,"\t\tts->tempeq_var%d = %s;\n",
10267                         p,generate_se_code(temporal_eq[p]->pr->get_right_se(),schema).c_str() );
10268                 ret += tmpstr;
10269         }
10270
10271         ret += "\t}\n";
10272
10273         ret += "\t return true;\n";
10274         ret += "}\n";
10275
10276
10277 //      ------------------------------
10278 //              Load ts from ts
10279 //              (i.e make a copy)
10280
10281         ret += "bool load_ts_from_ts("+this->generate_functor_name()+"_tempeqdef *lts,"+this->generate_functor_name()+"_tempeqdef *rts){\n";
10282         for(p=0;p<temporal_eq.size();p++){
10283                 sprintf(tmpstr,"\tlts->tempeq_var%d = rts->tempeq_var%d;\n",p,p);
10284                 ret += tmpstr;
10285         }
10286         ret += "}\n";
10287
10288 //      -------------------------------------
10289 //              compare_ts_to_ts
10290 //              There should be only one variable to compare.
10291 //              If there is more, assume an arbitrary lexicographic order.
10292
10293         ret += "int compare_ts_with_ts("+this->generate_functor_name()+"_tempeqdef *lts,"+this->generate_functor_name()+"_tempeqdef *rts){\n";
10294         for(p=0;p<temporal_eq.size();p++){
10295                 sprintf(tmpstr,"\tif(lts->tempeq_var%d < rts->tempeq_var%d) return(-1);\n",p,p);
10296                 ret += tmpstr;
10297                 sprintf(tmpstr,"\tif(lts->tempeq_var%d > rts->tempeq_var%d) return(1);\n",p,p);
10298                 ret += tmpstr;
10299         }
10300         ret += "\treturn(0);\n";
10301         ret += "}\n";
10302
10303 //      ------------------------------------------
10304 //              apply_prefilter
10305 //              apply the prefilter
10306
10307         ret += "bool apply_prefilter(host_tuple &tup){\n";
10308
10309 //              Variables for this procedure
10310         ret+="\tgs_int32_t problem = 0;\n";
10311         ret+="\tgs_retval_t retval;\n";
10312
10313 //              Switch the processing based on the channel
10314         ret+="\tif(tup.channel == 0){\n";
10315         ret+="// ------------ processing for channel 0\n";
10316         ret+="\t\thost_tuple &tup0 = tup;\n";
10317 //              Gather partial fcns and colids ref'd by this branch
10318         pfcn_refs.clear();
10319         new_cids.clear(); local_cids.clear();
10320         for(p=0;p<prefilter[0].size();p++){
10321                 collect_partial_fcns_pr((prefilter[0])[p]->pr, pfcn_refs);
10322         }
10323
10324 //              Start by cleaning up partial function results
10325         ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";
10326         ret += gen_partial_fcn_dtr(partial_fcns,pfcn_refs);
10327
10328         for(p=0;p<(prefilter[0]).size();++p){
10329                 sprintf(tmpstr,"//\t\tPredicate clause %d.\n",p);
10330                 ret += tmpstr;
10331 //                      Find the set of variables accessed in this CNF elem,
10332 //                      but in no previous element.
10333                 col_id_set new_pr_cids;
10334                 get_new_pred_cids((prefilter[0])[p]->pr,local_cids,new_pr_cids, NULL);
10335 //                      Unpack these values.
10336                 ret += gen_unpack_cids(schema, new_pr_cids, "false", needs_xform);
10337 //                      Find partial fcns ref'd in this cnf element
10338                 set<int> pr_pfcn_refs;
10339                 collect_partial_fcns_pr((prefilter[0])[p]->pr, pr_pfcn_refs);
10340                 ret += gen_unpack_partial_fcn(schema,partial_fcns,pr_pfcn_refs,"false");
10341
10342                 ret += "\t\tif( !("+generate_predicate_code((prefilter[0])[p]->pr,schema)+") ) return(false);\n";
10343         }
10344         ret += "\t}else{\n";
10345         ret+="// ------------ processing for channel 1\n";
10346         ret+="\t\thost_tuple &tup1 = tup;\n";
10347 //              Gather partial fcns and colids ref'd by this branch
10348         pfcn_refs.clear();
10349         new_cids.clear(); local_cids.clear();
10350         for(p=0;p<prefilter[1].size();p++){
10351                 collect_partial_fcns_pr((prefilter[1])[p]->pr, pfcn_refs);
10352         }
10353
10354 //              Start by cleaning up partial function results
10355         ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";
10356         ret += gen_partial_fcn_dtr(partial_fcns,pfcn_refs);
10357
10358         for(p=0;p<(prefilter[1]).size();++p){
10359                 sprintf(tmpstr,"//\t\tPredicate clause %d.\n",p);
10360                 ret += tmpstr;
10361 //                      Find the set of variables accessed in this CNF elem,
10362 //                      but in no previous element.
10363                 col_id_set pr_new_cids;
10364                 get_new_pred_cids((prefilter[1])[p]->pr,local_cids, pr_new_cids, NULL);
10365 //                      Unpack these values.
10366                 ret += gen_unpack_cids(schema, pr_new_cids, "false", needs_xform);
10367 //                      Find partial fcns ref'd in this cnf element
10368                 set<int> pr_pfcn_refs;
10369                 collect_partial_fcns_pr((prefilter[1])[p]->pr, pr_pfcn_refs);
10370                 ret += gen_unpack_partial_fcn(schema,partial_fcns,pr_pfcn_refs,"false");
10371
10372                 ret += "\t\tif( !("+generate_predicate_code((prefilter[1])[p]->pr,schema)+ ") ) return(false);\n";
10373         }
10374
10375         ret += "\t}\n";
10376         ret+="\treturn true;\n";
10377         ret += "}\n";
10378
10379
10380 //      -------------------------------------
10381 //                      create_output_tuple
10382 //                      If the postfilter on the pair of tuples passes,
10383 //                      create an output tuple from the combined information.
10384 //                      (Plus, outer join processing)
10385
10386         ret += "host_tuple create_output_tuple(const host_tuple &tup0, const host_tuple &tup1, bool &failed){\n";
10387
10388         ret += "\thost_tuple tup;\n";
10389         ret += "\tfailed = true;\n";
10390         ret += "\tgs_retval_t retval = 0;\n";
10391         ret += "\tgs_int32_t problem = 0;\n";
10392
10393 //              Start by cleaning up partial function results
10394         ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";
10395         pfcn_refs.clear();
10396         new_cids.clear(); local_cids.clear();
10397         for(p=0;p<postfilter.size();p++){
10398                 collect_partial_fcns_pr(postfilter[p]->pr, pfcn_refs);
10399         }
10400         for(s=0;s<select_list.size();s++){
10401                 collect_partial_fcns(select_list[s]->se, pfcn_refs);
10402         }
10403         ret += gen_partial_fcn_dtr(partial_fcns,pfcn_refs);
10404
10405
10406         ret+="\tif(tup0.data && tup1.data){\n";
10407 //                      Evaluate the postfilter
10408         new_cids.clear(); local_cids.clear();
10409         for(p=0;p<postfilter.size();p++){
10410                 sprintf(tmpstr,"//\t\tPredicate clause %d.\n",p);
10411                 ret += tmpstr;
10412 //                      Find the set of variables accessed in this CNF elem,
10413 //                      but in no previous element.
10414                 col_id_set pr_new_cids;
10415                 get_new_pred_cids(postfilter[p]->pr,local_cids, pr_new_cids, NULL);
10416 //                      Unpack these values.
10417                 ret += gen_unpack_cids(schema, pr_new_cids, "tup", needs_xform);
10418 //                      Find partial fcns ref'd in this cnf element
10419                 set<int> pr_pfcn_refs;
10420                 collect_partial_fcns_pr(postfilter[p]->pr, pr_pfcn_refs);
10421                 ret += gen_unpack_partial_fcn(schema,partial_fcns,pr_pfcn_refs,"tup");
10422
10423                 ret += "\t\tif( !("+generate_predicate_code(postfilter[p]->pr,schema)+ ") ) return(tup);\n";
10424         }
10425
10426
10427 //              postfilter passed, evaluate partial functions for select list
10428
10429         set<int> sl_pfcns;
10430         col_id_set se_cids;
10431         for(s=0;s<select_list.size();s++){
10432                 collect_partial_fcns(select_list[s]->se, sl_pfcns);
10433         }
10434
10435         if(sl_pfcns.size() > 0)
10436                 ret += "//\t\tUnpack remaining partial fcns.\n";
10437         ret += gen_full_unpack_partial_fcn(schema, partial_fcns, sl_pfcns,
10438                                         local_cids, NULL, "tup", needs_xform);
10439
10440 //                      Unpack remaining fields
10441         ret += "//\t\tunpack any remaining fields from the input tuples.\n";
10442         for(s=0;s<select_list.size();s++)
10443                 get_new_se_cids(select_list[s]->se, local_cids,se_cids,NULL);
10444         ret += gen_unpack_cids(schema,  se_cids,"tup", needs_xform);
10445
10446
10447 //                      Deal with outer join stuff
10448         col_id_set l_cids, r_cids;
10449         col_id_set::iterator ocsi;
10450         for(ocsi=local_cids.begin();ocsi!=local_cids.end();++ocsi){
10451                 if((*ocsi).tblvar_ref == 0) l_cids.insert((*ocsi));
10452                 else                                            r_cids.insert((*ocsi));
10453         }
10454         for(ocsi=se_cids.begin();ocsi!=se_cids.end();++ocsi){
10455                 if((*ocsi).tblvar_ref == 0) l_cids.insert((*ocsi));
10456                 else                                            r_cids.insert((*ocsi));
10457         }
10458
10459         ret += "\t}else if(tup0.data){\n";
10460         string unpack_null = ""; col_id_set extra_cids;
10461         for(ocsi=r_cids.begin();ocsi!=r_cids.end();++ocsi){
10462                 string field = (*ocsi).field;
10463                 if(r_equiv.count(field)){
10464                         unpack_null+="\t\tunpack_var_"+field+"_1="+generate_se_code(r_equiv[field],schema)+";\n";
10465                         get_new_se_cids(r_equiv[field],l_cids,new_cids,NULL);
10466                 }else{
10467                 int schref = (*ocsi).schema_ref;
10468                         data_type dt(schema->get_type_name(schref,field));
10469                         literal_t empty_lit(dt.type_indicator());
10470                         if(empty_lit.is_cpx_lit()){
10471 //                              sprintf(tmpstr,"&(unpack_var_%s_1)",field.c_str());
10472 //                              unpack_null += "\t"+empty_lit.to_hfta_C_code(tmpstr)+";\n";
10473 //                                      NB : works for string type only
10474 //                                      NNB: installed fix for ipv6, more of this should be pushed
10475 //                                              into the literal_t code.
10476                                 unpack_null+="\tunpack_var_"+field+"_1= "+empty_lit.hfta_empty_literal_name()+";\n";
10477                         }else{
10478                                 unpack_null+="\tunpack_var_"+field+"_1="+empty_lit.to_hfta_C_code("")+";\n";
10479                         }
10480                 }
10481         }
10482         ret += gen_unpack_cids(schema,  l_cids, "tup", needs_xform);
10483         ret += gen_unpack_cids(schema,  extra_cids, "tup", needs_xform);
10484         ret += unpack_null;
10485         ret += gen_unpack_partial_fcn(schema, partial_fcns, sl_pfcns, "tup");
10486
10487         ret+="\t}else{\n";
10488         unpack_null = ""; extra_cids.clear();
10489         for(ocsi=l_cids.begin();ocsi!=l_cids.end();++ocsi){
10490                 string field = (*ocsi).field;
10491                 if(l_equiv.count(field)){
10492                         unpack_null+="\t\tunpack_var_"+field+"_0="+generate_se_code(l_equiv[field],schema)+";\n";
10493                         get_new_se_cids(l_equiv[field],r_cids,new_cids,NULL);
10494                 }else{
10495                 int schref = (*ocsi).schema_ref;
10496                         data_type dt(schema->get_type_name(schref,field));
10497                         literal_t empty_lit(dt.type_indicator());
10498                         if(empty_lit.is_cpx_lit()){
10499 //                              sprintf(tmpstr,"&(unpack_var_%s_0)",field.c_str());
10500 //                              unpack_null += "\t"+empty_lit.to_hfta_C_code(tmpstr)+";\n";
10501 //                                      NB : works for string type only
10502 //                                      NNB: installed fix for ipv6, more of this should be pushed
10503 //                                              into the literal_t code.
10504                                 unpack_null+="\tunpack_var_"+field+"_0= "+empty_lit.hfta_empty_literal_name()+";\n";
10505                         }else{
10506                                 unpack_null+="\tunpack_var_"+field+"_0="+empty_lit.to_hfta_C_code("")+";\n";
10507                         }
10508                 }
10509         }
10510         ret += gen_unpack_cids(schema,  r_cids, "tup", needs_xform);
10511         ret += gen_unpack_cids(schema,  extra_cids, "tup", needs_xform);
10512         ret += unpack_null;
10513         ret += gen_unpack_partial_fcn(schema, partial_fcns, sl_pfcns, "tup");
10514         ret+="\t}\n";
10515
10516
10517
10518 //          Unpack any BUFFER type selections into temporaries
10519 //          so that I can compute their size and not have
10520 //          to recompute their value during tuple packing.
10521 //          I can use regular assignment here because
10522 //          these temporaries are non-persistent.
10523
10524         ret += "//\t\tCompute the size of the tuple.\n";
10525         ret += "//\t\t\tNote: buffer storage packed at the end of the tuple.\n";
10526
10527 //                      Unpack all buffer type selections, to be able to compute their size
10528         ret += gen_buffer_selvars(schema, select_list);
10529
10530 //      The size of the tuple is the size of the tuple struct plus the
10531 //      size of the buffers to be copied in.
10532
10533     ret+="\ttup.tuple_size = sizeof(" + generate_tuple_name( this->get_node_name()) +") + sizeof(gs_uint8_t)";
10534         ret += gen_buffer_selvars_size(select_list,schema);
10535       ret.append(";\n");
10536
10537 //              Allocate tuple data block.
10538         ret += "//\t\tCreate the tuple block.\n";
10539           ret += "\ttup.data = malloc(tup.tuple_size);\n";
10540           ret += "\ttup.heap_resident = true;\n";
10541 //        ret += "\ttup.channel = 0;\n";
10542
10543 //              Mark tuple as regular
10544           ret += "\t*((gs_sp_t )tup.data + sizeof(" + generate_tuple_name( this->get_node_name()) +")) = REGULAR_TUPLE;\n";
10545
10546
10547           ret += "\t"+generate_tuple_name( this->get_node_name())+" *tuple = ("+
10548                                 generate_tuple_name( this->get_node_name())+" *)(tup.data);\n";
10549
10550 //              Start packing.
10551 //                      (Here, offsets are hard-wired.  is this a problem?)
10552
10553         ret += "//\t\tPack the fields into the tuple.\n";
10554         ret += gen_pack_tuple(schema,select_list,this->get_node_name(), false );
10555
10556 //                      Delete string temporaries
10557         ret += gen_buffer_selvars_dtr(select_list);
10558
10559         ret += "\tfailed = false;\n";
10560         ret += "\treturn tup;\n";
10561         ret += "};\n";
10562
10563
10564
10565 //-----------------------------
10566 //                      Method for checking whether tuple is temporal
10567
10568         ret += "bool temp_status_received(host_tuple &tup){\n";
10569
10570 //              Switch the processing based on the channel
10571         ret+="\tif(tup.channel == 0){\n";
10572         ret+="\t\thost_tuple &tup0 = tup;\n";
10573         ret += gen_temp_tuple_check(this->node_name, 0);
10574         ret += "\t}else{\n";
10575         ret+="\t\thost_tuple &tup1 = tup;\n";
10576         ret += gen_temp_tuple_check(this->node_name, 1);
10577         ret += "\t}\n";
10578         ret += "\treturn temp_tuple_received;\n};\n\n";
10579
10580
10581 //-------------------------------------------------------------------
10582 //              Temporal update functions
10583
10584
10585 //              create a temp status tuple
10586         ret += "int create_temp_status_tuple(const host_tuple &tup0, const host_tuple &tup1, host_tuple& result) {\n\n";
10587
10588         ret += "\tgs_retval_t retval = 0;\n";
10589         ret += "\tgs_int32_t problem = 0;\n";
10590
10591         ret += "\tif(tup0.data){\n";
10592
10593 //              Unpack all the temporal attributes references in select list
10594         col_id_set found_cids;
10595
10596         for(s=0;s<select_list.size();s++){
10597                 if (select_list[s]->se->get_data_type()->is_temporal()) {
10598 //                      Find the set of attributes accessed in this SE
10599                         col_id_set new_cids;
10600                         get_new_se_cids(select_list[s]->se,found_cids, new_cids, NULL);
10601                 }
10602         }
10603
10604         //                      Deal with outer join stuff
10605         l_cids.clear(), r_cids.clear();
10606         for(ocsi=found_cids.begin();ocsi!=found_cids.end();++ocsi){
10607                 if((*ocsi).tblvar_ref == 0) l_cids.insert((*ocsi));
10608                 else                                            r_cids.insert((*ocsi));
10609         }
10610         unpack_null = "";
10611         extra_cids.clear();
10612         for(ocsi=r_cids.begin();ocsi!=r_cids.end();++ocsi){
10613                 string field = (*ocsi).field;
10614                 if(r_equiv.count(field)){
10615                         unpack_null+="\t\tunpack_var_"+field+"_1="+generate_se_code(r_equiv[field],schema)+";\n";
10616                         col_id_set addnl_cids;
10617                         get_new_se_cids(r_equiv[field],l_cids,addnl_cids,NULL);
10618                 }else{
10619                 int schref = (*ocsi).schema_ref;
10620                         data_type dt(schema->get_type_name(schref,field));
10621                         literal_t empty_lit(dt.type_indicator());
10622                         if(empty_lit.is_cpx_lit()){
10623                                 sprintf(tmpstr,"&(unpack_var_%s_1)",field.c_str());
10624                                 unpack_null += "\t"+empty_lit.to_hfta_C_code(tmpstr)+";\n";
10625                         }else{
10626                                 unpack_null+="\tunpack_var_"+field+"_1="+empty_lit.to_hfta_C_code("")+";\n";
10627                         }
10628                 }
10629         }
10630         ret += gen_unpack_cids(schema,  l_cids, "1", needs_xform);
10631         ret += gen_unpack_cids(schema,  extra_cids, "1", needs_xform);
10632         ret += unpack_null;
10633
10634         ret+="\t}else if (tup1.data) {\n";
10635         unpack_null = ""; extra_cids.clear();
10636         for(ocsi=l_cids.begin();ocsi!=l_cids.end();++ocsi){
10637                 string field = (*ocsi).field;
10638                 if(l_equiv.count(field)){
10639                         unpack_null+="\t\tunpack_var_"+field+"_0="+generate_se_code(l_equiv[field],schema)+";\n";
10640                         col_id_set addnl_cids;
10641                         get_new_se_cids(l_equiv[field],r_cids,addnl_cids,NULL);
10642                 }else{
10643                 int schref = (*ocsi).schema_ref;
10644                         data_type dt(schema->get_type_name(schref,field));
10645                         literal_t empty_lit(dt.type_indicator());
10646                         if(empty_lit.is_cpx_lit()){
10647                                 sprintf(tmpstr,"&(unpack_var_%s_0)",field.c_str());
10648                                 unpack_null += "\t"+empty_lit.to_hfta_C_code(tmpstr)+";\n";
10649                         }else{
10650                                 unpack_null+="\tunpack_var_"+field+"_0="+empty_lit.to_hfta_C_code("")+";\n";
10651                         }
10652                 }
10653         }
10654         ret += gen_unpack_cids(schema,  r_cids, "1", needs_xform);
10655         ret += gen_unpack_cids(schema,  extra_cids, "1", needs_xform);
10656         ret += unpack_null;
10657         ret+="\t}\n";
10658
10659         ret += gen_init_temp_status_tuple(this->get_node_name());
10660
10661 //              Start packing.
10662         ret += "//\t\tPack the fields into the tuple.\n";
10663         ret += gen_pack_tuple(schema,select_list,this->get_node_name(), true );
10664
10665
10666         ret += "\treturn 0;\n";
10667         ret += "};\n\n";
10668
10669
10670         ret += "};\n\n\n";
10671
10672 //----------------------------------------------------------
10673 //                      The hash function
10674
10675         ret += "struct "+generate_functor_name()+"_hash_func{\n";
10676         ret += "\tgs_uint32_t operator()(const "+generate_functor_name()+
10677                                 "_keydef *key) const{\n";
10678         ret += "\t\treturn( (";
10679         if(hashkey_dt.size() > 0){
10680           for(p=0;p<hashkey_dt.size();p++){
10681                 if(p>0) ret += "^";
10682                 if(hashkey_dt[p]->use_hashfunc()){
10683 //                      sprintf(tmpstr,"%s(&(key->hashkey_var%d))",hashkey_dt[p]->get_hfta_hashfunc().c_str(),p);
10684                         if(hashkey_dt[p]->is_buffer_type())
10685                                 sprintf(tmpstr,"(%s*%s(&(key->hashkey_var%d)))",hash_nums[p%NRANDS].c_str(),hashkey_dt[p]->get_hfta_hashfunc().c_str(),p);
10686                         else
10687                                 sprintf(tmpstr,"(%s*%s(key->hashkey_var%d))",hash_nums[p%NRANDS].c_str(),hashkey_dt[p]->get_hfta_hashfunc().c_str(),p);
10688                 }else{
10689                         sprintf(tmpstr,"(%s*key->hashkey_var%d)",hash_nums[p%NRANDS].c_str(),p);
10690                 }
10691                 ret += tmpstr;
10692           }
10693         }else{
10694                 ret += "0";
10695         }
10696         ret += ") >> 32);\n";
10697         ret += "\t}\n";
10698         ret += "};\n\n";
10699
10700 //----------------------------------------------------------
10701 //                      The comparison function
10702
10703         ret += "struct "+generate_functor_name()+"_equal_func{\n";
10704         ret += "\tbool operator()(const "+generate_functor_name()+"_keydef *key1, "+
10705                         generate_functor_name()+"_keydef *key2) const{\n";
10706         ret += "\t\treturn( (";
10707         if(hashkey_dt.size() > 0){
10708           for(p=0;p<hashkey_dt.size();p++){
10709                 if(p>0) ret += ") && (";
10710                 if(hashkey_dt[p]->complex_comparison(hashkey_dt[p])){
10711                   if(hashkey_dt[p]->is_buffer_type())
10712                         sprintf(tmpstr,"(%s(&(key1->hashkey_var%d), &(key2->hashkey_var%d))==0)",
10713                                 hashkey_dt[p]->get_hfta_comparison_fcn(hashkey_dt[p]).c_str(),p,p);
10714                   else
10715                         sprintf(tmpstr,"(%s((key1->hashkey_var%d), (key2->hashkey_var%d))==0)",
10716                                 hashkey_dt[p]->get_hfta_comparison_fcn(hashkey_dt[p]).c_str(),p,p);
10717                 }else{
10718                         sprintf(tmpstr,"key1->hashkey_var%d == key2->hashkey_var%d",p,p);
10719                 }
10720                 ret += tmpstr;
10721           }
10722         }else{
10723                 ret += "1";
10724         }
10725         ret += ") );\n";
10726         ret += "\t}\n";
10727         ret += "};\n\n";
10728
10729
10730         return(ret);
10731 }
10732
10733
10734
10735 string join_eq_hash_qpn::generate_operator(int i, string params){
10736
10737                 return(
10738                         "       join_eq_hash_operator<" +
10739                         generate_functor_name()+ ","+
10740                         generate_functor_name() + "_tempeqdef,"+
10741                         generate_functor_name() + "_keydef,"+
10742                         generate_functor_name()+"_hash_func,"+
10743                         generate_functor_name()+"_equal_func"
10744                         "> *op"+int_to_string(i)+" = new join_eq_hash_operator<"+
10745                         generate_functor_name()+","+
10746                         generate_functor_name() + "_tempeqdef,"+
10747                         generate_functor_name() + "_keydef,"+
10748                         generate_functor_name()+"_hash_func,"+
10749                         generate_functor_name()+"_equal_func"
10750                         ">("+params+", "+
10751                         int_to_string(from[0]->get_property()+2*from[1]->get_property())+", \"" + get_node_name() +
10752 "\");\n"
10753                 );
10754 }
10755
10756
10757
10758 ////////////////////////////////////////////////////////////////
10759 ////    SGAHCWCB functor
10760
10761
10762
10763 string sgahcwcb_qpn::generate_functor_name(){
10764         return("sgahcwcb_functor_" + normalize_name(this->get_node_name()));
10765 }
10766
10767
10768 string sgahcwcb_qpn::generate_functor(table_list *schema, ext_fcn_list *Ext_fcns, vector<bool> &needs_xform){
10769         int a,g,w,s;
10770
10771
10772 //                      Initialize generate utility globals
10773         segen_gb_tbl = &(gb_tbl);
10774
10775
10776 //--------------------------------
10777 //                      group definition class
10778         string ret = "class " + generate_functor_name() + "_groupdef{\n";
10779         ret += "public:\n";
10780         ret += "\tbool valid;\n";
10781         for(g=0;g<this->gb_tbl.size();g++){
10782                 sprintf(tmpstr,"gb_var%d",g);
10783                 ret+="\t"+this->gb_tbl.get_data_type(g)->make_host_cvar(tmpstr)+";\n";
10784         }
10785 //              Constructors
10786         ret += "\t"+generate_functor_name() + "_groupdef(){valid=true;};\n";
10787         ret += "\t"+generate_functor_name() + "_groupdef("+
10788                 this->generate_functor_name() + "_groupdef *gd){\n";
10789         for(g=0;g<gb_tbl.size();g++){
10790                 data_type *gdt = gb_tbl.get_data_type(g);
10791                 if(gdt->is_buffer_type()){
10792                         sprintf(tmpstr,"\t\t%s(&gb_var%d, &(gd->gb_var%d));\n",
10793                           gdt->get_hfta_buffer_assign_copy().c_str(),g,g );
10794                         ret += tmpstr;
10795                 }else{
10796                         sprintf(tmpstr,"\t\tgb_var%d = gd->gb_var%d;\n",g,g);
10797                         ret += tmpstr;
10798                 }
10799         }
10800         ret += "\tvalid=true;\n";
10801         ret += "\t};\n";
10802 //              destructor
10803         ret += "\t~"+ generate_functor_name() + "_groupdef(){\n";
10804         for(g=0;g<gb_tbl.size();g++){
10805                 data_type *gdt = gb_tbl.get_data_type(g);
10806                 if(gdt->is_buffer_type()){
10807                         sprintf(tmpstr,"\t\t%s(&gb_var%d);\n",
10808                           gdt->get_hfta_buffer_destroy().c_str(), g );
10809                         ret += tmpstr;
10810                 }
10811         }
10812         ret += "\t};\n";
10813         ret +="};\n\n";
10814
10815 //--------------------------------
10816 //                      aggr definition class
10817         ret += "class " + this->generate_functor_name() + "_aggrdef{\n";
10818         ret += "public:\n";
10819         for(a=0;a<aggr_tbl.size();a++){
10820 aggr_table_entry *ate = aggr_tbl.agr_tbl[a];
10821                 sprintf(tmpstr,"aggr_var%d",a);
10822                 if(aggr_tbl.is_builtin(a))
10823                 ret+="\t"+ aggr_tbl.get_data_type(a)->make_host_cvar(tmpstr)+";\n";
10824                 else
10825                 ret+="\t"+ aggr_tbl.get_storage_type(a)->make_host_cvar(tmpstr)+";\n";
10826         }
10827 //              Constructors
10828         ret += "\t"+this->generate_functor_name() + "_aggrdef(){};\n";
10829 //              destructor
10830         ret += "\t~"+this->generate_functor_name() + "_aggrdef(){\n";
10831         for(a=0;a<aggr_tbl.size();a++){
10832 aggr_table_entry *ate = aggr_tbl.agr_tbl[a];
10833                 if(aggr_tbl.is_builtin(a)){
10834                         data_type *adt = aggr_tbl.get_data_type(a);
10835                         if(adt->is_buffer_type()){
10836                                 sprintf(tmpstr,"\t\t%s(&aggr_var%d);\n",
10837                                 adt->get_hfta_buffer_destroy().c_str(), a );
10838                                 ret += tmpstr;
10839                         }
10840                 }else{
10841                         ret+="\t\t"+aggr_tbl.get_op(a)+"_HFTA_AGGR_DESTROY_(";
10842                         if(aggr_tbl.get_storage_type(a)->get_type() != fstring_t) ret+="&";
10843                         ret+="(aggr_var"+int_to_string(a)+"));\n";
10844                 }
10845         }
10846         ret += "\t};\n";
10847         ret +="};\n\n";
10848
10849 //--------------------------------
10850 //                      superaggr definition class
10851         ret += "class " + this->generate_functor_name() + "_statedef{\n";
10852         ret += "public:\n";
10853         for(a=0;a<aggr_tbl.size();a++){
10854 aggr_table_entry *ate = aggr_tbl.agr_tbl[a];
10855                 if(ate->is_superaggr()){
10856                         sprintf(tmpstr,"aggr_var%d",a);
10857                         if(aggr_tbl.is_builtin(a))
10858                         ret+="\t"+ aggr_tbl.get_data_type(a)->make_host_cvar(tmpstr)+";\n";
10859                         else
10860                         ret+="\t"+ aggr_tbl.get_storage_type(a)->make_host_cvar(tmpstr)+";\n";
10861                 }
10862         }
10863         set<string>::iterator ssi;
10864         for(ssi=states_refd.begin(); ssi!=states_refd.end(); ++ssi){
10865                 string state_nm = (*ssi);
10866                 int state_id = Ext_fcns->lookup_state(state_nm);
10867                 data_type *dt = Ext_fcns->get_storage_dt(state_id);
10868                 string state_var = "state_var_"+state_nm;
10869                 ret += "\t"+dt->make_host_cvar(state_var)+";\n";
10870         }
10871 //              Constructors
10872         ret += "\t"+this->generate_functor_name() + "_statedef(){};\n";
10873 //              destructor
10874         ret += "\t~"+this->generate_functor_name() + "_statedef(){\n";
10875         for(a=0;a<aggr_tbl.size();a++){
10876 aggr_table_entry *ate = aggr_tbl.agr_tbl[a];
10877                 if(ate->is_superaggr()){
10878                         if(aggr_tbl.is_builtin(a)){
10879                                 data_type *adt = aggr_tbl.get_data_type(a);
10880                                 if(adt->is_buffer_type()){
10881                                         sprintf(tmpstr,"\t\t%s(&aggr_var%d);\n",
10882                                         adt->get_hfta_buffer_destroy().c_str(), a );
10883                                         ret += tmpstr;
10884                                 }
10885                         }else{
10886                                 ret+="\t\t"+aggr_tbl.get_op(a)+"_HFTA_AGGR_DESTROY_(";
10887                                 if(aggr_tbl.get_storage_type(a)->get_type() != fstring_t) ret+="&";
10888                                 ret+="(aggr_var"+int_to_string(a)+"));\n";
10889                         }
10890                 }
10891         }
10892         for(ssi=states_refd.begin(); ssi!=states_refd.end(); ++ssi){
10893                 string state_nm = (*ssi);
10894                 int state_id = Ext_fcns->lookup_state(state_nm);
10895                 string state_var = "state_var_"+state_nm;
10896                 ret += "\t_sfun_state_destroy_"+state_nm+"(&"+state_var+");\n";
10897         }
10898
10899         ret += "\t};\n";
10900         ret +="};\n\n";
10901
10902
10903 //--------------------------------
10904 //                      gb functor class
10905         ret += "class " + this->generate_functor_name() + "{\n";
10906
10907 //                      Find variables referenced in this query node.
10908
10909   col_id_set cid_set;
10910   col_id_set::iterator csi;
10911
10912     for(w=0;w<where.size();++w)
10913         gather_pr_col_ids(where[w]->pr,cid_set,segen_gb_tbl);
10914     for(w=0;w<having.size();++w)
10915         gather_pr_col_ids(having[w]->pr,cid_set,segen_gb_tbl);
10916     for(w=0;w<cleanby.size();++w)
10917         gather_pr_col_ids(cleanby[w]->pr,cid_set,segen_gb_tbl);
10918     for(w=0;w<cleanwhen.size();++w)
10919         gather_pr_col_ids(cleanwhen[w]->pr,cid_set,segen_gb_tbl);
10920         for(g=0;g<gb_tbl.size();g++)
10921                 gather_se_col_ids(gb_tbl.get_def(g),cid_set,segen_gb_tbl);
10922
10923     for(s=0;s<select_list.size();s++){
10924         gather_se_col_ids(select_list[s]->se,cid_set,segen_gb_tbl);     // descends into aggregates
10925     }
10926
10927
10928 //                      Private variables : store the state of the functor.
10929 //                      1) variables for unpacked attributes
10930 //                      2) offsets of the upacked attributes
10931 //                      3) storage of partial functions
10932 //                      4) storage of complex literals (i.e., require a constructor)
10933
10934         ret += "private:\n";
10935
10936         // var to save the schema handle
10937         ret += "\tint schema_handle0;\n";
10938
10939         // generate the declaration of all the variables related to
10940         // temp tuples generation
10941         ret += gen_decl_temp_vars();
10942
10943 //                      unpacked attribute storage, offsets
10944         ret += "//\t\tstorage and offsets of accessed fields.\n";
10945         ret += generate_access_vars(cid_set, schema);
10946 //              tuple metadata offset
10947         ret += "\ttuple_metadata_offset0;\n";
10948
10949 //                      Variables to store results of partial functions.
10950 //                      WARNING find_partial_functions modifies the SE
10951 //                      (it marks the partial function id).
10952         ret += "//\t\tParital function result storage\n";
10953         vector<scalarexp_t *> partial_fcns;
10954         vector<int> fcn_ref_cnt;
10955         vector<bool> is_partial_fcn;
10956         for(s=0;s<select_list.size();s++){
10957                 find_partial_fcns(select_list[s]->se, &partial_fcns, NULL,NULL, Ext_fcns);
10958         }
10959         for(w=0;w<where.size();w++){
10960                 find_partial_fcns_pr(where[w]->pr, &partial_fcns, NULL,NULL, Ext_fcns);
10961         }
10962         for(w=0;w<having.size();w++){
10963                 find_partial_fcns_pr(having[w]->pr, &partial_fcns, NULL,NULL, Ext_fcns);
10964         }
10965         for(w=0;w<cleanby.size();w++){
10966                 find_partial_fcns_pr(cleanby[w]->pr, &partial_fcns, NULL,NULL, Ext_fcns);
10967         }
10968         for(w=0;w<cleanwhen.size();w++){
10969                 find_partial_fcns_pr(cleanwhen[w]->pr, &partial_fcns, NULL,NULL, Ext_fcns);
10970         }
10971         for(g=0;g<gb_tbl.size();g++){
10972                 find_partial_fcns(gb_tbl.get_def(g), &partial_fcns, NULL,NULL, Ext_fcns);
10973         }
10974         for(a=0;a<aggr_tbl.size();a++){
10975                 find_partial_fcns(aggr_tbl.get_aggr_se(a), &partial_fcns, NULL,NULL, Ext_fcns);
10976         }
10977         if(partial_fcns.size()>0){
10978           ret += "/*\t\tVariables for storing results of partial functions. \t*/\n";
10979           ret += generate_partial_fcn_vars(partial_fcns,fcn_ref_cnt,is_partial_fcn,false);
10980         }
10981
10982 //                      Complex literals (i.e., they need constructors)
10983         ret += "//\t\tComplex literal storage.\n";
10984         cplx_lit_table *complex_literals = this->get_cplx_lit_tbl(Ext_fcns);
10985         ret += generate_complex_lit_vars(complex_literals);
10986
10987 //                      Pass-by-handle parameters
10988         ret += "//\t\tPass-by-handle storage.\n";
10989         vector<handle_param_tbl_entry *> param_handle_table = this->get_handle_param_tbl(Ext_fcns);
10990         ret += generate_pass_by_handle_vars(param_handle_table);
10991
10992 //                      Create cached temporaries for UDAF return values.
10993         ret += "//\t\tTemporaries for UDAF return values.\n";
10994         for(a=0;a<aggr_tbl.size();a++){
10995                 if(! aggr_tbl.is_builtin(a)){
10996                         int afcn_id = aggr_tbl.get_fcn_id(a);
10997                         data_type *adt = Ext_fcns->get_fcn_dt(afcn_id);
10998                         sprintf(tmpstr,"udaf_ret_%d", a);
10999                         ret+="\t"+adt->make_host_cvar(tmpstr)+";\n";
11000                 }
11001         }
11002
11003
11004
11005 //                      variables to hold parameters.
11006         ret += "//\tfor query parameters\n";
11007         ret += generate_param_vars(param_tbl);
11008
11009 //              Is there a temporal flush?  If so create flush temporaries,
11010 //              create flush indicator.
11011         bool uses_temporal_flush = false;
11012         for(g=0;g<gb_tbl.size();g++){
11013                 data_type *gdt = gb_tbl.get_data_type(g);
11014                 if(gdt->is_temporal())
11015                         uses_temporal_flush = true;
11016         }
11017
11018         if(uses_temporal_flush){
11019                 ret += "//\t\tFor temporal flush\n";
11020                 for(g=0;g<gb_tbl.size();g++){
11021                         data_type *gdt = gb_tbl.get_data_type(g);
11022                         if(gdt->is_temporal()){
11023                           sprintf(tmpstr,"last_gb%d",g);
11024                           ret+="\t"+gb_tbl.get_data_type(g)->make_host_cvar(tmpstr)+";\n";
11025                           sprintf(tmpstr,"last_flushed_gb%d",g);
11026                           ret+="\t"+gb_tbl.get_data_type(g)->make_host_cvar(tmpstr)+";\n";
11027                         }
11028                 }
11029                 ret += "\tbool needs_temporal_flush;\n";
11030         }
11031
11032 //                      The publicly exposed functions
11033
11034         ret += "\npublic:\n";
11035
11036
11037 //-------------------
11038 //                      The functor constructor
11039 //                      pass in the schema handle.
11040 //                      1) make assignments to the unpack offset variables
11041 //                      2) initialize the complex literals
11042
11043         ret += "//\t\tFunctor constructor.\n";
11044         ret +=  this->generate_functor_name()+"(int schema_handle0){\n";
11045
11046         // save the schema handle
11047         ret += "\t\tthis->schema_handle0 = schema_handle0;\n";
11048 //              tuple metadata offset
11049         ret += "\ttuple_metadata_offset0 = ftaschema_get_tuple_metadata_offset(schema_handle0);\n";
11050
11051 //              unpack vars
11052         ret += "//\t\tGet offsets for unpacking fields from input tuple.\n";
11053         ret += gen_access_var_init(cid_set);
11054
11055 //              aggregate return vals : refd in both final_sample
11056 //              and create_output_tuple
11057 //                      Create cached temporaries for UDAF return values.
11058         for(a=0;a<aggr_tbl.size();a++){
11059                 if(! aggr_tbl.is_builtin(a)){
11060                         int afcn_id = aggr_tbl.get_fcn_id(a);
11061                         data_type *adt = Ext_fcns->get_fcn_dt(afcn_id);
11062                         sprintf(tmpstr,"udaf_ret_%d", a);
11063                         ret+="\t"+adt->make_host_cvar(tmpstr)+";\n";
11064                 }
11065         }
11066
11067 //              complex literals
11068         ret += "//\t\tInitialize complex literals.\n";
11069         ret += gen_complex_lit_init(complex_literals);
11070
11071 //              Initialize partial function results so they can be safely GC'd
11072         ret += gen_partial_fcn_init(partial_fcns);
11073
11074 //              Initialize non-query-parameter parameter handles
11075         ret += gen_pass_by_handle_init(param_handle_table);
11076
11077 //              temporal flush variables
11078 //              ASSUME that structured values won't be temporal.
11079         if(uses_temporal_flush){
11080                 ret += "//\t\tInitialize temporal flush variables.\n";
11081                 for(g=0;g<gb_tbl.size();g++){
11082                         data_type *gdt = gb_tbl.get_data_type(g);
11083                         if(gdt->is_temporal()){
11084                                 literal_t gl(gdt->type_indicator());
11085                                 sprintf(tmpstr,"\tlast_gb%d = %s;\n",g, gl.to_hfta_C_code("").c_str());
11086                                 ret.append(tmpstr);
11087                         }
11088                 }
11089                 ret += "\tneeds_temporal_flush = false;\n";
11090         }
11091
11092         //              Init temporal attributes referenced in select list
11093         ret += gen_init_temp_vars(schema, select_list, segen_gb_tbl);
11094
11095         ret += "};\n";
11096
11097
11098 //-------------------
11099 //                      Functor destructor
11100         ret += "//\t\tFunctor destructor.\n";
11101         ret +=  "~"+this->generate_functor_name()+"(){\n";
11102
11103 //                      clean up buffer type complex literals
11104         ret += gen_complex_lit_dtr(complex_literals);
11105
11106 //                      Deregister the pass-by-handle parameters
11107         ret += "/* register and de-register the pass-by-handle parameters */\n";
11108         ret += gen_pass_by_handle_dtr(param_handle_table);
11109
11110 //                      clean up partial function results.
11111         ret += "/* clean up partial function storage    */\n";
11112         ret += gen_partial_fcn_dtr(partial_fcns);
11113
11114 //                      Destroy the parameters, if any need to be destroyed
11115         ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";
11116
11117         ret += "};\n\n";
11118
11119
11120 //-------------------
11121 //                      Parameter manipulation routines
11122         ret += generate_load_param_block(this->generate_functor_name(),
11123                                                                         this->param_tbl,param_handle_table);
11124         ret += generate_delete_param_block(this->generate_functor_name(),
11125                                                                         this->param_tbl,param_handle_table);
11126
11127 //-------------------
11128 //                      Register new parameter block
11129
11130         ret += "int set_param_block(gs_int32_t sz, void* value){\n";
11131           ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";
11132           ret += "\treturn this->load_params_"+this->generate_functor_name()+
11133                                 "(sz, value);\n";
11134         ret += "};\n\n";
11135
11136 //-------------------
11137 //              the create_group method.
11138 //              This method creates a group in a buffer passed in
11139 //              (to allow for creation on the stack).
11140 //              There are also a couple of side effects:
11141 //              1) evaluate the WHERE clause (and therefore, unpack all partial fcns)
11142 //              2) determine if a temporal flush is required.
11143
11144         ret += this->generate_functor_name()+"_groupdef *create_group(host_tuple &tup0, gs_sp_t buffer){\n";
11145         //              Variables for execution of the function.
11146         ret += "\tgs_int32_t problem = 0;\n";   // return unpack failure
11147
11148         if(partial_fcns.size()>0){              // partial fcn access failure
11149           ret += "\tgs_retval_t retval = 0;\n";
11150           ret += "\n";
11151         }
11152 //              return value
11153         ret += "\t"+generate_functor_name()+"_groupdef *gbval = ("+generate_functor_name()+
11154                         "_groupdef *) buffer;\n";
11155
11156 //              Start by cleaning up partial function results
11157         ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";
11158
11159         set<int> gb_pfcns;      // partial fcns in gbdefs, aggr se's
11160         for(g=0;g<gb_tbl.size();g++){
11161                 collect_partial_fcns(gb_tbl.get_def(g), gb_pfcns);
11162         }
11163         ret += gen_partial_fcn_dtr(partial_fcns,gb_pfcns);
11164 //      ret += gen_partial_fcn_dtr(partial_fcns);
11165
11166
11167         ret += gen_temp_tuple_check(this->node_name, 0);
11168         col_id_set found_cids;  // colrefs unpacked thus far.
11169         ret += gen_unpack_temp_vars(schema, found_cids, select_list, segen_gb_tbl, needs_xform);
11170
11171
11172
11173 //                      Save temporal group-by variables
11174
11175
11176         ret.append("\n\t//\t\tCompute temporal groupby attributes\n\n");
11177
11178           for(g=0;g<gb_tbl.size();g++){
11179
11180                         data_type *gdt = gb_tbl.get_data_type(g);
11181
11182                         if(gdt->is_temporal()){
11183                                 sprintf(tmpstr,"\tgbval->gb_var%d = %s;\n",
11184                                         g, generate_se_code(gb_tbl.get_def(g),schema).c_str() );
11185                                 ret.append(tmpstr);
11186                         }
11187                 }
11188                 ret.append("\n");
11189
11190
11191
11192 //                      Compare the temporal GB vars with the stored ones,
11193 //                      set flush indicator and update stored GB vars if there is any change.
11194
11195         if(uses_temporal_flush){
11196                 ret+= "\tif( !( (";
11197                 bool first_one = true;
11198                 for(g=0;g<gb_tbl.size();g++){
11199                         data_type *gdt = gb_tbl.get_data_type(g);
11200
11201                         if(gdt->is_temporal()){
11202                           sprintf(tmpstr,"last_gb%d",g);   string lhs_op = tmpstr;
11203                           sprintf(tmpstr,"gbval->gb_var%d",g);   string rhs_op = tmpstr;
11204                           if(first_one){first_one = false;} else {ret += ") && (";}
11205                           ret += generate_equality_test(lhs_op, rhs_op, gdt);
11206                         }
11207                 }
11208                 ret += ") ) ){\n";
11209                 for(g=0;g<gb_tbl.size();g++){
11210                   data_type *gdt = gb_tbl.get_data_type(g);
11211                   if(gdt->is_temporal()){
11212                           if(gdt->is_buffer_type()){
11213                                 sprintf(tmpstr,"\t\t%s(&(gbval->gb_var%d),&last_gb%d);\n",gdt->get_hfta_buffer_replace().c_str(),g,g);
11214                           }else{
11215                                 sprintf(tmpstr,"\t\tlast_flushed_gb%d = last_gb%d;\n",g,g);
11216                                 ret += tmpstr;
11217                                 sprintf(tmpstr,"\t\tlast_gb%d = gbval->gb_var%d;\n",g,g);
11218                           }
11219                           ret += tmpstr;
11220                         }
11221                 }
11222 /*
11223                 if(uses_temporal_flush){
11224                         for(g=0;g<gb_tbl.size();g++){
11225                                 data_type *gdt = gb_tbl.get_data_type(g);
11226                                 if(gdt->is_temporal()){
11227                                         ret+="if(last_flushed_gb"+int_to_string(g)+">0)\n";
11228                                         break;
11229                                 }
11230                         }
11231                 }
11232 */
11233                 ret += "\t\tneeds_temporal_flush=true;\n";
11234                 ret += "\t\t}else{\n"
11235                         "\t\t\tneeds_temporal_flush=false;\n"
11236                         "\t\t}\n";
11237         }
11238
11239
11240 //              For temporal status tuple we don't need to do anything else
11241         ret += "\tif (temp_tuple_received) return NULL;\n\n";
11242
11243
11244 //              The partial functions ref'd in the group-by var
11245 //              definitions must be evaluated.  If one returns false,
11246 //              then implicitly the predicate is false.
11247         set<int>::iterator pfsi;
11248
11249         if(gb_pfcns.size() > 0)
11250                 ret += "//\t\tUnpack partial fcns.\n";
11251         ret += gen_full_unpack_partial_fcn(schema, partial_fcns, gb_pfcns,
11252                                                                                 found_cids, segen_gb_tbl, "NULL", needs_xform);
11253
11254 //                      Unpack the group-by variables
11255
11256           for(g=0;g<gb_tbl.size();g++){
11257 //                      Find the new fields ref'd by this GBvar def.
11258                 col_id_set new_cids;
11259                 get_new_se_cids(gb_tbl.get_def(g), found_cids, new_cids, segen_gb_tbl);
11260 //                      Unpack these values.
11261                 ret += gen_unpack_cids(schema, new_cids, "NULL", needs_xform);
11262
11263                 sprintf(tmpstr,"\tgbval->gb_var%d = %s;\n",
11264                                 g, generate_se_code(gb_tbl.get_def(g),schema).c_str() );
11265 /*
11266 //                              There seems to be no difference between the two
11267 //                              branches of the IF statement.
11268                 data_type *gdt = gb_tbl.get_data_type(g);
11269                   if(gdt->is_buffer_type()){
11270 //                              Create temporary copy.
11271                         sprintf(tmpstr,"\tgbval->gb_var%d = %s;\n",
11272                                 g, generate_se_code(gb_tbl.get_def(g),schema).c_str() );
11273                   }else{
11274                         scalarexp_t *gse = gb_tbl.get_def(g);
11275                         sprintf(tmpstr,"\tgbval->gb_var%d = %s;\n",
11276                                         g,generate_se_code(gse,schema).c_str());
11277                   }
11278 */
11279                   ret.append(tmpstr);
11280           }
11281           ret.append("\n");
11282
11283
11284         ret+= "\treturn gbval;\n";
11285         ret += "};\n\n\n";
11286
11287
11288
11289 //-------------------
11290 //              the create_group method.
11291 //              This method creates a group in a buffer passed in
11292 //              (to allow for creation on the stack).
11293 //              There are also a couple of side effects:
11294 //              1) evaluate the WHERE clause (and therefore, unpack all partial fcns)
11295 //              2) determine if a temporal flush is required.
11296
11297         ret += "bool evaluate_predicate(host_tuple &tup0, "+generate_functor_name()+"_groupdef *gbval, "+generate_functor_name()+"_statedef *stval, int cd){\n";
11298         //              Variables for execution of the function.
11299         ret += "\tgs_int32_t problem = 0;\n";   // return unpack failure
11300
11301         if(partial_fcns.size()>0){              // partial fcn access failure
11302           ret += "\tgs_retval_t retval = 0;\n";
11303           ret += "\n";
11304         }
11305
11306 //              Start by cleaning up partial function results
11307         ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";
11308         set<int> w_pfcns;       // partial fcns in where clause
11309         for(w=0;w<where.size();++w)
11310                 collect_partial_fcns_pr(where[w]->pr, w_pfcns);
11311
11312         set<int> ag_pfcns;      // partial fcns in gbdefs, aggr se's
11313         for(a=0;a<aggr_tbl.size();a++){
11314                 collect_partial_fcns(aggr_tbl.get_aggr_se(a), ag_pfcns);
11315         }
11316         ret += gen_partial_fcn_dtr(partial_fcns,w_pfcns);
11317         ret += gen_partial_fcn_dtr(partial_fcns,ag_pfcns);
11318
11319         ret+="//\t\tEvaluate clauses which don't reference stateful fcns first \n";
11320         for(w=0;w<where.size();++w){
11321                 if(! pred_refs_sfun(where[w]->pr)){
11322                         sprintf(tmpstr,"//\t\tPredicate clause %d.\n",w);
11323                         ret += tmpstr;
11324 //                      Find the set of variables accessed in this CNF elem,
11325 //                      but in no previous element.
11326                         col_id_set new_cids;
11327                         get_new_pred_cids(where[w]->pr, found_cids, new_cids, segen_gb_tbl);
11328
11329 //                      Unpack these values.
11330                         ret += gen_unpack_cids(schema, new_cids, "false", needs_xform);
11331 //                      Find partial fcns ref'd in this cnf element
11332                         set<int> pfcn_refs;
11333                         collect_partial_fcns_pr(where[w]->pr, pfcn_refs);
11334                         ret += gen_unpack_partial_fcn(schema, partial_fcns, pfcn_refs,"false");
11335
11336                         ret += "\tif( !("+generate_predicate_code(where[w]->pr,schema)+
11337                                 +") ) return(false);\n";
11338                 }
11339         }
11340
11341
11342 //              The partial functions ref'd in the and aggregate
11343 //              definitions must also be evaluated.  If one returns false,
11344 //              then implicitly the predicate is false.
11345 //              ASSUME that aggregates cannot reference stateful fcns.
11346
11347         if(ag_pfcns.size() > 0)
11348                 ret += "//\t\tUnpack remaining partial fcns.\n";
11349         ret += gen_full_unpack_partial_fcn(schema, partial_fcns, ag_pfcns,
11350                                                                                 found_cids, segen_gb_tbl, "false", needs_xform);
11351
11352         ret+="//\t\tEvaluate all remaining where clauses.\n";
11353         ret+="\tbool retval = true;\n";
11354         for(w=0;w<where.size();++w){
11355                 if( pred_refs_sfun(where[w]->pr)){
11356                         sprintf(tmpstr,"//\t\tPredicate clause %d.\n",w);
11357                         ret += tmpstr;
11358 //                      Find the set of variables accessed in this CNF elem,
11359 //                      but in no previous element.
11360                         col_id_set new_cids;
11361                         get_new_pred_cids(where[w]->pr, found_cids, new_cids, segen_gb_tbl);
11362
11363 //                      Unpack these values.
11364                         ret += gen_unpack_cids(schema, new_cids, "false", needs_xform);
11365 //                      Find partial fcns ref'd in this cnf element
11366                         set<int> pfcn_refs;
11367                         collect_partial_fcns_pr(where[w]->pr, pfcn_refs);
11368                         ret += gen_unpack_partial_fcn(schema, partial_fcns, pfcn_refs,"false");
11369
11370                         ret += "\tif( !("+generate_predicate_code(where[w]->pr,schema)+
11371                                 +") ) retval = false;\n";
11372                 }
11373         }
11374
11375         ret+="//                Unpack all remaining attributes\n";
11376         ret += gen_remaining_colrefs(schema, cid_set, found_cids, "false", needs_xform);
11377
11378     ret += "\n\treturn retval;\n";
11379         ret += "};\n\n\n";
11380
11381 //--------------------------------------------------------
11382 //                      Create and initialize an aggregate object
11383
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";
11385         //              Variables for execution of the function.
11386         ret += "\tgs_int32_t problem = 0;\n";   // return unpack failure
11387
11388 //              return value
11389         ret += "\t"+generate_functor_name()+"_aggrdef *aggval = ("+generate_functor_name()+ "_aggrdef *)a;\n";
11390
11391         for(a=0;a<aggr_tbl.size();a++){
11392                 if(aggr_tbl.is_builtin(a)){
11393 //                      Create temporaries for buffer return values
11394                   data_type *adt = aggr_tbl.get_data_type(a);
11395                   if(adt->is_buffer_type()){
11396                         sprintf(tmpstr,"aggr_tmp_%d", a);
11397                         ret+=adt->make_host_cvar(tmpstr)+";\n";
11398                   }
11399                 }
11400         }
11401
11402         for(a=0;a<aggr_tbl.size();a++){
11403                 sprintf(tmpstr,"aggval->aggr_var%d",a);
11404                 string assignto_var = tmpstr;
11405                 ret += "\t"+generate_aggr_init(assignto_var,&aggr_tbl,a, schema);
11406         }
11407
11408         ret += "\treturn aggval;\n";
11409         ret += "};\n\n";
11410
11411
11412 //--------------------------------------------------------
11413 //                      initialize an aggregate object inplace
11414
11415         ret += "void create_aggregate(host_tuple &tup0, "+this->generate_functor_name()+"_aggrdef *aggval,"+generate_functor_name()+"_statedef *stval, int cd){\n";
11416         //              Variables for execution of the function.
11417         ret += "\tgs_int32_t problem = 0;\n";   // return unpack failure
11418
11419 //              return value
11420
11421         for(a=0;a<aggr_tbl.size();a++){
11422                 if(aggr_tbl.is_builtin(a)){
11423 //                      Create temporaries for buffer return values
11424                   data_type *adt = aggr_tbl.get_data_type(a);
11425                   if(adt->is_buffer_type()){
11426                         sprintf(tmpstr,"aggr_tmp_%d", a);
11427                         ret+=adt->make_host_cvar(tmpstr)+";\n";
11428                   }
11429                 }
11430         }
11431
11432         for(a=0;a<aggr_tbl.size();a++){
11433                 sprintf(tmpstr,"aggval->aggr_var%d",a);
11434                 string assignto_var = tmpstr;
11435                 ret += "\t"+generate_aggr_init(assignto_var,&aggr_tbl,a, schema);
11436         }
11437
11438         ret += "};\n\n";
11439
11440
11441 //--------------------------------------------------------
11442 //                      Create and clean-initialize an state object
11443
11444         ret += "void initialize_state(host_tuple &tup0, "+generate_functor_name()+"_groupdef *gbval, "+generate_functor_name()+"_statedef *stval){\n";
11445         //              Variables for execution of the function.
11446         ret += "\tgs_int32_t problem = 0;\n";   // return unpack failure
11447
11448 //              return value
11449 //      ret += "\t"+generate_functor_name()+"_statedef *stval = ("+generate_functor_name()+ "_statedef *)s;\n";
11450
11451         for(a=0;a<aggr_tbl.size();a++){
11452                 if( aggr_tbl.is_superaggr(a)){
11453                         if(aggr_tbl.is_builtin(a)){
11454 //                      Create temporaries for buffer return values
11455                           data_type *adt = aggr_tbl.get_data_type(a);
11456                           if(adt->is_buffer_type()){
11457                                 sprintf(tmpstr,"aggr_tmp_%d", a);
11458                                 ret+=adt->make_host_cvar(tmpstr)+";\n";
11459                           }
11460                         }
11461                 }
11462         }
11463
11464         for(a=0;a<aggr_tbl.size();a++){
11465                 if( aggr_tbl.is_superaggr(a)){
11466                         sprintf(tmpstr,"stval->aggr_var%d",a);
11467                         string assignto_var = tmpstr;
11468                         ret += "\t"+generate_aggr_init(assignto_var,&aggr_tbl,a, schema);
11469                 }
11470         }
11471
11472         for(ssi=states_refd.begin(); ssi!=states_refd.end();++ssi){
11473                 string state_nm = (*ssi);
11474                 ret += "_sfun_state_clean_init_"+state_nm+"(&(stval->state_var_"+state_nm+"));\n";
11475         }
11476
11477         ret += "};\n\n";
11478
11479
11480 //--------------------------------------------------------
11481 //                      Create and dirty-initialize an state object
11482
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";
11484         //              Variables for execution of the function.
11485         ret += "\tgs_int32_t problem = 0;\n";   // return unpack failure
11486
11487 //              return value
11488 //      ret += "\t"+generate_functor_name()+"_statedef *stval = ("+generate_functor_name()+ "_statedef *)s;\n";
11489
11490         for(a=0;a<aggr_tbl.size();a++){
11491                 if( aggr_tbl.is_superaggr(a)){
11492                         if(aggr_tbl.is_builtin(a)){
11493 //                      Create temporaries for buffer return values
11494                           data_type *adt = aggr_tbl.get_data_type(a);
11495                           if(adt->is_buffer_type()){
11496                                 sprintf(tmpstr,"aggr_tmp_%d", a);
11497                                 ret+=adt->make_host_cvar(tmpstr)+";\n";
11498                           }
11499                         }
11500                 }
11501         }
11502
11503 //              initialize superaggregates
11504         for(a=0;a<aggr_tbl.size();a++){
11505                 if( aggr_tbl.is_superaggr(a)){
11506                         sprintf(tmpstr,"stval->aggr_var%d",a);
11507                         string assignto_var = tmpstr;
11508                         ret += "\t"+generate_aggr_init(assignto_var,&aggr_tbl,a, schema);
11509                 }
11510         }
11511
11512         for(ssi=states_refd.begin(); ssi!=states_refd.end();++ssi){
11513                 string state_nm = (*ssi);
11514                 ret += "_sfun_state_dirty_init_"+state_nm+"(&(stval->state_var_"+state_nm+"),&(old_stval->state_var_"+state_nm+"), cd );\n";
11515         }
11516
11517         ret += "};\n\n";
11518
11519 //--------------------------------------------------------
11520 //              Finalize_state : call the finalize fcn on all states
11521
11522
11523         ret += "void finalize_state( "+generate_functor_name()+"_statedef *stval, int cd){\n";
11524
11525         for(ssi=states_refd.begin(); ssi!=states_refd.end();++ssi){
11526                 string state_nm = (*ssi);
11527                 ret += "_sfun_state_final_init_"+state_nm+"(&(stval->state_var_"+state_nm+"), cd);\n";
11528         }
11529
11530         ret += "};\n\n";
11531
11532
11533
11534
11535 //--------------------------------------------------------
11536 //                      update (plus) a superaggregate object
11537
11538         ret += "void update_plus_superaggr(host_tuple &tup0, " +
11539                 generate_functor_name()+"_groupdef *gbval, "+
11540                 generate_functor_name()+"_statedef *stval){\n";
11541         //              Variables for execution of the function.
11542         ret += "\tgs_int32_t problem = 0;\n";   // return unpack failure
11543
11544 //                      use of temporaries depends on the aggregate,
11545 //                      generate them in generate_aggr_update
11546
11547
11548         for(a=0;a<aggr_tbl.size();a++){
11549           if(aggr_tbl.is_superaggr(a)){
11550                 sprintf(tmpstr,"stval->aggr_var%d",a);
11551                 string varname = tmpstr;
11552                 ret.append(generate_aggr_update(varname,&aggr_tbl,a, schema));
11553           }
11554         }
11555
11556         ret += "\treturn;\n";
11557         ret += "};\n";
11558
11559
11560
11561 //--------------------------------------------------------
11562 //                      update (minus) a superaggregate object
11563
11564         ret += "void update_minus_superaggr( "+
11565                 generate_functor_name()+"_groupdef *gbval, "+
11566                 generate_functor_name()+"_aggrdef *aggval,"+
11567                 generate_functor_name()+"_statedef *stval"+
11568                 "){\n";
11569         //              Variables for execution of the function.
11570         ret += "\tgs_int32_t problem = 0;\n";   // return unpack failure
11571
11572 //                      use of temporaries depends on the aggregate,
11573 //                      generate them in generate_aggr_update
11574
11575
11576         for(a=0;a<aggr_tbl.size();a++){
11577           if(aggr_tbl.is_superaggr(a)){
11578                 sprintf(tmpstr,"stval->aggr_var%d",a);
11579                 string super_varname = tmpstr;
11580                 sprintf(tmpstr,"aggval->aggr_var%d",a);
11581                 string sub_varname = tmpstr;
11582                 ret.append(generate_superaggr_minus(sub_varname, super_varname,&aggr_tbl,a, schema));
11583           }
11584         }
11585
11586         ret += "\treturn;\n";
11587         ret += "};\n";
11588
11589
11590 //--------------------------------------------------------
11591 //                      update an aggregate object
11592
11593         ret += "void update_aggregate(host_tuple &tup0, "
11594                 +generate_functor_name()+"_groupdef *gbval, "+
11595                 generate_functor_name()+"_aggrdef *aggval,"+generate_functor_name()+"_statedef *stval, int cd){\n";
11596         //              Variables for execution of the function.
11597         ret += "\tgs_int32_t problem = 0;\n";   // return unpack failure
11598
11599 //                      use of temporaries depends on the aggregate,
11600 //                      generate them in generate_aggr_update
11601
11602
11603         for(a=0;a<aggr_tbl.size();a++){
11604           sprintf(tmpstr,"aggval->aggr_var%d",a);
11605           string varname = tmpstr;
11606           ret.append(generate_aggr_update(varname,&aggr_tbl,a, schema));
11607         }
11608
11609         ret += "\treturn;\n";
11610         ret += "};\n";
11611
11612 //---------------------------------------------------
11613 //                      Flush test
11614
11615         ret += "\tbool flush_needed(){\n";
11616         if(uses_temporal_flush){
11617                 ret += "\t\treturn needs_temporal_flush;\n";
11618         }else{
11619                 ret += "\t\treturn false;\n";
11620         }
11621         ret += "\t};\n";
11622
11623
11624 //------------------------------------------------------
11625 //                      THe cleaning_when predicate
11626
11627         string gbvar = "gbval->gb_var";
11628         string aggvar = "aggval->";
11629
11630         ret += "bool need_to_clean( "
11631                 +generate_functor_name()+"_groupdef *gbval, "+
11632                 generate_functor_name()+"_statedef *stval, int cd"+
11633                 "){\n";
11634
11635         if(cleanwhen.size()>0)
11636                 ret += "\tbool predval = true;\n";
11637         else
11638                 ret += "\tbool predval = false;\n";
11639
11640 //                      Find the udafs ref'd in the having clause
11641         set<int> cw_aggs;
11642         for(w=0;w<cleanwhen.size();++w)
11643                 collect_aggr_refs_pr(cleanwhen[w]->pr, cw_aggs);
11644
11645
11646 //                      get the return values from the UDAFS
11647         for(a=0;a<aggr_tbl.size();a++){
11648                 if(! aggr_tbl.is_builtin(a) && cw_aggs.count(a)){
11649                         ret += "\t"+aggr_tbl.get_op(a)+"_HFTA_AGGR_OUTPUT_(&(udaf_ret_"+int_to_string(a)+"),";
11650                         if(aggr_tbl.get_storage_type(a)->get_type() != fstring_t) ret+="&";
11651                         ret+="("+aggvar+"aggr_var"+int_to_string(a)+"));\n";
11652                 }
11653         }
11654
11655
11656 //              Start by cleaning up partial function results
11657         ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";
11658         set<int> cw_pfcns;      // partial fcns in where clause
11659         for(w=0;w<cleanwhen.size();++w)
11660                 collect_partial_fcns_pr(cleanwhen[w]->pr, cw_pfcns);
11661
11662         ret += gen_partial_fcn_dtr(partial_fcns,cw_pfcns);
11663
11664
11665         for(w=0;w<cleanwhen.size();++w){
11666                 sprintf(tmpstr,"//\t\tPredicate clause %d.\n",w);
11667                 ret += tmpstr;
11668 //                      Find partial fcns ref'd in this cnf element
11669                 set<int> pfcn_refs;
11670                 collect_partial_fcns_pr(cleanwhen[w]->pr, pfcn_refs);
11671                 for(pfsi=pfcn_refs.begin();pfsi!=pfcn_refs.end();++pfsi){
11672                         ret += unpack_partial_fcn_fm_aggr(partial_fcns[(*pfsi)], (*pfsi), gbvar, aggvar, schema);
11673                         ret += "\tif(retval){ return false;}\n";
11674                 }
11675 //              ret += unpack_partial_fcn_fm_aggr(schema, partial_fcns, pfcn_refs,"false");
11676
11677                 ret += "\tif( !("+generate_predicate_code_fm_aggr(cleanwhen[w]->pr,gbvar, aggvar, schema)+
11678                                 ") ) predval = false;\n";
11679         }
11680
11681         ret += "\treturn predval;\n";
11682         ret += "\t};\n";
11683
11684 //------------------------------------------------------
11685 //                      THe cleaning_by predicate
11686
11687         ret += "bool sample_group("
11688                 +generate_functor_name()+"_groupdef *gbval, "+
11689                 generate_functor_name()+"_aggrdef *aggval,"+
11690                 generate_functor_name()+"_statedef *stval, int cd"+
11691                 "){\n";
11692
11693         if(cleanby.size()>0)
11694                 ret += "\tbool retval = true;\n";
11695         else
11696                 ret += "\tbool retval = false;\n";
11697
11698 //                      Find the udafs ref'd in the having clause
11699         set<int> cb_aggs;
11700         for(w=0;w<cleanby.size();++w)
11701                 collect_aggr_refs_pr(cleanby[w]->pr, cb_aggs);
11702
11703
11704 //                      get the return values from the UDAFS
11705         for(a=0;a<aggr_tbl.size();a++){
11706                 if(! aggr_tbl.is_builtin(a) && cb_aggs.count(a)){
11707                         ret += "\t"+aggr_tbl.get_op(a)+"_HFTA_AGGR_OUTPUT_(&(udaf_ret_"+int_to_string(a)+"),";
11708                         if(aggr_tbl.get_storage_type(a)->get_type() != fstring_t) ret+="&";
11709                         ret+="("+aggvar+"aggr_var"+int_to_string(a)+"));\n";
11710                 }
11711         }
11712
11713
11714 //              Start by cleaning up partial function results
11715         ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";
11716         set<int> cb_pfcns;      // partial fcns in where clause
11717         for(w=0;w<cleanby.size();++w)
11718                 collect_partial_fcns_pr(cleanby[w]->pr, cb_pfcns);
11719
11720         ret += gen_partial_fcn_dtr(partial_fcns,cb_pfcns);
11721
11722
11723         for(w=0;w<cleanwhen.size();++w){
11724                 sprintf(tmpstr,"//\t\tPredicate clause %d.\n",w);
11725                 ret += tmpstr;
11726
11727 /*
11728 //                      Find the set of variables accessed in this CNF elem,
11729 //                      but in no previous element.
11730                 col_id_set new_cids;
11731                 get_new_pred_cids(cleanby[w]->pr, found_cids, new_cids, segen_gb_tbl);
11732
11733 //                      Unpack these values.
11734                 ret += gen_unpack_cids(schema, new_cids, "false", needs_xform);
11735 */
11736
11737 //                      Find partial fcns ref'd in this cnf element
11738                 set<int> pfcn_refs;
11739                 collect_partial_fcns_pr(cleanby[w]->pr, pfcn_refs);
11740                 for(pfsi=pfcn_refs.begin();pfsi!=pfcn_refs.end();++pfsi){
11741                         ret += unpack_partial_fcn_fm_aggr(partial_fcns[(*pfsi)], (*pfsi), gbvar, aggvar, schema);
11742                         ret += "\tif(retval){ return false;}\n";
11743                 }
11744 //              ret += gen_unpack_partial_fcn(schema, partial_fcns, pfcn_refs,"false");
11745
11746                 ret += "\tif( !("+generate_predicate_code_fm_aggr(cleanby[w]->pr,gbvar, aggvar, schema)+
11747                         +") ) retval = false;\n";
11748         }
11749
11750         ret += "\treturn retval;\n";
11751         ret += "\t};\n";
11752
11753
11754 //-----------------------------------------------------
11755 //
11756         ret += "bool final_sample_group("
11757                 +generate_functor_name()+"_groupdef *gbval, "+
11758                 generate_functor_name()+"_aggrdef *aggval,"+
11759                 generate_functor_name()+"_statedef *stval,"+
11760                 "int cd){\n";
11761
11762         ret += "\tgs_retval_t retval = 0;\n";
11763
11764 //                      Find the udafs ref'd in the having clause
11765         set<int> hv_aggs;
11766         for(w=0;w<having.size();++w)
11767                 collect_aggr_refs_pr(having[w]->pr, hv_aggs);
11768
11769
11770 //                      get the return values from the UDAFS
11771         for(a=0;a<aggr_tbl.size();a++){
11772                 if(! aggr_tbl.is_builtin(a) && hv_aggs.count(a)){
11773                         ret += "\t"+aggr_tbl.get_op(a)+"_HFTA_AGGR_OUTPUT_(&(udaf_ret_"+int_to_string(a)+"),";
11774                         if(aggr_tbl.get_storage_type(a)->get_type() != fstring_t) ret+="&";
11775                         ret+="("+aggvar+"aggr_var"+int_to_string(a)+"));\n";
11776                 }
11777         }
11778
11779
11780         set<int> hv_sl_pfcns;
11781         for(w=0;w<having.size();w++){
11782                 collect_partial_fcns_pr(having[w]->pr, hv_sl_pfcns);
11783         }
11784
11785 //              clean up the partial fcn results from any previous execution
11786         ret += gen_partial_fcn_dtr(partial_fcns,hv_sl_pfcns);
11787
11788 //              Unpack them now
11789         for(pfsi=hv_sl_pfcns.begin();pfsi!=hv_sl_pfcns.end();++pfsi){
11790                 ret += unpack_partial_fcn_fm_aggr(partial_fcns[(*pfsi)], (*pfsi), gbvar, aggvar, schema);
11791                 ret += "\tif(retval){ return false;}\n";
11792         }
11793
11794 //              Evalaute the HAVING clause
11795 //              TODO: this seems to have a ++ operator rather than a + operator.
11796         for(w=0;w<having.size();++w){
11797                 ret += "\tif( !("+generate_predicate_code_fm_aggr(having[w]->pr,gbvar, aggvar, schema) +") ) { return false;}\n";
11798         }
11799
11800         ret += "\treturn true;\n";
11801         ret+="}\n\n";
11802
11803 //---------------------------------------------------
11804 //                      create output tuple
11805 //                      Unpack the partial functions ref'd in the where clause,
11806 //                      select clause.  Evaluate the where clause.
11807 //                      Finally, pack the tuple.
11808
11809 //                      I need to use special code generation here,
11810 //                      so I'll leave it in longhand.
11811
11812         ret += "host_tuple create_output_tuple("
11813                 +generate_functor_name()+"_groupdef *gbval, "+
11814                 generate_functor_name()+"_aggrdef *aggval,"+
11815                 generate_functor_name()+"_statedef *stval,"+
11816                 "int cd, bool &failed){\n";
11817
11818         ret += "\thost_tuple tup;\n";
11819         ret += "\tfailed = false;\n";
11820         ret += "\tgs_retval_t retval = 0;\n";
11821
11822
11823 //                      Find the udafs ref'd in the select clause
11824         set<int> sl_aggs;
11825         for(s=0;s<select_list.size();s++)
11826                 collect_agg_refs(select_list[s]->se, sl_aggs);
11827
11828
11829 //                      get the return values from the UDAFS
11830         for(a=0;a<aggr_tbl.size();a++){
11831                 if(! aggr_tbl.is_builtin(a) && sl_aggs.count(a)){
11832                         ret += "\t"+aggr_tbl.get_op(a)+"_HFTA_AGGR_OUTPUT_(&(udaf_ret_"+int_to_string(a)+"),";
11833                         if(aggr_tbl.get_storage_type(a)->get_type() != fstring_t) ret+="&";
11834                         ret+="("+aggvar+"aggr_var"+int_to_string(a)+"));\n";
11835                 }
11836         }
11837
11838
11839 //                      I can't cache partial fcn results from the having
11840 //                      clause because evaluation is separated.
11841         set<int> sl_pfcns;
11842         for(s=0;s<select_list.size();s++){
11843                 collect_partial_fcns(select_list[s]->se, sl_pfcns);
11844         }
11845 //              Unpack them now
11846         for(pfsi=sl_pfcns.begin();pfsi!=sl_pfcns.end();++pfsi){
11847                 ret += unpack_partial_fcn_fm_aggr(partial_fcns[(*pfsi)], (*pfsi), gbvar, aggvar, schema);
11848                 ret += "\tif(retval){ failed=true; return tup;}\n";
11849         }
11850
11851
11852 //          Now, compute the size of the tuple.
11853
11854 //          Unpack any BUFFER type selections into temporaries
11855 //          so that I can compute their size and not have
11856 //          to recompute their value during tuple packing.
11857 //          I can use regular assignment here because
11858 //          these temporaries are non-persistent.
11859 //                      TODO: should I be using the selvar generation routine?
11860
11861         ret += "//\t\tCompute the size of the tuple.\n";
11862         ret += "//\t\t\tNote: buffer storage packed at the end of the tuple.\n";
11863       for(s=0;s<select_list.size();s++){
11864                 scalarexp_t *se = select_list[s]->se;
11865         data_type *sdt = se->get_data_type();
11866         if(sdt->is_buffer_type() &&
11867                          !( (se->get_operator_type() == SE_COLREF) ||
11868                                 (se->get_operator_type() == SE_AGGR_STAR) ||
11869                                 (se->get_operator_type() == SE_AGGR_SE) ||
11870                            (se->get_operator_type() == SE_FUNC && se->is_partial()) ||
11871                            (se->get_operator_type() == SE_FUNC && se->get_aggr_ref() >= 0))
11872                 ){
11873             sprintf(tmpstr,"selvar_%d",s);
11874                         ret+="\t"+sdt->make_host_cvar(tmpstr)+" = ";
11875                         ret += generate_se_code_fm_aggr(se,gbvar, aggvar, schema) +";\n";
11876         }
11877       }
11878
11879 //      The size of the tuple is the size of the tuple struct plus the
11880 //      size of the buffers to be copied in.
11881
11882       ret+="\ttup.tuple_size = sizeof(" + generate_tuple_name( this->get_node_name()) +") + sizeof(gs_uint8_t)";
11883       for(s=0;s<select_list.size();s++){
11884 //              if(s>0) ret += "+";
11885                 scalarexp_t *se = select_list[s]->se;
11886         data_type *sdt = select_list[s]->se->get_data_type();
11887         if(sdt->is_buffer_type()){
11888                   if(!( (se->get_operator_type() == SE_COLREF) ||
11889                                 (se->get_operator_type() == SE_AGGR_STAR) ||
11890                                 (se->get_operator_type() == SE_AGGR_SE) ||
11891                            (se->get_operator_type() == SE_FUNC && se->is_partial()) ||
11892                            (se->get_operator_type() == SE_FUNC && se->get_aggr_ref() >= 0))
11893                   ){
11894             sprintf(tmpstr," + %s(&selvar_%d)", sdt->get_hfta_buffer_size().c_str(),s);
11895             ret.append(tmpstr);
11896                   }else{
11897             sprintf(tmpstr," + %s(&%s)", sdt->get_hfta_buffer_size().c_str(),generate_se_code_fm_aggr(se,gbvar, aggvar, schema).c_str());
11898             ret.append(tmpstr);
11899                   }
11900         }
11901       }
11902       ret.append(";\n");
11903
11904 //              Allocate tuple data block.
11905         ret += "//\t\tCreate the tuple block.\n";
11906           ret += "\ttup.data = malloc(tup.tuple_size);\n";
11907           ret += "\ttup.heap_resident = true;\n";
11908
11909 //              Mark tuple as regular
11910           ret += "\t*((gs_sp_t )tup.data + sizeof(" + generate_tuple_name( this->get_node_name()) +")) = REGULAR_TUPLE;\n";
11911
11912 //        ret += "\ttup.channel = 0;\n";
11913           ret += "\t"+generate_tuple_name( this->get_node_name())+" *tuple = ("+
11914                                 generate_tuple_name( this->get_node_name())+" *)(tup.data);\n";
11915
11916 //              Start packing.
11917 //                      (Here, offsets are hard-wired.  is this a problem?)
11918
11919         ret += "//\t\tPack the fields into the tuple.\n";
11920           ret += "\tint tuple_pos = sizeof("+generate_tuple_name( this->get_node_name()) +") + sizeof(gs_uint8_t);\n";
11921       for(s=0;s<select_list.size();s++){
11922                 scalarexp_t *se = select_list[s]->se;
11923         data_type *sdt = se->get_data_type();
11924         if(sdt->is_buffer_type()){
11925                   if(!( (se->get_operator_type() == SE_COLREF) ||
11926                                 (se->get_operator_type() == SE_AGGR_STAR) ||
11927                                 (se->get_operator_type() == SE_AGGR_SE) ||
11928                            (se->get_operator_type() == SE_FUNC && se->is_partial()) ||
11929                            (se->get_operator_type() == SE_FUNC && se->get_aggr_ref() >= 0))
11930                   ){
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);
11932             ret.append(tmpstr);
11933             sprintf(tmpstr,"\ttuple_pos += %s(&selvar_%d);\n", sdt->get_hfta_buffer_size().c_str(), s);
11934             ret.append(tmpstr);
11935                   }else{
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());
11937             ret.append(tmpstr);
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());
11939             ret.append(tmpstr);
11940                   }
11941         }else{
11942             sprintf(tmpstr,"\ttuple->tuple_var%d = ",s);
11943             ret.append(tmpstr);
11944             ret.append(generate_se_code_fm_aggr(se,gbvar, aggvar, schema) );
11945             ret.append(";\n");
11946         }
11947       }
11948
11949 //                      Destroy string temporaries
11950           ret += gen_buffer_selvars_dtr(select_list);
11951 //                      Destroy string return vals of UDAFs
11952         for(a=0;a<aggr_tbl.size();a++){
11953                 if(! aggr_tbl.is_builtin(a)){
11954                         int afcn_id = aggr_tbl.get_fcn_id(a);
11955                         data_type *adt = Ext_fcns->get_fcn_dt(afcn_id);
11956                         if(adt->is_buffer_type()){
11957                                 sprintf(tmpstr,"\t%s(&udaf_ret_%d);\n",
11958                                 adt->get_hfta_buffer_destroy().c_str(), a );
11959                                 ret += tmpstr;
11960                         }
11961                 }
11962         }
11963
11964
11965           ret += "\treturn tup;\n";
11966           ret += "};\n";
11967
11968
11969 //-------------------------------------------------------------------
11970 //              Temporal update functions
11971
11972         ret+="bool temp_status_received(){return temp_tuple_received;};\n\n";
11973
11974 //              create a temp status tuple
11975         ret += "int create_temp_status_tuple(host_tuple& result, bool flush_finished) {\n\n";
11976
11977         ret += gen_init_temp_status_tuple(this->get_node_name());
11978
11979 //              Start packing.
11980 //                      (Here, offsets are hard-wired.  is this a problem?)
11981
11982         ret += "//\t\tPack the fields into the tuple.\n";
11983         for(s=0;s<select_list.size();s++){
11984                 data_type *sdt = select_list[s]->se->get_data_type();
11985                 if(sdt->is_temporal()){
11986                         sprintf(tmpstr,"\ttuple->tuple_var%d = ",s);
11987                         ret += tmpstr;
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());
11989                         ret += tmpstr;
11990                         ret += ";\n";
11991                 }
11992         }
11993
11994         ret += "\treturn 0;\n";
11995         ret += "};};\n\n\n";
11996
11997
11998 //----------------------------------------------------------
11999 //                      The hash function
12000
12001         ret += "struct "+generate_functor_name()+"_hash_func{\n";
12002         ret += "\tgs_uint32_t operator()(const "+generate_functor_name()+
12003                                 "_groupdef *grp) const{\n";
12004         ret += "\t\treturn(";
12005         for(g=0;g<gb_tbl.size();g++){
12006                 if(g>0) ret += "^";
12007                 data_type *gdt = gb_tbl.get_data_type(g);
12008                 if(gdt->use_hashfunc()){
12009                         if(gdt->is_buffer_type())
12010                                 sprintf(tmpstr,"(%s*%s(&)grp->gb_var%d)))",hash_nums[g%NRANDS].c_str(),gdt->get_hfta_hashfunc().c_str(),g);
12011                         else
12012                                 sprintf(tmpstr,"(%s*%s(grp->gb_var%d))",hash_nums[g%NRANDS].c_str(),gdt->get_hfta_hashfunc().c_str(),g);
12013                 }else{
12014                         sprintf(tmpstr,"(%s*grp->gb_var%d)",hash_nums[g%NRANDS].c_str(),g);
12015                 }
12016                 ret += tmpstr;
12017         }
12018         ret += ") >> 32);\n";
12019         ret += "\t}\n";
12020         ret += "};\n\n";
12021
12022 //----------------------------------------------------------
12023 //                      The superhash function
12024
12025         ret += "struct "+generate_functor_name()+"_superhash_func{\n";
12026         ret += "\tgs_uint32_t operator()(const "+generate_functor_name()+
12027                                 "_groupdef *grp) const{\n";
12028         ret += "\t\treturn(0";
12029
12030         for(g=0;g<gb_tbl.size();g++){
12031                 if(sg_tbl.count(g)>0){
12032                         ret += "^";
12033                         data_type *gdt = gb_tbl.get_data_type(g);
12034                         if(gdt->use_hashfunc()){
12035                                 sprintf(tmpstr,"(%s*%s(&(grp->gb_var%d)))",hash_nums[g%NRANDS].c_str(),gdt->get_hfta_hashfunc().c_str(),g);
12036                         }else{
12037                                 sprintf(tmpstr,"(%s*grp->gb_var%d)",hash_nums[g%NRANDS].c_str(),g);
12038                         }
12039                         ret += tmpstr;
12040                 }
12041         }
12042         ret += ") >> 32);\n";
12043
12044         ret += "\t}\n";
12045         ret += "};\n\n";
12046
12047 //----------------------------------------------------------
12048 //                      The comparison function
12049
12050         ret += "struct "+generate_functor_name()+"_equal_func{\n";
12051         ret += "\tbool operator()(const "+generate_functor_name()+"_groupdef *grp1, "+
12052                         generate_functor_name()+"_groupdef *grp2) const{\n";
12053         ret += "\t\treturn( (";
12054         for(g=0;g<gb_tbl.size();g++){
12055                 if(g>0) ret += ") && (";
12056                 data_type *gdt = gb_tbl.get_data_type(g);
12057                 if(gdt->complex_comparison(gdt)){
12058                   if(gdt->is_buffer_type())
12059                         sprintf(tmpstr,"(%s(&(grp1->gb_var%d), &(grp2->gb_var%d))==0)",
12060                                 gdt->get_hfta_comparison_fcn(gdt).c_str(),g,g);
12061                   else
12062                         sprintf(tmpstr,"(%s((grp1->gb_var%d), (grp2->gb_var%d))==0)",
12063                                 gdt->get_hfta_comparison_fcn(gdt).c_str(),g,g);
12064                 }else{
12065                         sprintf(tmpstr,"grp1->gb_var%d == grp2->gb_var%d",g,g);
12066                 }
12067                 ret += tmpstr;
12068         }
12069         ret += ") );\n";
12070         ret += "\t}\n";
12071         ret += "};\n\n";
12072
12073
12074 //----------------------------------------------------------
12075 //                      The superhashcomparison function
12076
12077         ret += "struct "+generate_functor_name()+"_superequal_func{\n";
12078         ret += "\tbool operator()(const "+generate_functor_name()+"_groupdef *grp1, "+
12079                         generate_functor_name()+"_groupdef *grp2) const{\n";
12080         ret += "\t\treturn( (";
12081     if(sg_tbl.size()){
12082                 bool first_elem = true;
12083                 for(g=0;g<gb_tbl.size();g++){
12084                         if(sg_tbl.count(g)){
12085                                 if(first_elem) first_elem=false; else ret += ") && (";
12086                                 data_type *gdt = gb_tbl.get_data_type(g);
12087                                 if(gdt->complex_comparison(gdt)){
12088                                   if(gdt->is_buffer_type())
12089                                         sprintf(tmpstr,"(%s(&(grp1->gb_var%d), &(grp2->gb_var%d))==0)",
12090                                                 gdt->get_hfta_comparison_fcn(gdt).c_str(),g,g);
12091                                   else
12092                                         sprintf(tmpstr,"(%s((grp1->gb_var%d), (grp2->gb_var%d))==0)",
12093                                                 gdt->get_hfta_comparison_fcn(gdt).c_str(),g,g);
12094                                 }else{
12095                                         sprintf(tmpstr,"grp1->gb_var%d == grp2->gb_var%d",g,g);
12096                                 }
12097                         ret += tmpstr;
12098                         }
12099                 }
12100         }else{
12101                 ret += "true";
12102         }
12103
12104         ret += ") );\n";
12105         ret += "\t}\n";
12106
12107
12108         ret += "};\n\n";
12109         return(ret);
12110 }
12111
12112 string sgahcwcb_qpn::generate_operator(int i, string params){
12113
12114                 return(
12115                         "       clean_operator<" +
12116                         generate_functor_name()+",\n\t"+
12117                         generate_functor_name() + "_groupdef, \n\t" +
12118                         generate_functor_name() + "_aggrdef, \n\t" +
12119                         generate_functor_name() + "_statedef, \n\t" +
12120                         generate_functor_name()+"_hash_func, \n\t"+
12121                         generate_functor_name()+"_equal_func ,\n\t"+
12122                         generate_functor_name()+"_superhash_func,\n\t "+
12123                         generate_functor_name()+"_superequal_func \n\t"+
12124                         "> *op"+int_to_string(i)+" = new clean_operator<"+
12125                         generate_functor_name()+",\n\t"+
12126                         generate_functor_name() + "_groupdef,\n\t " +
12127                         generate_functor_name() + "_aggrdef, \n\t" +
12128                         generate_functor_name() + "_statedef, \n\t" +
12129                         generate_functor_name()+"_hash_func, \n\t"+
12130                         generate_functor_name()+"_equal_func, \n\t"+
12131                         generate_functor_name()+"_superhash_func, \n\t"+
12132                         generate_functor_name()+"_superequal_func\n\t "
12133                         ">("+params+", \"" + get_node_name() + "\");\n"
12134                 );
12135 }
12136
12137 ////////////////////////////////////////////////////////////////
12138 ////    RSGAH functor
12139
12140
12141
12142 string rsgah_qpn::generate_functor_name(){
12143         return("rsgah_functor_" + normalize_name(this->get_node_name()));
12144 }
12145
12146
12147 string rsgah_qpn::generate_functor(table_list *schema, ext_fcn_list *Ext_fcns, vector<bool> &needs_xform){
12148         int a,g,w,s;
12149
12150
12151 //                      Initialize generate utility globals
12152         segen_gb_tbl = &(gb_tbl);
12153
12154
12155 //--------------------------------
12156 //                      group definition class
12157         string ret = "class " + generate_functor_name() + "_groupdef{\n";
12158         ret += "public:\n";
12159         for(g=0;g<this->gb_tbl.size();g++){
12160                 sprintf(tmpstr,"gb_var%d",g);
12161                 ret+="\t"+this->gb_tbl.get_data_type(g)->make_host_cvar(tmpstr)+";\n";
12162         }
12163 //              Constructors
12164         ret += "\t"+generate_functor_name() + "_groupdef(){};\n";
12165         ret += "\t"+generate_functor_name() + "_groupdef("+
12166                 this->generate_functor_name() + "_groupdef *gd){\n";
12167         for(g=0;g<gb_tbl.size();g++){
12168                 data_type *gdt = gb_tbl.get_data_type(g);
12169                 if(gdt->is_buffer_type()){
12170                         sprintf(tmpstr,"\t\t%s(&gb_var%d, &(gd->gb_var%d));\n",
12171                           gdt->get_hfta_buffer_assign_copy().c_str(),g,g );
12172                         ret += tmpstr;
12173                 }else{
12174                         sprintf(tmpstr,"\t\tgb_var%d = gd->gb_var%d;\n",g,g);
12175                         ret += tmpstr;
12176                 }
12177         }
12178         ret += "\t};\n";
12179 //              destructor
12180         ret += "\t~"+ generate_functor_name() + "_groupdef(){\n";
12181         for(g=0;g<gb_tbl.size();g++){
12182                 data_type *gdt = gb_tbl.get_data_type(g);
12183                 if(gdt->is_buffer_type()){
12184                         sprintf(tmpstr,"\t\t%s(&gb_var%d);\n",
12185                           gdt->get_hfta_buffer_destroy().c_str(), g );
12186                         ret += tmpstr;
12187                 }
12188         }
12189         ret += "\t};\n";
12190         ret +="};\n\n";
12191
12192 //--------------------------------
12193 //                      aggr definition class
12194         ret += "class " + this->generate_functor_name() + "_aggrdef{\n";
12195         ret += "public:\n";
12196         for(a=0;a<aggr_tbl.size();a++){
12197 aggr_table_entry *ate = aggr_tbl.agr_tbl[a];
12198                 sprintf(tmpstr,"aggr_var%d",a);
12199                 if(aggr_tbl.is_builtin(a))
12200                   ret+="\t"+ aggr_tbl.get_data_type(a)->make_host_cvar(tmpstr)+";\n";
12201                 else
12202                   ret+="\t"+ aggr_tbl.get_storage_type(a)->make_host_cvar(tmpstr)+";\n";
12203         }
12204 //              Constructors
12205         ret += "\t"+this->generate_functor_name() + "_aggrdef(){};\n";
12206 //              destructor
12207         ret += "\t~"+this->generate_functor_name() + "_aggrdef(){\n";
12208         for(a=0;a<aggr_tbl.size();a++){
12209                 if(aggr_tbl.is_builtin(a)){
12210                         data_type *adt = aggr_tbl.get_data_type(a);
12211                         if(adt->is_buffer_type()){
12212                                 sprintf(tmpstr,"\t\t%s(&aggr_var%d);\n",
12213                                 adt->get_hfta_buffer_destroy().c_str(), a );
12214                                 ret += tmpstr;
12215                         }
12216                 }else{
12217                         ret+="\t\t"+aggr_tbl.get_op(a)+"_HFTA_AGGR_DESTROY_(";
12218                         if(aggr_tbl.get_storage_type(a)->get_type() != fstring_t) ret+="&";
12219                         ret+="(aggr_var"+int_to_string(a)+"));\n";
12220                 }
12221         }
12222         ret += "\t};\n";
12223         ret +="};\n\n";
12224
12225 //--------------------------------
12226 //                      gb functor class
12227         ret += "class " + this->generate_functor_name() + "{\n";
12228
12229 //                      Find variables referenced in this query node.
12230
12231   col_id_set cid_set;
12232   col_id_set::iterator csi;
12233
12234     for(w=0;w<where.size();++w)
12235         gather_pr_col_ids(where[w]->pr,cid_set,segen_gb_tbl);
12236     for(w=0;w<having.size();++w)
12237         gather_pr_col_ids(having[w]->pr,cid_set,segen_gb_tbl);
12238     for(w=0;w<closing_when.size();++w)
12239         gather_pr_col_ids(closing_when[w]->pr,cid_set,segen_gb_tbl);
12240         for(g=0;g<gb_tbl.size();g++)
12241                 gather_se_col_ids(gb_tbl.get_def(g),cid_set,segen_gb_tbl);
12242
12243     for(s=0;s<select_list.size();s++){
12244         gather_se_col_ids(select_list[s]->se,cid_set,segen_gb_tbl);     // descends into aggregates
12245     }
12246
12247
12248 //                      Private variables : store the state of the functor.
12249 //                      1) variables for unpacked attributes
12250 //                      2) offsets of the upacked attributes
12251 //                      3) storage of partial functions
12252 //                      4) storage of complex literals (i.e., require a constructor)
12253
12254         ret += "private:\n";
12255
12256         // var to save the schema handle
12257         ret += "\tint schema_handle0;\n";
12258
12259         // generate the declaration of all the variables related to
12260         // temp tuples generation
12261         ret += gen_decl_temp_vars();
12262
12263 //                      unpacked attribute storage, offsets
12264         ret += "//\t\tstorage and offsets of accessed fields.\n";
12265         ret += generate_access_vars(cid_set, schema);
12266 //                      tuple metadata offset
12267         ret += "\tint tuple_metadata_offset0;\n";
12268
12269 //                      Variables to store results of partial functions.
12270 //                      WARNING find_partial_functions modifies the SE
12271 //                      (it marks the partial function id).
12272         ret += "//\t\tParital function result storage\n";
12273         vector<scalarexp_t *> partial_fcns;
12274         vector<int> fcn_ref_cnt;
12275         vector<bool> is_partial_fcn;
12276         for(s=0;s<select_list.size();s++){
12277                 find_partial_fcns(select_list[s]->se, &partial_fcns, NULL,NULL, Ext_fcns);
12278         }
12279         for(w=0;w<where.size();w++){
12280                 find_partial_fcns_pr(where[w]->pr, &partial_fcns, NULL,NULL, Ext_fcns);
12281         }
12282         for(w=0;w<having.size();w++){
12283                 find_partial_fcns_pr(having[w]->pr, &partial_fcns, NULL,NULL, Ext_fcns);
12284         }
12285         for(w=0;w<closing_when.size();w++){
12286                 find_partial_fcns_pr(closing_when[w]->pr, &partial_fcns, NULL,NULL, Ext_fcns);
12287         }
12288         for(g=0;g<gb_tbl.size();g++){
12289                 find_partial_fcns(gb_tbl.get_def(g), &partial_fcns, NULL,NULL, Ext_fcns);
12290         }
12291         for(a=0;a<aggr_tbl.size();a++){
12292                 find_partial_fcns(aggr_tbl.get_aggr_se(a), &partial_fcns, NULL,NULL, Ext_fcns);
12293         }
12294         if(partial_fcns.size()>0){
12295           ret += "/*\t\tVariables for storing results of partial functions. \t*/\n";
12296           ret += generate_partial_fcn_vars(partial_fcns,fcn_ref_cnt,is_partial_fcn,false);
12297         }
12298
12299 //                      Create cached temporaries for UDAF return values.
12300         for(a=0;a<aggr_tbl.size();a++){
12301                 if(! aggr_tbl.is_builtin(a)){
12302                         int afcn_id = aggr_tbl.get_fcn_id(a);
12303                         data_type *adt = Ext_fcns->get_fcn_dt(afcn_id);
12304                         sprintf(tmpstr,"udaf_ret_%d", a);
12305                         ret+="\t"+adt->make_host_cvar(tmpstr)+";\n";
12306                 }
12307         }
12308
12309
12310 //                      Complex literals (i.e., they need constructors)
12311         ret += "//\t\tComplex literal storage.\n";
12312         cplx_lit_table *complex_literals = this->get_cplx_lit_tbl(Ext_fcns);
12313         ret += generate_complex_lit_vars(complex_literals);
12314
12315 //                      Pass-by-handle parameters
12316         ret += "//\t\tPass-by-handle storage.\n";
12317         vector<handle_param_tbl_entry *> param_handle_table = this->get_handle_param_tbl(Ext_fcns);
12318         ret += generate_pass_by_handle_vars(param_handle_table);
12319
12320
12321 //                      variables to hold parameters.
12322         ret += "//\tfor query parameters\n";
12323         ret += generate_param_vars(param_tbl);
12324
12325 //              Is there a temporal flush?  If so create flush temporaries,
12326 //              create flush indicator.
12327         bool uses_temporal_flush = false;
12328         for(g=0;g<gb_tbl.size();g++){
12329                 data_type *gdt = gb_tbl.get_data_type(g);
12330                 if(gdt->is_temporal())
12331                         uses_temporal_flush = true;
12332         }
12333
12334         if(uses_temporal_flush){
12335                 ret += "//\t\tFor temporal flush\n";
12336                 for(g=0;g<gb_tbl.size();g++){
12337                         data_type *gdt = gb_tbl.get_data_type(g);
12338                         if(gdt->is_temporal()){
12339                           sprintf(tmpstr,"last_gb%d",g);
12340                           ret+="\t"+gb_tbl.get_data_type(g)->make_host_cvar(tmpstr)+";\n";
12341                           sprintf(tmpstr,"last_flushed_gb%d",g);
12342                           ret+="\t"+gb_tbl.get_data_type(g)->make_host_cvar(tmpstr)+";\n";
12343                         }
12344                 }
12345                 ret += "\tbool needs_temporal_flush;\n";
12346         }
12347
12348 //                      The publicly exposed functions
12349
12350         ret += "\npublic:\n";
12351
12352
12353 //-------------------
12354 //                      The functor constructor
12355 //                      pass in the schema handle.
12356 //                      1) make assignments to the unpack offset variables
12357 //                      2) initialize the complex literals
12358
12359         ret += "//\t\tFunctor constructor.\n";
12360         ret +=  this->generate_functor_name()+"(int schema_handle0){\n";
12361
12362         // save the schema handle
12363         ret += "\t\tthis->schema_handle0 = schema_handle0;\n";
12364 //              metadata offset
12365         ret += "\ttuple_metadata_offset0 = ftaschema_get_tuple_metadata_offset(schema_handle0);\n";
12366
12367 //              unpack vars
12368         ret += "//\t\tGet offsets for unpacking fields from input tuple.\n";
12369         ret += gen_access_var_init(cid_set);
12370
12371 //              complex literals
12372         ret += "//\t\tInitialize complex literals.\n";
12373         ret += gen_complex_lit_init(complex_literals);
12374
12375 //              Initialize partial function results so they can be safely GC'd
12376         ret += gen_partial_fcn_init(partial_fcns);
12377
12378 //              Initialize non-query-parameter parameter handles
12379         ret += gen_pass_by_handle_init(param_handle_table);
12380
12381 //              temporal flush variables
12382 //              ASSUME that structured values won't be temporal.
12383         if(uses_temporal_flush){
12384                 ret += "//\t\tInitialize temporal flush variables.\n";
12385                 for(g=0;g<gb_tbl.size();g++){
12386                         data_type *gdt = gb_tbl.get_data_type(g);
12387                         if(gdt->is_temporal()){
12388                                 literal_t gl(gdt->type_indicator());
12389                                 sprintf(tmpstr,"\tlast_gb%d = %s;\n",g, gl.to_hfta_C_code("").c_str());
12390                                 ret.append(tmpstr);
12391                         }
12392                 }
12393                 ret += "\tneeds_temporal_flush = false;\n";
12394         }
12395
12396         //              Init temporal attributes referenced in select list
12397         ret += gen_init_temp_vars(schema, select_list, segen_gb_tbl);
12398
12399         ret += "};\n";
12400
12401
12402 //-------------------
12403 //                      Functor destructor
12404         ret += "//\t\tFunctor destructor.\n";
12405         ret +=  "~"+this->generate_functor_name()+"(){\n";
12406
12407 //                      clean up buffer type complex literals
12408         ret += gen_complex_lit_dtr(complex_literals);
12409
12410 //                      Deregister the pass-by-handle parameters
12411         ret += "/* register and de-register the pass-by-handle parameters */\n";
12412         ret += gen_pass_by_handle_dtr(param_handle_table);
12413
12414 //                      clean up partial function results.
12415         ret += "/* clean up partial function storage    */\n";
12416         ret += gen_partial_fcn_dtr(partial_fcns);
12417
12418 //                      Destroy the parameters, if any need to be destroyed
12419         ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";
12420
12421         ret += "};\n\n";
12422
12423
12424 //-------------------
12425 //                      Parameter manipulation routines
12426         ret += generate_load_param_block(this->generate_functor_name(),
12427                                                                         this->param_tbl,param_handle_table);
12428         ret += generate_delete_param_block(this->generate_functor_name(),
12429                                                                         this->param_tbl,param_handle_table);
12430
12431 //-------------------
12432 //                      Register new parameter block
12433
12434         ret += "int set_param_block(gs_int32_t sz, void* value){\n";
12435           ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";
12436           ret += "\treturn this->load_params_"+this->generate_functor_name()+
12437                                 "(sz, value);\n";
12438         ret += "};\n\n";
12439
12440
12441 //-------------------
12442 //              the create_group method.
12443 //              This method creates a group in a buffer passed in
12444 //              (to allow for creation on the stack).
12445 //              There are also a couple of side effects:
12446 //              1) evaluate the WHERE clause (and therefore, unpack all partial fcns)
12447 //              2) determine if a temporal flush is required.
12448
12449         ret += this->generate_functor_name()+"_groupdef *create_group(host_tuple &tup0, gs_sp_t buffer){\n";
12450         //              Variables for execution of the function.
12451         ret += "\tgs_int32_t problem = 0;\n";   // return unpack failure
12452
12453         if(partial_fcns.size()>0){              // partial fcn access failure
12454           ret += "\tgs_retval_t retval = 0;\n";
12455           ret += "\n";
12456         }
12457 //              return value
12458         ret += "\t"+generate_functor_name()+"_groupdef *gbval = ("+generate_functor_name()+
12459                         "_groupdef *) buffer;\n";
12460
12461 //              Start by cleaning up partial function results
12462         ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";
12463         set<int> w_pfcns;       // partial fcns in where clause
12464         for(w=0;w<where.size();++w)
12465                 collect_partial_fcns_pr(where[w]->pr, w_pfcns);
12466
12467         set<int> ag_gb_pfcns;   // partial fcns in gbdefs, aggr se's
12468         for(g=0;g<gb_tbl.size();g++){
12469                 collect_partial_fcns(gb_tbl.get_def(g), ag_gb_pfcns);
12470         }
12471         for(a=0;a<aggr_tbl.size();a++){
12472                 collect_partial_fcns(aggr_tbl.get_aggr_se(a), ag_gb_pfcns);
12473         }
12474         ret += gen_partial_fcn_dtr(partial_fcns,w_pfcns);
12475         ret += gen_partial_fcn_dtr(partial_fcns,ag_gb_pfcns);
12476 //      ret += gen_partial_fcn_dtr(partial_fcns);
12477
12478
12479         ret += gen_temp_tuple_check(this->node_name, 0);
12480         col_id_set found_cids;  // colrefs unpacked thus far.
12481         ret += gen_unpack_temp_vars(schema, found_cids, select_list, segen_gb_tbl, needs_xform);
12482
12483
12484 //                      Save temporal group-by variables
12485
12486
12487         ret.append("\n\t//\t\tCompute temporal groupby attributes\n\n");
12488
12489           for(g=0;g<gb_tbl.size();g++){
12490
12491                         data_type *gdt = gb_tbl.get_data_type(g);
12492
12493                         if(gdt->is_temporal()){
12494                                 sprintf(tmpstr,"\tgbval->gb_var%d = %s;\n",
12495                                         g, generate_se_code(gb_tbl.get_def(g),schema).c_str() );
12496                                 ret.append(tmpstr);
12497                         }
12498                 }
12499                 ret.append("\n");
12500
12501
12502
12503 //                      Compare the temporal GB vars with the stored ones,
12504 //                      set flush indicator and update stored GB vars if there is any change.
12505
12506         if(uses_temporal_flush){
12507                 ret+= "\tif( !( (";
12508                 bool first_one = true;
12509                 for(g=0;g<gb_tbl.size();g++){
12510                         data_type *gdt = gb_tbl.get_data_type(g);
12511
12512                         if(gdt->is_temporal()){
12513                           sprintf(tmpstr,"last_gb%d",g);   string lhs_op = tmpstr;
12514                           sprintf(tmpstr,"gbval->gb_var%d",g);   string rhs_op = tmpstr;
12515                           if(first_one){first_one = false;} else {ret += ") && (";}
12516                           ret += generate_equality_test(lhs_op, rhs_op, gdt);
12517                         }
12518                 }
12519                 ret += ") ) ){\n";
12520                 for(g=0;g<gb_tbl.size();g++){
12521                   data_type *gdt = gb_tbl.get_data_type(g);
12522                   if(gdt->is_temporal()){
12523                           if(gdt->is_buffer_type()){
12524                                 sprintf(tmpstr,"\t\t%s(&(gbval->gb_var%d),&last_gb%d);\n",gdt->get_hfta_buffer_replace().c_str(),g,g);
12525                           }else{
12526                                 sprintf(tmpstr,"\t\tlast_flushed_gb%d = last_gb%d;\n",g,g);
12527                                 ret += tmpstr;
12528                                 sprintf(tmpstr,"\t\tlast_gb%d = gbval->gb_var%d;\n",g,g);
12529                           }
12530                           ret += tmpstr;
12531                         }
12532                 }
12533                 ret += "\t\tneeds_temporal_flush=true;\n";
12534                 ret += "\t\t}else{\n"
12535                         "\t\t\tneeds_temporal_flush=false;\n"
12536                         "\t\t}\n";
12537         }
12538
12539
12540 //              For temporal status tuple we don't need to do anything else
12541         ret += "\tif (temp_tuple_received) return NULL;\n\n";
12542
12543         for(w=0;w<where.size();++w){
12544                 sprintf(tmpstr,"//\t\tPredicate clause %d.\n",w);
12545                 ret += tmpstr;
12546 //                      Find the set of variables accessed in this CNF elem,
12547 //                      but in no previous element.
12548                 col_id_set new_cids;
12549                 get_new_pred_cids(where[w]->pr, found_cids, new_cids, segen_gb_tbl);
12550
12551 //                      Unpack these values.
12552                 ret += gen_unpack_cids(schema, new_cids, "NULL", needs_xform);
12553 //                      Find partial fcns ref'd in this cnf element
12554                 set<int> pfcn_refs;
12555                 collect_partial_fcns_pr(where[w]->pr, pfcn_refs);
12556                 ret += gen_unpack_partial_fcn(schema, partial_fcns, pfcn_refs,"NULL");
12557
12558                 ret += "\tif( !("+generate_predicate_code(where[w]->pr,schema)+
12559                                 +") ) return(NULL);\n";
12560         }
12561
12562 //              The partial functions ref'd in the group-by var and aggregate
12563 //              definitions must also be evaluated.  If one returns false,
12564 //              then implicitly the predicate is false.
12565         set<int>::iterator pfsi;
12566
12567         if(ag_gb_pfcns.size() > 0)
12568                 ret += "//\t\tUnpack remaining partial fcns.\n";
12569         ret += gen_full_unpack_partial_fcn(schema, partial_fcns, ag_gb_pfcns,
12570                                                                                 found_cids, segen_gb_tbl, "NULL", needs_xform);
12571
12572 //                      Unpack the group-by variables
12573
12574           for(g=0;g<gb_tbl.size();g++){
12575                 data_type *gdt = gb_tbl.get_data_type(g);
12576                 if(!gdt->is_temporal()){        // temproal gbs already computed
12577 //                      Find the new fields ref'd by this GBvar def.
12578                         col_id_set new_cids;
12579                         get_new_se_cids(gb_tbl.get_def(g), found_cids, new_cids, segen_gb_tbl);
12580 //                      Unpack these values.
12581                         ret += gen_unpack_cids(schema, new_cids, "NULL", needs_xform);
12582
12583                         sprintf(tmpstr,"\tgbval->gb_var%d = %s;\n",
12584                                 g, generate_se_code(gb_tbl.get_def(g),schema).c_str() );
12585 /*
12586 //                              There seems to be no difference between the two
12587 //                              branches of the IF statement.
12588                 data_type *gdt = gb_tbl.get_data_type(g);
12589                   if(gdt->is_buffer_type()){
12590 //                              Create temporary copy.
12591                         sprintf(tmpstr,"\tgbval->gb_var%d = %s;\n",
12592                                 g, generate_se_code(gb_tbl.get_def(g),schema).c_str() );
12593                   }else{
12594                         scalarexp_t *gse = gb_tbl.get_def(g);
12595                         sprintf(tmpstr,"\tgbval->gb_var%d = %s;\n",
12596                                         g,generate_se_code(gse,schema).c_str());
12597                   }
12598 */
12599                         ret.append(tmpstr);
12600                 }
12601           }
12602           ret.append("\n");
12603
12604
12605         ret+= "\treturn gbval;\n";
12606         ret += "};\n\n\n";
12607
12608 //--------------------------------------------------------
12609 //                      Create and initialize an aggregate object
12610
12611         ret += this->generate_functor_name()+"_aggrdef *create_aggregate(host_tuple &tup0, gs_sp_t buffer){\n";
12612         //              Variables for execution of the function.
12613         ret += "\tgs_int32_t problem = 0;\n";   // return unpack failure
12614
12615 //              return value
12616         ret += "\t"+generate_functor_name()+"_aggrdef *aggval = ("+generate_functor_name()+
12617                         "_aggrdef *)buffer;\n";
12618
12619         for(a=0;a<aggr_tbl.size();a++){
12620                 if(aggr_tbl.is_builtin(a)){
12621 //                      Create temporaries for buffer return values
12622                   data_type *adt = aggr_tbl.get_data_type(a);
12623                   if(adt->is_buffer_type()){
12624                         sprintf(tmpstr,"aggr_tmp_%d", a);
12625                         ret+=adt->make_host_cvar(tmpstr)+";\n";
12626                   }
12627                 }
12628         }
12629
12630 //              Unpack all remaining attributes
12631         ret += gen_remaining_colrefs(schema, cid_set, found_cids, "NULL", needs_xform);
12632         for(a=0;a<aggr_tbl.size();a++){
12633           sprintf(tmpstr,"aggval->aggr_var%d",a);
12634           string assignto_var = tmpstr;
12635           ret += "\t"+generate_aggr_init(assignto_var,&aggr_tbl,a, schema);
12636         }
12637
12638         ret += "\treturn aggval;\n";
12639         ret += "};\n\n";
12640
12641 //--------------------------------------------------------
12642 //                      update an aggregate object
12643
12644         ret += "void update_aggregate(host_tuple &tup0, "
12645                 +generate_functor_name()+"_groupdef *gbval, "+
12646                 generate_functor_name()+"_aggrdef *aggval){\n";
12647         //              Variables for execution of the function.
12648         ret += "\tgs_int32_t problem = 0;\n";   // return unpack failure
12649
12650 //                      use of temporaries depends on the aggregate,
12651 //                      generate them in generate_aggr_update
12652
12653
12654 //              Unpack all remaining attributes
12655         ret += gen_remaining_colrefs(schema, cid_set, found_cids, "", needs_xform);
12656         for(a=0;a<aggr_tbl.size();a++){
12657           sprintf(tmpstr,"aggval->aggr_var%d",a);
12658           string varname = tmpstr;
12659           ret.append(generate_aggr_update(varname,&aggr_tbl,a, schema));
12660         }
12661
12662         ret += "\treturn;\n";
12663         ret += "};\n";
12664
12665 //--------------------------------------------------------
12666 //                      reinitialize an aggregate object
12667
12668         ret += "void reinit_aggregates( "+
12669                 generate_functor_name()+"_groupdef *gbval, "+
12670                 generate_functor_name()+"_aggrdef *aggval){\n";
12671         //              Variables for execution of the function.
12672         ret += "\tgs_int32_t problem = 0;\n";   // return unpack failure
12673
12674 //                      use of temporaries depends on the aggregate,
12675 //                      generate them in generate_aggr_update
12676
12677         for(g=0;g<gb_tbl.size();g++){
12678           data_type *gdt = gb_tbl.get_data_type(g);
12679           if(gdt->is_temporal()){
12680                   if(gdt->is_buffer_type()){
12681                         sprintf(tmpstr,"\t\t%s(&(gbval->gb_var%d),&last_gb%d);\n",gdt->get_hfta_buffer_replace().c_str(),g,g);
12682                   }else{
12683                         sprintf(tmpstr,"\t\t gbval->gb_var%d =last_gb%d;\n",g,g);
12684                   }
12685                   ret += tmpstr;
12686                 }
12687         }
12688
12689 //              Unpack all remaining attributes
12690         for(a=0;a<aggr_tbl.size();a++){
12691           sprintf(tmpstr,"aggval->aggr_var%d",a);
12692           string varname = tmpstr;
12693           ret.append(generate_aggr_reinitialize(varname,&aggr_tbl,a, schema));
12694         }
12695
12696         ret += "\treturn;\n";
12697         ret += "};\n";
12698
12699
12700
12701
12702
12703 //---------------------------------------------------
12704 //                      Flush test
12705
12706         ret += "\tbool flush_needed(){\n";
12707         if(uses_temporal_flush){
12708                 ret += "\t\treturn needs_temporal_flush;\n";
12709         }else{
12710                 ret += "\t\treturn false;\n";
12711         }
12712         ret += "\t};\n";
12713
12714 //---------------------------------------------------
12715 //                      create output tuple
12716 //                      Unpack the partial functions ref'd in the where clause,
12717 //                      select clause.  Evaluate the where clause.
12718 //                      Finally, pack the tuple.
12719
12720 //                      I need to use special code generation here,
12721 //                      so I'll leave it in longhand.
12722
12723         ret += "host_tuple create_output_tuple("
12724                 +generate_functor_name()+"_groupdef *gbval, "+
12725                 generate_functor_name()+"_aggrdef *aggval, bool &failed){\n";
12726
12727         ret += "\thost_tuple tup;\n";
12728         ret += "\tfailed = false;\n";
12729         ret += "\tgs_retval_t retval = 0;\n";
12730
12731         string gbvar = "gbval->gb_var";
12732         string aggvar = "aggval->";
12733
12734
12735 //                      First, get the return values from the UDAFS
12736         for(a=0;a<aggr_tbl.size();a++){
12737                 if(! aggr_tbl.is_builtin(a)){
12738                         ret += "\t"+aggr_tbl.get_op(a)+"_HFTA_AGGR_OUTPUT_(&(udaf_ret_"+int_to_string(a)+"),";
12739                         if(aggr_tbl.get_storage_type(a)->get_type() != fstring_t) ret+="&";
12740                         ret+="("+aggvar+"aggr_var"+int_to_string(a)+"));\n";
12741                 }
12742         }
12743
12744         set<int> hv_sl_pfcns;
12745         for(w=0;w<having.size();w++){
12746                 collect_partial_fcns_pr(having[w]->pr, hv_sl_pfcns);
12747         }
12748         for(s=0;s<select_list.size();s++){
12749                 collect_partial_fcns(select_list[s]->se, hv_sl_pfcns);
12750         }
12751
12752 //              clean up the partial fcn results from any previous execution
12753         ret += gen_partial_fcn_dtr(partial_fcns,hv_sl_pfcns);
12754
12755 //              Unpack them now
12756         for(pfsi=hv_sl_pfcns.begin();pfsi!=hv_sl_pfcns.end();++pfsi){
12757                 ret += unpack_partial_fcn_fm_aggr(partial_fcns[(*pfsi)], (*pfsi), gbvar, aggvar, schema);
12758                 ret += "\tif(retval){ failed = true; return(tup);}\n";
12759         }
12760
12761 //              Evalaute the HAVING clause
12762 //              TODO: this seems to have a ++ operator rather than a + operator.
12763         for(w=0;w<having.size();++w){
12764                 ret += "\tif( !("+generate_predicate_code_fm_aggr(having[w]->pr,gbvar, aggvar, schema) +") ) { failed = true; return(tup);}\n";
12765         }
12766
12767 //          Now, compute the size of the tuple.
12768
12769 //          Unpack any BUFFER type selections into temporaries
12770 //          so that I can compute their size and not have
12771 //          to recompute their value during tuple packing.
12772 //          I can use regular assignment here because
12773 //          these temporaries are non-persistent.
12774 //                      TODO: should I be using the selvar generation routine?
12775
12776         ret += "//\t\tCompute the size of the tuple.\n";
12777         ret += "//\t\t\tNote: buffer storage packed at the end of the tuple.\n";
12778       for(s=0;s<select_list.size();s++){
12779                 scalarexp_t *se = select_list[s]->se;
12780         data_type *sdt = se->get_data_type();
12781         if(sdt->is_buffer_type() &&
12782                          !( (se->get_operator_type() == SE_COLREF) ||
12783                                 (se->get_operator_type() == SE_AGGR_STAR) ||
12784                                 (se->get_operator_type() == SE_AGGR_SE) ||
12785                            (se->get_operator_type() == SE_FUNC && se->is_partial()) ||
12786                            (se->get_operator_type() == SE_FUNC && se->get_aggr_ref() >= 0))
12787                 ){
12788             sprintf(tmpstr,"selvar_%d",s);
12789                         ret+="\t"+sdt->make_host_cvar(tmpstr)+" = ";
12790                         ret += generate_se_code_fm_aggr(se,gbvar, aggvar, schema) +";\n";
12791         }
12792       }
12793
12794 //      The size of the tuple is the size of the tuple struct plus the
12795 //      size of the buffers to be copied in.
12796
12797       ret+="\ttup.tuple_size = sizeof(" + generate_tuple_name( this->get_node_name()) +") + sizeof(gs_uint8_t)";
12798       for(s=0;s<select_list.size();s++){
12799 //              if(s>0) ret += "+";
12800                 scalarexp_t *se = select_list[s]->se;
12801         data_type *sdt = select_list[s]->se->get_data_type();
12802         if(sdt->is_buffer_type()){
12803                   if(!( (se->get_operator_type() == SE_COLREF) ||
12804                                 (se->get_operator_type() == SE_AGGR_STAR) ||
12805                                 (se->get_operator_type() == SE_AGGR_SE) ||
12806                            (se->get_operator_type() == SE_FUNC && se->is_partial()) ||
12807                            (se->get_operator_type() == SE_FUNC && se->get_aggr_ref() >= 0))
12808                   ){
12809             sprintf(tmpstr," + %s(&selvar_%d)", sdt->get_hfta_buffer_size().c_str(),s);
12810             ret.append(tmpstr);
12811                   }else{
12812             sprintf(tmpstr," + %s(&%s)", sdt->get_hfta_buffer_size().c_str(),generate_se_code_fm_aggr(se,gbvar, aggvar, schema).c_str());
12813             ret.append(tmpstr);
12814                   }
12815         }
12816       }
12817       ret.append(";\n");
12818
12819 //              Allocate tuple data block.
12820         ret += "//\t\tCreate the tuple block.\n";
12821           ret += "\ttup.data = malloc(tup.tuple_size);\n";
12822           ret += "\ttup.heap_resident = true;\n";
12823
12824 //              Mark tuple as regular
12825           ret += "\t*((gs_sp_t )tup.data + sizeof(" + generate_tuple_name( this->get_node_name()) +")) = REGULAR_TUPLE;\n";
12826
12827 //        ret += "\ttup.channel = 0;\n";
12828           ret += "\t"+generate_tuple_name( this->get_node_name())+" *tuple = ("+
12829                                 generate_tuple_name( this->get_node_name())+" *)(tup.data);\n";
12830
12831 //              Start packing.
12832 //                      (Here, offsets are hard-wired.  is this a problem?)
12833
12834         ret += "//\t\tPack the fields into the tuple.\n";
12835           ret += "\tint tuple_pos = sizeof("+generate_tuple_name( this->get_node_name()) +") + sizeof(gs_uint8_t);\n";
12836       for(s=0;s<select_list.size();s++){
12837                 scalarexp_t *se = select_list[s]->se;
12838         data_type *sdt = se->get_data_type();
12839         if(sdt->is_buffer_type()){
12840                   if(!( (se->get_operator_type() == SE_COLREF) ||
12841                                 (se->get_operator_type() == SE_AGGR_STAR) ||
12842                                 (se->get_operator_type() == SE_AGGR_SE) ||
12843                            (se->get_operator_type() == SE_FUNC && se->is_partial()) ||
12844                            (se->get_operator_type() == SE_FUNC && se->get_aggr_ref() >= 0))
12845                   ){
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);
12847             ret.append(tmpstr);
12848             sprintf(tmpstr,"\ttuple_pos += %s(&selvar_%d);\n", sdt->get_hfta_buffer_size().c_str(), s);
12849             ret.append(tmpstr);
12850                   }else{
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());
12852             ret.append(tmpstr);
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());
12854             ret.append(tmpstr);
12855                   }
12856         }else{
12857             sprintf(tmpstr,"\ttuple->tuple_var%d = ",s);
12858             ret.append(tmpstr);
12859             ret.append(generate_se_code_fm_aggr(se,gbvar, aggvar, schema) );
12860             ret.append(";\n");
12861         }
12862       }
12863
12864 //                      Destroy string temporaries
12865           ret += gen_buffer_selvars_dtr(select_list);
12866
12867           ret += "\treturn tup;\n";
12868           ret += "};\n";
12869
12870 //------------------------------------------------------------------
12871 //              Cleaning_when : evaluate the cleaning_when clause.
12872 //              ASSUME that the udaf return values have already
12873 //              been unpacked.  delete the string udaf return values at the end.
12874
12875         ret += "bool cleaning_when("
12876                 +generate_functor_name()+"_groupdef *gbval, "+
12877                 generate_functor_name()+"_aggrdef *aggval){\n";
12878
12879         ret += "\tbool retval = true;\n";
12880
12881
12882         gbvar = "gbval->gb_var";
12883         aggvar = "aggval->";
12884
12885
12886         set<int> clw_pfcns;
12887         for(w=0;w<closing_when.size();w++){
12888                 collect_partial_fcns_pr(closing_when[w]->pr, clw_pfcns);
12889         }
12890
12891 //              clean up the partial fcn results from any previous execution
12892         ret += gen_partial_fcn_dtr(partial_fcns,clw_pfcns);
12893
12894 //              Unpack them now
12895         for(pfsi=clw_pfcns.begin();pfsi!=clw_pfcns.end();++pfsi){
12896                 ret += unpack_partial_fcn_fm_aggr(partial_fcns[(*pfsi)], (*pfsi), gbvar, aggvar, schema);
12897                 ret += "\tif(retval){ return false;}\n";
12898         }
12899
12900 //              Evalaute the Closing When clause
12901 //              TODO: this seems to have a ++ operator rather than a + operator.
12902         for(w=0;w<closing_when.size();++w){
12903                 ret += "\tif( !("+generate_predicate_code_fm_aggr(closing_when[w]->pr,gbvar, aggvar, schema) +") ) { return false;}\n";
12904         }
12905
12906
12907 //                      Destroy string return vals of UDAFs
12908         for(a=0;a<aggr_tbl.size();a++){
12909                 if(! aggr_tbl.is_builtin(a)){
12910                         int afcn_id = aggr_tbl.get_fcn_id(a);
12911                         data_type *adt = Ext_fcns->get_fcn_dt(afcn_id);
12912                         if(adt->is_buffer_type()){
12913                                 sprintf(tmpstr,"\t%s(&udaf_ret_%d);\n",
12914                                 adt->get_hfta_buffer_destroy().c_str(), a );
12915                                 ret += tmpstr;
12916                         }
12917                 }
12918         }
12919
12920         ret += "\treturn retval;\n";
12921         ret += "};\n";
12922
12923
12924
12925
12926 //-------------------------------------------------------------------
12927 //              Temporal update functions
12928
12929         ret+="bool temp_status_received(){return temp_tuple_received;};\n\n";
12930
12931 //              create a temp status tuple
12932         ret += "int create_temp_status_tuple(host_tuple& result, bool flush_finished) {\n\n";
12933
12934         ret += gen_init_temp_status_tuple(this->get_node_name());
12935
12936 //              Start packing.
12937 //                      (Here, offsets are hard-wired.  is this a problem?)
12938
12939         ret += "//\t\tPack the fields into the tuple.\n";
12940         for(s=0;s<select_list.size();s++){
12941                 data_type *sdt = select_list[s]->se->get_data_type();
12942                 if(sdt->is_temporal()){
12943                         sprintf(tmpstr,"\ttuple->tuple_var%d = ",s);
12944                         ret += tmpstr;
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());
12946                         ret += tmpstr;
12947                         ret += ";\n";
12948                 }
12949         }
12950
12951         ret += "\treturn 0;\n";
12952         ret += "};};\n\n\n";
12953
12954
12955 //----------------------------------------------------------
12956 //                      The hash function
12957
12958         ret += "struct "+generate_functor_name()+"_hash_func{\n";
12959         ret += "\tgs_uint32_t operator()(const "+generate_functor_name()+
12960                                 "_groupdef *grp) const{\n";
12961         ret += "\t\treturn(0";
12962         for(g=0;g<gb_tbl.size();g++){
12963                 data_type *gdt = gb_tbl.get_data_type(g);
12964                 if(! gdt->is_temporal()){
12965                         ret += "^";
12966                         if(gdt->use_hashfunc()){
12967                                 if(gdt->is_buffer_type())
12968                                         sprintf(tmpstr,"(%s*%s(&(grp->gb_var%d)))",hash_nums[g%NRANDS].c_str(),gdt->get_hfta_hashfunc().c_str(),g);
12969                                         else
12970                                 sprintf(tmpstr,"(%s*%s(grp->gb_var%d))",hash_nums[g%NRANDS].c_str(),gdt->get_hfta_hashfunc().c_str(),g);
12971                         }else{
12972                                 sprintf(tmpstr,"(%s*grp->gb_var%d)",hash_nums[g%NRANDS].c_str(),g);
12973                         }
12974                         ret += tmpstr;
12975                 }
12976         }
12977         ret += " >> 32);\n";
12978         ret += "\t}\n";
12979         ret += "};\n\n";
12980
12981 //----------------------------------------------------------
12982 //                      The comparison function
12983
12984         ret += "struct "+generate_functor_name()+"_equal_func{\n";
12985         ret += "\tbool operator()(const "+generate_functor_name()+"_groupdef *grp1, "+
12986                         generate_functor_name()+"_groupdef *grp2) const{\n";
12987         ret += "\t\treturn( (";
12988
12989         string hcmpr = "";
12990         bool first_exec = true;
12991         for(g=0;g<gb_tbl.size();g++){
12992                 data_type *gdt = gb_tbl.get_data_type(g);
12993                 if(! gdt->is_temporal()){
12994                         if(first_exec){first_exec=false;}else{ hcmpr += ") && (";}
12995                         if(gdt->complex_comparison(gdt)){
12996                           if(gdt->is_buffer_type())
12997                                 sprintf(tmpstr,"(%s(&(grp1->gb_var%d), &(grp2->gb_var%d))==0)",
12998                                 gdt->get_hfta_comparison_fcn(gdt).c_str(),g,g);
12999                           else
13000                                 sprintf(tmpstr,"(%s((grp1->gb_var%d), (grp2->gb_var%d))==0)",
13001                                 gdt->get_hfta_comparison_fcn(gdt).c_str(),g,g);
13002                         }else{
13003                                 sprintf(tmpstr,"grp1->gb_var%d == grp2->gb_var%d",g,g);
13004                         }
13005                         hcmpr += tmpstr;
13006                 }
13007         }
13008         if(hcmpr == "")
13009                 hcmpr = "true";
13010         ret += hcmpr;
13011
13012         ret += ") );\n";
13013         ret += "\t}\n";
13014         ret += "};\n\n";
13015
13016
13017         return(ret);
13018 }
13019
13020 string rsgah_qpn::generate_operator(int i, string params){
13021
13022                 return(
13023                         "       running_agg_operator<" +
13024                         generate_functor_name()+","+
13025                         generate_functor_name() + "_groupdef, " +
13026                         generate_functor_name() + "_aggrdef, " +
13027                         generate_functor_name()+"_hash_func, "+
13028                         generate_functor_name()+"_equal_func "
13029                         "> *op"+int_to_string(i)+" = new running_agg_operator<"+
13030                         generate_functor_name()+","+
13031                         generate_functor_name() + "_groupdef, " +
13032                         generate_functor_name() + "_aggrdef, " +
13033                         generate_functor_name()+"_hash_func, "+
13034                         generate_functor_name()+"_equal_func "
13035                         ">("+params+", \"" + get_node_name() + "\");\n"
13036                 );
13037 }
13038
13039
13040
13041 //              Split aggregation into two HFTA components - sub and superaggregation
13042 //              If unable to split the aggreagates, empty vector will be returned
13043 vector<qp_node *> sgah_qpn::split_node_for_hfta(ext_fcn_list *Ext_fcns, table_list *Schema){
13044
13045         vector<qp_node *> ret_vec;
13046         int s, p, g, a, o, i;
13047         int si;
13048
13049         vector<string> fta_flds, stream_flds;
13050         int t = table_name->get_schema_ref();
13051
13052 //                      Get the set of interfaces it accesses.
13053         int ierr;
13054         vector<string> sel_names;
13055
13056 //                      Verify that all of the ref'd UDAFs can be split.
13057
13058         for(a=0;a<aggr_tbl.size();++a){
13059                 if(! aggr_tbl.is_builtin(a)){
13060                         int afcn = aggr_tbl.get_fcn_id(a);
13061                         int hfta_super_id = Ext_fcns->get_hfta_superaggr_id(afcn);
13062                         int hfta_sub_id = Ext_fcns->get_hfta_subaggr_id(afcn);
13063                         if(hfta_super_id < 0 || hfta_sub_id < 0){
13064                                 return(ret_vec);
13065                         }
13066                 }
13067     }
13068
13069 /////////////////////////////////////////////////////
13070 //                      Split into  aggr/aggr.
13071
13072
13073         sgah_qpn *low_hfta_node = new sgah_qpn();
13074         low_hfta_node->table_name = table_name;
13075         low_hfta_node->set_node_name( "_"+node_name );
13076         low_hfta_node->table_name->set_range_var(table_name->get_var_name());
13077
13078
13079         sgah_qpn *hi_hfta_node = new sgah_qpn();
13080         hi_hfta_node->table_name = new tablevar_t(  ("_"+node_name).c_str());
13081         hi_hfta_node->set_node_name( node_name );
13082         hi_hfta_node->table_name->set_range_var(table_name->get_var_name());
13083
13084 //                      First, process the group-by variables.
13085 //                      both low and hi level queries duplicate group-by variables of original query
13086
13087
13088         for(g=0;g<gb_tbl.size();g++){
13089 //                      Insert the gbvar into both low- and hi level hfta.
13090                 scalarexp_t *gbvar_def = dup_se(gb_tbl.get_def(g), &aggr_tbl);
13091                 low_hfta_node->gb_tbl.add_gb_var(
13092                         gb_tbl.get_name(g), gb_tbl.get_tblvar_ref(g), gbvar_def, gb_tbl.get_reftype(g)
13093                 );
13094
13095 //                      Insert a ref to the value of the gbvar into the low-level hfta select list.
13096                 colref_t *new_cr = new colref_t(gb_tbl.get_name(g).c_str() );
13097                 scalarexp_t *gbvar_fta = new scalarexp_t(new_cr);
13098                 gbvar_fta->set_gb_ref(g);
13099                 gbvar_fta->set_data_type( gb_tbl.get_def(g)->get_data_type() );
13100                 scalarexp_t *gbvar_stream = make_fta_se_ref(low_hfta_node->select_list, gbvar_fta,0);
13101
13102 //                      Insert the corresponding gbvar ref (gbvar_stream) into the stream.
13103                 gbvar_stream->set_gb_ref(-1);   // used as GBvar def
13104                 hi_hfta_node->gb_tbl.add_gb_var(
13105                         gbvar_stream->get_colref()->get_field(), -1, gbvar_stream,  gb_tbl.get_reftype(g)
13106                 );
13107
13108         }
13109 //      hi_hfta_node->gb_tbl.gb_patterns = gb_tbl.gb_patterns; // pattern processing at higtest level
13110         hi_hfta_node->gb_tbl.set_pattern_info( &gb_tbl); // pattern processing at higtest level
13111
13112 //                      SEs in the aggregate definitions.
13113 //                      They are all safe, so split them up for later processing.
13114         map<int, scalarexp_t *> hfta_aggr_se;
13115         for(a=0;a<aggr_tbl.size();++a){
13116                 split_hfta_aggr( &(aggr_tbl), a,
13117                                                 &(hi_hfta_node->aggr_tbl), &(low_hfta_node->aggr_tbl)  ,
13118                                                 low_hfta_node->select_list,
13119                                                 hfta_aggr_se,
13120                                                 Ext_fcns
13121                                         );
13122         }
13123
13124
13125 //                      Next, the select list.
13126
13127         for(s=0;s<select_list.size();s++){
13128                 bool fta_forbidden = false;
13129                 scalarexp_t *root_se = rehome_fta_se(select_list[s]->se, &hfta_aggr_se);
13130                 hi_hfta_node->select_list.push_back(
13131                         new select_element(root_se, select_list[s]->name));
13132         }
13133
13134
13135
13136 //                      All the predicates in the where clause must execute
13137 //                      in the low-level hfta.
13138
13139         for(p=0;p<where.size();p++){
13140                 predicate_t *new_pr = dup_pr(where[p]->pr, &aggr_tbl);
13141                 cnf_elem *new_cnf = new cnf_elem(new_pr);
13142                 analyze_cnf(new_cnf);
13143
13144                 low_hfta_node->where.push_back(new_cnf);
13145         }
13146
13147 //                      All of the predicates in the having clause must
13148 //                      execute in the high-level hfta node.
13149
13150         for(p=0;p<having.size();p++){
13151                 predicate_t *pr_root = rehome_fta_pr( having[p]->pr,  &hfta_aggr_se);
13152                 cnf_elem *cnf_root = new cnf_elem(pr_root);
13153                 analyze_cnf(cnf_root);
13154
13155                 hi_hfta_node->having.push_back(cnf_root);
13156         }
13157
13158
13159 //                      Copy parameters to both nodes
13160         vector<string> param_names = param_tbl->get_param_names();
13161         int pi;
13162         for(pi=0;pi<param_names.size();pi++){
13163                 data_type *dt = param_tbl->get_data_type(param_names[pi]);
13164                 low_hfta_node->param_tbl->add_param(param_names[pi],dt->duplicate(),
13165                                                                         param_tbl->handle_access(param_names[pi]));
13166                 hi_hfta_node->param_tbl->add_param(param_names[pi],dt->duplicate(),
13167                                                                         param_tbl->handle_access(param_names[pi]));
13168         }
13169         low_hfta_node->definitions = definitions;
13170         hi_hfta_node->definitions = definitions;
13171
13172
13173         low_hfta_node->table_name->set_machine(table_name->get_machine());
13174         low_hfta_node->table_name->set_interface(table_name->get_interface());
13175         low_hfta_node->table_name->set_ifq(false);
13176
13177         hi_hfta_node->table_name->set_machine(table_name->get_machine());
13178         hi_hfta_node->table_name->set_interface(table_name->get_interface());
13179         hi_hfta_node->table_name->set_ifq(false);
13180
13181         ret_vec.push_back(low_hfta_node);
13182         ret_vec.push_back(hi_hfta_node);
13183
13184
13185         return(ret_vec);
13186
13187
13188         // TODO: add splitting into selection/aggregation
13189 }
13190
13191
13192 //              Split aggregation into two HFTA components - sub and superaggregation
13193 //              If unable to split the aggreagates, empty vector will be returned
13194 //                      Similar to sgah, but super aggregate is rsgah, subaggr is sgah
13195 vector<qp_node *> rsgah_qpn::split_node_for_hfta(ext_fcn_list *Ext_fcns, table_list *Schema){
13196
13197         vector<qp_node *> ret_vec;
13198         int s, p, g, a, o, i;
13199         int si;
13200
13201         vector<string> fta_flds, stream_flds;
13202         int t = table_name->get_schema_ref();
13203
13204 //                      Get the set of interfaces it accesses.
13205         int ierr;
13206         vector<string> sel_names;
13207
13208 //                      Verify that all of the ref'd UDAFs can be split.
13209
13210         for(a=0;a<aggr_tbl.size();++a){
13211                 if(! aggr_tbl.is_builtin(a)){
13212                         int afcn = aggr_tbl.get_fcn_id(a);
13213                         int hfta_super_id = Ext_fcns->get_hfta_superaggr_id(afcn);
13214                         int hfta_sub_id = Ext_fcns->get_hfta_subaggr_id(afcn);
13215                         if(hfta_super_id < 0 || hfta_sub_id < 0){
13216                                 return(ret_vec);
13217                         }
13218                 }
13219     }
13220
13221 /////////////////////////////////////////////////////
13222 //                      Split into  aggr/aggr.
13223
13224
13225         sgah_qpn *low_hfta_node = new sgah_qpn();
13226         low_hfta_node->table_name = table_name;
13227         low_hfta_node->set_node_name( "_"+node_name );
13228         low_hfta_node->table_name->set_range_var(table_name->get_var_name());
13229
13230
13231         rsgah_qpn *hi_hfta_node = new rsgah_qpn();
13232         hi_hfta_node->table_name = new tablevar_t(  ("_"+node_name).c_str());
13233         hi_hfta_node->set_node_name( node_name );
13234         hi_hfta_node->table_name->set_range_var(table_name->get_var_name());
13235
13236 //                      First, process the group-by variables.
13237 //                      both low and hi level queries duplicate group-by variables of original query
13238
13239
13240         for(g=0;g<gb_tbl.size();g++){
13241 //                      Insert the gbvar into both low- and hi level hfta.
13242                 scalarexp_t *gbvar_def = dup_se(gb_tbl.get_def(g), &aggr_tbl);
13243                 low_hfta_node->gb_tbl.add_gb_var(
13244                         gb_tbl.get_name(g), gb_tbl.get_tblvar_ref(g), gbvar_def, gb_tbl.get_reftype(g)
13245                 );
13246
13247 //                      Insert a ref to the value of the gbvar into the low-level hfta select list.
13248                 colref_t *new_cr = new colref_t(gb_tbl.get_name(g).c_str() );
13249                 scalarexp_t *gbvar_fta = new scalarexp_t(new_cr);
13250                 gbvar_fta->set_gb_ref(g);
13251                 gbvar_fta->set_data_type( gb_tbl.get_def(g)->get_data_type() );
13252                 scalarexp_t *gbvar_stream = make_fta_se_ref(low_hfta_node->select_list, gbvar_fta,0);
13253
13254 //                      Insert the corresponding gbvar ref (gbvar_stream) into the stream.
13255                 gbvar_stream->set_gb_ref(-1);   // used as GBvar def
13256                 hi_hfta_node->gb_tbl.add_gb_var(
13257                         gbvar_stream->get_colref()->get_field(), -1, gbvar_stream,  gb_tbl.get_reftype(g)
13258                 );
13259
13260         }
13261
13262 //                      SEs in the aggregate definitions.
13263 //                      They are all safe, so split them up for later processing.
13264         map<int, scalarexp_t *> hfta_aggr_se;
13265         for(a=0;a<aggr_tbl.size();++a){
13266                 split_hfta_aggr( &(aggr_tbl), a,
13267                                                 &(hi_hfta_node->aggr_tbl), &(low_hfta_node->aggr_tbl)  ,
13268                                                 low_hfta_node->select_list,
13269                                                 hfta_aggr_se,
13270                                                 Ext_fcns
13271                                         );
13272         }
13273
13274
13275 //                      Next, the select list.
13276
13277         for(s=0;s<select_list.size();s++){
13278                 bool fta_forbidden = false;
13279                 scalarexp_t *root_se = rehome_fta_se(select_list[s]->se, &hfta_aggr_se);
13280                 hi_hfta_node->select_list.push_back(
13281                         new select_element(root_se, select_list[s]->name));
13282         }
13283
13284
13285
13286 //                      All the predicates in the where clause must execute
13287 //                      in the low-level hfta.
13288
13289         for(p=0;p<where.size();p++){
13290                 predicate_t *new_pr = dup_pr(where[p]->pr, &aggr_tbl);
13291                 cnf_elem *new_cnf = new cnf_elem(new_pr);
13292                 analyze_cnf(new_cnf);
13293
13294                 low_hfta_node->where.push_back(new_cnf);
13295         }
13296
13297 //                      All of the predicates in the having clause must
13298 //                      execute in the high-level hfta node.
13299
13300         for(p=0;p<having.size();p++){
13301                 predicate_t *pr_root = rehome_fta_pr( having[p]->pr,  &hfta_aggr_se);
13302                 cnf_elem *cnf_root = new cnf_elem(pr_root);
13303                 analyze_cnf(cnf_root);
13304
13305                 hi_hfta_node->having.push_back(cnf_root);
13306         }
13307
13308 //              Similar for closing when
13309         for(p=0;p<closing_when.size();p++){
13310                 predicate_t *pr_root = rehome_fta_pr( closing_when[p]->pr,  &hfta_aggr_se);
13311                 cnf_elem *cnf_root = new cnf_elem(pr_root);
13312                 analyze_cnf(cnf_root);
13313
13314                 hi_hfta_node->closing_when.push_back(cnf_root);
13315         }
13316
13317
13318 //                      Copy parameters to both nodes
13319         vector<string> param_names = param_tbl->get_param_names();
13320         int pi;
13321         for(pi=0;pi<param_names.size();pi++){
13322                 data_type *dt = param_tbl->get_data_type(param_names[pi]);
13323                 low_hfta_node->param_tbl->add_param(param_names[pi],dt->duplicate(),
13324                                                                         param_tbl->handle_access(param_names[pi]));
13325                 hi_hfta_node->param_tbl->add_param(param_names[pi],dt->duplicate(),
13326                                                                         param_tbl->handle_access(param_names[pi]));
13327         }
13328         low_hfta_node->definitions = definitions;
13329         hi_hfta_node->definitions = definitions;
13330
13331
13332         low_hfta_node->table_name->set_machine(table_name->get_machine());
13333         low_hfta_node->table_name->set_interface(table_name->get_interface());
13334         low_hfta_node->table_name->set_ifq(false);
13335
13336         hi_hfta_node->table_name->set_machine(table_name->get_machine());
13337         hi_hfta_node->table_name->set_interface(table_name->get_interface());
13338         hi_hfta_node->table_name->set_ifq(false);
13339
13340         ret_vec.push_back(low_hfta_node);
13341         ret_vec.push_back(hi_hfta_node);
13342
13343
13344         return(ret_vec);
13345
13346
13347         // TODO: add splitting into selection/aggregation
13348 }
13349
13350 //---------------------------------------------------------------
13351 //              Code for propagating Protocol field source information
13352
13353
13354 scalarexp_t *resolve_protocol_se(scalarexp_t *se, vector<map<string, scalarexp_t *> *> &src_vec, gb_table *gb_tbl, table_list *Schema){
13355         scalarexp_t *rse, *lse,*p_se, *gb_se;
13356         int tno, schema_type;
13357         map<string, scalarexp_t *> *pse_map;
13358
13359   switch(se->get_operator_type()){
13360     case SE_LITERAL:
13361                 return new scalarexp_t(se->get_literal());
13362     case SE_PARAM:
13363                 return scalarexp_t::make_param_reference(se->get_op().c_str());
13364     case SE_COLREF:
13365         if(se->is_gb()){
13366                         if(gb_tbl == NULL)
13367                                         fprintf(stderr,"INTERNAL ERROR, in resolve_protocol_se, se->gb_ref=%d, but gb_tbl is NULL\n",se->get_gb_ref());
13368                         gb_se = gb_tbl->get_def(se->get_gb_ref());
13369                         return resolve_protocol_se(gb_se,src_vec,gb_tbl,Schema);
13370                 }
13371
13372                 schema_type = Schema->get_schema_type(se->get_colref()->get_schema_ref());
13373                 if(schema_type == PROTOCOL_SCHEMA)
13374                         return dup_se(se,NULL);
13375
13376         tno = se->get_colref()->get_tablevar_ref();
13377         if(tno >= src_vec.size()){
13378                         fprintf(stderr,"INTERNAL ERROR, in resolve_protocol_se, tno=%d, src_vec.size()=%lu\n",tno,src_vec.size());
13379                 }
13380                 if(src_vec[tno] == NULL)
13381                         return NULL;
13382
13383                 pse_map =src_vec[tno];
13384                 p_se = (*pse_map)[se->get_colref()->get_field()];
13385                 if(p_se == NULL)
13386                         return NULL;
13387                 return dup_se(p_se,NULL);
13388     case SE_UNARY_OP:
13389         lse = resolve_protocol_se(se->get_left_se(),src_vec,gb_tbl,Schema);
13390         if(lse == NULL)
13391                 return NULL;
13392         else
13393                 return new scalarexp_t(se->get_op().c_str(),lse);
13394     case SE_BINARY_OP:
13395         lse = resolve_protocol_se(se->get_left_se(),src_vec,gb_tbl,Schema);
13396         if(lse == NULL)
13397                 return NULL;
13398         rse = resolve_protocol_se(se->get_right_se(),src_vec,gb_tbl,Schema);
13399         if(rse == NULL)
13400                 return NULL;
13401                 return new scalarexp_t(se->get_op().c_str(),lse,rse);
13402     case SE_AGGR_STAR:
13403                 return( NULL );
13404     case SE_AGGR_SE:
13405                 return( NULL );
13406         case SE_FUNC:
13407                 return(NULL);
13408         default:
13409                 return(NULL);
13410         break;
13411   }
13412
13413 }
13414
13415 void spx_qpn::create_protocol_se(vector<qp_node *> q_sources, table_list *Schema){
13416         int i;
13417         vector<map<string, scalarexp_t *> *> src_vec;
13418
13419         for(i=0;i<q_sources.size();i++){
13420                 if(q_sources[i] != NULL)
13421                         src_vec.push_back(q_sources[i]->get_protocol_se());
13422                 else
13423                         src_vec.push_back(NULL);
13424         }
13425
13426         for(i=0;i<select_list.size();i++){
13427                 protocol_map[select_list[i]->name] = resolve_protocol_se(select_list[i]->se,src_vec,NULL,Schema);
13428         }
13429 }
13430
13431 void join_eq_hash_qpn::create_protocol_se(vector<qp_node *> q_sources, table_list *Schema){
13432         int i;
13433         vector<map<string, scalarexp_t *> *> src_vec;
13434
13435         for(i=0;i<q_sources.size();i++){
13436                 if(q_sources[i] != NULL)
13437                         src_vec.push_back(q_sources[i]->get_protocol_se());
13438                 else
13439                         src_vec.push_back(NULL);
13440         }
13441
13442         for(i=0;i<select_list.size();i++){
13443                 protocol_map[select_list[i]->name] = resolve_protocol_se(select_list[i]->se,src_vec,NULL,Schema);
13444         }
13445
13446         for(i=0;i<hash_eq.size();i++){
13447                 hash_src_l.push_back(resolve_protocol_se(hash_eq[i]->pr->get_left_se(),src_vec,NULL,Schema));
13448                 hash_src_r.push_back(resolve_protocol_se(hash_eq[i]->pr->get_right_se(),src_vec,NULL,Schema));
13449         }
13450 }
13451
13452 void filter_join_qpn::create_protocol_se(vector<qp_node *> q_sources, table_list *Schema){
13453         int i;
13454         vector<map<string, scalarexp_t *> *> src_vec;
13455
13456         for(i=0;i<q_sources.size();i++){
13457                 if(q_sources[i] != NULL)
13458                         src_vec.push_back(q_sources[i]->get_protocol_se());
13459                 else
13460                         src_vec.push_back(NULL);
13461         }
13462
13463         for(i=0;i<select_list.size();i++){
13464                 protocol_map[select_list[i]->name] = resolve_protocol_se(select_list[i]->se,src_vec,NULL,Schema);
13465         }
13466
13467         for(i=0;i<hash_eq.size();i++){
13468                 hash_src_l.push_back(resolve_protocol_se(hash_eq[i]->pr->get_left_se(),src_vec,NULL,Schema));
13469                 hash_src_r.push_back(resolve_protocol_se(hash_eq[i]->pr->get_right_se(),src_vec,NULL,Schema));
13470         }
13471 }
13472
13473 void sgah_qpn::create_protocol_se(vector<qp_node *> q_sources, table_list *Schema){
13474         int i;
13475         vector<map<string, scalarexp_t *> *> src_vec;
13476
13477         for(i=0;i<q_sources.size();i++){
13478                 if(q_sources[i] != NULL)
13479                         src_vec.push_back(q_sources[i]->get_protocol_se());
13480                 else
13481                         src_vec.push_back(NULL);
13482         }
13483
13484         for(i=0;i<select_list.size();i++){
13485                 protocol_map[select_list[i]->name] = resolve_protocol_se(select_list[i]->se,src_vec,&gb_tbl,Schema);
13486         }
13487
13488         for(i=0;i<gb_tbl.size();i++)
13489                 gb_sources.push_back(resolve_protocol_se(gb_tbl.get_def(i),src_vec,&gb_tbl,Schema));
13490
13491 }
13492
13493 void rsgah_qpn::create_protocol_se(vector<qp_node *> q_sources, table_list *Schema){
13494         int i;
13495         vector<map<string, scalarexp_t *> *> src_vec;
13496
13497         for(i=0;i<q_sources.size();i++){
13498                 if(q_sources[i] != NULL)
13499                         src_vec.push_back(q_sources[i]->get_protocol_se());
13500                 else
13501                         src_vec.push_back(NULL);
13502         }
13503
13504         for(i=0;i<select_list.size();i++){
13505                 protocol_map[select_list[i]->name] = resolve_protocol_se(select_list[i]->se,src_vec,&gb_tbl,Schema);
13506         }
13507
13508         for(i=0;i<gb_tbl.size();i++)
13509                 gb_sources.push_back(resolve_protocol_se(gb_tbl.get_def(i),src_vec,&gb_tbl,Schema));
13510 }
13511
13512 void sgahcwcb_qpn::create_protocol_se(vector<qp_node *> q_sources, table_list *Schema){
13513         int i;
13514         vector<map<string, scalarexp_t *> *> src_vec;
13515
13516         for(i=0;i<q_sources.size();i++){
13517                 if(q_sources[i] != NULL)
13518                         src_vec.push_back(q_sources[i]->get_protocol_se());
13519                 else
13520                         src_vec.push_back(NULL);
13521         }
13522
13523         for(i=0;i<select_list.size();i++){
13524                 protocol_map[select_list[i]->name] = resolve_protocol_se(select_list[i]->se,src_vec,&gb_tbl,Schema);
13525         }
13526
13527         for(i=0;i<gb_tbl.size();i++)
13528                 gb_sources.push_back(resolve_protocol_se(gb_tbl.get_def(i),src_vec,&gb_tbl,Schema));
13529 }
13530
13531 void mrg_qpn::create_protocol_se(vector<qp_node *> q_sources, table_list *Schema){
13532         int f,s,i;
13533         scalarexp_t *first_se;
13534
13535         vector<map<string, scalarexp_t *> *> src_vec;
13536         map<string, scalarexp_t *> *pse_map;
13537
13538         for(i=0;i<q_sources.size();i++){
13539                 if(q_sources[i] != NULL)
13540                         src_vec.push_back(q_sources[i]->get_protocol_se());
13541                 else
13542                         src_vec.push_back(NULL);
13543         }
13544
13545         if(q_sources.size() == 0){
13546                 fprintf(stderr,"INTERNAL ERROR in mrg_qpn::create_protocol_se, q_sources.size() == 0\n");
13547                 exit(1);
13548         }
13549
13550         vector<field_entry *> tbl_flds = table_layout->get_fields();
13551         for(f=0;f<tbl_flds.size();f++){
13552                 bool match = true;
13553                 string fld_nm = tbl_flds[f]->get_name();
13554                 pse_map = src_vec[0];
13555                 first_se = (*pse_map)[fld_nm];
13556                 if(first_se == NULL)
13557                         match = false;
13558                 for(s=1;s<src_vec.size() && match;s++){
13559                         pse_map = src_vec[s];
13560                         scalarexp_t *match_se = (*pse_map)[fld_nm];
13561                         if(match_se == false)
13562                                 match = false;
13563                         else
13564                                 match = is_equivalent_se_base(first_se, match_se, Schema);
13565                 }
13566                 if(match)
13567                         protocol_map[fld_nm] = first_se;
13568                 else
13569                         protocol_map[fld_nm] = NULL;
13570         }
13571 }