-/* ------------------------------------------------\r
-Copyright 2014 AT&T Intellectual Property\r
- Licensed under the Apache License, Version 2.0 (the "License");\r
- you may not use this file except in compliance with the License.\r
- You may obtain a copy of the License at\r
-\r
- http://www.apache.org/licenses/LICENSE-2.0\r
-\r
- Unless required by applicable law or agreed to in writing, software\r
- distributed under the License is distributed on an "AS IS" BASIS,\r
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- See the License for the specific language governing permissions and\r
- limitations under the License.\r
- ------------------------------------------- */\r
-\r
-// Create, manipulate, and dump query plans.\r
-\r
-#include "query_plan.h"\r
-#include "analyze_fta.h"\r
-#include "generate_utils.h"\r
-\r
-#include<vector>\r
-\r
-using namespace std;\r
-\r
-extern string hash_nums[NRANDS]; // for fast hashing\r
-\r
-\r
-char tmpstr[1000];\r
-\r
-void untaboo(string &s){\r
- int c;\r
- for(c=0;c<s.size();++c){\r
- if(s[c] == '.'){\r
- s[c] = '_';\r
- }\r
- }\r
-}\r
-\r
-// mrg_qpn constructor, define here to avoid\r
-// circular references in the .h file\r
-mrg_qpn::mrg_qpn(filter_join_qpn *spx, std::string n_name, std::vector<std::string> &sources, std::vector<std::pair<std::string, std::string> > &ifaces, ifq_t *ifdb){\r
- param_tbl = spx->param_tbl;\r
- int i;\r
- node_name = n_name;\r
- field_entry_list *fel = new field_entry_list();\r
- merge_fieldpos = -1;\r
-\r
- disorder = 1;\r
-\r
- for(i=0;i<spx->select_list.size();++i){\r
- data_type *dt = spx->select_list[i]->se->get_data_type()->duplicate();\r
- if(dt->is_temporal()){\r
- if(merge_fieldpos < 0){\r
- merge_fieldpos = i;\r
- }else{\r
- fprintf(stderr,"Warning: Merge subquery %s found two temporal fields (%s, %s), using %s\n", n_name.c_str(), spx->select_list[merge_fieldpos]->name.c_str(), spx->select_list[i]->name.c_str(), spx->select_list[merge_fieldpos]->name.c_str() );\r
- dt->reset_temporal();\r
- }\r
- }\r
-\r
- field_entry *fe = dt->make_field_entry(spx->select_list[i]->name);\r
- fel->append_field(fe);\r
- delete dt;\r
- }\r
- if(merge_fieldpos<0){\r
- fprintf(stderr,"ERROR, no temporal attribute for merge subquery %s\n",n_name.c_str());\r
- exit(1);\r
- }\r
- table_layout = new table_def( n_name.c_str(), NULL, NULL, fel, STREAM_SCHEMA);\r
-\r
-// NEED TO HANDLE USER_SPECIFIED SLACK\r
- this->resolve_slack(spx->select_list[merge_fieldpos]->se,\r
- spx->select_list[merge_fieldpos]->name, ifaces, ifdb,NULL);\r
-// if(this->slack == NULL)\r
-// fprintf(stderr,"Zero slack.\n");\r
-// else\r
-// fprintf(stderr,"slack is %s\n",slack->to_string().c_str());\r
-\r
- for(i=0;i<sources.size();i++){\r
- std::string rvar = "_m"+int_to_string(i);\r
- mvars.push_back(new colref_t(rvar.c_str(), spx->select_list[merge_fieldpos]->name.c_str()));\r
- mvars[i]->set_tablevar_ref(i);\r
- fm.push_back(new tablevar_t(sources[i].c_str()));\r
- fm[i]->set_range_var(rvar);\r
- }\r
-\r
- param_tbl = new param_table();\r
- std::vector<std::string> param_names = spx->param_tbl->get_param_names();\r
- int pi;\r
- for(pi=0;pi<param_names.size();pi++){\r
- data_type *dt = spx->param_tbl->get_data_type(param_names[pi]);\r
- param_tbl->add_param(param_names[pi],dt->duplicate(),\r
- spx->param_tbl->handle_access(param_names[pi]));\r
- }\r
- definitions = spx->definitions;\r
-\r
-}\r
-\r
-\r
-\r
-// This function translates an analyzed parse tree\r
-// into one or more query nodes (qp_node).\r
-// Currently only one node is created, but some query\r
-// fragments might create more than one query node,\r
-// e.g. aggregation over a joim, or nested subqueries\r
-// in the FROM clause (unless this is handles at parse tree\r
-// analysis time). At this stage, they will be linked\r
-// by the names in the FROM clause.\r
-// INVARIANT : if mroe than one query node is returned,\r
-// the last one represents the output of the query.\r
-vector<qp_node *> create_query_nodes(query_summary_class *qs,table_list *Schema){\r
-\r
-// Classify the query.\r
-\r
- vector <qp_node *> local_plan;\r
- qp_node *plan_root;\r
-\r
-// TODO\r
-// I should probably move a lot of this code\r
-// into the qp_node constructors,\r
-// and have this code focus on building the query plan tree.\r
-\r
-// MERGE node\r
- if(qs->query_type == MERGE_QUERY){\r
- mrg_qpn *merge_node = new mrg_qpn(qs,Schema);\r
-\r
-// Done\r
- plan_root = merge_node;\r
- local_plan.push_back(merge_node);\r
-\r
- /*\r
- Do not split sources until we are done with optimizations\r
- vector<mrg_qpn *> split_merge = merge_node->split_sources();\r
- local_plan.insert(local_plan.begin(), split_merge.begin(), split_merge.end());\r
- */\r
-// If children are created, add them to the schema.\r
-/*\r
- int i;\r
-printf("split_merge size is %d\n",split_merge.size());\r
- for(i=1;i<split_merge.size();++i){\r
- Schema->add_table(split_merge[i]->get_fields());\r
-printf("Adding split merge table %d\n",i);\r
- }\r
-*/\r
-\r
-/*\r
-printf("Did split sources on %s:\n",qs->query_name.c_str());\r
-int ss;\r
-for(ss=0;ss<local_plan.size();ss++){\r
-printf("node %d, name=%s, sources=",ss,local_plan[ss]->get_node_name().c_str());\r
-vector<tablevar_t *> inv = local_plan[ss]->get_input_tbls();\r
-int nn;\r
-for(nn=0;nn<inv.size();nn++){\r
-printf("%s ",inv[nn]->to_string().c_str());\r
-}\r
-printf("\n");\r
-}\r
-*/\r
-\r
-\r
- } else{\r
-\r
-// Select / Aggregation / Join\r
- if(qs->gb_tbl->size() == 0 && qs->aggr_tbl->size() == 0){\r
-\r
- if(qs->fta_tree->get_from()->size() == 1){\r
- spx_qpn *spx_node = new spx_qpn(qs,Schema);\r
-\r
- plan_root = spx_node;\r
- local_plan.push_back(spx_node);\r
- }else{\r
- if(qs->fta_tree->get_from()->get_properties() == FILTER_JOIN_PROPERTY){\r
- filter_join_qpn *join_node = new filter_join_qpn(qs,Schema);\r
- plan_root = join_node;\r
- local_plan.push_back(join_node);\r
- }else{\r
- join_eq_hash_qpn *join_node = new join_eq_hash_qpn(qs,Schema);\r
- plan_root = join_node;\r
- local_plan.push_back(join_node);\r
- }\r
- }\r
- }else{\r
-// aggregation\r
-\r
- if(qs->states_refd.size() || qs->sg_tbl.size() || qs->cb_cnf.size()){\r
- sgahcwcb_qpn *sgahcwcb_node = new sgahcwcb_qpn(qs,Schema);\r
- plan_root = sgahcwcb_node;\r
- local_plan.push_back(sgahcwcb_node);\r
- }else{\r
- if(qs->closew_cnf.size()){\r
- rsgah_qpn *rsgah_node = new rsgah_qpn(qs,Schema);\r
- plan_root = rsgah_node;\r
- local_plan.push_back(rsgah_node);\r
- }else{\r
- sgah_qpn *sgah_node = new sgah_qpn(qs,Schema);\r
- plan_root = sgah_node;\r
- local_plan.push_back(sgah_node);\r
- }\r
- }\r
- }\r
- }\r
-\r
-\r
-// Get the query name and other definitions.\r
- plan_root->set_node_name( qs->query_name);\r
- plan_root->set_definitions( qs->definitions) ;\r
-\r
-\r
-// return(plan_root);\r
- return(local_plan);\r
-\r
-}\r
-\r
-\r
-string se_to_query_string(scalarexp_t *se, aggregate_table *aggr_tbl){\r
- string l_str;\r
- string r_str;\r
- string ret;\r
- int p;\r
- vector<scalarexp_t *> operand_list;\r
- string su_ind = "";\r
-\r
- if(se->is_superaggr())\r
- su_ind = "$";\r
-\r
- switch(se->get_operator_type()){\r
- case SE_LITERAL:\r
- l_str = se->get_literal()->to_query_string();\r
- return l_str;\r
- case SE_PARAM:\r
- l_str = "$" + se->get_op();\r
- return l_str;\r
- case SE_COLREF:\r
- l_str = se->get_colref()->to_query_string() ;\r
- return l_str;\r
- case SE_UNARY_OP:\r
- l_str = se_to_query_string(se->get_left_se(),aggr_tbl);\r
-\r
- return se->get_op()+"( "+l_str+" )";;\r
- case SE_BINARY_OP:\r
- l_str = se_to_query_string(se->get_left_se(),aggr_tbl);\r
- r_str = se_to_query_string(se->get_right_se(),aggr_tbl);\r
- return( "("+l_str+")"+se->get_op()+"("+r_str+")" );\r
- case SE_AGGR_STAR:\r
- return( se->get_op() + su_ind + "(*)");\r
- case SE_AGGR_SE:\r
- l_str = se_to_query_string(aggr_tbl->get_aggr_se(se->get_aggr_ref()),aggr_tbl);\r
- return( se->get_op() + su_ind + "(" + l_str + ")" );\r
- case SE_FUNC:\r
- if(se->get_aggr_ref() >= 0)\r
- operand_list = aggr_tbl->get_operand_list(se->get_aggr_ref());\r
- else\r
- operand_list = se->get_operands();\r
-\r
- ret = se->get_op() + su_ind + "(";\r
- for(p=0;p<operand_list.size();p++){\r
- l_str = se_to_query_string(operand_list[p],aggr_tbl);\r
- if(p>0) ret += ", ";\r
- ret += l_str;\r
- }\r
- ret += ")";\r
- return(ret);\r
- break;\r
- }\r
- return "ERROR SE op type not recognized in se_to_query_string.\n";\r
-}\r
-\r
-\r
-string pred_to_query_str(predicate_t *pr, aggregate_table *aggr_tbl){\r
- string l_str;\r
- string r_str;\r
- string ret;\r
- int o,l;\r
- vector<literal_t *> llist;\r
- vector<scalarexp_t *> op_list;\r
-\r
- switch(pr->get_operator_type()){\r
- case PRED_IN:\r
- l_str = se_to_query_string(pr->get_left_se(),aggr_tbl);\r
- ret = l_str + " IN [";\r
- llist = pr->get_lit_vec();\r
- for(l=0;l<llist.size();l++){\r
- if(l>0) ret += ", ";\r
- ret += llist[l]->to_query_string();\r
- }\r
- ret += "]";\r
-\r
- return(ret);\r
- case PRED_COMPARE:\r
- l_str = se_to_query_string(pr->get_left_se(),aggr_tbl);\r
- r_str = se_to_query_string(pr->get_right_se(),aggr_tbl);\r
- return( l_str + " " + pr->get_op() + " " + r_str );\r
- case PRED_UNARY_OP:\r
- l_str = pred_to_query_str(pr->get_left_pr(),aggr_tbl);\r
- return(pr->get_op() + "( " + l_str + " )");\r
- case PRED_BINARY_OP:\r
- l_str = pred_to_query_str(pr->get_left_pr(),aggr_tbl);\r
- r_str = pred_to_query_str(pr->get_right_pr(),aggr_tbl);\r
- return("( " + r_str + " )" + pr->get_op() + "( " + l_str + " )");\r
- case PRED_FUNC:\r
- ret = pr->get_op()+"[";\r
- op_list = pr->get_op_list();\r
- for(o=0;o<op_list.size();++o){\r
- if(o>0) ret += ", ";\r
- ret += se_to_query_string(op_list[o],aggr_tbl);\r
- }\r
- ret += "]";\r
- return(ret);\r
- default:\r
- fprintf(stderr,"INTERNAL ERROR in pred_to_query_str, line %d, character %d, unknown predicate operator type %d\n",\r
- pr->get_lineno(), pr->get_charno(), pr->get_operator_type() );\r
- exit(1);\r
- }\r
-\r
- return(0);\r
-}\r
-\r
-\r
-\r
-// Build a selection list,\r
-// but avoid adding duplicate SEs.\r
-\r
-\r
-int add_select_list_nodup(vector<select_element *> &lfta_select_list, scalarexp_t *se,\r
- bool &new_element){\r
- new_element = false;\r
- int s;\r
- for(s=0;s<lfta_select_list.size();s++){\r
- if(is_equivalent_se(lfta_select_list[s]->se, se)){\r
- return(s);\r
- }\r
- }\r
- new_element = true;\r
- lfta_select_list.push_back(new select_element(se,"NoNameIn:add_select_list_nodup"));\r
- return(lfta_select_list.size()-1);\r
-}\r
-\r
-\r
-\r
-// TODO: The generated colref should be tied to the tablevar\r
-// representing the lfta output. For now, always 0.\r
-\r
-scalarexp_t *make_fta_se_ref(vector<select_element *> &lfta_select_list, scalarexp_t *se, int h_tvref){\r
- bool new_element;\r
- int fta_se_nbr = add_select_list_nodup(lfta_select_list, se, new_element);\r
- string colname;\r
- if(!new_element){\r
- colname = lfta_select_list[fta_se_nbr]->name;\r
- }else{\r
- colname = impute_colname(lfta_select_list, se);\r
- lfta_select_list[fta_se_nbr]->name = colname;\r
- }\r
-//\r
-// TODO: fill in the tablevar and schema of the colref here.\r
- colref_t *new_cr = new colref_t(colname.c_str());\r
- new_cr->set_tablevar_ref(h_tvref);\r
-\r
-\r
- scalarexp_t *new_se= new scalarexp_t(new_cr);\r
- new_se->use_decorations_of(se);\r
-\r
- return(new_se);\r
-}\r
-\r
-\r
-// Build a selection list,\r
-// but avoid adding duplicate SEs.\r
-\r
-\r
-int add_select_list_nodup(vector<select_element *> *lfta_select_list, scalarexp_t *se,\r
- bool &new_element){\r
- new_element = false;\r
- int s;\r
- for(s=0;s<lfta_select_list->size();s++){\r
- if(is_equivalent_se((*lfta_select_list)[s]->se, se)){\r
- return(s);\r
- }\r
- }\r
- new_element = true;\r
- lfta_select_list->push_back(new select_element(se,"NoNameIn:add_select_list_nodup"));\r
- return(lfta_select_list->size()-1);\r
-}\r
-\r
-\r
-\r
-// TODO: The generated colref should be tied to the tablevar\r
-// representing the lfta output. For now, always 0.\r
-\r
-scalarexp_t *make_fta_se_ref(vector<vector<select_element *> *> &lfta_select_list, scalarexp_t *se, int h_tvref){\r
- bool new_element;\r
- vector<select_element *> *the_sel_list = lfta_select_list[h_tvref];\r
- int fta_se_nbr = add_select_list_nodup(the_sel_list, se, new_element);\r
- string colname;\r
- if(!new_element){\r
- colname = (*the_sel_list)[fta_se_nbr]->name;\r
- }else{\r
- colname = impute_colname(*the_sel_list, se);\r
- (*the_sel_list)[fta_se_nbr]->name = colname;\r
- }\r
-//\r
-// TODO: fill in the tablevar and schema of the colref here.\r
- colref_t *new_cr = new colref_t(colname.c_str());\r
- new_cr->set_tablevar_ref(h_tvref);\r
-\r
-\r
- scalarexp_t *new_se= new scalarexp_t(new_cr);\r
- new_se->use_decorations_of(se);\r
-\r
- return(new_se);\r
-}\r
-\r
-\r
-\r
-\r
-//\r
-// Test if a se can be evaluated at the fta.\r
-// check forbidden types (e.g. float), forbidden operations\r
-// between types (e.g. divide a long long), forbidden operations\r
-// (too expensive, not implemented).\r
-//\r
-// Return true if not forbidden, false if forbidden\r
-//\r
-// TODO: the parameter aggr_tbl is not used, delete it.\r
-\r
-bool check_fta_forbidden_se(scalarexp_t *se,\r
- aggregate_table *aggr_tbl,\r
- ext_fcn_list *Ext_fcns\r
- ){\r
-\r
- int p, fcn_id;\r
- vector<scalarexp_t *> operand_list;\r
- vector<data_type *> dt_signature;\r
- data_type *dt = se->get_data_type();\r
-\r
-\r
-\r
- switch(se->get_operator_type()){\r
- case SE_LITERAL:\r
- case SE_PARAM:\r
- case SE_COLREF:\r
- return( se->get_data_type()->fta_legal_type() );\r
- case SE_IFACE_PARAM:\r
- return true;\r
- case SE_UNARY_OP:\r
- if(!check_fta_forbidden_se(se->get_left_se(), aggr_tbl, Ext_fcns))\r
- return(false);\r
- return(\r
- dt->fta_legal_operation(se->get_left_se()->get_data_type(), se->get_op())\r
- );\r
- case SE_BINARY_OP:\r
- if(!check_fta_forbidden_se(se->get_left_se(),aggr_tbl, Ext_fcns))\r
- return(false);\r
- if(!check_fta_forbidden_se(se->get_right_se(),aggr_tbl, Ext_fcns))\r
- return(false);\r
- return(dt->fta_legal_operation(se->get_left_se()->get_data_type(),\r
- se->get_right_se()->get_data_type(),\r
- se->get_op()\r
- )\r
- );\r
-\r
-// return true, aggregate fta-safeness is determined elsewhere.\r
- case SE_AGGR_STAR:\r
- return(true);\r
- case SE_AGGR_SE:\r
- return(true);\r
-\r
- case SE_FUNC:\r
- if(se->get_aggr_ref() >= 0) return true;\r
-\r
- operand_list = se->get_operands();\r
- for(p=0;p<operand_list.size();p++){\r
- if(!check_fta_forbidden_se(operand_list[p],aggr_tbl, Ext_fcns))\r
- return(false);\r
- dt_signature.push_back(operand_list[p]->get_data_type() );\r
- }\r
- fcn_id = Ext_fcns->lookup_fcn(se->get_op(), dt_signature);\r
- if( fcn_id < 0 ){\r
- fprintf(stderr,"ERROR, no external function %s(",se->get_op().c_str());\r
- int o;\r
- for(o=0;o<operand_list.size();o++){\r
- if(o>0) fprintf(stderr,", ");\r
- fprintf(stderr,"%s",operand_list[o]->get_data_type()->to_string().c_str());\r
- }\r
- fprintf(stderr,") is defined, line %d, char %d\n", se->get_lineno(), se->get_charno() );\r
- if(fcn_id == -2) fprintf(stderr,"(multiple subsuming functions found)\n");\r
- return(false);\r
- }\r
-\r
- return(Ext_fcns->fta_legal(fcn_id) );\r
- default:\r
- printf("INTERNAL ERROR in check_fta_forbidden_se: operator type %d\n",se->get_operator_type());\r
- exit(1);\r
- break;\r
- }\r
- return(false);\r
-\r
-}\r
-\r
-\r
-// test if a pr can be executed at the fta.\r
-//\r
-// Return true if not forbidden, false if forbidden\r
-\r
-bool check_fta_forbidden_pr(predicate_t *pr,\r
- aggregate_table *aggr_tbl,\r
- ext_fcn_list *Ext_fcns\r
- ){\r
-\r
- vector<literal_t *> llist;\r
- data_type *dt;\r
- int l,o, fcn_id;\r
- vector<scalarexp_t *> op_list;\r
- vector<data_type *> dt_signature;\r
-\r
-\r
-\r
- switch(pr->get_operator_type()){\r
- case PRED_IN:\r
- if(! check_fta_forbidden_se(pr->get_left_se(), aggr_tbl, Ext_fcns) )\r
- return(false);\r
- llist = pr->get_lit_vec();\r
- for(l=0;l<llist.size();l++){\r
- dt = new data_type(llist[l]->get_type());\r
- if(! dt->fta_legal_type()){\r
- delete dt;\r
- return(false);\r
- }\r
- delete dt;\r
- }\r
- return(true);\r
- case PRED_COMPARE:\r
- if(! check_fta_forbidden_se(pr->get_left_se(), aggr_tbl, Ext_fcns))\r
- return(false);\r
- if(! check_fta_forbidden_se(pr->get_right_se(), aggr_tbl, Ext_fcns))\r
- return(false);\r
- return(true);\r
- case PRED_UNARY_OP:\r
- return( check_fta_forbidden_pr(pr->get_left_pr(), aggr_tbl, Ext_fcns) );\r
- case PRED_BINARY_OP:\r
- if(! check_fta_forbidden_pr(pr->get_left_pr(), aggr_tbl, Ext_fcns))\r
- return(false);\r
- if(! check_fta_forbidden_pr(pr->get_right_pr(), aggr_tbl, Ext_fcns))\r
- return(false);\r
- return(true);\r
- case PRED_FUNC:\r
- op_list = pr->get_op_list();\r
- for(o=0;o<op_list.size();o++){\r
- if(!check_fta_forbidden_se(op_list[o],aggr_tbl, Ext_fcns))\r
- return(false);\r
- dt_signature.push_back(op_list[o]->get_data_type() );\r
- }\r
- fcn_id = Ext_fcns->lookup_pred(pr->get_op(), dt_signature);\r
- if( fcn_id < 0 ){\r
- fprintf(stderr,"ERROR, no external predicate %s(",pr->get_op().c_str());\r
- int o;\r
- for(o=0;o<op_list.size();o++){\r
- if(o>0) fprintf(stderr,", ");\r
- fprintf(stderr,"%s",op_list[o]->get_data_type()->to_string().c_str());\r
- }\r
- fprintf(stderr,") is defined, line %d, char %d\n", pr->get_lineno(), pr->get_charno() );\r
- if(fcn_id == -2) fprintf(stderr,"(multiple subsuming predicates found)\n");\r
- return(false);\r
- }\r
-\r
- return(Ext_fcns->fta_legal(fcn_id) );\r
- default:\r
- fprintf(stderr,"INTERNAL ERROR in check_fta_forbidden_pr, line %d, character %d, unknown predicate operator type %d\n",\r
- pr->get_lineno(), pr->get_charno(), pr->get_operator_type() );\r
- exit(1);\r
- }\r
-\r
- return(0);\r
-\r
-}\r
-\r
-\r
-// Split the aggregates in orig_aggr_tbl, into superaggregates and\r
-// subaggregates.\r
-// (the value of the HFTA aggregate might be a SE of several LFTA\r
-// subaggregates, e.g. avg : sum / count )\r
-// Register the superaggregates in hfta_aggr_tbl, and the\r
-// subaggregates in lfta_aggr_tbl.\r
-// Insert references to the subaggregates into lfta_select_list.\r
-// (and record their names in the currnames list)\r
-// Create a SE for the superaggregate, put it in hfta_aggr_se,\r
-// keyed on agr_id.\r
-\r
-void split_fta_aggr(aggregate_table *orig_aggr_tbl, int agr_id,\r
- aggregate_table *hfta_aggr_tbl,\r
- aggregate_table *lfta_aggr_tbl,\r
- vector<select_element *> &lfta_select_list,\r
- map<int,scalarexp_t *> &hfta_aggr_se,\r
- ext_fcn_list *Ext_fcns\r
- ){\r
- bool new_element;\r
- scalarexp_t *subaggr_se;\r
- int fta_se_nbr;\r
- string colname;\r
- int ano;\r
- colref_t *new_cr;\r
- scalarexp_t *new_se, *l_se;\r
- vector<scalarexp_t *> subaggr_ref_se;\r
-\r
-// UDAF processing\r
- if(! orig_aggr_tbl->is_builtin(agr_id)){\r
-// Construct the subaggregate\r
- int fcn_id = orig_aggr_tbl->get_fcn_id(agr_id);\r
- vector<scalarexp_t *> opl = orig_aggr_tbl->get_operand_list(agr_id);\r
- vector<scalarexp_t *> subopl;\r
- int o;\r
- for(o=0;o<opl.size();++o){\r
- subopl.push_back(dup_se(opl[o], NULL));\r
- }\r
- int sub_id = Ext_fcns->get_subaggr_id(fcn_id);\r
- subaggr_se = new scalarexp_t(Ext_fcns->get_fcn_name(sub_id).c_str(), subopl);\r
- subaggr_se->set_fcn_id(sub_id);\r
- subaggr_se->set_data_type(Ext_fcns->get_fcn_dt(sub_id));\r
-// Add it to the lfta select list.\r
- fta_se_nbr = add_select_list_nodup(lfta_select_list, subaggr_se,new_element);\r
- if(!new_element){\r
- colname = lfta_select_list[fta_se_nbr]->name;\r
- }else{\r
- colname = impute_colname(lfta_select_list, subaggr_se);\r
- lfta_select_list[fta_se_nbr]->name = colname;\r
- ano = lfta_aggr_tbl->add_aggr(Ext_fcns->get_fcn_name(sub_id), sub_id, subopl,Ext_fcns->get_storage_dt(sub_id), false, false,Ext_fcns->has_lfta_bailout(sub_id));\r
- subaggr_se->set_aggr_id(ano);\r
- }\r
-\r
-// Construct a reference to the subaggregate\r
- new_cr = new colref_t(colname.c_str());\r
- new_se = new scalarexp_t(new_cr);\r
-// I'm not certain what the types should be ....\r
-// This will need to be filled in by later analysis.\r
-// NOTE: this might not capture all the meaning of data_type ...\r
- new_se->set_data_type(Ext_fcns->get_fcn_dt(sub_id));\r
- subaggr_ref_se.push_back(new_se);\r
-\r
-// Construct the superaggregate\r
- int super_id = Ext_fcns->get_superaggr_id(fcn_id);\r
- scalarexp_t *ret_se = new scalarexp_t(Ext_fcns->get_fcn_name(super_id).c_str(), subaggr_ref_se);\r
- ret_se->set_fcn_id(super_id);\r
- ret_se->set_data_type(Ext_fcns->get_fcn_dt(super_id));\r
-// Register it in the hfta aggregate table\r
- ano = hfta_aggr_tbl->add_aggr(ret_se->get_op(), super_id, subaggr_ref_se,Ext_fcns->get_storage_dt(super_id), false, Ext_fcns->is_running_aggr(sub_id),false);\r
- ret_se->set_aggr_id(ano);\r
- hfta_aggr_se[agr_id] = ret_se;\r
-\r
- return;\r
- }\r
-\r
-\r
-// builtin aggregate processing\r
- bool l_forbid;\r
-\r
- vector<bool> use_se;\r
- vector<string> subaggr_names = orig_aggr_tbl->get_subaggr_fcns(agr_id, use_se);\r
- vector<data_type *> subaggr_dt = orig_aggr_tbl->get_subaggr_dt(agr_id);\r
- int sa;\r
-\r
- if(orig_aggr_tbl->is_star_aggr(agr_id)){\r
- for(sa=0;sa<subaggr_names.size();sa++){\r
- subaggr_se = scalarexp_t::make_star_aggr(subaggr_names[sa].c_str());\r
- subaggr_se->set_data_type(subaggr_dt[sa]);\r
-\r
-// The following sequence is similar to the code in make_fta_se_ref,\r
-// but there is special processing for the aggregate tables.\r
- int fta_se_nbr = add_select_list_nodup(lfta_select_list, subaggr_se,new_element);\r
- if(!new_element){\r
- colname = lfta_select_list[fta_se_nbr]->name;\r
- }else{\r
- colname = impute_colname(lfta_select_list, subaggr_se);\r
- lfta_select_list[fta_se_nbr]->name = colname;\r
- ano = lfta_aggr_tbl->add_aggr(subaggr_names[sa].c_str(),NULL, false);\r
- subaggr_se->set_aggr_id(ano);\r
- }\r
- new_cr = new colref_t(colname.c_str());\r
- new_cr->set_tablevar_ref(0);\r
- new_se = new scalarexp_t(new_cr);\r
-\r
-// I'm not certain what the types should be ....\r
-// This will need to be filled in by later analysis.\r
-// Actually, this is causing a problem.\r
-// I will assume a UINT data type. / change to INT\r
-// (consistent with assign_data_types in analyze_fta.cc)\r
-// TODO: why can't I use subaggr_dt, as I do in the other IF branch?\r
- data_type *ndt = new data_type("Int"); // used to be Uint\r
- new_se->set_data_type(ndt);\r
-\r
- subaggr_ref_se.push_back(new_se);\r
- }\r
- }else{\r
- for(sa=0;sa<subaggr_names.size();sa++){\r
- if(use_se[sa]){\r
- scalarexp_t *aggr_operand = orig_aggr_tbl->get_aggr_se(agr_id);\r
- l_se = dup_se(aggr_operand, NULL);\r
- subaggr_se = scalarexp_t::make_se_aggr(subaggr_names[sa].c_str(),l_se);\r
- }else{\r
- subaggr_se = scalarexp_t::make_star_aggr(subaggr_names[sa].c_str());\r
- }\r
- subaggr_se->set_data_type(subaggr_dt[sa]);\r
-\r
-// again, similar to make_fta_se_ref.\r
- fta_se_nbr = add_select_list_nodup(lfta_select_list, subaggr_se,new_element);\r
- if(!new_element){\r
- colname = lfta_select_list[fta_se_nbr]->name;\r
- }else{\r
- colname = impute_colname(lfta_select_list, subaggr_se);\r
- lfta_select_list[fta_se_nbr]->name = colname;\r
- if(use_se[sa])\r
- ano = lfta_aggr_tbl->add_aggr(subaggr_names[sa].c_str(),l_se, false);\r
- else\r
- ano = lfta_aggr_tbl->add_aggr(subaggr_names[sa].c_str(),NULL,false);\r
- subaggr_se->set_aggr_id(ano);\r
- }\r
- new_cr = new colref_t(colname.c_str());\r
- new_se = new scalarexp_t(new_cr);\r
-// I'm not certain what the types should be ....\r
-// This will need to be filled in by later analysis.\r
-// NOTE: this might not capture all the meaning of data_type ...\r
- new_se->set_data_type(subaggr_dt[sa]);\r
- subaggr_ref_se.push_back(new_se);\r
- }\r
- }\r
- scalarexp_t *ret_se = orig_aggr_tbl->make_superaggr_se(agr_id, subaggr_ref_se);\r
- ret_se->set_data_type(orig_aggr_tbl->get_data_type(agr_id));\r
-\r
-// ASSUME either the return value is an aggregation,\r
-// or a binary_op between two aggregations\r
- if(ret_se->get_operator_type() == SE_AGGR_SE || ret_se->get_operator_type() == SE_AGGR_SE){\r
- ano = hfta_aggr_tbl->add_aggr(ret_se->get_op(), ret_se->get_left_se(), false );\r
- ret_se->set_aggr_id(ano);\r
- }else{\r
-// Basically processing for AVG. \r
-// set the data type of the superagg to that of the subagg.\r
- scalarexp_t *left_se = ret_se->get_left_se();\r
- left_se->set_data_type(subaggr_dt[0]);\r
- ano = hfta_aggr_tbl->add_aggr(left_se->get_op(), left_se->get_left_se(), false );\r
- left_se->set_aggr_id(ano);\r
-\r
- scalarexp_t *right_se = ret_se->get_right_se();\r
- right_se->set_data_type(subaggr_dt[1]);\r
- ano = hfta_aggr_tbl->add_aggr(right_se->get_op(), right_se->get_left_se(), false );\r
- right_se->set_aggr_id(ano);\r
- }\r
-\r
- hfta_aggr_se[agr_id] = ret_se;\r
-\r
-}\r
-\r
-\r
-// Split the aggregates in orig_aggr_tbl, into hfta_superaggregates and\r
-// hfta_subaggregates.\r
-// Register the superaggregates in hi_aggr_tbl, and the\r
-// subaggregates in loq_aggr_tbl.\r
-// Insert references to the subaggregates into low_select_list.\r
-// (and record their names in the currnames list)\r
-// Create a SE for the superaggregate, put it in hfta_aggr_se,\r
-// keyed on agr_id.\r
-\r
-void split_hfta_aggr(aggregate_table *orig_aggr_tbl, int agr_id,\r
- aggregate_table *hi_aggr_tbl,\r
- aggregate_table *low_aggr_tbl,\r
- vector<select_element *> &low_select_list,\r
- map<int,scalarexp_t *> &hi_aggr_se,\r
- ext_fcn_list *Ext_fcns\r
- ){\r
- bool new_element;\r
- scalarexp_t *subaggr_se;\r
- int fta_se_nbr;\r
- string colname;\r
- int ano;\r
- colref_t *new_cr;\r
- scalarexp_t *new_se, *l_se;\r
- vector<scalarexp_t *> subaggr_ref_se;\r
-\r
-// UDAF processing\r
- if(! orig_aggr_tbl->is_builtin(agr_id)){\r
-// Construct the subaggregate\r
- int fcn_id = orig_aggr_tbl->get_fcn_id(agr_id);\r
- vector<scalarexp_t *> opl = orig_aggr_tbl->get_operand_list(agr_id);\r
- vector<scalarexp_t *> subopl;\r
- int o;\r
- for(o=0;o<opl.size();++o){\r
- subopl.push_back(dup_se(opl[o], NULL));\r
- }\r
- int sub_id = Ext_fcns->get_hfta_subaggr_id(fcn_id);\r
- subaggr_se = new scalarexp_t(Ext_fcns->get_fcn_name(sub_id).c_str(), subopl);\r
- subaggr_se->set_fcn_id(sub_id);\r
- subaggr_se->set_data_type(Ext_fcns->get_fcn_dt(sub_id));\r
-// Add it to the low select list.\r
- fta_se_nbr = add_select_list_nodup(low_select_list, subaggr_se,new_element);\r
- if(!new_element){\r
- colname = low_select_list[fta_se_nbr]->name;\r
- }else{\r
- colname = impute_colname(low_select_list, subaggr_se);\r
- low_select_list[fta_se_nbr]->name = colname;\r
- ano = low_aggr_tbl->add_aggr(Ext_fcns->get_fcn_name(sub_id), sub_id, subopl,Ext_fcns->get_storage_dt(sub_id), false, false,false);\r
- subaggr_se->set_aggr_id(ano);\r
- }\r
-\r
-// Construct a reference to the subaggregate\r
- new_cr = new colref_t(colname.c_str());\r
- new_se = new scalarexp_t(new_cr);\r
-// I'm not certain what the types should be ....\r
-// This will need to be filled in by later analysis.\r
-// NOTE: this might not capture all the meaning of data_type ...\r
- new_se->set_data_type(Ext_fcns->get_fcn_dt(sub_id));\r
- subaggr_ref_se.push_back(new_se);\r
-\r
-// Construct the superaggregate\r
- int super_id = Ext_fcns->get_hfta_superaggr_id(fcn_id);\r
- scalarexp_t *ret_se = new scalarexp_t(Ext_fcns->get_fcn_name(super_id).c_str(), subaggr_ref_se);\r
- ret_se->set_fcn_id(super_id);\r
- ret_se->set_data_type(Ext_fcns->get_fcn_dt(super_id));\r
-// Register it in the high aggregate table\r
- ano = hi_aggr_tbl->add_aggr(ret_se->get_op(), super_id, subaggr_ref_se,Ext_fcns->get_storage_dt(super_id), false, false,false);\r
- ret_se->set_aggr_id(ano);\r
- hi_aggr_se[agr_id] = ret_se;\r
-\r
- return;\r
- }\r
-\r
-\r
-// builtin aggregate processing\r
- bool l_forbid;\r
-\r
- vector<bool> use_se;\r
- vector<string> subaggr_names = orig_aggr_tbl->get_subaggr_fcns(agr_id, use_se);\r
- vector<data_type *> subaggr_dt = orig_aggr_tbl->get_subaggr_dt(agr_id);\r
- int sa;\r
-\r
- if(orig_aggr_tbl->is_star_aggr(agr_id)){\r
- for(sa=0;sa<subaggr_names.size();sa++){\r
- subaggr_se = scalarexp_t::make_star_aggr(subaggr_names[sa].c_str());\r
- subaggr_se->set_data_type(subaggr_dt[sa]);\r
-\r
-// The following sequence is similar to the code in make_fta_se_ref,\r
-// but there is special processing for the aggregate tables.\r
- int fta_se_nbr = add_select_list_nodup(low_select_list, subaggr_se,new_element);\r
- if(!new_element){\r
- colname = low_select_list[fta_se_nbr]->name;\r
- }else{\r
- colname = impute_colname(low_select_list, subaggr_se);\r
- low_select_list[fta_se_nbr]->name = colname;\r
- ano = low_aggr_tbl->add_aggr(subaggr_names[sa].c_str(),NULL, false);\r
- subaggr_se->set_aggr_id(ano);\r
- }\r
- new_cr = new colref_t(colname.c_str());\r
- new_cr->set_tablevar_ref(0);\r
- new_se = new scalarexp_t(new_cr);\r
-\r
-// I'm not certain what the types should be ....\r
-// This will need to be filled in by later analysis.\r
-// Actually, this is causing a problem.\r
-// I will assume a UINT data type.\r
-// (consistent with assign_data_types in analyze_fta.cc)\r
-// TODO: why can't I use subaggr_dt, as I do in the other IF branch?\r
- data_type *ndt = new data_type("Int"); // was Uint\r
- new_se->set_data_type(ndt);\r
-\r
- subaggr_ref_se.push_back(new_se);\r
- }\r
- }else{\r
- for(sa=0;sa<subaggr_names.size();sa++){\r
- if(use_se[sa]){\r
- scalarexp_t *aggr_operand = orig_aggr_tbl->get_aggr_se(agr_id);\r
- l_se = dup_se(aggr_operand, NULL);\r
- subaggr_se = scalarexp_t::make_se_aggr(subaggr_names[sa].c_str(),l_se);\r
- }else{\r
- subaggr_se = scalarexp_t::make_star_aggr(subaggr_names[sa].c_str());\r
- }\r
- subaggr_se->set_data_type(subaggr_dt[sa]);\r
-\r
-// again, similar to make_fta_se_ref.\r
- fta_se_nbr = add_select_list_nodup(low_select_list, subaggr_se,new_element);\r
- if(!new_element){\r
- colname = low_select_list[fta_se_nbr]->name;\r
- }else{\r
- colname = impute_colname(low_select_list, subaggr_se);\r
- low_select_list[fta_se_nbr]->name = colname;\r
- if(use_se[sa])\r
- ano = low_aggr_tbl->add_aggr(subaggr_names[sa].c_str(),l_se, false);\r
- else\r
- ano = low_aggr_tbl->add_aggr(subaggr_names[sa].c_str(),NULL,false);\r
- subaggr_se->set_aggr_id(ano);\r
- }\r
- new_cr = new colref_t(colname.c_str());\r
- new_se = new scalarexp_t(new_cr);\r
-// I'm not certain what the types should be ....\r
-// This will need to be filled in by later analysis.\r
-// NOTE: this might not capture all the meaning of data_type ...\r
- new_se->set_data_type(subaggr_dt[sa]);\r
- subaggr_ref_se.push_back(new_se);\r
- }\r
- }\r
- scalarexp_t *ret_se = orig_aggr_tbl->make_superaggr_se(agr_id, subaggr_ref_se);\r
-// ASSUME either the return value is an aggregation,\r
-// or a binary_op between two aggregations\r
- if(ret_se->get_operator_type() == SE_AGGR_SE || ret_se->get_operator_type() == SE_AGGR_SE){\r
- ret_se->set_data_type(orig_aggr_tbl->get_data_type(agr_id));\r
- ano = hi_aggr_tbl->add_aggr(ret_se->get_op(), ret_se->get_left_se(), false );\r
- }else{\r
-// Basically processing for AVG. \r
-// set the data type of the superagg to that of the subagg.\r
- scalarexp_t *left_se = ret_se->get_left_se();\r
- left_se->set_data_type(subaggr_dt[0]);\r
- ano = hi_aggr_tbl->add_aggr(left_se->get_op(), left_se->get_left_se(), false );\r
- left_se->set_aggr_id(ano);\r
-\r
- scalarexp_t *right_se = ret_se->get_right_se();\r
- right_se->set_data_type(subaggr_dt[1]);\r
- ano = hi_aggr_tbl->add_aggr(right_se->get_op(), right_se->get_left_se(), false );\r
- right_se->set_aggr_id(ano);\r
- }\r
-\r
- ret_se->set_aggr_id(ano);\r
- hi_aggr_se[agr_id] = ret_se;\r
-\r
-}\r
-\r
-\r
-\r
-\r
-\r
-// Split a scalar expression into one part which executes\r
-// at the stream and another set of parts which execute\r
-// at the FTA.\r
-// Because I'm actually modifying the SEs, I will make\r
-// copies. But I will assume that literals, params, and\r
-// colrefs are immutable at this point.\r
-// (if there is ever a need to change one, must make a\r
-// new value).\r
-// NOTE : if se is constant (only refrences literals),\r
-// avoid making the fta compute it.\r
-//\r
-// NOTE : This will need to be generalized to\r
-// handle join expressions, namely to handle a vector\r
-// of lftas.\r
-//\r
-// Return value is the HFTA se.\r
-// Add lftas select_elements to the fta_select_list.\r
-// set fta_forbidden if this node or any child cannot\r
-// execute at the lfta.\r
-\r
-/*\r
-\r
-scalarexp_t *split_fta_se(scalarexp_t *se,\r
- bool &fta_forbidden,\r
- vector<select_element *> &lfta_select_list,\r
- ext_fcn_list *Ext_fcns\r
- ){\r
-\r
- int p, fcn_id;\r
- vector<scalarexp_t *> operand_list;\r
- vector<data_type *> dt_signature;\r
- scalarexp_t *ret_se, *l_se, *r_se;\r
- bool l_forbid, r_forbid, this_forbid;\r
- colref_t *new_cr;\r
- scalarexp_t *new_se;\r
- data_type *dt = se->get_data_type();\r
-\r
- switch(se->get_operator_type()){\r
- case SE_LITERAL:\r
- fta_forbidden = ! se->get_data_type()->fta_legal_type();\r
- ret_se = new scalarexp_t(se->get_literal());\r
- ret_se->use_decorations_of(se);\r
- return(ret_se);\r
-\r
- case SE_PARAM:\r
- fta_forbidden = ! se->get_data_type()->fta_legal_type();\r
- ret_se = scalarexp_t::make_param_reference(se->get_op().c_str());\r
- ret_se->use_decorations_of(se);\r
- return(ret_se);\r
-\r
- case SE_COLREF:\r
-// No colref should be forbidden,\r
-// the schema is wrong, the fta_legal_type() fcn is wrong,\r
-// or the source table is actually a stream.\r
-// Issue a warning, but proceed with processing.\r
-// Also, should not be a ref to a gbvar.\r
-// (a gbvar ref only occurs in an aggregation node,\r
-// and these SEs are rehomed, not split.\r
- fta_forbidden = ! se->get_data_type()->fta_legal_type();\r
-\r
- if(fta_forbidden){\r
- fprintf(stderr,"WARNING, a colref is a forbidden data type in split_fta_se,"\r
- " colref is %s,"\r
- " type is %s, line=%d, col=%d\n",\r
- se->get_colref()->to_string().c_str(),\r
- se->get_data_type()->get_type_str().c_str(),\r
- se->lineno, se->charno\r
- );\r
- }\r
-\r
- if(se->is_gb()){\r
- fprintf(stderr,"INTERNAL ERROR, a colref is a gbvar ref in split_fta_se,"\r
- " type is %s, line=%d, col=%d\n",\r
- se->get_data_type()->get_type_str().c_str(),\r
- se->lineno, se->charno\r
- );\r
- exit(1);\r
- }\r
-\r
- ret_se = new scalarexp_t(se->get_colref());\r
- ret_se->use_decorations_of(se);\r
- return(ret_se);\r
-\r
- case SE_UNARY_OP:\r
- l_se = split_fta_se(se->get_left_se(), l_forbid, lfta_select_list, Ext_fcns);\r
-\r
- this_forbid = ! dt->fta_legal_operation(l_se->get_data_type(), se->get_op());\r
-\r
-// If this operation is forbidden but the child SE is not,\r
-// put the child se on the lfta_select_list, create a colref\r
-// which accesses this se, and make it the child of this op.\r
-// Exception : the child se is constant (only literal refs).\r
- if(this_forbid && !l_forbid){\r
- if(!is_literal_or_param_only(l_se)){\r
- new_se = make_fta_se_ref(lfta_select_list, l_se,0);\r
- ret_se = new scalarexp_t(se->get_op().c_str(), new_se);\r
- }\r
- }else{\r
- ret_se = new scalarexp_t(se->get_op().c_str(), l_se);\r
- }\r
- ret_se->use_decorations_of(se);\r
- fta_forbidden = this_forbid | l_forbid;\r
- return(ret_se);\r
-\r
- case SE_BINARY_OP:\r
- l_se = split_fta_se(se->get_left_se(), l_forbid, lfta_select_list, Ext_fcns);\r
- r_se = split_fta_se(se->get_right_se(), r_forbid, lfta_select_list, Ext_fcns);\r
-\r
- this_forbid = ! dt->fta_legal_operation(l_se->get_data_type(), r_se->get_data_type(), se->get_op());\r
-\r
-// Replace the left se if it is not forbidden, but something else is.\r
- if((this_forbid || r_forbid) & !l_forbid){\r
- if(!is_literal_or_param_only(l_se)){\r
- new_se = make_fta_se_ref(lfta_select_list, l_se,0);\r
- l_se = new_se;\r
- }\r
- }\r
-\r
-// Replace the right se if it is not forbidden, but something else is.\r
- if((this_forbid || l_forbid) & !r_forbid){\r
- if(!is_literal_or_param_only(r_se)){\r
- new_se = make_fta_se_ref(lfta_select_list, r_se,0);\r
- r_se = new_se;\r
- }\r
- }\r
-\r
- ret_se = new scalarexp_t(se->get_op().c_str(), l_se, r_se);\r
- ret_se->use_decorations_of(se);\r
- fta_forbidden = this_forbid || r_forbid || l_forbid;\r
-\r
- return(ret_se);\r
-\r
- case SE_AGGR_STAR:\r
- case SE_AGGR_SE:\r
-\r
- fprintf(stderr,"INTERNAL ERROR, aggregate ref (%s) in split_fta_se."\r
- " line=%d, col=%d\n",\r
- se->get_op().c_str(),\r
- se->lineno, se->charno\r
- );\r
- exit(1);\r
- break;\r
-\r
- case SE_FUNC:\r
- {\r
- fta_forbidden = false;\r
- operand_list = se->get_operands();\r
- vector<scalarexp_t *> new_operands;\r
- vector<bool> forbidden_op;\r
- for(p=0;p<operand_list.size();p++){\r
- l_se = split_fta_se(operand_list[p], l_forbid, lfta_select_list, Ext_fcns);\r
-\r
- fta_forbidden |= l_forbid;\r
- new_operands.push_back(l_se);\r
- forbidden_op.push_back(l_forbid);\r
- dt_signature.push_back(operand_list[p]->get_data_type() );\r
- }\r
-\r
- fcn_id = Ext_fcns->lookup_fcn(se->get_op(), dt_signature);\r
- if( fcn_id < 0 ){\r
- fprintf(stderr,"ERROR, no external function %s(",se->get_op().c_str());\r
- int o;\r
- for(o=0;o<operand_list.size();o++){\r
- if(o>0) fprintf(stderr,", ");\r
- fprintf(stderr,"%s",operand_list[o]->get_data_type()->get_type_str().c_str());\r
- }\r
- fprintf(stderr,") is defined, line %d, char %d\n", se->get_lineno(), se->get_charno() );\r
- if(fcn_id == -2) fprintf(stderr,"(multiple subsuming functions found)\n");\r
- return(false);\r
- }\r
-\r
- fta_forbidden |= (! Ext_fcns->fta_legal(fcn_id));\r
-\r
-// Replace the non-forbidden operands.\r
-// the forbidden ones are already replaced.\r
- if(fta_forbidden){\r
- for(p=0;p<new_operands.size();p++){\r
- if(! forbidden_op[p]){\r
-// if(new_operands[p]->get_data_type()->get_temporal() != constant_t){\r
- if(!is_literal_or_param_only(new_operands[p])){\r
- new_se = make_fta_se_ref(lfta_select_list, new_operands[p],0);\r
- new_operands[p] = new_se;\r
- }\r
- }\r
- }\r
- }\r
-\r
- ret_se = new scalarexp_t(se->get_op().c_str(), new_operands);\r
- ret_se->use_decorations_of(se);\r
-\r
- return(ret_se);\r
-\r
- }\r
- default:\r
- printf("INTERNAL ERROR in check_fta_forbidden_se: operator type %d\n",se->get_operator_type());\r
- exit(1);\r
- break;\r
- }\r
- return(false);\r
-\r
-}\r
-\r
-*/\r
-\r
-\r
-// The predicates have already been\r
-// broken into conjunctions.\r
-// If any part of a conjunction is fta-forbidden,\r
-// it must be executed in the stream operator.\r
-// Else it is executed in the FTA.\r
-// A pre-analysis should determine whether this\r
-// predicate is fta-safe. This procedure will\r
-// assume that it is fta-forbidden and will\r
-// prepare it for execution in the stream.\r
-\r
-/*\r
-\r
-predicate_t *split_fta_pr(predicate_t *pr,\r
- vector<select_element *> &lfta_select_list,\r
- ext_fcn_list *Ext_fcns\r
- ){\r
-\r
- vector<literal_t *> llist;\r
- scalarexp_t *se_l, *se_r;\r
- bool l_forbid, r_forbid;\r
- predicate_t *ret_pr, *pr_l, *pr_r;\r
- vector<scalarexp_t *> op_list, new_op_list;\r
- int o;\r
- vector<data_type *> dt_signature;\r
-\r
-\r
- switch(pr->get_operator_type()){\r
- case PRED_IN:\r
- se_l = split_fta_se(pr->get_left_se(), l_forbid, lfta_select_list, Ext_fcns);\r
-\r
- if(!l_forbid){\r
- if(!is_literal_or_param_only(se_l)){\r
- scalarexp_t *new_se = make_fta_se_ref(lfta_select_list, se_l,0);\r
- se_l = new_se;\r
- }\r
- }\r
- ret_pr = new predicate_t(se_l, pr->get_lit_vec());\r
-\r
- return(ret_pr);\r
-\r
- case PRED_COMPARE:\r
- se_l = split_fta_se(pr->get_left_se(), l_forbid, lfta_select_list, Ext_fcns);\r
- if(!l_forbid){\r
- if(!is_literal_or_param_only(se_l)){\r
- scalarexp_t *new_se = make_fta_se_ref(lfta_select_list, se_l,0);\r
- se_l = new_se;\r
- }\r
- }\r
-\r
- se_r = split_fta_se(pr->get_right_se(), r_forbid, lfta_select_list, Ext_fcns);\r
- if(!r_forbid){\r
- if(!is_literal_or_param_only(se_r)){\r
- scalarexp_t *new_se = make_fta_se_ref(lfta_select_list, se_r,0);\r
- se_r = new_se;\r
- }\r
- }\r
-\r
- ret_pr = new predicate_t(se_l, pr->get_op().c_str(), se_r);\r
- return(ret_pr);\r
-\r
- case PRED_UNARY_OP:\r
- pr_l = split_fta_pr(pr->get_left_pr(), lfta_select_list, Ext_fcns);\r
- ret_pr = new predicate_t(pr->get_op().c_str(), pr_l);\r
- return(ret_pr);\r
-\r
- case PRED_BINARY_OP:\r
- pr_l = split_fta_pr(pr->get_left_pr(), lfta_select_list, Ext_fcns);\r
- pr_r = split_fta_pr(pr->get_right_pr(), lfta_select_list, Ext_fcns);\r
- ret_pr = new predicate_t(pr->get_op().c_str(), pr_l, pr_r);\r
- return(ret_pr);\r
-\r
- case PRED_FUNC:\r
-// I can't push the predicate into the lfta, except by\r
-// returning a bool value, and that is not worth the trouble,\r
- op_list = pr->get_op_list();\r
- for(o=0;o<op_list.size();++o){\r
- se_l = split_fta_se(op_list[o],l_forbid,lfta_select_list,Ext_fcns);\r
- if(!l_forbid){\r
- if(!is_literal_or_param_only(se_l)){\r
- scalarexp_t *new_se = make_fta_se_ref(lfta_select_list, se_l,0);\r
- se_l = new_se;\r
- }\r
- }\r
- new_op_list.push_back(se_l);\r
- }\r
-\r
- ret_pr = new predicate_t(pr->get_op().c_str(), new_op_list);\r
- ret_pr->set_fcn_id(pr->get_fcn_id());\r
- return(ret_pr);\r
- default:\r
- fprintf(stderr,"INTERNAL ERROR in split_fta_pr, line %d, character %d, unknown predicate operator type %d\n",\r
- pr->get_lineno(), pr->get_charno(), pr->get_operator_type() );\r
- exit(1);\r
- }\r
-\r
- return(0);\r
-\r
-}\r
-\r
-*/\r
-\r
-\r
-//--------------------------------------------------------------------\r
-\r
-\r
-\r
-// Split a scalar expression into one part which executes\r
-// at the stream and another set of parts which execute\r
-// at the FTA.\r
-// Because I'm actually modifying the SEs, I will make\r
-// copies. But I will assume that literals, params, and\r
-// colrefs are immutable at this point.\r
-// (if there is ever a need to change one, must make a\r
-// new value).\r
-// NOTE : if se is constant (only refrences literals),\r
-// avoid making the fta compute it.\r
-//\r
-// NOTE : This will need to be generalized to\r
-// handle join expressions, namely to handle a vector\r
-// of lftas.\r
-//\r
-// Return value is the HFTA se.\r
-// Add lftas select_elements to the fta_select_list.\r
-// set fta_forbidden if this node or any child cannot\r
-// execute at the lfta.\r
-\r
-#define SPLIT_FTAVEC_NOTBLVAR -1\r
-#define SPLIT_FTAVEC_MIXED -2\r
-\r
-bool is_PROTOCOL_source(int colref_source,\r
- vector< vector<select_element *> *> &lfta_select_list){\r
- if(colref_source>=0 && lfta_select_list[colref_source]!=NULL) return true;\r
- return false;\r
-}\r
-\r
-int combine_colref_source(int s1, int s2){\r
- if(s1==s2) return(s1);\r
- if(s1==SPLIT_FTAVEC_NOTBLVAR) return s2;\r
- if(s2==SPLIT_FTAVEC_NOTBLVAR) return s1;\r
- return SPLIT_FTAVEC_MIXED;\r
-}\r
-\r
-scalarexp_t *split_ftavec_se(\r
- scalarexp_t *se, // the SE to split\r
- bool &fta_forbidden, // return true if some part of se\r
- // is fta-unsafe\r
- int &colref_source, // the tblvar which sources the\r
- // colref, or NOTBLVAR, or MIXED\r
- vector< vector<select_element *> *> &lfta_select_list,\r
- // NULL if the tblvar is not PROTOCOL,\r
- // else build the select list.\r
- ext_fcn_list *Ext_fcns // is the fcn lfta-safe?\r
- ){\r
-// Return value is the HFTA SE, unless fta_forbidden is true and\r
-// colref_source>=0 and the indicated source is PROTOCOL.\r
-// In that case no split was done, the make_fta_se_ref must\r
-// be done by the caller.\r
-\r
- int p, fcn_id;\r
- vector<scalarexp_t *> operand_list;\r
- vector<data_type *> dt_signature;\r
- scalarexp_t *ret_se, *l_se, *r_se;\r
- bool l_forbid, r_forbid, this_forbid;\r
- int l_csource, r_csource, this_csource;\r
- colref_t *new_cr;\r
- scalarexp_t *new_se;\r
- data_type *dt = se->get_data_type();\r
-\r
- switch(se->get_operator_type()){\r
- case SE_LITERAL:\r
- fta_forbidden = ! se->get_data_type()->fta_legal_type();\r
- colref_source = SPLIT_FTAVEC_NOTBLVAR;\r
- ret_se = new scalarexp_t(se->get_literal());\r
- ret_se->use_decorations_of(se);\r
- return(ret_se);\r
-\r
- case SE_PARAM:\r
- fta_forbidden = ! se->get_data_type()->fta_legal_type();\r
- colref_source = SPLIT_FTAVEC_NOTBLVAR;\r
- ret_se = scalarexp_t::make_param_reference(se->get_op().c_str());\r
- ret_se->use_decorations_of(se);\r
- return(ret_se);\r
-\r
- case SE_IFACE_PARAM:\r
- fta_forbidden = false;\r
- colref_source = se->get_ifpref()->get_tablevar_ref();\r
- ret_se = scalarexp_t::make_iface_param_reference(se->get_ifpref());\r
- ret_se->use_decorations_of(se);\r
- return(ret_se);\r
-\r
- case SE_COLREF:\r
-// No colref should be forbidden,\r
-// the schema is wrong, the fta_legal_type() fcn is wrong,\r
-// or the source table is actually a stream.\r
-// Issue a warning, but proceed with processing.\r
-// Also, should not be a ref to a gbvar.\r
-// (a gbvar ref only occurs in an aggregation node,\r
-// and these SEs are rehomed, not split.\r
- fta_forbidden = ! se->get_data_type()->fta_legal_type();\r
- colref_source = se->get_colref()->get_tablevar_ref();\r
-\r
- if(fta_forbidden && is_PROTOCOL_source(colref_source, lfta_select_list)){\r
- fprintf(stderr,"WARNING, a PROTOCOL colref is a forbidden data type in split_ftavec_se,"\r
- " colref is %s,"\r
- " type is %s, line=%d, col=%d\n",\r
- se->get_colref()->to_string().c_str(),\r
- se->get_data_type()->to_string().c_str(),\r
- se->lineno, se->charno\r
- );\r
- }\r
-\r
- if(se->is_gb()){\r
- fta_forbidden = true; // eval in hfta. ASSUME make copy as below.\r
- }\r
-\r
- ret_se = new scalarexp_t(se->get_colref());\r
- ret_se->use_decorations_of(se);\r
- return(ret_se);\r
-\r
- case SE_UNARY_OP:\r
- l_se = split_ftavec_se(se->get_left_se(), l_forbid, colref_source, lfta_select_list, Ext_fcns);\r
-\r
- this_forbid = ! dt->fta_legal_operation(l_se->get_data_type(), se->get_op());\r
-\r
-// If this operation is forbidden but the child SE is not,\r
-// AND the colref source in the se is a single PROTOCOL source\r
-// put the child se on the lfta_select_list, create a colref\r
-// which accesses this se, and make it the child of this op.\r
-// Exception : the child se is constant (only literal refs).\r
-// TODO: I think the exception is expressed by is_PROTOCOL_source\r
- if(this_forbid && !l_forbid && is_PROTOCOL_source(colref_source, lfta_select_list)){\r
- if(!is_literal_or_param_only(l_se)){\r
- new_se = make_fta_se_ref(lfta_select_list, l_se,colref_source);\r
- ret_se = new scalarexp_t(se->get_op().c_str(), new_se);\r
- }\r
- }else{\r
- ret_se = new scalarexp_t(se->get_op().c_str(), l_se);\r
- }\r
- ret_se->use_decorations_of(se);\r
- fta_forbidden = this_forbid | l_forbid;\r
- return(ret_se);\r
-\r
- case SE_BINARY_OP:\r
- l_se = split_ftavec_se(se->get_left_se(), l_forbid, l_csource, lfta_select_list, Ext_fcns);\r
- r_se = split_ftavec_se(se->get_right_se(), r_forbid, r_csource, lfta_select_list, Ext_fcns);\r
-\r
- this_forbid = ! dt->fta_legal_operation(l_se->get_data_type(), r_se->get_data_type(), se->get_op());\r
- colref_source=combine_colref_source(l_csource, r_csource);\r
-\r
-// Replace the left se if the parent must be hfta but the child can\r
-// be lfta. This translates to\r
-// a) result is PROTOCOL and forbidden, but left SE is not forbidden\r
-// OR b) if result is mixed but the left se is PROTOCOL, not forbidden\r
- if( ((this_forbid || r_forbid) && !l_forbid && is_PROTOCOL_source(colref_source, lfta_select_list) ) ||\r
- (colref_source==SPLIT_FTAVEC_MIXED && !l_forbid &&\r
- is_PROTOCOL_source(l_csource, lfta_select_list)) ){\r
- if(!is_literal_or_param_only(l_se)){\r
- new_se = make_fta_se_ref(lfta_select_list, l_se,l_csource);\r
- l_se = new_se;\r
- }\r
- }\r
-\r
-// same logic as for right se.\r
- if( ((this_forbid || l_forbid) && !r_forbid && is_PROTOCOL_source(colref_source, lfta_select_list) ) ||\r
- (colref_source==SPLIT_FTAVEC_MIXED && !r_forbid &&\r
- is_PROTOCOL_source(r_csource, lfta_select_list)) ){\r
- if(!is_literal_or_param_only(r_se)){\r
- new_se = make_fta_se_ref(lfta_select_list, r_se,r_csource);\r
- r_se = new_se;\r
- }\r
- }\r
-\r
- ret_se = new scalarexp_t(se->get_op().c_str(), l_se, r_se);\r
- ret_se->use_decorations_of(se);\r
- fta_forbidden = this_forbid || r_forbid || l_forbid;\r
-\r
- return(ret_se);\r
-\r
- case SE_AGGR_STAR:\r
- case SE_AGGR_SE:\r
-\r
- fprintf(stderr,"INTERNAL ERROR, aggregate ref (%s) in split_ftavec_se."\r
- " line=%d, col=%d\n",\r
- se->get_op().c_str(),\r
- se->lineno, se->charno\r
- );\r
- exit(1);\r
- break;\r
-\r
- case SE_FUNC:\r
- {\r
- operand_list = se->get_operands();\r
- vector<scalarexp_t *> new_operands;\r
- vector<bool> forbidden_op;\r
- vector<int> csource;\r
-\r
- fta_forbidden = false;\r
- colref_source = SPLIT_FTAVEC_NOTBLVAR;\r
- for(p=0;p<operand_list.size();p++){\r
- l_se = split_ftavec_se(operand_list[p], l_forbid, l_csource, lfta_select_list, Ext_fcns);\r
-\r
- fta_forbidden |= l_forbid;\r
- colref_source = combine_colref_source(colref_source, l_csource);\r
- new_operands.push_back(l_se);\r
- forbidden_op.push_back(l_forbid);\r
- csource.push_back(l_csource);\r
- dt_signature.push_back(operand_list[p]->get_data_type() );\r
- }\r
-\r
- fcn_id = Ext_fcns->lookup_fcn(se->get_op(), dt_signature);\r
- if( fcn_id < 0 ){\r
- fprintf(stderr,"ERROR, no external function %s(",se->get_op().c_str());\r
- int o;\r
- for(o=0;o<operand_list.size();o++){\r
- if(o>0) fprintf(stderr,", ");\r
- fprintf(stderr,"%s",operand_list[o]->get_data_type()->to_string().c_str());\r
- }\r
- fprintf(stderr,") is defined, line %d, char %d\n", se->get_lineno(), se->get_charno() );\r
- if(fcn_id == -2) fprintf(stderr,"(multiple subsuming functions found)\n");\r
- return NULL;\r
- }\r
-\r
- fta_forbidden |= (! Ext_fcns->fta_legal(fcn_id));\r
-\r
-// Replace the non-forbidden operands.\r
-// the forbidden ones are already replaced.\r
- if(fta_forbidden || colref_source == SPLIT_FTAVEC_MIXED){\r
- for(p=0;p<new_operands.size();p++){\r
- if(! forbidden_op[p] && is_PROTOCOL_source(csource[p], lfta_select_list)){\r
- if(!is_literal_or_param_only(new_operands[p])){\r
- new_se = make_fta_se_ref(lfta_select_list, new_operands[p],csource[p]);\r
- new_operands[p] = new_se;\r
- }\r
- }\r
- }\r
- }\r
-\r
- ret_se = new scalarexp_t(se->get_op().c_str(), new_operands);\r
- ret_se->use_decorations_of(se);\r
-\r
- return(ret_se);\r
-\r
- }\r
- default:\r
- printf("INTERNAL ERROR in split_ftavec_se: operator type %d\n",se->get_operator_type());\r
- exit(1);\r
- break;\r
- }\r
- return(NULL);\r
-\r
-}\r
-\r
-\r
-// The predicates have already been\r
-// broken into conjunctions.\r
-// If any part of a conjunction is fta-forbidden,\r
-// it must be executed in the stream operator.\r
-// Else it is executed in the FTA.\r
-// A pre-analysis should determine whether this\r
-// predicate is fta-safe. This procedure will\r
-// assume that it is fta-forbidden and will\r
-// prepare it for execution in the stream.\r
-\r
-predicate_t *split_ftavec_pr(predicate_t *pr,\r
- vector< vector<select_element *> *> &lfta_select_list,\r
- ext_fcn_list *Ext_fcns\r
- ){\r
-\r
- vector<literal_t *> llist;\r
- scalarexp_t *se_l, *se_r;\r
- bool l_forbid, r_forbid;\r
- int l_csource, r_csource;\r
- predicate_t *ret_pr, *pr_l, *pr_r;\r
- vector<scalarexp_t *> op_list, new_op_list;\r
- int o;\r
- vector<data_type *> dt_signature;\r
-\r
-\r
- switch(pr->get_operator_type()){\r
- case PRED_IN:\r
- se_l = split_ftavec_se(pr->get_left_se(), l_forbid, l_csource, lfta_select_list, Ext_fcns);\r
-\r
-// TODO: checking that the se is a PROTOCOL source should\r
-// take care of literal_or_param_only.\r
- if(!l_forbid && is_PROTOCOL_source(l_csource, lfta_select_list)){\r
- if(!is_literal_or_param_only(se_l)){\r
- scalarexp_t *new_se = make_fta_se_ref(lfta_select_list, se_l,l_csource);\r
- se_l = new_se;\r
- }\r
- }\r
- ret_pr = new predicate_t(se_l, pr->get_lit_vec());\r
-\r
- return(ret_pr);\r
-\r
- case PRED_COMPARE:\r
- se_l = split_ftavec_se(pr->get_left_se(), l_forbid, l_csource, lfta_select_list, Ext_fcns);\r
- if(!l_forbid && is_PROTOCOL_source(l_csource, lfta_select_list)){\r
- if(!is_literal_or_param_only(se_l)){\r
- scalarexp_t *new_se = make_fta_se_ref(lfta_select_list, se_l,l_csource);\r
- se_l = new_se;\r
- }\r
- }\r
-\r
- se_r = split_ftavec_se(pr->get_right_se(), r_forbid, r_csource, lfta_select_list, Ext_fcns);\r
- if(!r_forbid && is_PROTOCOL_source(r_csource, lfta_select_list)){\r
- if(!is_literal_or_param_only(se_r)){\r
- scalarexp_t *new_se = make_fta_se_ref(lfta_select_list, se_r,r_csource);\r
- se_r = new_se;\r
- }\r
- }\r
-\r
- ret_pr = new predicate_t(se_l, pr->get_op().c_str(), se_r);\r
- return(ret_pr);\r
-\r
- case PRED_UNARY_OP:\r
- pr_l = split_ftavec_pr(pr->get_left_pr(), lfta_select_list, Ext_fcns);\r
- ret_pr = new predicate_t(pr->get_op().c_str(), pr_l);\r
- return(ret_pr);\r
-\r
- case PRED_BINARY_OP:\r
- pr_l = split_ftavec_pr(pr->get_left_pr(), lfta_select_list, Ext_fcns);\r
- pr_r = split_ftavec_pr(pr->get_right_pr(), lfta_select_list, Ext_fcns);\r
- ret_pr = new predicate_t(pr->get_op().c_str(), pr_l, pr_r);\r
- return(ret_pr);\r
-\r
- case PRED_FUNC:\r
-// I can't push the predicate into the lfta, except by\r
-// returning a bool value, and that is not worth the trouble,\r
- op_list = pr->get_op_list();\r
- for(o=0;o<op_list.size();++o){\r
- se_l = split_ftavec_se(op_list[o],l_forbid,l_csource,lfta_select_list,Ext_fcns);\r
- if(!l_forbid && is_PROTOCOL_source(l_csource, lfta_select_list)){\r
- if(!is_literal_or_param_only(se_l)){\r
- scalarexp_t *new_se = make_fta_se_ref(lfta_select_list, se_l,l_csource);\r
- se_l = new_se;\r
- }\r
- }\r
- new_op_list.push_back(se_l);\r
- }\r
-\r
- ret_pr = new predicate_t(pr->get_op().c_str(), new_op_list);\r
- ret_pr->set_fcn_id(pr->get_fcn_id());\r
- return(ret_pr);\r
- default:\r
- fprintf(stderr,"INTERNAL ERROR in split_fta_pr, line %d, character %d, unknown predicate operator type %d\n",\r
- pr->get_lineno(), pr->get_charno(), pr->get_operator_type() );\r
- exit(1);\r
- }\r
-\r
- return(0);\r
-\r
-}\r
-\r
-\r
-\r
-////////////////////////////////////////////////////////////////////////\r
-/// rehome_hfta_se rehome_hfta_pr\r
-/// This is use to split an sgah operator (aggregation),\r
-/// I just need to make gb, aggr references point to the\r
-/// new gb, aggr table entries.\r
-\r
-\r
-scalarexp_t *rehome_fta_se(scalarexp_t *se,\r
- map< int, scalarexp_t * > *aggr_map\r
- ){\r
-\r
- int p, fcn_id;\r
- int agr_id;\r
- vector<scalarexp_t *> operand_list;\r
- scalarexp_t *ret_se, *l_se, *r_se;\r
- colref_t *new_cr;\r
- scalarexp_t *new_se;\r
- data_type *dt = se->get_data_type();\r
- vector<scalarexp_t *> new_operands;\r
-\r
- switch(se->get_operator_type()){\r
- case SE_LITERAL:\r
- ret_se = new scalarexp_t(se->get_literal());\r
- ret_se->use_decorations_of(se);\r
- return(ret_se);\r
-\r
- case SE_PARAM:\r
- ret_se = scalarexp_t::make_param_reference(se->get_op().c_str());\r
- ret_se->use_decorations_of(se);\r
- return(ret_se);\r
-\r
- case SE_IFACE_PARAM:\r
- ret_se = scalarexp_t::make_iface_param_reference(se->get_ifpref());\r
- ret_se->use_decorations_of(se);\r
- return(ret_se);\r
-\r
-\r
-\r
- case SE_COLREF:\r
-// Must be a GB REF ...\r
-// I'm assuming that the hfta gbvar table has the\r
-// same sequence of entries as the input query's gbvar table.\r
-// Else I'll need some kind of translation table.\r
-\r
- if(! se->is_gb()){\r
- fprintf(stderr,"WARNING, a colref is not a gbver ref in rehome_hfta_se"\r
- " type is %s, line=%d, col=%d\n",\r
- se->get_data_type()->to_string().c_str(),\r
- se->lineno, se->charno\r
- );\r
- }\r
-\r
- ret_se = new scalarexp_t(se->get_colref());\r
- ret_se->use_decorations_of(se); // just inherit the gbref\r
- return(ret_se);\r
-\r
- case SE_UNARY_OP:\r
- l_se = rehome_fta_se(se->get_left_se(), aggr_map);\r
-\r
- ret_se = new scalarexp_t(se->get_op().c_str(), l_se);\r
- ret_se->use_decorations_of(se);\r
- return(ret_se);\r
-\r
- case SE_BINARY_OP:\r
- l_se = rehome_fta_se(se->get_left_se(), aggr_map);\r
- r_se = rehome_fta_se(se->get_right_se(), aggr_map);\r
-\r
- ret_se = new scalarexp_t(se->get_op().c_str(), l_se, r_se);\r
- ret_se->use_decorations_of(se);\r
-\r
- return(ret_se);\r
-\r
- case SE_AGGR_STAR:\r
- case SE_AGGR_SE:\r
- agr_id = se->get_aggr_ref();\r
- return (*aggr_map)[agr_id];\r
- break;\r
-\r
- case SE_FUNC:\r
- agr_id = se->get_aggr_ref();\r
- if(agr_id >= 0) return (*aggr_map)[agr_id];\r
-\r
- operand_list = se->get_operands();\r
- for(p=0;p<operand_list.size();p++){\r
- l_se = rehome_fta_se(operand_list[p], aggr_map);\r
-\r
- new_operands.push_back(l_se);\r
- }\r
-\r
-\r
- ret_se = new scalarexp_t(se->get_op().c_str(), new_operands);\r
- ret_se->use_decorations_of(se);\r
-\r
- return(ret_se);\r
-\r
- default:\r
- printf("INTERNAL ERROR in rehome_fta_se: operator type %d\n",se->get_operator_type());\r
- exit(1);\r
- break;\r
- }\r
- return(NULL);\r
-\r
-}\r
-\r
-\r
-// The predicates have already been\r
-// broken into conjunctions.\r
-// If any part of a conjunction is fta-forbidden,\r
-// it must be executed in the stream operator.\r
-// Else it is executed in the FTA.\r
-// A pre-analysis should determine whether this\r
-// predicate is fta-safe. This procedure will\r
-// assume that it is fta-forbidden and will\r
-// prepare it for execution in the stream.\r
-\r
-predicate_t *rehome_fta_pr(predicate_t *pr,\r
- map<int, scalarexp_t *> *aggr_map\r
- ){\r
-\r
- vector<literal_t *> llist;\r
- scalarexp_t *se_l, *se_r;\r
- predicate_t *ret_pr, *pr_l, *pr_r;\r
- vector<scalarexp_t *> op_list, new_op_list;\r
- int o;\r
-\r
- switch(pr->get_operator_type()){\r
- case PRED_IN:\r
- se_l = rehome_fta_se(pr->get_left_se(), aggr_map);\r
- ret_pr = new predicate_t(se_l, pr->get_lit_vec());\r
- return(ret_pr);\r
-\r
- case PRED_COMPARE:\r
- se_l = rehome_fta_se(pr->get_left_se(), aggr_map);\r
- se_r = rehome_fta_se(pr->get_right_se(), aggr_map);\r
- ret_pr = new predicate_t(se_l, pr->get_op().c_str(), se_r);\r
- return(ret_pr);\r
-\r
- case PRED_UNARY_OP:\r
- pr_l = rehome_fta_pr(pr->get_left_pr(), aggr_map);\r
- ret_pr = new predicate_t(pr->get_op().c_str(), pr_l);\r
- return(ret_pr);\r
-\r
- case PRED_BINARY_OP:\r
- pr_l = rehome_fta_pr(pr->get_left_pr(), aggr_map);\r
- pr_r = rehome_fta_pr(pr->get_right_pr(), aggr_map);\r
- ret_pr = new predicate_t(pr->get_op().c_str(), pr_l, pr_r);\r
- return(ret_pr);\r
-\r
- case PRED_FUNC:\r
- op_list = pr->get_op_list();\r
- for(o=0;o<op_list.size();++o){\r
- se_l = rehome_fta_se(op_list[o], aggr_map);\r
- new_op_list.push_back(se_l);\r
- }\r
- ret_pr= new predicate_t(pr->get_op().c_str(), new_op_list);\r
- ret_pr->set_fcn_id(pr->get_fcn_id());\r
- return(ret_pr);\r
-\r
- default:\r
- fprintf(stderr,"INTERNAL ERROR in rehome_fta_pr, line %d, character %d, unknown predicate operator type %d\n",\r
- pr->get_lineno(), pr->get_charno(), pr->get_operator_type() );\r
- exit(1);\r
- }\r
-\r
- return(0);\r
-\r
-}\r
-\r
-\r
-////////////////////////////////////////////////////////////////////\r
-///////////////// Create a STREAM table to represent the FTA output.\r
-\r
-table_def *create_attributes(string tname, vector<select_element *> &select_list){\r
- int s;\r
-\r
-\r
-// Create a new STREAM schema for the output of the FTA.\r
-\r
- field_entry_list *fel = new field_entry_list();\r
- set<string> ufcns;\r
- for(s=0;s<select_list.size();s++){\r
- scalarexp_t *sel_se = select_list[s]->se;\r
- data_type *dt = sel_se->get_data_type();\r
-\r
-// Grab the annotations of the field.\r
-// As of this writing, the only meaningful annotations\r
-// are whether or not the attribute is temporal.\r
-// There can be an annotation of constant_t, but\r
-// I'll ignore this, it feels like an unsafe assumption\r
- param_list *plist = new param_list();\r
-// if(dt->is_temporal()){\r
- vector<string> param_strings = dt->get_param_keys();\r
- int p;\r
- for(p=0;p<param_strings.size();++p){\r
- string v = dt->get_param_val(param_strings[p]);\r
- if(v != "")\r
- plist->append(param_strings[p].c_str(),v.c_str());\r
- else\r
- plist->append(param_strings[p].c_str());\r
- }\r
-// }\r
-\r
-// char access_fcn_name[500];\r
- string colname = select_list[s]->name;\r
-// sprintf(access_fcn_name,"get_field_%s",colname.c_str());\r
- string access_fcn_name = "get_field_"+colname;\r
- field_entry *fe = new field_entry(\r
- dt->get_type_str(), colname, access_fcn_name, plist, ufcns\r
- );\r
-\r
- fel->append_field(fe);\r
- }\r
-\r
- table_def *fta_tbl = new table_def(\r
- tname.c_str(), NULL, NULL, fel, STREAM_SCHEMA\r
- );\r
-\r
- return(fta_tbl);\r
-\r
-}\r
-\r
-//------------------------------------------------------------------\r
-// Textual representation of the query node.\r
-\r
-\r
-\r
-string spx_qpn::to_query_string(){\r
-\r
- string ret = "Select ";\r
- int s;\r
- for(s=0;s<select_list.size();s++){\r
- if(s>0) ret+=", ";\r
- ret += se_to_query_string(select_list[s]->se, NULL);\r
- if(select_list[s]->name != "") ret += " AS "+select_list[s]->name;\r
- }\r
- ret += "\n";\r
-\r
- ret += "From "+table_name->to_string()+"\n";\r
-\r
- if(where.size() > 0){\r
- ret += "Where ";\r
- int w;\r
- for(w=0;w<where.size();w++){\r
- if(w>0) ret += " AND ";\r
- ret += "(" + pred_to_query_str(where[w]->pr,NULL) + ")";\r
- }\r
- ret += "\n";\r
- }\r
-\r
- return(ret);\r
-}\r
-\r
-\r
-\r
-\r
-string sgah_qpn::to_query_string(){\r
-\r
- string ret = "Select ";\r
- int s;\r
- for(s=0;s<select_list.size();s++){\r
- if(s>0) ret+=", ";\r
- ret += se_to_query_string(select_list[s]->se, &aggr_tbl);\r
- if(select_list[s]->name != "") ret += " AS "+select_list[s]->name;\r
- }\r
- ret += "\n";\r
-\r
- ret += "From "+table_name->to_string()+"\n";\r
-\r
- if(where.size() > 0){\r
- ret += "Where ";\r
- int w;\r
- for(w=0;w<where.size();w++){\r
- if(w>0) ret += " AND ";\r
- ret += "(" + pred_to_query_str(where[w]->pr,&aggr_tbl) + ")";\r
- }\r
- ret += "\n";\r
- }\r
-\r
- if(gb_tbl.size() > 0){\r
- ret += "Group By ";\r
- int g;\r
- if(gb_tbl.gb_patterns.size() <= 1 || gb_tbl.gb_entry_type.size()==0){\r
- for(g=0;g<gb_tbl.size();g++){\r
- if(g>0) ret += ", ";\r
-// if(gb_tbl.get_reftype(g) == GBVAR_SE){\r
- ret += se_to_query_string(gb_tbl.get_def(g), &aggr_tbl) + " AS ";\r
-// }\r
- ret += gb_tbl.get_name(g);\r
- }\r
- }else{\r
- int gb_pos = 0;\r
- for(g=0;g<gb_tbl.gb_entry_type.size();++g){\r
- if(g>0) ret += ", ";\r
- if(gb_tbl.gb_entry_type[g] == ""){\r
- ret += se_to_query_string(gb_tbl.get_def(gb_pos),&aggr_tbl)+\r
- " AS "+ gb_tbl.get_name(gb_pos);\r
- gb_pos++;\r
- }\r
- if(gb_tbl.gb_entry_type[g] == "CUBE" ||\r
- gb_tbl.gb_entry_type[g] == "ROLLUP"){\r
- ret += gb_tbl.gb_entry_type[g] + "(";\r
- int gg = 0;\r
- for(gg=0;gg<gb_tbl.gb_entry_count[g];++gg){\r
- if(gg>0) ret += ", ";\r
- ret += se_to_query_string(gb_tbl.get_def(gb_pos),&aggr_tbl)+ " AS "+ gb_tbl.get_name(gb_pos);\r
- gb_pos++;\r
- }\r
- ret += ")";\r
- }\r
- if(gb_tbl.gb_entry_type[g] == "GROUPING_SETS"){\r
- ret += gb_tbl.gb_entry_type[g] + "(";\r
- int g1, g2;\r
- vector<vector<bool> > &local_components = gb_tbl.pattern_components[g];\r
- for(g1=0;g1<local_components.size();++g1){\r
- if(g1>0) ret+=",";\r
- bool first_field = true;\r
- ret += "\n\t\t(";\r
- for(g2=0;g2<=gb_tbl.gb_entry_count[g];g2++){\r
- if(local_components[g1][g2]){\r
- if(!first_field) ret+=", ";\r
- else first_field = false;\r
- ret += gb_tbl.get_name(gb_pos+g2);\r
- }\r
- }\r
- ret += ")";\r
- }\r
- ret += ") ";\r
- gb_pos += gb_tbl.gb_entry_count[g];\r
- }\r
- }\r
- }\r
- ret += "\n";\r
- }\r
-\r
- if(having.size() > 0){\r
- ret += "Having ";\r
- int h;\r
- for(h=0;h<having.size();h++){\r
- if(h>0) ret += " AND ";\r
- ret += "(" + pred_to_query_str(having[h]->pr,&aggr_tbl) + ")";\r
- }\r
- ret += "\n";\r
- }\r
-\r
- return(ret);\r
-}\r
-\r
-\r
-string rsgah_qpn::to_query_string(){\r
-\r
- string ret = "Select ";\r
- int s;\r
- for(s=0;s<select_list.size();s++){\r
- if(s>0) ret+=", ";\r
- ret += se_to_query_string(select_list[s]->se, &aggr_tbl);\r
- if(select_list[s]->name != "") ret += " AS "+select_list[s]->name;\r
- }\r
- ret += "\n";\r
-\r
- ret += "From "+table_name->to_string()+"\n";\r
-\r
- if(where.size() > 0){\r
- ret += "Where ";\r
- int w;\r
- for(w=0;w<where.size();w++){\r
- if(w>0) ret += " AND ";\r
- ret += "(" + pred_to_query_str(where[w]->pr,&aggr_tbl) + ")";\r
- }\r
- ret += "\n";\r
- }\r
-\r
- if(gb_tbl.size() > 0){\r
- ret += "Group By ";\r
- int g;\r
- for(g=0;g<gb_tbl.size();g++){\r
- if(g>0) ret += ", ";\r
-// if(gb_tbl.get_reftype(g) == GBVAR_SE){\r
- ret += se_to_query_string(gb_tbl.get_def(g), &aggr_tbl)+" AS ";\r
-// }\r
- ret += gb_tbl.get_name(g);\r
- }\r
- ret += "\n";\r
- }\r
-\r
- if(having.size() > 0){\r
- ret += "Having ";\r
- int h;\r
- for(h=0;h<having.size();h++){\r
- if(h>0) ret += " AND ";\r
- ret += "(" + pred_to_query_str(having[h]->pr,&aggr_tbl) + ")";\r
- }\r
- ret += "\n";\r
- }\r
-\r
- if(closing_when.size() > 0){\r
- ret += "Closing_When ";\r
- int h;\r
- for(h=0;h<closing_when.size();h++){\r
- if(h>0) ret += " AND ";\r
- ret += "(" + pred_to_query_str(closing_when[h]->pr,&aggr_tbl) + ")";\r
- }\r
- ret += "\n";\r
- }\r
-\r
- return(ret);\r
-}\r
-\r
-\r
-string sgahcwcb_qpn::to_query_string(){\r
-\r
- string ret = "Select ";\r
- int s;\r
- for(s=0;s<select_list.size();s++){\r
- if(s>0) ret+=", ";\r
- ret += se_to_query_string(select_list[s]->se, &aggr_tbl);\r
- if(select_list[s]->name != "") ret += " AS "+select_list[s]->name;\r
- }\r
- ret += "\n";\r
-\r
- ret += "From "+table_name->to_string()+"\n";\r
-\r
- if(where.size() > 0){\r
- ret += "Where ";\r
- int w;\r
- for(w=0;w<where.size();w++){\r
- if(w>0) ret += " AND ";\r
- ret += "(" + pred_to_query_str(where[w]->pr,&aggr_tbl) + ")";\r
- }\r
- ret += "\n";\r
- }\r
-\r
- if(gb_tbl.size() > 0){\r
- ret += "Group By ";\r
- int g;\r
- for(g=0;g<gb_tbl.size();g++){\r
- if(g>0) ret += ", ";\r
-// if(gb_tbl.get_reftype(g) == GBVAR_SE){\r
- ret += se_to_query_string(gb_tbl.get_def(g), &aggr_tbl) + " AS ";\r
-// }\r
- ret += gb_tbl.get_name(g);\r
- }\r
- ret += "\n";\r
- }\r
-\r
- if(sg_tbl.size() > 0){\r
- ret += "Supergroup ";\r
- int g;\r
- bool first_elem = true;\r
- for(g=0;g<gb_tbl.size();g++){\r
- if(sg_tbl.count(g)){\r
- if(first_elem){\r
- ret += ", ";\r
- first_elem = false;\r
- }\r
- ret += gb_tbl.get_name(g);\r
- }\r
- }\r
- ret += "\n";\r
- }\r
-\r
- if(having.size() > 0){\r
- ret += "Having ";\r
- int h;\r
- for(h=0;h<having.size();h++){\r
- if(h>0) ret += " AND ";\r
- ret += "(" + pred_to_query_str(having[h]->pr,&aggr_tbl) + ")";\r
- }\r
- ret += "\n";\r
- }\r
-\r
-\r
- if(cleanwhen.size() > 0){\r
- ret += "Cleaning_When ";\r
- int h;\r
- for(h=0;h<cleanwhen.size();h++){\r
- if(h>0) ret += " AND ";\r
- ret += "(" + pred_to_query_str(cleanwhen[h]->pr,&aggr_tbl) + ")";\r
- }\r
- ret += "\n";\r
- }\r
-\r
- if(cleanby.size() > 0){\r
- ret += "Cleaning_By ";\r
- int h;\r
- for(h=0;h<cleanby.size();h++){\r
- if(h>0) ret += " AND ";\r
- ret += "(" + pred_to_query_str(cleanby[h]->pr,&aggr_tbl) + ")";\r
- }\r
- ret += "\n";\r
- }\r
-\r
- return(ret);\r
-}\r
-\r
-\r
-string mrg_qpn::to_query_string(){\r
-\r
- string ret="Merge ";\r
- ret += mvars[0]->to_query_string() + " : " + mvars[1]->to_query_string();\r
- if(slack != NULL){\r
- ret += " SLACK "+se_to_query_string(slack, NULL);\r
- }\r
-\r
- ret += "\nFrom ";\r
- int t;\r
- for(t=0;t<fm.size();++t){\r
- if(t>0) ret += ", ";\r
- ret += fm[t]->to_string();\r
- }\r
- ret += "\n";\r
-\r
- return(ret);\r
-}\r
-\r
-string join_eq_hash_qpn::to_query_string(){\r
-\r
- string ret = "Select ";\r
- int s;\r
- for(s=0;s<select_list.size();s++){\r
- if(s>0) ret+=", ";\r
- ret += se_to_query_string(select_list[s]->se, NULL);\r
- if(select_list[s]->name != "") ret += " AS "+select_list[s]->name;\r
- }\r
- ret += "\n";\r
-\r
-// NOTE: assuming binary join.\r
- int properties = from[0]->get_property()+2*from[1]->get_property();\r
- switch(properties){\r
- case 0:\r
- ret += "INNER_JOIN ";\r
- break;\r
- case 1:\r
- ret += "LEFT_OUTER_JOIN ";\r
- break;\r
- case 2:\r
- ret += "RIGHT_OUTER_JOIN ";\r
- break;\r
- case 3:\r
- ret += "OUTER_JOIN ";\r
- break;\r
- }\r
-\r
- ret += "From ";\r
- int f;\r
- for(f=0;f<from.size();++f){\r
- if(f>0) ret+=", ";\r
- ret += from[f]->to_string();\r
- }\r
- ret += "\n";\r
-\r
- if(where.size() > 0){\r
- ret += "Where ";\r
- int w;\r
- for(w=0;w<where.size();w++){\r
- if(w>0) ret += " AND ";\r
- ret += "(" + pred_to_query_str(where[w]->pr,NULL) + ")";\r
- }\r
- ret += "\n";\r
- }\r
-\r
- return(ret);\r
-}\r
-\r
-string filter_join_qpn::to_query_string(){\r
-\r
- string ret = "Select ";\r
- int s;\r
- for(s=0;s<select_list.size();s++){\r
- if(s>0) ret+=", ";\r
- ret += se_to_query_string(select_list[s]->se, NULL);\r
- if(select_list[s]->name != "") ret += " AS "+select_list[s]->name;\r
- }\r
- ret += "\n";\r
-\r
-// NOTE: assuming binary join.\r
- ret += "FILTER_JOIN("+temporal_var->field+","+int_to_string(temporal_range)+") ";\r
-\r
- ret += "From ";\r
- int f;\r
- for(f=0;f<from.size();++f){\r
- if(f>0) ret+=", ";\r
- ret += from[f]->to_string();\r
- }\r
- ret += "\n";\r
-\r
- if(where.size() > 0){\r
- ret += "Where ";\r
- int w;\r
- for(w=0;w<where.size();w++){\r
- if(w>0) ret += " AND ";\r
- ret += "(" + pred_to_query_str(where[w]->pr,NULL) + ")";\r
- }\r
- ret += "\n";\r
- }\r
-\r
- return(ret);\r
-}\r
-\r
-\r
-// -----------------------------------------------------------------\r
-// Query node subclass specific processing.\r
-\r
-\r
-vector<mrg_qpn *> mrg_qpn::split_sources(){\r
- vector<mrg_qpn *> ret;\r
- int i;\r
-\r
-// sanity check\r
- if(fm.size() != mvars.size()){\r
- fprintf(stderr,"INTERNAL ERROR in mrg_qpn::split_sources. fm.size() = %lu, mvars.size() = %lu\n",fm.size(),mvars.size());\r
- exit(1);\r
- }\r
- if(fm.size() == 1){\r
- fprintf(stderr,"INTERNAL ERROR in mrg_qpn::split_sources, fm size is 1.\n");\r
- exit(1);\r
- }\r
-\r
-/*\r
-int ff;\r
-printf("spliting sources merge node, name = %s, %d sources.\n\t",node_name.c_str(), fm.size());\r
-for(ff=0;ff<fm.size();++ff){\r
-printf("%s ",fm[ff]->to_string().c_str());\r
-}\r
-printf("\n");\r
-*/\r
-\r
-// Handle special cases.\r
- if(fm.size() == 2){\r
- ret.push_back(this);\r
- return ret;\r
- }\r
-\r
- if(fm.size() == 3){\r
- mrg_qpn *new_mrg = (mrg_qpn *)this->make_copy("_cH1");\r
- new_mrg->fm.push_back(this->fm[0]);\r
- new_mrg->fm.push_back(this->fm[1]);\r
- new_mrg->mvars.push_back(this->mvars[0]);\r
- new_mrg->mvars.push_back(this->mvars[1]);\r
-\r
- this->fm.erase(this->fm.begin());\r
- this->mvars.erase(this->mvars.begin());\r
- string vname = fm[0]->get_var_name();\r
- this->fm[0] = new tablevar_t(new_mrg->node_name.c_str());\r
- this->fm[0]->set_range_var(vname);\r
- this->mvars[0]->set_field(table_layout->get_field_name(merge_fieldpos));\r
- this->mvars[0]->set_tablevar_ref(0);\r
- this->mvars[1]->set_tablevar_ref(1);\r
-\r
- ret.push_back(new_mrg);\r
- ret.push_back(this);\r
-\r
-/*\r
-printf("split sources %s (%s %s)\n",node_name.c_str(),new_mrg->node_name.c_str(),this->node_name.c_str());\r
-for(i=0;i<new_mrg->fm.size();++i)\r
-printf("\tsource %s var %d (%s, %s) \n",new_mrg->node_name.c_str(),i,new_mrg->fm[i]->to_string().c_str(), new_mrg->mvars[i]->to_string().c_str());\r
-for(i=0;i<this->fm.size();++i)\r
-printf("\tsource %s var %d (%s, %s) \n",this->node_name.c_str(),i,this->fm[i]->to_string().c_str(), this->mvars[i]->to_string().c_str());\r
-*/\r
-\r
- return ret;\r
- }\r
-\r
-// General case.\r
-// divide up the sources between two children.\r
-// Then, recurse on the children.\r
-\r
- mrg_qpn *new_mrg1 = (mrg_qpn *)this->make_copy("_cH1");\r
- mrg_qpn *new_mrg2 = (mrg_qpn *)this->make_copy("_cH2");\r
- for(i=0;i<this->fm.size()/2;++i){\r
- new_mrg1->fm.push_back(this->fm[i]);\r
- new_mrg1->mvars.push_back(this->mvars[i]);\r
-//printf("Pushing %d (%s, %s) to new_mrg1\n",i,fm[i]->to_string().c_str(), mvars[i]->to_string().c_str());\r
- }\r
- for(;i<this->fm.size();++i){\r
- new_mrg2->fm.push_back(this->fm[i]);\r
- new_mrg2->mvars.push_back(this->mvars[i]);\r
-//printf("Pushing %d (%s, %s) to new_mrg2\n",i,fm[i]->to_string().c_str(), mvars[i]->to_string().c_str());\r
- }\r
- for(i=0;i<new_mrg1->mvars.size();++i)\r
- new_mrg1->mvars[i]->set_tablevar_ref(i);\r
- for(i=0;i<new_mrg2->mvars.size();++i)\r
- new_mrg2->mvars[i]->set_tablevar_ref(i);\r
-\r
-// Children created, make this merge them.\r
- fm.clear();\r
- mvars.clear();\r
-// var 1\r
- tablevar_t *tmp_tblvar = new tablevar_t(new_mrg1->node_name.c_str());\r
- tmp_tblvar->set_range_var("_mrg_var_1");\r
- fm.push_back(tmp_tblvar);\r
- colref_t *tmp_cref = new colref_t("_mrg_var_1",table_layout->get_field_name(merge_fieldpos).c_str());\r
- tmp_cref->set_tablevar_ref(0);\r
- mvars.push_back(tmp_cref);\r
-// var 2\r
- tmp_tblvar = new tablevar_t(new_mrg2->node_name.c_str());\r
- tmp_tblvar->set_range_var("_mrg_var_2");\r
- fm.push_back(tmp_tblvar);\r
- tmp_cref = new colref_t("_mrg_var_2",table_layout->get_field_name(merge_fieldpos).c_str());\r
- tmp_cref->set_tablevar_ref(1);\r
- mvars.push_back(tmp_cref);\r
-\r
-\r
-/*\r
-printf("split sources %s (%s %s)\n",node_name.c_str(),new_mrg1->node_name.c_str(),new_mrg2->node_name.c_str());\r
-for(i=0;i<new_mrg1->fm.size();++i)\r
-printf("\tsource %s var %d (%s, %s) \n",new_mrg1->node_name.c_str(),i,new_mrg1->fm[i]->to_string().c_str(), new_mrg1->mvars[i]->to_string().c_str());\r
-for(i=0;i<new_mrg2->fm.size();++i)\r
-printf("\tsource %s var %d (%s, %s) \n",new_mrg2->node_name.c_str(),i,new_mrg2->fm[i]->to_string().c_str(), new_mrg2->mvars[i]->to_string().c_str());\r
-*/\r
-\r
-// Recurse and put them together\r
- vector<mrg_qpn *> st1 = new_mrg1->split_sources();\r
- ret.insert(ret.end(), st1.begin(), st1.end());\r
- vector<mrg_qpn *> st2 = new_mrg2->split_sources();\r
- ret.insert(ret.end(), st2.begin(), st2.end());\r
-\r
- ret.push_back(this);\r
-\r
- return(ret);\r
-\r
-}\r
-\r
-\r
-\r
-//////// Split helper function : resolve interfaces\r
-\r
-vector<pair<string,string> > get_ifaces(tablevar_t *table, ifq_t *ifdb, int n_virtual_ifaces, int hfta_parallelism, int hfta_idx){\r
- vector<pair<string,string> > basic_ifaces;\r
- int ierr;\r
- if(table->get_ifq()){\r
- basic_ifaces= ifdb->eval(table->get_interface(),ierr);\r
- if(ierr==1){\r
- fprintf(stderr,"ERROR, Interface set %s not found.\n",table->get_interface().c_str());\r
- }\r
- if(ierr==2){\r
- fprintf(stderr,"ERROR, interface definition file didn't parse.\n");\r
- }\r
- }else{\r
- basic_ifaces.push_back(make_pair(table->get_machine(), table->get_interface()));\r
- }\r
-\r
- if(n_virtual_ifaces == 1)\r
- return basic_ifaces;\r
-\r
- int stride = n_virtual_ifaces / hfta_parallelism;\r
- int i,s;\r
- vector<pair<string,string> > ifaces;\r
-\r
- for(i=0;i<basic_ifaces.size();++i){\r
- string mach = basic_ifaces[i].first;\r
- string iface = basic_ifaces[i].second;\r
- for(s=hfta_idx*stride;s<(hfta_idx+1)*stride;++s){\r
- ifaces.push_back(pair<string, string>(mach,iface+"X"+int_to_string(2*s)));\r
- }\r
- }\r
-\r
- return ifaces;\r
-}\r
-\r
-\r
-///////// Split helper function : compute slack in a generated\r
-///////// merge.\r
-\r
-void mrg_qpn::resolve_slack(scalarexp_t *t_se, string fname, vector<pair<string, string> > &sources, ifq_t *ifdb, gb_table *gbt){\r
- int s,e,v;\r
- string es;\r
-\r
-// Find slack divisor, if any.\r
- string fnm;\r
- long long int slack_divisor = find_temporal_divisor(t_se,gbt, fnm);\r
- if(slack_divisor <= 0){\r
- slack = NULL;\r
- return;\r
- }\r
-\r
-// find max slack in the iface spec\r
- long long int max_slacker = 0, this_slacker;\r
- string rname = "Slack_"+fnm;\r
- for(s=0;s<sources.size();++s){\r
- string src_machine = sources[s].first;\r
- string src_iface = sources[s].second;\r
- vector<string> slack_vec = ifdb->get_iface_vals(src_machine, src_iface,rname,e,es);\r
- for(v=0;v<slack_vec.size();++v){\r
- if(sscanf(slack_vec[v].c_str(),"%qd",&this_slacker)){\r
- if(this_slacker > max_slacker)\r
- max_slacker = this_slacker;\r
- }\r
- }\r
- }\r
-\r
- if(max_slacker <= 0){\r
- slack = NULL;\r
- return;\r
- }\r
-\r
-// convert to SE\r
- long long int the_slack=(long long int)(ceil(((double)max_slacker)/((double)slack_divisor)));\r
- char tmps[256];\r
- sprintf(tmps,"%lld",the_slack);\r
- literal_t *slack_lit = new literal_t(tmps, LITERAL_LONGINT);\r
- slack = new scalarexp_t(slack_lit);\r
-}\r
-\r
-\r
-//------------------------------------------------------------------\r
-// split a node to extract LFTA components.\r
-\r
-\r
-vector<qp_node *> mrg_qpn::split_node_for_fta(ext_fcn_list *Ext_fcns, table_list *Schema, int &hfta_returned, ifq_t *ifdb, int n_virtual_ifaces, int hfta_parallelism, int hfta_idx){\r
- // nothing to do, nothing to split, return copy of self.\r
-\r
- hfta_returned = 1;\r
-\r
- vector<qp_node *> ret_vec;\r
-\r
- ret_vec.push_back(this);\r
- return(ret_vec);\r
-\r
-}\r
-\r
-vector<qp_node *> filter_join_qpn::split_node_for_fta(ext_fcn_list *Ext_fcns, table_list *Schema, int &hfta_returned, ifq_t *ifdb, int n_virtual_ifaces, int hfta_parallelism, int hfta_idx){\r
- vector<qp_node *> ret_vec;\r
-\r
-// First check if the query can be pushed to the FTA.\r
- bool fta_ok = true;\r
- int s;\r
- for(s=0;s<select_list.size();s++){\r
- fta_ok &= check_fta_forbidden_se(select_list[s]->se,NULL, Ext_fcns);\r
- }\r
- int p;\r
- for(p=0;p<where.size();p++){\r
- fta_ok &= check_fta_forbidden_pr(where[p]->pr,NULL, Ext_fcns);\r
- }\r
-\r
- if(!fta_ok){\r
- fprintf(stderr,"ERROR, filter join %s is fta-unsafe.\n",node_name.c_str());\r
- exit(1);\r
- }\r
-\r
-// Can it be done in a single lfta?\r
-// Get the set of interfaces it accesses.\r
- int ierr;\r
- int si;\r
- vector<string> sel_names;\r
- vector<pair<string,string> > ifaces = get_ifaces(from[0], ifdb, n_virtual_ifaces, hfta_parallelism, hfta_idx);\r
- if (ifaces.empty()) {\r
- fprintf(stderr,"INTERNAL ERROR in filter_join_qpn::split_node_for_fta - empty interface set\n");\r
- exit(1);\r
- }\r
-\r
- if(ifaces.size() == 1){\r
-// Single interface, no need to merge.\r
- hfta_returned = 0;\r
- ret_vec.push_back(this);\r
- int i;\r
- for(i=0;i<from.size();i++){\r
- from[i]->set_machine(ifaces[0].first);\r
- from[i]->set_interface(ifaces[0].second);\r
- from[i]->set_ifq(false);\r
- }\r
- return(ret_vec);\r
- }else{\r
-// Multiple interfaces, generate the interface-specific queries plus\r
-// the merge.\r
- hfta_returned = 1;\r
-\r
- vector<string> sel_names;\r
- for(si=0;si<ifaces.size();++si){\r
- filter_join_qpn *fta_node = new filter_join_qpn();\r
-\r
-// Name the fta\r
- if(ifaces.size()==1)\r
- fta_node->set_node_name( node_name );\r
- else{\r
- string new_name = "_"+node_name+"_"+ifaces[si].first+"_"+ifaces[si].second;\r
- untaboo(new_name);\r
- fta_node->set_node_name(new_name);\r
- }\r
- sel_names.push_back(fta_node->get_node_name());\r
-\r
-// Assign the table\r
- int f;\r
- for(f=0;f<from.size();f++){\r
- fta_node->from.push_back(from[f]->duplicate());\r
- fta_node->from[f]->set_machine(ifaces[si].first);\r
- fta_node->from[f]->set_interface(ifaces[si].second);\r
- fta_node->from[f]->set_ifq(false);\r
- }\r
- fta_node->temporal_var = temporal_var;\r
- fta_node->temporal_range = temporal_range;\r
-\r
- fta_node->use_bloom = use_bloom;\r
-\r
- for(s=0;s<select_list.size();s++){\r
- fta_node->select_list.push_back( dup_select(select_list[s], NULL) );\r
- }\r
-\r
- for(p=0;p<shared_pred.size();p++){\r
- predicate_t *new_pr = dup_pr(where[p]->pr, NULL);\r
- cnf_elem *new_cnf = new cnf_elem(new_pr);\r
- analyze_cnf(new_cnf);\r
- fta_node->shared_pred.push_back(new_cnf);\r
- fta_node->where.push_back(new_cnf);\r
- }\r
- for(p=0;p<pred_t0.size();p++){\r
- predicate_t *new_pr = dup_pr(where[p]->pr, NULL);\r
- cnf_elem *new_cnf = new cnf_elem(new_pr);\r
- analyze_cnf(new_cnf);\r
- fta_node->pred_t0.push_back(new_cnf);\r
- fta_node->where.push_back(new_cnf);\r
- }\r
- for(p=0;p<pred_t1.size();p++){\r
- predicate_t *new_pr = dup_pr(where[p]->pr, NULL);\r
- cnf_elem *new_cnf = new cnf_elem(new_pr);\r
- analyze_cnf(new_cnf);\r
- fta_node->pred_t1.push_back(new_cnf);\r
- fta_node->where.push_back(new_cnf);\r
- }\r
- for(p=0;p<hash_eq.size();p++){\r
- predicate_t *new_pr = dup_pr(where[p]->pr, NULL);\r
- cnf_elem *new_cnf = new cnf_elem(new_pr);\r
- analyze_cnf(new_cnf);\r
- fta_node->hash_eq.push_back(new_cnf);\r
- fta_node->where.push_back(new_cnf);\r
- }\r
- for(p=0;p<postfilter.size();p++){\r
- predicate_t *new_pr = dup_pr(where[p]->pr, NULL);\r
- cnf_elem *new_cnf = new cnf_elem(new_pr);\r
- analyze_cnf(new_cnf);\r
- fta_node->postfilter.push_back(new_cnf);\r
- fta_node->where.push_back(new_cnf);\r
- }\r
-\r
-// Xfer all of the parameters.\r
-// Use existing handle annotations.\r
- vector<string> param_names = param_tbl->get_param_names();\r
- int pi;\r
- for(pi=0;pi<param_names.size();pi++){\r
- data_type *dt = param_tbl->get_data_type(param_names[pi]);\r
- fta_node->param_tbl->add_param(param_names[pi],dt->duplicate(),\r
- param_tbl->handle_access(param_names[pi]));\r
- }\r
- fta_node->definitions = definitions;\r
- if(fta_node->resolve_if_params(ifdb, this->err_str)){\r
- this->error_code = 3;\r
- return ret_vec;\r
- }\r
-\r
- ret_vec.push_back(fta_node);\r
- }\r
-\r
- mrg_qpn *mrg_node = new mrg_qpn((filter_join_qpn *)ret_vec[0],\r
- node_name, sel_names,ifaces, ifdb);\r
- ret_vec.push_back(mrg_node);\r
-\r
- return(ret_vec);\r
- }\r
-\r
-}\r
-\r
-// Use to search for unresolved interface param refs in an hfta.\r
-\r
-int spx_qpn::count_ifp_refs(set<string> &ifpnames){\r
- int ret = 0;\r
- int i;\r
- for(i=0;i<select_list.size();++i)\r
- ret += count_se_ifp_refs(select_list[i]->se,ifpnames);\r
- for(i=0;i<where.size();++i)\r
- ret += count_pr_ifp_refs(where[i]->pr,ifpnames);\r
- return ret;\r
-}\r
-\r
-int sgah_qpn::count_ifp_refs(set<string> &ifpnames){\r
- int ret = 0;\r
- int i,j;\r
- for(i=0;i<select_list.size();++i)\r
- ret += count_se_ifp_refs(select_list[i]->se,ifpnames);\r
- for(i=0;i<where.size();++i)\r
- ret += count_pr_ifp_refs(where[i]->pr,ifpnames);\r
- for(i=0;i<having.size();++i)\r
- ret += count_pr_ifp_refs(having[i]->pr,ifpnames);\r
- for(i=0;i<aggr_tbl.size();++i){\r
- if(aggr_tbl.is_builtin(i) && !aggr_tbl.is_star_aggr(i)){\r
- ret += count_se_ifp_refs(aggr_tbl.get_aggr_se(i),ifpnames);\r
- }else{\r
- vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(i);\r
- for(j=0;j<opl.size();++j)\r
- ret += count_se_ifp_refs(opl[j],ifpnames);\r
- }\r
- }\r
- for(i=0;i<gb_tbl.size();++i){\r
- ret += count_se_ifp_refs(gb_tbl.get_def(i), ifpnames);\r
- }\r
- return ret;\r
-}\r
-\r
-\r
-int rsgah_qpn::count_ifp_refs(set<string> &ifpnames){\r
- int ret = 0;\r
- int i,j;\r
- for(i=0;i<select_list.size();++i)\r
- ret += count_se_ifp_refs(select_list[i]->se,ifpnames);\r
- for(i=0;i<where.size();++i)\r
- ret += count_pr_ifp_refs(where[i]->pr,ifpnames);\r
- for(i=0;i<having.size();++i)\r
- ret += count_pr_ifp_refs(having[i]->pr,ifpnames);\r
- for(i=0;i<closing_when.size();++i)\r
- ret += count_pr_ifp_refs(closing_when[i]->pr,ifpnames);\r
- for(i=0;i<aggr_tbl.size();++i){\r
- if(aggr_tbl.is_builtin(i) && !aggr_tbl.is_star_aggr(i)){\r
- ret += count_se_ifp_refs(aggr_tbl.get_aggr_se(i),ifpnames);\r
- }else{\r
- vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(i);\r
- for(j=0;j<opl.size();++j)\r
- ret += count_se_ifp_refs(opl[j],ifpnames);\r
- }\r
- }\r
- for(i=0;i<gb_tbl.size();++i){\r
- ret += count_se_ifp_refs(gb_tbl.get_def(i), ifpnames);\r
- }\r
- return ret;\r
-}\r
-\r
-int mrg_qpn::count_ifp_refs(set<string> &ifpnames){\r
- return 0;\r
-}\r
-\r
-int join_eq_hash_qpn::count_ifp_refs(set<string> &ifpnames){\r
- int ret = 0;\r
- int i;\r
- for(i=0;i<select_list.size();++i)\r
- ret += count_se_ifp_refs(select_list[i]->se,ifpnames);\r
- for(i=0;i<prefilter[0].size();++i)\r
- ret += count_pr_ifp_refs(prefilter[0][i]->pr,ifpnames);\r
- for(i=0;i<prefilter[1].size();++i)\r
- ret += count_pr_ifp_refs(prefilter[1][i]->pr,ifpnames);\r
- for(i=0;i<temporal_eq.size();++i)\r
- ret += count_pr_ifp_refs(temporal_eq[i]->pr,ifpnames);\r
- for(i=0;i<hash_eq.size();++i)\r
- ret += count_pr_ifp_refs(hash_eq[i]->pr,ifpnames);\r
- for(i=0;i<postfilter.size();++i)\r
- ret += count_pr_ifp_refs(postfilter[i]->pr,ifpnames);\r
- return ret;\r
-}\r
-\r
-int filter_join_qpn::count_ifp_refs(set<string> &ifpnames){\r
- int ret = 0;\r
- int i;\r
- for(i=0;i<select_list.size();++i)\r
- ret += count_se_ifp_refs(select_list[i]->se,ifpnames);\r
- for(i=0;i<where.size();++i)\r
- ret += count_pr_ifp_refs(where[i]->pr,ifpnames);\r
- return ret;\r
-}\r
-\r
-\r
-// Resolve interface params to string literals\r
-int filter_join_qpn::resolve_if_params( ifq_t *ifdb, string &err){\r
- int ret = 0;\r
- int i;\r
- string ifname = from[0]->get_interface();\r
- string ifmach = from[0]->get_machine();\r
- for(i=0;i<select_list.size();++i)\r
- if( resolve_se_ifp_refs(select_list[i]->se,ifmach, ifname, ifdb, err) )\r
- ret = 1;\r
- for(i=0;i<where.size();++i)\r
- if( resolve_pr_ifp_refs(where[i]->pr,ifmach, ifname, ifdb, err))\r
- ret = 1;\r
- return ret;\r
-}\r
-\r
-\r
-int spx_qpn::resolve_if_params( ifq_t *ifdb, string &err){\r
- int ret = 0;\r
- int i;\r
- string ifname = table_name->get_interface();\r
- string ifmach = table_name->get_machine();\r
- for(i=0;i<select_list.size();++i)\r
- if( resolve_se_ifp_refs(select_list[i]->se,ifmach, ifname, ifdb, err) )\r
- ret = 1;\r
- for(i=0;i<where.size();++i)\r
- if( resolve_pr_ifp_refs(where[i]->pr,ifmach, ifname, ifdb, err))\r
- ret = 1;\r
- return ret;\r
-}\r
-\r
-int sgah_qpn::resolve_if_params( ifq_t *ifdb, string &err){\r
- int ret = 0;\r
- int i,j;\r
- string ifname = table_name->get_interface();\r
- string ifmach = table_name->get_machine();\r
-\r
-//printf("Select list has %d elements\n",select_list.size());\r
- for(i=0;i<select_list.size();++i){\r
-//printf("\tresolving elemet %d\n",i);\r
- if( resolve_se_ifp_refs(select_list[i]->se,ifmach, ifname, ifdb, err) ){\r
- ret = 1;\r
- }\r
- }\r
- for(i=0;i<where.size();++i){\r
- if( resolve_pr_ifp_refs(where[i]->pr,ifmach, ifname, ifdb, err) )\r
- ret = 1;\r
- }\r
- for(i=0;i<having.size();++i){\r
- if( resolve_pr_ifp_refs(having[i]->pr,ifmach, ifname, ifdb, err) )\r
- ret = 1;\r
- }\r
-//printf("aggr list has %d elements\n",select_list.size());\r
- for(i=0;i<aggr_tbl.size();++i){\r
-//printf("\tresolving elemet %d\n",i);\r
- if(aggr_tbl.is_builtin(i) && !aggr_tbl.is_star_aggr(i)){\r
-//printf("\t\t\tbuiltin\n");\r
- if( resolve_se_ifp_refs(aggr_tbl.get_aggr_se(i),ifmach, ifname, ifdb, err) )\r
- ret = 1;\r
- }else{\r
-//printf("\t\t\tudaf\n");\r
- vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(i);\r
- for(j=0;j<opl.size();++j)\r
- if( resolve_se_ifp_refs(opl[j],ifmach, ifname, ifdb, err) )\r
- ret = 1;\r
- }\r
- }\r
- for(i=0;i<gb_tbl.size();++i){\r
- if( resolve_se_ifp_refs(gb_tbl.get_def(i), ifmach, ifname, ifdb, err) )\r
- ret = 1;\r
- }\r
- return ret;\r
-}\r
-\r
-\r
-\r
-/*\r
- SPLITTING A SELECTION_PROJECTION OPERATOR\r
-\r
- An SPX node may reference:\r
- literals, parameters, colrefs, functions, operators\r
- An SPX node may not reference:\r
- group-by variables, aggregates\r
-\r
- An SPX node contains\r
- selection list of SEs\r
- where list of CNF predicates\r
-\r
- Algorithm:\r
- If each selection SE and each where predicate is fta-safe\r
- execute entire operator as an LFTA.\r
- Else\r
- for each predicate in the where clause\r
- if it is fta safe, execute it in the lfta\r
- else, split each SE in the predicate, evaluate the\r
- top-level SEs in the hfta and eval the predicate on that.\r
- For each SE in the se list\r
- Split the SE, eval the high level part, push onto hfta\r
- selection list\r
-\r
- Splitting an SE:\r
- A SE represents a value which must be computed. The LFTA\r
- must provide sub-values from which the HFTA can compute the\r
- desired value.\r
- 1) the SE is fta-safe\r
- Create an entry in the selection list of the LFTA which is\r
- the SE itself. Reference this LFTA selection list entry in\r
- the HFTA (via a field name assigned to the lfta selection\r
- list entry).\r
- 2) The SE is not fta-safe\r
- Determine the boundary between the fta-safe and the fta-unsafe\r
- portions of the SE. The result is a rooted tree (which is\r
- evaluated at the HFTA) which references sub-SEs (which are\r
- evaluated at the LFTA). Each of the sub-SEs is placed on\r
- the selection list of the LFTA and assigned field names,\r
- the top part is evaluated at the HFTA and references the\r
- sub-SEs through their assigned field names.\r
- The only SEs on the LFTA selection list are those created by\r
- the above mechanism. The collection of assigned field names becomes\r
- the schema of the LFTA.\r
-\r
- TODO: insert tablevar names into the colrefs.\r
-\r
-*/\r
-\r
-vector<qp_node *> spx_qpn::split_node_for_fta(ext_fcn_list *Ext_fcns, table_list *Schema, int &hfta_returned, ifq_t *ifdb, int n_virtual_ifaces, int hfta_parallelism, int hfta_idx){\r
-\r
- int i;\r
- vector<qp_node *> ret_vec;\r
-\r
-// If the node reads from a stream, don't split.\r
-// int t = Schema->get_table_ref(table_name->get_schema_name());\r
- int t = table_name->get_schema_ref();\r
- if(Schema->get_schema_type(t) != PROTOCOL_SCHEMA){\r
- hfta_returned = 1;\r
- ret_vec.push_back(this);\r
- return(ret_vec);\r
- }\r
-\r
-\r
-// Get the set of interfaces it accesses.\r
- int ierr;\r
- int si;\r
- vector<string> sel_names;\r
- vector<pair<string,string> > ifaces = get_ifaces(table_name, ifdb, n_virtual_ifaces, hfta_parallelism, hfta_idx);\r
- if (ifaces.empty()) {\r
- fprintf(stderr,"INTERNAL ERROR in spx_qpn::split_node_for_fta - empty interface set\n");\r
- exit(1);\r
- }\r
-\r
-\r
-// The FTA node, it is always returned.\r
-\r
- spx_qpn *fta_node = new spx_qpn();\r
- fta_node->table_name = table_name;\r
-\r
-// for colname imputation\r
-// vector<string> fta_flds, stream_flds;\r
-\r
-\r
-// First check if the query can be pushed to the FTA.\r
- bool fta_ok = true;\r
- int s;\r
- for(s=0;s<select_list.size();s++){\r
- fta_ok &= check_fta_forbidden_se(select_list[s]->se,NULL, Ext_fcns);\r
- }\r
- int p;\r
- for(p=0;p<where.size();p++){\r
- fta_ok &= check_fta_forbidden_pr(where[p]->pr,NULL, Ext_fcns);\r
- }\r
-\r
- if(fta_ok){\r
-////////////////////////////////////////////////////////////\r
-// The query can be executed entirely in the FTA.\r
- hfta_returned = 0;\r
-\r
- for(si=0;si<ifaces.size();++si){\r
- fta_node = new spx_qpn();\r
-\r
-// Name the fta\r
- if(ifaces.size()==1)\r
- fta_node->set_node_name( node_name );\r
- else{\r
- string new_name = "_"+node_name+"_"+ifaces[si].first+"_"+ifaces[si].second;\r
- untaboo(new_name);\r
- fta_node->set_node_name(new_name);\r
- }\r
- sel_names.push_back(fta_node->get_node_name());\r
-\r
-// Assign the table\r
- fta_node->table_name = table_name->duplicate();\r
- fta_node->table_name->set_machine(ifaces[si].first);\r
- fta_node->table_name->set_interface(ifaces[si].second);\r
- fta_node->table_name->set_ifq(false);\r
-\r
- for(s=0;s<select_list.size();s++){\r
- fta_node->select_list.push_back( dup_select(select_list[s], NULL) );\r
- }\r
- for(p=0;p<where.size();p++){\r
- predicate_t *new_pr = dup_pr(where[p]->pr, NULL);\r
- cnf_elem *new_cnf = new cnf_elem(new_pr);\r
- analyze_cnf(new_cnf);\r
-\r
- fta_node->where.push_back(new_cnf);\r
- }\r
-\r
-// Xfer all of the parameters.\r
-// Use existing handle annotations.\r
- vector<string> param_names = param_tbl->get_param_names();\r
- int pi;\r
- for(pi=0;pi<param_names.size();pi++){\r
- data_type *dt = param_tbl->get_data_type(param_names[pi]);\r
- fta_node->param_tbl->add_param(param_names[pi],dt->duplicate(),\r
- param_tbl->handle_access(param_names[pi]));\r
- }\r
- fta_node->definitions = definitions;\r
- if(fta_node->resolve_if_params(ifdb, this->err_str)){\r
- this->error_code = 3;\r
- return ret_vec;\r
- }\r
-\r
- ret_vec.push_back(fta_node);\r
- }\r
-\r
- if(ifaces.size() > 1){\r
- spx_qpn *tmp_spx = (spx_qpn *)(ret_vec[0]);\r
- mrg_qpn *mrg_node = new mrg_qpn(tmp_spx,\r
- node_name, sel_names,ifaces, ifdb);\r
- /*\r
- Do not split sources until we are done with optimizations\r
- vector<mrg_qpn *> split_merge = mrg_node->split_sources();\r
- for(i=0;i<split_merge.size();++i){\r
- ret_vec.push_back(split_merge[i]);\r
- }\r
- hfta_returned = split_merge.size();\r
- */\r
- ret_vec.push_back(mrg_node);\r
- hfta_returned = 1;\r
- }\r
-\r
-\r
-// printf("OK as FTA.\n");\r
-// printf("FTA node is:\n%s\n\n",fta_node->to_query_string().c_str() );\r
-\r
- return(ret_vec);\r
- }\r
-\r
-////////////////////////////////////////////////////\r
-// The fta must be split. Create a stream node.\r
-// NOTE : I am counting on the single\r
-// table in the from list. (Joins handled in a different operator).\r
-\r
- hfta_returned = 1;\r
-\r
- spx_qpn *stream_node = new spx_qpn();\r
- stream_node->set_node_name( node_name );\r
-// Create the tablevar in the stream's FROM clause.\r
-// set the schema name to the name of the LFTA,\r
-// and use the same tablevar name.\r
- stream_node->table_name = new tablevar_t(\r
- ("_fta_"+node_name).c_str()\r
- );\r
- stream_node->table_name->set_range_var(table_name->get_var_name());\r
-\r
-// Name the fta\r
- fta_node->set_node_name( "_fta_"+node_name );\r
-\r
-// table var names of fta, stream.\r
- string fta_var = fta_node->table_name->get_var_name();\r
- string stream_var = stream_node->table_name->get_var_name();\r
-\r
-// Set up select list vector\r
- vector< vector<select_element *> *> select_vec;\r
- select_vec.push_back(&(fta_node->select_list)); // only one child\r
-\r
-\r
-// Split the select list into its FTA and stream parts.\r
-// If any part of the SE is fta-unsafe, it will return\r
-// a SE to execute at the stream ref'ing SE's evaluated\r
-// at the fta (which are put on the FTA's select list as a side effect).\r
-// If the SE is fta-safe, put it on the fta select list, make\r
-// a ref to it and put the ref on the stream select list.\r
- for(s=0;s<select_list.size();s++){\r
- bool fta_forbidden = false;\r
- int se_src = SPLIT_FTAVEC_NOTBLVAR;\r
-// scalarexp_t *root_se = split_fta_se(\r
-// select_list[s]->se,fta_forbidden, fta_node->select_list, Ext_fcns\r
-// );\r
- scalarexp_t *root_se = split_ftavec_se( select_list[s]->se,\r
- fta_forbidden, se_src, select_vec, Ext_fcns\r
- );\r
-// if(fta_forbidden){\r
- if(fta_forbidden || se_src == SPLIT_FTAVEC_NOTBLVAR){\r
- stream_node->select_list.push_back(\r
- new select_element(root_se, select_list[s]->name)\r
- );\r
- }else{\r
- scalarexp_t *new_se=make_fta_se_ref(fta_node->select_list,root_se,0);\r
- stream_node->select_list.push_back(\r
- new select_element(new_se, select_list[s]->name)\r
- );\r
- }\r
- }\r
-\r
-\r
-// The WHERE clause has already been split into a set of clauses\r
-// that are ANDED together. For each clause, check if its FTA-safe.\r
-// If not, split its SE's into fta-safe and stream-executing parts,\r
-// then put a clause which ref's the SEs into the stream.\r
-// Else put it into the LFTA.\r
- predicate_t *pr_root;\r
- bool fta_forbidden;\r
- for(p=0;p<where.size();p++){\r
- if(! check_fta_forbidden_pr(where[p]->pr, NULL, Ext_fcns) ){\r
- pr_root = split_ftavec_pr(where[p]->pr,select_vec,Ext_fcns);\r
-// pr_root = split_fta_pr( where[p]->pr, fta_node->select_list, Ext_fcns);\r
- fta_forbidden = true;\r
- }else{\r
- pr_root = dup_pr(where[p]->pr, NULL);\r
- fta_forbidden = false;\r
- }\r
- cnf_elem *cnf_root = new cnf_elem(pr_root);\r
- analyze_cnf(cnf_root);\r
-\r
- if(fta_forbidden){\r
- stream_node->where.push_back(cnf_root);\r
- }else{\r
- fta_node->where.push_back(cnf_root);\r
- }\r
- }\r
-\r
-\r
-\r
-// Divide the parameters among the stream, FTA.\r
-// Currently : assume that the stream receives all parameters\r
-// and parameter updates, incorporates them, then passes\r
-// all of the parameters to the FTA.\r
-// This will need to change (tables, fta-unsafe types. etc.)\r
-\r
-// I will pass on the use_handle_access marking, even\r
-// though the fcn call that requires handle access might\r
-// exist in only one of the parts of the query.\r
-// Parameter manipulation and handle access determination will\r
-// need to be revisited anyway.\r
- vector<string> param_names = param_tbl->get_param_names();\r
- int pi;\r
- for(pi=0;pi<param_names.size();pi++){\r
- data_type *dt = param_tbl->get_data_type(param_names[pi]);\r
- fta_node->param_tbl->add_param(param_names[pi],dt->duplicate(),\r
- param_tbl->handle_access(param_names[pi]));\r
- stream_node->param_tbl->add_param(param_names[pi],dt->duplicate(),\r
- param_tbl->handle_access(param_names[pi]));\r
- }\r
-\r
- fta_node->definitions = definitions; fta_node->definitions.erase("_referenced_ifaces");\r
- stream_node->definitions = definitions;\r
-\r
-// Now split by interfaces\r
- if(ifaces.size() > 1){\r
- for(si=0;si<ifaces.size();++si){\r
- spx_qpn *subq_node = new spx_qpn();\r
-\r
-// Name the subquery\r
- string new_name = "_"+node_name+"_"+ifaces[si].first+"_"+ifaces[si].second;\r
- untaboo(new_name);\r
- subq_node->set_node_name( new_name) ;\r
- sel_names.push_back(subq_node->get_node_name());\r
-\r
-// Assign the table\r
- subq_node->table_name = fta_node->table_name->duplicate();\r
- subq_node->table_name->set_machine(ifaces[si].first);\r
- subq_node->table_name->set_interface(ifaces[si].second);\r
- subq_node->table_name->set_ifq(false);\r
-\r
- for(s=0;s<fta_node->select_list.size();s++){\r
- subq_node->select_list.push_back( dup_select(fta_node->select_list[s], NULL) );\r
- }\r
- for(p=0;p<fta_node->where.size();p++){\r
- predicate_t *new_pr = dup_pr(fta_node->where[p]->pr, NULL);\r
- cnf_elem *new_cnf = new cnf_elem(new_pr);\r
- analyze_cnf(new_cnf);\r
-\r
- subq_node->where.push_back(new_cnf);\r
- }\r
-// Xfer all of the parameters.\r
-// Use existing handle annotations.\r
- vector<string> param_names = param_tbl->get_param_names();\r
- int pi;\r
- for(pi=0;pi<param_names.size();pi++){\r
- data_type *dt = param_tbl->get_data_type(param_names[pi]);\r
- subq_node->param_tbl->add_param(param_names[pi],dt->duplicate(),\r
- param_tbl->handle_access(param_names[pi]));\r
- }\r
- if(subq_node->resolve_if_params(ifdb, this->err_str)){\r
- this->error_code = 3;\r
- return ret_vec;\r
- }\r
- subq_node->definitions = definitions; subq_node->definitions.erase("_referenced_ifaces");\r
-\r
- ret_vec.push_back(subq_node);\r
- }\r
-\r
- mrg_qpn *mrg_node = new mrg_qpn((spx_qpn *)(ret_vec[0]),\r
- fta_node->node_name, sel_names, ifaces, ifdb);\r
- /*\r
- Do not split sources until we are done with optimizations\r
- vector<mrg_qpn *> split_merge = mrg_node->split_sources();\r
- for(i=0;i<split_merge.size();++i){\r
- ret_vec.push_back(split_merge[i]);\r
- }\r
- */\r
- ret_vec.push_back(mrg_node);\r
- ret_vec.push_back(stream_node);\r
- hfta_returned = 1/*split_merge.size()*/ + 1;\r
-\r
- }else{\r
- fta_node->table_name->set_machine(ifaces[0].first);\r
- fta_node->table_name->set_interface(ifaces[0].second);\r
- fta_node->table_name->set_ifq(false);\r
- if(fta_node->resolve_if_params(ifdb, this->err_str)){\r
- this->error_code = 3;\r
- return ret_vec;\r
- }\r
- ret_vec.push_back(fta_node);\r
- ret_vec.push_back(stream_node);\r
- hfta_returned = 1;\r
- }\r
-\r
-// printf("FTA node is:\n%s\n\n",fta_node->to_query_string().c_str() );\r
-// printf("Stream node is:\n%s\n\n",stream_node->to_query_string().c_str() );\r
-\r
-\r
- return(ret_vec);\r
-}\r
-\r
-\r
-/*\r
- Splitting a aggregation+sampling operator.\r
- right now, return an error if any splitting is required.\r
-*/\r
-\r
-vector<qp_node *> sgahcwcb_qpn::split_node_for_fta(ext_fcn_list *Ext_fcns, table_list *Schema, int &hfta_returned, ifq_t *ifdb, int n_virtual_ifaces, int hfta_parallelism, int hfta_idx){\r
-\r
- hfta_returned = 1;\r
-\r
- vector<qp_node *> ret_vec;\r
- int s, p, g, a, o, i;\r
- int si;\r
-\r
- vector<string> fta_flds, stream_flds;\r
-\r
-// If the node reads from a stream, don't split.\r
-// int t = Schema->get_table_ref(table_name->get_schema_name());\r
- int t = table_name->get_schema_ref();\r
- if(Schema->get_schema_type(t) != PROTOCOL_SCHEMA){\r
- ret_vec.push_back(this);\r
- return(ret_vec);\r
- }\r
-\r
- fprintf(stderr,"ERROR : cannot split a sampling operator (not yet implemented).\n");\r
- exit(1);\r
-\r
- return ret_vec;\r
-\r
-\r
-}\r
-\r
-\r
-/*\r
- Splitting a running aggregation operator.\r
- The code is almost identical to that of the the sgah operator\r
- except that\r
- - there is no lfta-only option.\r
- - the stream node is rsagh_qpn (lfta is sgah or spx)\r
- - need to handle the closing when (similar to having)\r
-*/\r
-\r
-vector<qp_node *> rsgah_qpn::split_node_for_fta(ext_fcn_list *Ext_fcns, table_list *Schema, int &hfta_returned, ifq_t *ifdb, int n_virtual_ifaces, int hfta_parallelism, int hfta_idx){\r
-\r
- hfta_returned = 1;\r
-\r
- vector<qp_node *> ret_vec;\r
- int s, p, g, a, o, i;\r
- int si;\r
-\r
- vector<string> fta_flds, stream_flds;\r
-\r
-// If the node reads from a stream, don't split.\r
-// int t = Schema->get_table_ref(table_name->get_schema_name());\r
- int t = table_name->get_schema_ref();\r
- if(Schema->get_schema_type(t) != PROTOCOL_SCHEMA){\r
- ret_vec.push_back(this);\r
- return(ret_vec);\r
- }\r
-\r
-// Get the set of interfaces it accesses.\r
- int ierr;\r
- vector<string> sel_names;\r
- vector<pair<string,string> > ifaces = get_ifaces(table_name, ifdb, n_virtual_ifaces, hfta_parallelism, hfta_idx);\r
- if (ifaces.empty()) {\r
- fprintf(stderr,"INTERNAL ERROR in rsgah_qpn::split_node_for_fta - empty interface set\n");\r
- exit(1);\r
- }\r
-\r
-\r
-\r
-\r
-//////////////////////////////////////////////////////////////\r
-/// Split into lfta, hfta.\r
-\r
-// A rsgah node must always be split,\r
-// if for no other reason than to complete the\r
-// partial aggregation.\r
-\r
-// First, determine if the query can be spit into aggr/aggr,\r
-// or if it must be selection/aggr.\r
-// Splitting into selection/aggr is allowed only\r
-// if select_lfta is set.\r
-\r
-\r
- bool select_allowed = definitions.count("select_lfta")>0;\r
- bool select_rqd = false;\r
-\r
- set<int> unsafe_gbvars; // for processing where clause\r
- for(g=0;g<gb_tbl.size();g++){\r
- if(! check_fta_forbidden_se(gb_tbl.get_def(g), &aggr_tbl, Ext_fcns)){\r
- if(!select_allowed){\r
- sprintf(tmpstr,"ERROR in rsgah_qpn::split_node_for_fta : group by attribute (%s) has LFTA-unsafe definition but select_lfta is not enabled (%s).\n",\r
- gb_tbl.get_name(g).c_str(), se_to_query_string(gb_tbl.get_def(g), &aggr_tbl).c_str()\r
- );\r
- this->error_code = 1;\r
- this->err_str = tmpstr;\r
- return(ret_vec);\r
- }else{\r
- select_rqd = true;\r
- unsafe_gbvars.insert(g);\r
- }\r
- }\r
- }\r
-\r
-// Verify that the SEs in the aggregate definitions are fta-safe\r
- for(a=0;a<aggr_tbl.size();++a){\r
- scalarexp_t *ase = aggr_tbl.get_aggr_se(a);\r
- if(ase != NULL){ // COUNT(*) does not have a SE.\r
- if(!select_allowed){\r
- if(! check_fta_forbidden_se(aggr_tbl.get_aggr_se(a), &aggr_tbl, Ext_fcns)){\r
- sprintf(tmpstr,"ERROR in rsgah_qpn::split_node_for_fta : aggregate (%s) has FTA-unsafe scalar expression but select_lfta is not enabled (%s).\n",\r
- aggr_tbl.get_op(a).c_str(), se_to_query_string(aggr_tbl.get_aggr_se(a), &aggr_tbl).c_str()\r
- );\r
- this->error_code = 1;\r
- this->err_str = tmpstr;\r
- return(ret_vec);\r
- }\r
- }else{\r
- select_rqd = true;\r
- }\r
- }\r
- }\r
-\r
-// Verify that all of the ref'd UDAFs can be split.\r
-\r
- for(a=0;a<aggr_tbl.size();++a){\r
- if(! aggr_tbl.is_builtin(a)){\r
- int afcn = aggr_tbl.get_fcn_id(a);\r
- int super_id = Ext_fcns->get_superaggr_id(afcn);\r
- int sub_id = Ext_fcns->get_subaggr_id(afcn);\r
- if(super_id < 0 || sub_id < 0){\r
- if(!select_allowed){\r
- this->err_str += "ERROR in rsgah_qpn::split_node_for_fta : UDAF "+aggr_tbl.get_op(a)+" doesn't have sub/super UDAFS so it can't be split, but select_lfta is not enabled.\n";\r
- this->error_code = 1;\r
- return(ret_vec);\r
- }else{\r
- select_rqd = true;\r
- }\r
- }\r
- }\r
- }\r
-\r
- for(p=0;p<where.size();p++){\r
- if(! check_fta_forbidden_pr(where[p]->pr, &aggr_tbl, Ext_fcns) ){\r
- if(!select_allowed){\r
- sprintf(tmpstr,"ERROR in rsgah_qpn::split_node_for_fta : all of the WHERE predicate must be FTA-safe, but select_lfta is not enabled (%s).\n",\r
- pred_to_query_str(where[p]->pr,&aggr_tbl).c_str()\r
- );\r
- this->error_code = 1;\r
- this->err_str = tmpstr;\r
- return(ret_vec);\r
- }else{\r
- select_rqd = true;\r
- }\r
- }\r
- }\r
-\r
-\r
- if(! select_rqd){\r
-\r
-/////////////////////////////////////////////////////\r
-// Split into aggr/aggr.\r
-\r
-\r
-\r
-\r
-\r
- sgah_qpn *fta_node = new sgah_qpn();\r
- fta_node->table_name = table_name;\r
- fta_node->set_node_name( "_fta_"+node_name );\r
- fta_node->table_name->set_range_var(table_name->get_var_name());\r
-\r
-\r
- rsgah_qpn *stream_node = new rsgah_qpn();\r
- stream_node->table_name = new tablevar_t( ("_fta_"+node_name).c_str());\r
- stream_node->set_node_name( node_name );\r
- stream_node->table_name->set_range_var(table_name->get_var_name());\r
-\r
-// First, process the group-by variables.\r
-// The fta must supply the values of all the gbvars.\r
-// If a gb is computed, the computation must be\r
-// performed at the FTA, so the SE must be FTA-safe.\r
-// Nice side effect : the gbvar table contains\r
-// matching entries for the original query, the lfta query,\r
-// and the hfta query. So gbrefs in the new queries are set\r
-// correctly just by inheriting the gbrefs from the old query.\r
-// If this property changed, I'll need translation tables.\r
-\r
-\r
- for(g=0;g<gb_tbl.size();g++){\r
-// Insert the gbvar into the lfta.\r
- scalarexp_t *gbvar_def = dup_se(gb_tbl.get_def(g), &aggr_tbl);\r
- fta_node->gb_tbl.add_gb_var(\r
- gb_tbl.get_name(g), gb_tbl.get_tblvar_ref(g), gbvar_def, gb_tbl.get_reftype(g)\r
- );\r
-\r
-// Insert a ref to the value of the gbvar into the lfta select list.\r
- colref_t *new_cr = new colref_t(gb_tbl.get_name(g).c_str() );\r
- scalarexp_t *gbvar_fta = new scalarexp_t(new_cr);\r
- gbvar_fta->set_gb_ref(g);\r
- gbvar_fta->set_data_type( gb_tbl.get_def(g)->get_data_type() );\r
- scalarexp_t *gbvar_stream = make_fta_se_ref(fta_node->select_list, gbvar_fta,0);\r
-\r
-// Insert the corresponding gbvar ref (gbvar_stream) into the stream.\r
- gbvar_stream->set_gb_ref(-1); // used as GBvar def\r
- stream_node->gb_tbl.add_gb_var(\r
- gbvar_stream->get_colref()->get_field(), -1, gbvar_stream, gb_tbl.get_reftype(g)\r
- );\r
-\r
- }\r
-\r
-// SEs in the aggregate definitions.\r
-// They are all safe, so split them up for later processing.\r
- map<int, scalarexp_t *> hfta_aggr_se;\r
- for(a=0;a<aggr_tbl.size();++a){\r
- split_fta_aggr( &(aggr_tbl), a,\r
- &(stream_node->aggr_tbl), &(fta_node->aggr_tbl) ,\r
- fta_node->select_list,\r
- hfta_aggr_se,\r
- Ext_fcns\r
- );\r
- }\r
-\r
-\r
-// Next, the select list.\r
-\r
- for(s=0;s<select_list.size();s++){\r
- bool fta_forbidden = false;\r
- scalarexp_t *root_se = rehome_fta_se(select_list[s]->se, &hfta_aggr_se);\r
- stream_node->select_list.push_back(\r
- new select_element(root_se, select_list[s]->name));\r
- }\r
-\r
-\r
-\r
-// All the predicates in the where clause must execute\r
-// in the fta.\r
-\r
- for(p=0;p<where.size();p++){\r
- predicate_t *new_pr = dup_pr(where[p]->pr, &aggr_tbl);\r
- cnf_elem *new_cnf = new cnf_elem(new_pr);\r
- analyze_cnf(new_cnf);\r
-\r
- fta_node->where.push_back(new_cnf);\r
- }\r
-\r
-// All of the predicates in the having clause must\r
-// execute in the stream node.\r
-\r
- for(p=0;p<having.size();p++){\r
- predicate_t *pr_root = rehome_fta_pr( having[p]->pr, &hfta_aggr_se);\r
- cnf_elem *cnf_root = new cnf_elem(pr_root);\r
- analyze_cnf(cnf_root);\r
-\r
- stream_node->having.push_back(cnf_root);\r
- }\r
-\r
-// All of the predicates in the closing when clause must\r
-// execute in the stream node.\r
-\r
- for(p=0;p<closing_when.size();p++){\r
- predicate_t *pr_root=rehome_fta_pr(closing_when[p]->pr,&hfta_aggr_se);\r
- cnf_elem *cnf_root = new cnf_elem(pr_root);\r
- analyze_cnf(cnf_root);\r
-\r
- stream_node->closing_when.push_back(cnf_root);\r
- }\r
-\r
-\r
-// Divide the parameters among the stream, FTA.\r
-// Currently : assume that the stream receives all parameters\r
-// and parameter updates, incorporates them, then passes\r
-// all of the parameters to the FTA.\r
-// This will need to change (tables, fta-unsafe types. etc.)\r
-\r
-// I will pass on the use_handle_access marking, even\r
-// though the fcn call that requires handle access might\r
-// exist in only one of the parts of the query.\r
-// Parameter manipulation and handle access determination will\r
-// need to be revisited anyway.\r
- vector<string> param_names = param_tbl->get_param_names();\r
- int pi;\r
- for(pi=0;pi<param_names.size();pi++){\r
- data_type *dt = param_tbl->get_data_type(param_names[pi]);\r
- fta_node->param_tbl->add_param(param_names[pi],dt->duplicate(),\r
- param_tbl->handle_access(param_names[pi]));\r
- stream_node->param_tbl->add_param(param_names[pi],dt->duplicate(),\r
- param_tbl->handle_access(param_names[pi]));\r
- }\r
- fta_node->definitions = definitions; fta_node->definitions.erase("_referenced_ifaces");\r
- stream_node->definitions = definitions;\r
-\r
-// Now split by interfaces XXXX\r
- if(ifaces.size() > 1){\r
- for(si=0;si<ifaces.size();++si){\r
- sgah_qpn *subq_node = new sgah_qpn();\r
-\r
-// Name the subquery\r
- string new_name = "_"+node_name+"_"+ifaces[si].first+"_"+ifaces[si].second;\r
- untaboo(new_name);\r
- subq_node->set_node_name( new_name) ;\r
- sel_names.push_back(subq_node->get_node_name());\r
-\r
-// Assign the table\r
- subq_node->table_name = fta_node->table_name->duplicate();\r
- subq_node->table_name->set_machine(ifaces[si].first);\r
- subq_node->table_name->set_interface(ifaces[si].second);\r
- subq_node->table_name->set_ifq(false);\r
-\r
-// the GB vars.\r
- for(g=0;g<fta_node->gb_tbl.size();g++){\r
-// Insert the gbvar into the lfta.\r
- scalarexp_t *gbvar_def = dup_se(fta_node->gb_tbl.get_def(g), NULL);\r
- subq_node->gb_tbl.add_gb_var(\r
- fta_node->gb_tbl.get_name(g), fta_node->gb_tbl.get_tblvar_ref(g), gbvar_def, fta_node->gb_tbl.get_reftype(g)\r
- );\r
- }\r
-\r
-// Insert the aggregates\r
- for(a=0;a<fta_node->aggr_tbl.size();++a){\r
- subq_node->aggr_tbl.add_aggr(fta_node->aggr_tbl.duplicate(a));\r
- }\r
-\r
- for(s=0;s<fta_node->select_list.size();s++){\r
- subq_node->select_list.push_back( dup_select(fta_node->select_list[s], NULL) );\r
- }\r
- for(p=0;p<fta_node->where.size();p++){\r
- predicate_t *new_pr = dup_pr(fta_node->where[p]->pr, NULL);\r
- cnf_elem *new_cnf = new cnf_elem(new_pr);\r
- analyze_cnf(new_cnf);\r
-\r
- subq_node->where.push_back(new_cnf);\r
- }\r
- for(p=0;p<fta_node->having.size();p++){\r
- predicate_t *new_pr = dup_pr(fta_node->having[p]->pr, NULL);\r
- cnf_elem *new_cnf = new cnf_elem(new_pr);\r
- analyze_cnf(new_cnf);\r
-\r
- subq_node->having.push_back(new_cnf);\r
- }\r
-// Xfer all of the parameters.\r
-// Use existing handle annotations.\r
- vector<string> param_names = param_tbl->get_param_names();\r
- int pi;\r
- for(pi=0;pi<param_names.size();pi++){\r
- data_type *dt = param_tbl->get_data_type(param_names[pi]);\r
- subq_node->param_tbl->add_param(param_names[pi],dt->duplicate(),\r
- param_tbl->handle_access(param_names[pi]));\r
- }\r
- subq_node->definitions = definitions; subq_node->definitions.erase("_referenced_ifaces");\r
- if(subq_node->resolve_if_params(ifdb, this->err_str)){\r
- this->error_code = 3;\r
- return ret_vec;\r
- }\r
-\r
- ret_vec.push_back(subq_node);\r
- }\r
-\r
- mrg_qpn *mrg_node = new mrg_qpn((sgah_qpn *)(ret_vec[0]),\r
- fta_node->node_name, sel_names, ifaces, ifdb);\r
-\r
- /*\r
- Do not split sources until we are done with optimizations\r
- vector<mrg_qpn *> split_merge = mrg_node->split_sources();\r
- for(i=0;i<split_merge.size();++i){\r
- ret_vec.push_back(split_merge[i]);\r
- }\r
- */\r
- ret_vec.push_back(mrg_node);\r
- ret_vec.push_back(stream_node);\r
- hfta_returned = 1/*split_merge.size()*/+1;\r
-\r
- }else{\r
- fta_node->table_name->set_machine(ifaces[0].first);\r
- fta_node->table_name->set_interface(ifaces[0].second);\r
- fta_node->table_name->set_ifq(false);\r
- if(fta_node->resolve_if_params(ifdb, this->err_str)){\r
- this->error_code = 3;\r
- return ret_vec;\r
- }\r
- ret_vec.push_back(fta_node);\r
- ret_vec.push_back(stream_node);\r
- hfta_returned = 1;\r
- }\r
-\r
-\r
-// ret_vec.push_back(fta_node);\r
-// ret_vec.push_back(stream_node);\r
-\r
-\r
- return(ret_vec);\r
-\r
- }\r
-\r
-/////////////////////////////////////////////////////////////////////\r
-/// Split into selection LFTA, aggregation HFTA.\r
-\r
- spx_qpn *fta_node = new spx_qpn();\r
- fta_node->table_name = table_name;\r
- fta_node->set_node_name( "_fta_"+node_name );\r
- fta_node->table_name->set_range_var(table_name->get_var_name());\r
-\r
-\r
- rsgah_qpn *stream_node = new rsgah_qpn();\r
- stream_node->table_name = new tablevar_t( ("_fta_"+node_name).c_str());\r
- stream_node->set_node_name( node_name );\r
- stream_node->table_name->set_range_var(table_name->get_var_name());\r
-\r
-\r
- vector< vector<select_element *> *> select_vec;\r
- select_vec.push_back(&(fta_node->select_list)); // only one child\r
-\r
-// Process the gbvars. Split their defining SEs.\r
- for(g=0;g<gb_tbl.size();g++){\r
- bool fta_forbidden = false;\r
- int se_src = SPLIT_FTAVEC_NOTBLVAR;\r
-\r
- scalarexp_t *gbvar_se = split_ftavec_se( gb_tbl.get_def(g),\r
- fta_forbidden, se_src, select_vec, Ext_fcns\r
- );\r
-// if(fta_forbidden) (\r
- if(fta_forbidden || se_src == SPLIT_FTAVEC_NOTBLVAR){\r
- stream_node->gb_tbl.add_gb_var(\r
- gb_tbl.get_name(g),gb_tbl.get_tblvar_ref(g),gbvar_se,gb_tbl.get_reftype(g)\r
- );\r
- }else{\r
- scalarexp_t *new_se=make_fta_se_ref(fta_node->select_list,gbvar_se,0);\r
- stream_node->gb_tbl.add_gb_var(\r
- gb_tbl.get_name(g),gb_tbl.get_tblvar_ref(g),new_se,gb_tbl.get_reftype(g)\r
- );\r
- }\r
- }\r
-\r
-// Process the aggregate table.\r
-// Copy to stream, split the SEs.\r
- map<int, scalarexp_t *> hfta_aggr_se; // for rehome\r
- for(a=0;a<aggr_tbl.size();++a){\r
- scalarexp_t *hse;\r
- if(aggr_tbl.is_builtin(a)){\r
- if(aggr_tbl.is_star_aggr(a)){\r
- stream_node->aggr_tbl.add_aggr(aggr_tbl.get_op(a),NULL, false);\r
- hse=scalarexp_t::make_star_aggr(aggr_tbl.get_op(a).c_str());\r
- }else{\r
- bool fta_forbidden = false;\r
- int se_src = SPLIT_FTAVEC_NOTBLVAR;\r
-\r
- scalarexp_t *agg_se = split_ftavec_se( aggr_tbl.get_aggr_se(a),\r
- fta_forbidden, se_src, select_vec, Ext_fcns\r
- );\r
-// if(fta_forbidden) (\r
- if(fta_forbidden || se_src == SPLIT_FTAVEC_NOTBLVAR){\r
- stream_node->aggr_tbl.add_aggr(aggr_tbl.get_op(a), agg_se,false);\r
- hse=scalarexp_t::make_se_aggr(aggr_tbl.get_op(a).c_str(),agg_se);\r
- }else{\r
- scalarexp_t *new_se=make_fta_se_ref(fta_node->select_list,agg_se,0);\r
- stream_node->aggr_tbl.add_aggr(aggr_tbl.get_op(a), new_se,false);\r
- hse=scalarexp_t::make_se_aggr(aggr_tbl.get_op(a).c_str(),new_se);\r
- }\r
- }\r
- hse->set_data_type(aggr_tbl.get_data_type(a));\r
- hse->set_aggr_id(a);\r
- hfta_aggr_se[a]=hse;\r
- }else{\r
- vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(a);\r
- vector<scalarexp_t *> new_opl;\r
- for(o=0;o<opl.size();++o){\r
- bool fta_forbidden = false;\r
- int se_src = SPLIT_FTAVEC_NOTBLVAR;\r
- scalarexp_t *agg_se = split_ftavec_se( opl[o],\r
- fta_forbidden, se_src, select_vec, Ext_fcns\r
- );\r
-// scalarexp_t *agg_se = split_ftavec_se( aggr_tbl.get_aggr_se(a),\r
-// fta_forbidden, se_src, select_vec, Ext_fcns\r
-// );\r
-// if(fta_forbidden) (\r
- if(fta_forbidden || se_src == SPLIT_FTAVEC_NOTBLVAR){\r
- new_opl.push_back(agg_se);\r
- }else{\r
- scalarexp_t *new_se=make_fta_se_ref(fta_node->select_list,agg_se,0);\r
- new_opl.push_back(new_se);\r
- }\r
- }\r
- stream_node->aggr_tbl.add_aggr(aggr_tbl.get_op(a), aggr_tbl.get_fcn_id(a), new_opl, aggr_tbl.get_storage_type(a),false, false,aggr_tbl.has_bailout(a));\r
- hse = new scalarexp_t(aggr_tbl.get_op(a).c_str(),new_opl);\r
- hse->set_data_type(Ext_fcns->get_fcn_dt(aggr_tbl.get_fcn_id(a)));\r
- hse->set_fcn_id(aggr_tbl.get_fcn_id(a));\r
- hse->set_aggr_id(a);\r
- hfta_aggr_se[a]=hse;\r
- }\r
- }\r
-\r
-\r
-// Process the WHERE clause.\r
-// If it is fta-safe AND it refs only fta-safe gbvars,\r
-// then expand the gbvars and put it into the lfta.\r
-// Else, split it into an hfta predicate ref'ing\r
-// se's computed partially in the lfta.\r
-\r
- predicate_t *pr_root;\r
- bool fta_forbidden;\r
- for(p=0;p<where.size();p++){\r
- if(! check_fta_forbidden_pr(where[p]->pr, NULL, Ext_fcns) || contains_gb_pr(where[p]->pr, unsafe_gbvars) ){\r
- pr_root = split_ftavec_pr(where[p]->pr,select_vec,Ext_fcns);\r
- fta_forbidden = true;\r
- }else{\r
- pr_root = dup_pr(where[p]->pr, NULL);\r
- expand_gbvars_pr(pr_root, gb_tbl);\r
- fta_forbidden = false;\r
- }\r
- cnf_elem *cnf_root = new cnf_elem(pr_root);\r
- analyze_cnf(cnf_root);\r
-\r
- if(fta_forbidden){\r
- stream_node->where.push_back(cnf_root);\r
- }else{\r
- fta_node->where.push_back(cnf_root);\r
- }\r
- }\r
-\r
-\r
-// Process the Select clause, rehome it on the\r
-// new defs.\r
- for(s=0;s<select_list.size();s++){\r
- bool fta_forbidden = false;\r
- scalarexp_t *root_se = rehome_fta_se(select_list[s]->se, &hfta_aggr_se);\r
- stream_node->select_list.push_back(\r
- new select_element(root_se, select_list[s]->name));\r
- }\r
-\r
-\r
-// Process the Having clause\r
-\r
-// All of the predicates in the having clause must\r
-// execute in the stream node.\r
-\r
- for(p=0;p<having.size();p++){\r
- predicate_t *pr_root = rehome_fta_pr( having[p]->pr, &hfta_aggr_se);\r
- cnf_elem *cnf_root = new cnf_elem(pr_root);\r
- analyze_cnf(cnf_root);\r
-\r
- stream_node->having.push_back(cnf_root);\r
- }\r
-// Same for closing when\r
- for(p=0;p<closing_when.size();p++){\r
- predicate_t *pr_root=rehome_fta_pr(closing_when[p]->pr,&hfta_aggr_se);\r
- cnf_elem *cnf_root = new cnf_elem(pr_root);\r
- analyze_cnf(cnf_root);\r
-\r
- stream_node->closing_when.push_back(cnf_root);\r
- }\r
-\r
-\r
-// Handle parameters and a few last details.\r
- vector<string> param_names = param_tbl->get_param_names();\r
- int pi;\r
- for(pi=0;pi<param_names.size();pi++){\r
- data_type *dt = param_tbl->get_data_type(param_names[pi]);\r
- fta_node->param_tbl->add_param(param_names[pi],dt->duplicate(),\r
- param_tbl->handle_access(param_names[pi]));\r
- stream_node->param_tbl->add_param(param_names[pi],dt->duplicate(),\r
- param_tbl->handle_access(param_names[pi]));\r
- }\r
-\r
- fta_node->definitions = definitions; fta_node->definitions.erase("_referenced_ifaces");\r
- stream_node->definitions = definitions;\r
-\r
-// Now split by interfaces YYYY\r
- if(ifaces.size() > 1){\r
- for(si=0;si<ifaces.size();++si){\r
- spx_qpn *subq_node = new spx_qpn();\r
-\r
-// Name the subquery\r
- string new_name = "_"+node_name+"_"+ifaces[si].first+"_"+ifaces[si].second;\r
- untaboo(new_name);\r
- subq_node->set_node_name( new_name) ;\r
- sel_names.push_back(subq_node->get_node_name());\r
-\r
-// Assign the table\r
- subq_node->table_name = fta_node->table_name->duplicate();\r
- subq_node->table_name->set_machine(ifaces[si].first);\r
- subq_node->table_name->set_interface(ifaces[si].second);\r
- subq_node->table_name->set_ifq(false);\r
-\r
- for(s=0;s<fta_node->select_list.size();s++){\r
- subq_node->select_list.push_back( dup_select(fta_node->select_list[s], NULL) );\r
- }\r
- for(p=0;p<fta_node->where.size();p++){\r
- predicate_t *new_pr = dup_pr(fta_node->where[p]->pr, NULL);\r
- cnf_elem *new_cnf = new cnf_elem(new_pr);\r
- analyze_cnf(new_cnf);\r
-\r
- subq_node->where.push_back(new_cnf);\r
- }\r
-// Xfer all of the parameters.\r
-// Use existing handle annotations.\r
- vector<string> param_names = param_tbl->get_param_names();\r
- int pi;\r
- for(pi=0;pi<param_names.size();pi++){\r
- data_type *dt = param_tbl->get_data_type(param_names[pi]);\r
- subq_node->param_tbl->add_param(param_names[pi],dt->duplicate(),\r
- param_tbl->handle_access(param_names[pi]));\r
- }\r
- subq_node->definitions = definitions; subq_node->definitions.erase("_referenced_ifaces");\r
- if(subq_node->resolve_if_params(ifdb, this->err_str)){\r
- this->error_code = 3;\r
- return ret_vec;\r
- }\r
-\r
- ret_vec.push_back(subq_node);\r
- }\r
-\r
- mrg_qpn *mrg_node = new mrg_qpn((spx_qpn *)(ret_vec[0]),\r
- fta_node->node_name, sel_names, ifaces, ifdb);\r
- /*\r
- Do not split sources until we are done with optimizations\r
- vector<mrg_qpn *> split_merge = mrg_node->split_sources();\r
- for(i=0;i<split_merge.size();++i){\r
- ret_vec.push_back(split_merge[i]);\r
- }\r
- */\r
- ret_vec.push_back(mrg_node);\r
- ret_vec.push_back(stream_node);\r
- hfta_returned = 1/*split_merge.size()*/+1;\r
-\r
- }else{\r
- fta_node->table_name->set_machine(ifaces[0].first);\r
- fta_node->table_name->set_interface(ifaces[0].second);\r
- fta_node->table_name->set_ifq(false);\r
- if(fta_node->resolve_if_params(ifdb, this->err_str)){\r
- this->error_code = 3;\r
- return ret_vec;\r
- }\r
- ret_vec.push_back(fta_node);\r
- ret_vec.push_back(stream_node);\r
- hfta_returned = 1;\r
- }\r
-\r
- return(ret_vec);\r
-\r
-}\r
-\r
-\r
-/*\r
- Splitting an aggregation operator\r
-\r
- An aggregation operator can reference\r
- literals, parameters, colrefs, group-by vars, aggregates,\r
- operators, functions\r
-\r
- an aggregation contains\r
- A selection list of SEs\r
- A where list of predicates\r
- A list group-by variable definition\r
- A list of aggregates to be computed\r
- A HAVING list of predicates.\r
-\r
- Aggregation involves two phases:\r
- 1) given an input tuple, determine if it satisfies all of\r
- the WHERE predicates. If so, compute the group.\r
- Look up the group, update its aggregates.\r
- 2) given a closed group and its aggregates, determine\r
- if these values satisfy all of the HAVING predicates.\r
- If so, evaluate the SEs on the selection list from the\r
- group and its aggregates.\r
- The two-phase nature of aggregation places restrictions on\r
- what can be referenced by different components of the operator\r
- (in addition to functions and operators).\r
- - group-by variables : literals, parameters, colrefs\r
- - WHERE predicates : group-by vars, literals, params, colrefs\r
- - HAVING predicates : group-by vars, literals, params, aggregates\r
- - Selection list SEs : group-by vars, literals, params, aggregates\r
-\r
- Splitting an aggregation operator into an LFTA/HFTA part\r
- involves performing partial aggregation at the LFTA and\r
- completing the aggregation at the HFTA.\r
- - given a tuple, the LFTA part evaluates the WHERE clause,\r
- and if it is satisfied, computes the group. lookup the group\r
- and update the aggregates. output the group and its partial\r
- aggregates\r
- - Given a partial aggregate from the LFTA, look up the group and\r
- update its aggregates. When the group is closed, evalute\r
- the HAVING clause and the SEs on the selection list.\r
- THEREFORE the selection list of the LFTA must consist of the\r
- group-by variables and the set of (bare) subaggregate values\r
- necessary to compute the super aggregates.\r
- Unlike the case with the SPX operator, the SE splitting point\r
- is at the GBvar and the aggregate value level.\r
-\r
- ALGORITHM:\r
- For each group-by variable\r
- Put the GB variable definition in the LFTA GBVAR list.\r
- Put the GBVAR in the LFTA selection list (as an SE).\r
- Put a reference to that GBVAR in the HFTA GBVAR list.\r
- For each aggregate\r
- Split the aggregate into a superaggregate and a subaggregate.\r
- The SE of the superaggregate references the subaggregate value.\r
- (this will need modifications for MF aggregation)\r
- For each SE in the selection list, HAVING predicate\r
- Make GBVAR references point to the new GBVAR\r
- make the aggregate value references point to the new aggregates.\r
-\r
- SEs are not so much split as their ref's are changed.\r
-\r
- TODO: insert tablevar names into the colrefs.\r
-*/\r
-\r
-\r
-\r
-vector<qp_node *> sgah_qpn::split_node_for_fta(ext_fcn_list *Ext_fcns, table_list *Schema, int &hfta_returned, ifq_t *ifdb, int n_virtual_ifaces, int hfta_parallelism, int hfta_idx){\r
-\r
- hfta_returned = 1;\r
-\r
- vector<qp_node *> ret_vec;\r
- int s, p, g, a, o, i;\r
- int si;\r
-\r
- vector<string> fta_flds, stream_flds;\r
-\r
-// If the node reads from a stream, don't split.\r
-// int t = Schema->get_table_ref(table_name->get_schema_name());\r
- int t = table_name->get_schema_ref();\r
- if(Schema->get_schema_type(t) != PROTOCOL_SCHEMA){\r
- ret_vec.push_back(this);\r
- return(ret_vec);\r
- }\r
-\r
-// Get the set of interfaces it accesses.\r
- int ierr;\r
- vector<string> sel_names;\r
- vector<pair<string,string> > ifaces = get_ifaces(table_name, ifdb, n_virtual_ifaces, hfta_parallelism, hfta_idx);\r
- if (ifaces.empty()) {\r
- fprintf(stderr,"INTERNAL ERROR in sgah_qpn::split_node_for_fta - empty interface set\n");\r
- exit(1);\r
- }\r
-\r
-\r
-\r
-//////////////////////////////////////////////\r
-// Is this LFTA-only?\r
- if(definitions.count("lfta_aggregation")>0){\r
-// Yes. Ensure that everything is lfta-safe.\r
-\r
-// Check only one interface is accessed.\r
- if(ifaces.size()>1){\r
- this->err_str = "ERROR, group-by query "+node_name+" is lfta-only, but it accesses more than one interface:\n";\r
- for(si=0;si<ifaces.size();++si)\r
- this->err_str += "\t"+ifaces[si].first+"."+ifaces[si].second+"\n";\r
- this->error_code = 2;\r
- return(ret_vec);\r
- }\r
-\r
-// Check the group-by attributes\r
- for(g=0;g<gb_tbl.size();g++){\r
- if(! check_fta_forbidden_se(gb_tbl.get_def(g), &aggr_tbl, Ext_fcns)){\r
- sprintf(tmpstr,"ERROR in sgah_qpn::split_node_for_fta : group by attribute (%s) has LFTA-unsafe definition and the query is lfta-only (%s).\n",\r
- gb_tbl.get_name(g).c_str(), se_to_query_string(gb_tbl.get_def(g), &aggr_tbl).c_str()\r
- );\r
- this->error_code = 1;\r
- this->err_str = tmpstr;\r
- return(ret_vec);\r
- }\r
- }\r
-\r
-// Verify that the SEs in the aggregate definitions are fta-safe\r
- for(a=0;a<aggr_tbl.size();++a){\r
- scalarexp_t *ase = aggr_tbl.get_aggr_se(a);\r
- if(ase != NULL){ // COUNT(*) does not have a SE.\r
- if(! check_fta_forbidden_se(aggr_tbl.get_aggr_se(a), &aggr_tbl, Ext_fcns)){\r
- sprintf(tmpstr,"ERROR in sgah_qpn::split_node_for_fta : aggregate (%s) has LFTA-unsafe scalar expression and the query is lfta-only (%s).\n",\r
- aggr_tbl.get_op(a).c_str(), se_to_query_string(aggr_tbl.get_aggr_se(a), &aggr_tbl).c_str()\r
- );\r
- this->error_code = 1;\r
- this->err_str = tmpstr;\r
- return(ret_vec);\r
- }\r
- }\r
- if(! aggr_tbl.fta_legal(a,Ext_fcns)){\r
- if(! check_fta_forbidden_se(aggr_tbl.get_aggr_se(a), &aggr_tbl, Ext_fcns)){\r
- sprintf(tmpstr,"ERROR in sgah_qpn::split_node_for_fta : aggregate (%s) has LFTA-unsafe aggregate and the query is lfta-only (%s).\n",\r
- aggr_tbl.get_op(a).c_str(), se_to_query_string(aggr_tbl.get_aggr_se(a), &aggr_tbl).c_str()\r
- );\r
- this->error_code = 1;\r
- this->err_str = tmpstr;\r
- return(ret_vec);\r
- }\r
- }\r
- }\r
-\r
-// Ensure that all the aggregates are fta-safe ....\r
-\r
-// select list\r
-\r
- for(s=0;s<select_list.size();s++){\r
- if(! check_fta_forbidden_se(select_list[s]->se,NULL, Ext_fcns)){\r
- sprintf(tmpstr,"ERROR in sgah_qpn::split_node_for_fta : all of the WHERE predicate must be LFTA-safe and the query is lfta-only (%s).\n",\r
- pred_to_query_str(where[p]->pr,&aggr_tbl).c_str()\r
- );\r
- this->error_code = 1;\r
- this->err_str = tmpstr;\r
- return(ret_vec);\r
- }\r
- }\r
-\r
-// where predicate\r
-\r
- for(p=0;p<where.size();p++){\r
- if(! check_fta_forbidden_pr(where[p]->pr, &aggr_tbl, Ext_fcns) ){\r
- sprintf(tmpstr,"ERROR in sgah_qpn::split_node_for_fta : all of the WHERE predicate must be LFTA-safe and the query is lfta-only (%s).\n",\r
- pred_to_query_str(where[p]->pr,&aggr_tbl).c_str()\r
- );\r
- this->error_code = 1;\r
- this->err_str = tmpstr;\r
- return(ret_vec);\r
- }\r
- }\r
-\r
-\r
-// having predicate\r
- if(having.size()>0){\r
- sprintf(tmpstr,"ERROR in sgah_qpn::split_node_for_fta : the query is lfta-only, so it can't have a HAVING clause.(%s).\n",\r
- pred_to_query_str(where[p]->pr,&aggr_tbl).c_str()\r
- );\r
- this->error_code = 1;\r
- this->err_str = tmpstr;\r
- return(ret_vec);\r
- }\r
-// The query is lfta safe, return it.\r
-\r
- hfta_returned = 0;\r
- ret_vec.push_back(this);\r
- return(ret_vec);\r
- }\r
-\r
-//////////////////////////////////////////////////////////////\r
-/// Split into lfta, hfta.\r
-\r
-// A sgah node must always be split,\r
-// if for no other reason than to complete the\r
-// partial aggregation.\r
-\r
-// First, determine if the query can be spit into aggr/aggr,\r
-// or if it must be selection/aggr.\r
-// Splitting into selection/aggr is allowed only\r
-// if select_lfta is set.\r
-\r
-\r
- bool select_allowed = definitions.count("select_lfta")>0;\r
- bool select_rqd = false;\r
-\r
- set<int> unsafe_gbvars; // for processing where clause\r
- for(g=0;g<gb_tbl.size();g++){\r
- if(! check_fta_forbidden_se(gb_tbl.get_def(g), &aggr_tbl, Ext_fcns)){\r
- if(!select_allowed){\r
- sprintf(tmpstr,"ERROR in sgah_qpn::split_node_for_fta : group by attribute (%s) has LFTA-unsafe definition but select_lfta is not enabled (%s).\n",\r
- gb_tbl.get_name(g).c_str(), se_to_query_string(gb_tbl.get_def(g), &aggr_tbl).c_str()\r
- );\r
- this->error_code = 1;\r
- this->err_str = tmpstr;\r
- return(ret_vec);\r
- }else{\r
- select_rqd = true;\r
- unsafe_gbvars.insert(g);\r
- }\r
- }\r
- }\r
-\r
-// Verify that the SEs in the aggregate definitions are fta-safe\r
- for(a=0;a<aggr_tbl.size();++a){\r
- scalarexp_t *ase = aggr_tbl.get_aggr_se(a);\r
- if(ase != NULL){ // COUNT(*) does not have a SE.\r
- if(!select_allowed){\r
- if(! check_fta_forbidden_se(aggr_tbl.get_aggr_se(a), &aggr_tbl, Ext_fcns)){\r
- sprintf(tmpstr,"ERROR in sgah_qpn::split_node_for_fta : aggregate (%s) has FTA-unsafe scalar expression but select_lfta is not enabled (%s).\n",\r
- aggr_tbl.get_op(a).c_str(), se_to_query_string(aggr_tbl.get_aggr_se(a), &aggr_tbl).c_str()\r
- );\r
- this->error_code = 1;\r
- this->err_str = tmpstr;\r
- return(ret_vec);\r
- }\r
- }else{\r
- select_rqd = true;\r
- }\r
- }\r
- }\r
-\r
-// Verify that all of the ref'd UDAFs can be split.\r
-\r
- for(a=0;a<aggr_tbl.size();++a){\r
- if(! aggr_tbl.is_builtin(a)){\r
- int afcn = aggr_tbl.get_fcn_id(a);\r
- int super_id = Ext_fcns->get_superaggr_id(afcn);\r
- int sub_id = Ext_fcns->get_subaggr_id(afcn);\r
- if(super_id < 0 || sub_id < 0){\r
- if(!select_allowed){\r
- this->err_str += "ERROR in sgah_qpn::split_node_for_fta : UDAF "+aggr_tbl.get_op(a)+" doesn't have sub/super UDAFS so it can't be split, but select_lfta is not enabled.\n";\r
- this->error_code = 1;\r
- return(ret_vec);\r
- }else{\r
- select_rqd = true;\r
- }\r
- }\r
- }\r
- }\r
-\r
- for(p=0;p<where.size();p++){\r
- if(! check_fta_forbidden_pr(where[p]->pr, &aggr_tbl, Ext_fcns) ){\r
- if(!select_allowed){\r
- sprintf(tmpstr,"ERROR in sgah_qpn::split_node_for_fta : all of the WHERE predicate must be FTA-safe, but select_lfta is not enabled (%s).\n",\r
- pred_to_query_str(where[p]->pr,&aggr_tbl).c_str()\r
- );\r
- this->error_code = 1;\r
- this->err_str = tmpstr;\r
- return(ret_vec);\r
- }else{\r
- select_rqd = true;\r
- }\r
- }\r
- }\r
-\r
-\r
- if(! select_rqd){\r
-\r
-/////////////////////////////////////////////////////\r
-// Split into aggr/aggr.\r
-\r
-\r
-\r
-\r
-\r
- sgah_qpn *fta_node = new sgah_qpn();\r
- fta_node->table_name = table_name;\r
- fta_node->set_node_name( "_fta_"+node_name );\r
- fta_node->table_name->set_range_var(table_name->get_var_name());\r
-\r
-\r
- sgah_qpn *stream_node = new sgah_qpn();\r
- stream_node->table_name = new tablevar_t( ("_fta_"+node_name).c_str());\r
- stream_node->set_node_name( node_name );\r
- stream_node->table_name->set_range_var(table_name->get_var_name());\r
-\r
-// allowed stream disorder. Default is 2,\r
-// can override with max_lfta_disorder setting.\r
-// Also limit the hfta disorder, set to lfta disorder + 1.\r
-// can override with max_hfta_disorder.\r
-\r
- fta_node->lfta_disorder = 2;\r
- if(this->get_val_of_def("max_lfta_disorder") != ""){\r
- int d = atoi(this->get_val_of_def("max_lfta_disorder").c_str() );\r
- if(d<1){\r
- fprintf(stderr,"Warning, max_lfta_disorder in node %s is %d, must be at least 1, ignoring.\n",node_name.c_str(), d);\r
- }else{\r
- fta_node->lfta_disorder = d;\r
-printf("node %s setting lfta_disorder = %d\n",node_name.c_str(),fta_node->lfta_disorder);\r
- }\r
- }\r
- if(fta_node->lfta_disorder > 1)\r
- stream_node->hfta_disorder = fta_node->lfta_disorder + 1;\r
- else\r
- stream_node->hfta_disorder = 1;\r
-\r
- if(this->get_val_of_def("max_hfta_disorder") != ""){\r
- int d = atoi(this->get_val_of_def("max_hfta_disorder").c_str() );\r
- if(d<fta_node->lfta_disorder){\r
- fprintf(stderr,"Warning, max_hfta_disorder in node %s is %d, must be at least the max lfta disorder %d, ignoring.\n",node_name.c_str(), d,fta_node->lfta_disorder);\r
- }else{\r
- fta_node->lfta_disorder = d;\r
- }\r
- if(fta_node->lfta_disorder < fta_node->hfta_disorder){\r
- fta_node->hfta_disorder = fta_node->lfta_disorder + 1;\r
- }\r
- }\r
-\r
-// First, process the group-by variables.\r
-// The fta must supply the values of all the gbvars.\r
-// If a gb is computed, the computation must be\r
-// performed at the FTA, so the SE must be FTA-safe.\r
-// Nice side effect : the gbvar table contains\r
-// matching entries for the original query, the lfta query,\r
-// and the hfta query. So gbrefs in the new queries are set\r
-// correctly just by inheriting the gbrefs from the old query.\r
-// If this property changed, I'll need translation tables.\r
-\r
-\r
- for(g=0;g<gb_tbl.size();g++){\r
-// Insert the gbvar into the lfta.\r
- scalarexp_t *gbvar_def = dup_se(gb_tbl.get_def(g), &aggr_tbl);\r
- fta_node->gb_tbl.add_gb_var(\r
- gb_tbl.get_name(g), gb_tbl.get_tblvar_ref(g), gbvar_def, gb_tbl.get_reftype(g)\r
- );\r
-\r
-// Insert a ref to the value of the gbvar into the lfta select list.\r
- colref_t *new_cr = new colref_t(gb_tbl.get_name(g).c_str() );\r
- scalarexp_t *gbvar_fta = new scalarexp_t(new_cr);\r
- gbvar_fta->set_gb_ref(g);\r
- gbvar_fta->set_data_type( gb_tbl.get_def(g)->get_data_type() );\r
- scalarexp_t *gbvar_stream = make_fta_se_ref(fta_node->select_list, gbvar_fta,0);\r
-\r
-// Insert the corresponding gbvar ref (gbvar_stream) into the stream.\r
- gbvar_stream->set_gb_ref(-1); // used as GBvar def\r
- stream_node->gb_tbl.add_gb_var(\r
- gbvar_stream->get_colref()->get_field(), -1, gbvar_stream, gb_tbl.get_reftype(g)\r
- );\r
- }\r
-// multiple aggregation patterns, if any, go with the hfta\r
- stream_node->gb_tbl.set_pattern_info( &gb_tbl);\r
-\r
-// SEs in the aggregate definitions.\r
-// They are all safe, so split them up for later processing.\r
- map<int, scalarexp_t *> hfta_aggr_se;\r
- for(a=0;a<aggr_tbl.size();++a){\r
- split_fta_aggr( &(aggr_tbl), a,\r
- &(stream_node->aggr_tbl), &(fta_node->aggr_tbl) ,\r
- fta_node->select_list,\r
- hfta_aggr_se,\r
- Ext_fcns\r
- );\r
-/*\r
-// OLD TRACING CODE\r
-\r
-int ii;\r
-for(ii=0;ii<fta_flds.size() || ii < fta_node->select_list.size();++ii){\r
- if(ii<fta_flds.size())\r
- printf("\t%s : ",fta_flds[ii].c_str());\r
- else\r
- printf("\t. : ");\r
- if(ii<fta_node->select_list.size())\r
- printf("%s\n",fta_node->select_list[ii]->to_string().c_str());\r
- else\r
- printf(".\n");\r
-}\r
-printf("hfta aggregates are:");\r
-for(ii=0;ii<stream_node->aggr_tbl.size();++ii){\r
- printf(" %s",stream_node->aggr_tbl.get_op(ii).c_str());\r
-}\r
-printf("\nlfta aggregates are:");\r
-for(ii=0;ii<fta_node->aggr_tbl.size();++ii){\r
- printf(" %s",fta_node->aggr_tbl.get_op(ii).c_str());\r
-}\r
-printf("\n\n");\r
-*/\r
-\r
- }\r
-\r
-\r
-// Next, the select list.\r
-\r
- for(s=0;s<select_list.size();s++){\r
- bool fta_forbidden = false;\r
- scalarexp_t *root_se = rehome_fta_se(select_list[s]->se, &hfta_aggr_se);\r
- stream_node->select_list.push_back(\r
- new select_element(root_se, select_list[s]->name));\r
- }\r
-\r
-\r
-\r
-// All the predicates in the where clause must execute\r
-// in the fta.\r
-\r
- for(p=0;p<where.size();p++){\r
- predicate_t *new_pr = dup_pr(where[p]->pr, &aggr_tbl);\r
- cnf_elem *new_cnf = new cnf_elem(new_pr);\r
- analyze_cnf(new_cnf);\r
-\r
- fta_node->where.push_back(new_cnf);\r
- }\r
-\r
-// All of the predicates in the having clause must\r
-// execute in the stream node.\r
-\r
- for(p=0;p<having.size();p++){\r
- predicate_t *pr_root = rehome_fta_pr( having[p]->pr, &hfta_aggr_se);\r
- cnf_elem *cnf_root = new cnf_elem(pr_root);\r
- analyze_cnf(cnf_root);\r
-\r
- stream_node->having.push_back(cnf_root);\r
- }\r
-\r
-\r
-// Divide the parameters among the stream, FTA.\r
-// Currently : assume that the stream receives all parameters\r
-// and parameter updates, incorporates them, then passes\r
-// all of the parameters to the FTA.\r
-// This will need to change (tables, fta-unsafe types. etc.)\r
-\r
-// I will pass on the use_handle_access marking, even\r
-// though the fcn call that requires handle access might\r
-// exist in only one of the parts of the query.\r
-// Parameter manipulation and handle access determination will\r
-// need to be revisited anyway.\r
- vector<string> param_names = param_tbl->get_param_names();\r
- int pi;\r
- for(pi=0;pi<param_names.size();pi++){\r
- data_type *dt = param_tbl->get_data_type(param_names[pi]);\r
- fta_node->param_tbl->add_param(param_names[pi],dt->duplicate(),\r
- param_tbl->handle_access(param_names[pi]));\r
- stream_node->param_tbl->add_param(param_names[pi],dt->duplicate(),\r
- param_tbl->handle_access(param_names[pi]));\r
- }\r
- fta_node->definitions = definitions; fta_node->definitions.erase("_referenced_ifaces");\r
- stream_node->definitions = definitions;\r
-\r
-// Now split by interfaces XXXX\r
- if(ifaces.size() > 1){\r
- for(si=0;si<ifaces.size();++si){\r
- sgah_qpn *subq_node = new sgah_qpn();\r
-\r
-// Name the subquery\r
- string new_name = "_"+node_name+"_"+ifaces[si].first+"_"+ifaces[si].second;\r
- untaboo(new_name);\r
- subq_node->set_node_name( new_name) ;\r
- sel_names.push_back(subq_node->get_node_name());\r
-\r
-// Assign the table\r
- subq_node->table_name = fta_node->table_name->duplicate();\r
- subq_node->table_name->set_machine(ifaces[si].first);\r
- subq_node->table_name->set_interface(ifaces[si].second);\r
- subq_node->table_name->set_ifq(false);\r
-\r
-// the GB vars.\r
- for(g=0;g<fta_node->gb_tbl.size();g++){\r
-// Insert the gbvar into the lfta.\r
- scalarexp_t *gbvar_def = dup_se(fta_node->gb_tbl.get_def(g), NULL);\r
- subq_node->gb_tbl.add_gb_var(\r
- fta_node->gb_tbl.get_name(g), fta_node->gb_tbl.get_tblvar_ref(g), gbvar_def, fta_node->gb_tbl.get_reftype(g)\r
- );\r
- }\r
-\r
-// Insert the aggregates\r
- for(a=0;a<fta_node->aggr_tbl.size();++a){\r
- subq_node->aggr_tbl.add_aggr(fta_node->aggr_tbl.duplicate(a));\r
- }\r
-\r
- for(s=0;s<fta_node->select_list.size();s++){\r
- subq_node->select_list.push_back( dup_select(fta_node->select_list[s], NULL) );\r
- }\r
- for(p=0;p<fta_node->where.size();p++){\r
- predicate_t *new_pr = dup_pr(fta_node->where[p]->pr, NULL);\r
- cnf_elem *new_cnf = new cnf_elem(new_pr);\r
- analyze_cnf(new_cnf);\r
-\r
- subq_node->where.push_back(new_cnf);\r
- }\r
- for(p=0;p<fta_node->having.size();p++){\r
- predicate_t *new_pr = dup_pr(fta_node->having[p]->pr, NULL);\r
- cnf_elem *new_cnf = new cnf_elem(new_pr);\r
- analyze_cnf(new_cnf);\r
-\r
- subq_node->having.push_back(new_cnf);\r
- }\r
-// Xfer all of the parameters.\r
-// Use existing handle annotations.\r
- vector<string> param_names = param_tbl->get_param_names();\r
- int pi;\r
- for(pi=0;pi<param_names.size();pi++){\r
- data_type *dt = param_tbl->get_data_type(param_names[pi]);\r
- subq_node->param_tbl->add_param(param_names[pi],dt->duplicate(),\r
- param_tbl->handle_access(param_names[pi]));\r
- }\r
- subq_node->definitions = definitions; subq_node->definitions.erase("_referenced_ifaces");\r
- if(subq_node->resolve_if_params(ifdb, this->err_str)){\r
- this->error_code = 3;\r
- return ret_vec;\r
- }\r
-\r
-// THe disorder\r
- subq_node->lfta_disorder = fta_node->lfta_disorder;\r
-\r
- ret_vec.push_back(subq_node);\r
- }\r
-\r
- mrg_qpn *mrg_node = new mrg_qpn((sgah_qpn *)(ret_vec[0]),\r
- fta_node->node_name, sel_names, ifaces, ifdb);\r
- mrg_node->set_disorder(fta_node->lfta_disorder);\r
-\r
- /*\r
- Do not split sources until we are done with optimizations\r
- vector<mrg_qpn *> split_merge = mrg_node->split_sources();\r
- for(i=0;i<split_merge.size();++i){\r
- ret_vec.push_back(split_merge[i]);\r
- }\r
- */\r
- ret_vec.push_back(mrg_node);\r
- ret_vec.push_back(stream_node);\r
- hfta_returned = 1/*split_merge.size()*/+1;\r
-\r
- }else{\r
- fta_node->table_name->set_machine(ifaces[0].first);\r
- fta_node->table_name->set_interface(ifaces[0].second);\r
- fta_node->table_name->set_ifq(false);\r
- if(fta_node->resolve_if_params(ifdb, this->err_str)){\r
- this->error_code = 3;\r
- return ret_vec;\r
- }\r
- ret_vec.push_back(fta_node);\r
- ret_vec.push_back(stream_node);\r
- hfta_returned = 1;\r
- }\r
-\r
-\r
-// ret_vec.push_back(fta_node);\r
-// ret_vec.push_back(stream_node);\r
-\r
-\r
- return(ret_vec);\r
-\r
- }\r
-\r
-/////////////////////////////////////////////////////////////////////\r
-/// Split into selection LFTA, aggregation HFTA.\r
-\r
- spx_qpn *fta_node = new spx_qpn();\r
- fta_node->table_name = table_name;\r
- fta_node->set_node_name( "_fta_"+node_name );\r
- fta_node->table_name->set_range_var(table_name->get_var_name());\r
-\r
-\r
- sgah_qpn *stream_node = new sgah_qpn();\r
- stream_node->table_name = new tablevar_t( ("_fta_"+node_name).c_str());\r
- stream_node->set_node_name( node_name );\r
- stream_node->table_name->set_range_var(table_name->get_var_name());\r
-\r
-\r
- vector< vector<select_element *> *> select_vec;\r
- select_vec.push_back(&(fta_node->select_list)); // only one child\r
-\r
-// Process the gbvars. Split their defining SEs.\r
- for(g=0;g<gb_tbl.size();g++){\r
- bool fta_forbidden = false;\r
- int se_src = SPLIT_FTAVEC_NOTBLVAR;\r
-\r
- scalarexp_t *gbvar_se = split_ftavec_se( gb_tbl.get_def(g),\r
- fta_forbidden, se_src, select_vec, Ext_fcns\r
- );\r
-// if(fta_forbidden) (\r
- if(fta_forbidden || se_src == SPLIT_FTAVEC_NOTBLVAR){\r
- stream_node->gb_tbl.add_gb_var(\r
- gb_tbl.get_name(g),gb_tbl.get_tblvar_ref(g),gbvar_se,gb_tbl.get_reftype(g)\r
- );\r
- }else{\r
- scalarexp_t *new_se=make_fta_se_ref(fta_node->select_list,gbvar_se,0);\r
- stream_node->gb_tbl.add_gb_var(\r
- gb_tbl.get_name(g),gb_tbl.get_tblvar_ref(g),new_se,gb_tbl.get_reftype(g)\r
- );\r
- }\r
- }\r
- stream_node->gb_tbl.set_pattern_info( &gb_tbl);\r
-\r
-// Process the aggregate table.\r
-// Copy to stream, split the SEs.\r
- map<int, scalarexp_t *> hfta_aggr_se; // for rehome\r
- for(a=0;a<aggr_tbl.size();++a){\r
- scalarexp_t *hse;\r
- if(aggr_tbl.is_builtin(a)){\r
- if(aggr_tbl.is_star_aggr(a)){\r
- stream_node->aggr_tbl.add_aggr(aggr_tbl.get_op(a),NULL, false);\r
- hse=scalarexp_t::make_star_aggr(aggr_tbl.get_op(a).c_str());\r
- }else{\r
- bool fta_forbidden = false;\r
- int se_src = SPLIT_FTAVEC_NOTBLVAR;\r
-\r
- scalarexp_t *agg_se = split_ftavec_se( aggr_tbl.get_aggr_se(a),\r
- fta_forbidden, se_src, select_vec, Ext_fcns\r
- );\r
-// if(fta_forbidden) (\r
- if(fta_forbidden || se_src == SPLIT_FTAVEC_NOTBLVAR){\r
- stream_node->aggr_tbl.add_aggr(aggr_tbl.get_op(a), agg_se,false);\r
- hse=scalarexp_t::make_se_aggr(aggr_tbl.get_op(a).c_str(),agg_se);\r
- }else{\r
- scalarexp_t *new_se=make_fta_se_ref(fta_node->select_list,agg_se,0);\r
- stream_node->aggr_tbl.add_aggr(aggr_tbl.get_op(a), new_se,false);\r
- hse=scalarexp_t::make_se_aggr(aggr_tbl.get_op(a).c_str(),new_se);\r
- }\r
- }\r
- hse->set_data_type(aggr_tbl.get_data_type(a));\r
- hse->set_aggr_id(a);\r
- hfta_aggr_se[a]=hse;\r
- }else{\r
- vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(a);\r
- vector<scalarexp_t *> new_opl;\r
- for(o=0;o<opl.size();++o){\r
- bool fta_forbidden = false;\r
- int se_src = SPLIT_FTAVEC_NOTBLVAR;\r
- scalarexp_t *agg_se = split_ftavec_se( opl[o],\r
- fta_forbidden, se_src, select_vec, Ext_fcns\r
- );\r
-// scalarexp_t *agg_se = split_ftavec_se( aggr_tbl.get_aggr_se(a),\r
-// fta_forbidden, se_src, select_vec, Ext_fcns\r
-// );\r
-// if(fta_forbidden) (\r
- if(fta_forbidden || se_src == SPLIT_FTAVEC_NOTBLVAR){\r
- new_opl.push_back(agg_se);\r
- }else{\r
- scalarexp_t *new_se=make_fta_se_ref(fta_node->select_list,agg_se,0);\r
- new_opl.push_back(new_se);\r
- }\r
- }\r
- stream_node->aggr_tbl.add_aggr(aggr_tbl.get_op(a), aggr_tbl.get_fcn_id(a), new_opl, aggr_tbl.get_storage_type(a),false, false,aggr_tbl.has_bailout(a));\r
- hse = new scalarexp_t(aggr_tbl.get_op(a).c_str(),new_opl);\r
- hse->set_data_type(Ext_fcns->get_fcn_dt(aggr_tbl.get_fcn_id(a)));\r
- hse->set_fcn_id(aggr_tbl.get_fcn_id(a));\r
- hse->set_aggr_id(a);\r
- hfta_aggr_se[a]=hse;\r
- }\r
- }\r
-\r
-\r
-// Process the WHERE clause.\r
-// If it is fta-safe AND it refs only fta-safe gbvars,\r
-// then expand the gbvars and put it into the lfta.\r
-// Else, split it into an hfta predicate ref'ing\r
-// se's computed partially in the lfta.\r
-\r
- predicate_t *pr_root;\r
- bool fta_forbidden;\r
- for(p=0;p<where.size();p++){\r
- if(! check_fta_forbidden_pr(where[p]->pr, NULL, Ext_fcns) || contains_gb_pr(where[p]->pr, unsafe_gbvars) ){\r
- pr_root = split_ftavec_pr(where[p]->pr,select_vec,Ext_fcns);\r
- fta_forbidden = true;\r
- }else{\r
- pr_root = dup_pr(where[p]->pr, NULL);\r
- expand_gbvars_pr(pr_root, gb_tbl);\r
- fta_forbidden = false;\r
- }\r
- cnf_elem *cnf_root = new cnf_elem(pr_root);\r
- analyze_cnf(cnf_root);\r
-\r
- if(fta_forbidden){\r
- stream_node->where.push_back(cnf_root);\r
- }else{\r
- fta_node->where.push_back(cnf_root);\r
- }\r
- }\r
-\r
-\r
-// Process the Select clause, rehome it on the\r
-// new defs.\r
- for(s=0;s<select_list.size();s++){\r
- bool fta_forbidden = false;\r
- scalarexp_t *root_se = rehome_fta_se(select_list[s]->se, &hfta_aggr_se);\r
- stream_node->select_list.push_back(\r
- new select_element(root_se, select_list[s]->name));\r
- }\r
-\r
-\r
-// Process the Having clause\r
-\r
-// All of the predicates in the having clause must\r
-// execute in the stream node.\r
-\r
- for(p=0;p<having.size();p++){\r
- predicate_t *pr_root = rehome_fta_pr( having[p]->pr, &hfta_aggr_se);\r
- cnf_elem *cnf_root = new cnf_elem(pr_root);\r
- analyze_cnf(cnf_root);\r
-\r
- stream_node->having.push_back(cnf_root);\r
- }\r
-\r
-// Handle parameters and a few last details.\r
- vector<string> param_names = param_tbl->get_param_names();\r
- int pi;\r
- for(pi=0;pi<param_names.size();pi++){\r
- data_type *dt = param_tbl->get_data_type(param_names[pi]);\r
- fta_node->param_tbl->add_param(param_names[pi],dt->duplicate(),\r
- param_tbl->handle_access(param_names[pi]));\r
- stream_node->param_tbl->add_param(param_names[pi],dt->duplicate(),\r
- param_tbl->handle_access(param_names[pi]));\r
- }\r
-\r
- fta_node->definitions = definitions; fta_node->definitions.erase("_referenced_ifaces");\r
- stream_node->definitions = definitions;\r
-\r
-// Now split by interfaces YYYY\r
- if(ifaces.size() > 1){\r
- for(si=0;si<ifaces.size();++si){\r
- spx_qpn *subq_node = new spx_qpn();\r
-\r
-// Name the subquery\r
- string new_name = "_"+node_name+"_"+ifaces[si].first+"_"+ifaces[si].second;\r
- untaboo(new_name);\r
- subq_node->set_node_name( new_name) ;\r
- sel_names.push_back(subq_node->get_node_name());\r
-\r
-// Assign the table\r
- subq_node->table_name = fta_node->table_name->duplicate();\r
- subq_node->table_name->set_machine(ifaces[si].first);\r
- subq_node->table_name->set_interface(ifaces[si].second);\r
- subq_node->table_name->set_ifq(false);\r
-\r
- for(s=0;s<fta_node->select_list.size();s++){\r
- subq_node->select_list.push_back( dup_select(fta_node->select_list[s], NULL) );\r
- }\r
- for(p=0;p<fta_node->where.size();p++){\r
- predicate_t *new_pr = dup_pr(fta_node->where[p]->pr, NULL);\r
- cnf_elem *new_cnf = new cnf_elem(new_pr);\r
- analyze_cnf(new_cnf);\r
-\r
- subq_node->where.push_back(new_cnf);\r
- }\r
-// Xfer all of the parameters.\r
-// Use existing handle annotations.\r
- vector<string> param_names = param_tbl->get_param_names();\r
- int pi;\r
- for(pi=0;pi<param_names.size();pi++){\r
- data_type *dt = param_tbl->get_data_type(param_names[pi]);\r
- subq_node->param_tbl->add_param(param_names[pi],dt->duplicate(),\r
- param_tbl->handle_access(param_names[pi]));\r
- }\r
- subq_node->definitions = definitions; subq_node->definitions.erase("_referenced_ifaces");\r
- if(subq_node->resolve_if_params(ifdb, this->err_str)){\r
- this->error_code = 3;\r
- return ret_vec;\r
- }\r
-\r
- ret_vec.push_back(subq_node);\r
- }\r
-\r
- mrg_qpn *mrg_node = new mrg_qpn((spx_qpn *)(ret_vec[0]),\r
- fta_node->node_name, sel_names, ifaces, ifdb);\r
- /*\r
- Do not split sources until we are done with optimizations\r
- vector<mrg_qpn *> split_merge = mrg_node->split_sources();\r
- for(i=0;i<split_merge.size();++i){\r
- ret_vec.push_back(split_merge[i]);\r
- }\r
- */\r
- ret_vec.push_back(mrg_node);\r
- ret_vec.push_back(stream_node);\r
- hfta_returned = 1/*split_merge.size()*/+1;\r
-\r
- }else{\r
- fta_node->table_name->set_machine(ifaces[0].first);\r
- fta_node->table_name->set_interface(ifaces[0].second);\r
- fta_node->table_name->set_ifq(false);\r
- if(fta_node->resolve_if_params(ifdb, this->err_str)){\r
- this->error_code = 3;\r
- return ret_vec;\r
- }\r
- ret_vec.push_back(fta_node);\r
- ret_vec.push_back(stream_node);\r
- hfta_returned = 1;\r
- }\r
-\r
-\r
-// ret_vec.push_back(fta_node);\r
-// ret_vec.push_back(stream_node);\r
-\r
-\r
- return(ret_vec);\r
-\r
-}\r
-\r
-\r
-/*\r
- SPLITTING A EQ-TEMPORAL, HASH JOIN OPERATOR\r
-\r
- An JOIN_EQ_HASH_QPN node may reference:\r
- literals, parameters, colrefs, functions, operators\r
- An JOIN_EQ_HASH_QPN node may not reference:\r
- group-by variables, aggregates\r
-\r
- An JOIN_EQ_HASH_QPN node contains\r
- selection list of SEs\r
- where list of CNF predicates, broken into:\r
- prefilter[2]\r
- temporal_eq\r
- hash_eq\r
- postfilter\r
-\r
- Algorithm:\r
- For each tablevar whose source is a PROTOCOL\r
- Create a LFTA for that tablevar\r
- Push as many prefilter[..] predicates to that tablevar as is\r
- possible.\r
- Split the SEs in the select list, and the predicates not\r
- pushed to the LFTA.\r
-\r
-*/\r
-\r
-vector<qp_node *> join_eq_hash_qpn::split_node_for_fta(ext_fcn_list *Ext_fcns, table_list *Schema, int &hfta_returned, ifq_t *ifdb, int n_virtual_ifaces, int hfta_parallelism, int hfta_idx){\r
-\r
- vector<qp_node *> ret_vec;\r
- int f,p,s;\r
-\r
-// If the node reads from streams only, don't split.\r
- bool stream_only = true;\r
- for(f=0;f<from.size();++f){\r
-// int t = Schema->get_table_ref(from[f]->get_schema_name());\r
- int t = from[f]->get_schema_ref();\r
- if(Schema->get_schema_type(t) == PROTOCOL_SCHEMA) stream_only = false;\r
- }\r
- if(stream_only){\r
- hfta_returned = 1;\r
- ret_vec.push_back(this);\r
- return(ret_vec);\r
- }\r
-\r
-\r
-// The HFTA node, it is always returned.\r
-\r
- join_eq_hash_qpn *stream_node = new join_eq_hash_qpn();\r
- for(f=0;f<from.size();++f){\r
-// tablevar_t *tmp_tblvar = new tablevar_t( from[f]->get_interface().c_str(), from[f]->get_schema_name().c_str());\r
- tablevar_t *tmp_tblvar = from[f]->duplicate();\r
-// tmp_tblvar->set_range_var(from[f]->get_var_name());\r
-\r
- stream_node->from.push_back(tmp_tblvar);\r
- }\r
- stream_node->set_node_name(node_name);\r
-\r
-// Create spx (selection) children for each PROTOCOL source.\r
- vector<spx_qpn *> child_vec;\r
- vector< vector<select_element *> *> select_vec;\r
- for(f=0;f<from.size();++f){\r
-// int t = Schema->get_table_ref(from[f]->get_schema_name());\r
- int t = from[f]->get_schema_ref();\r
- if(Schema->get_schema_type(t) == PROTOCOL_SCHEMA){\r
- spx_qpn *child_qpn = new spx_qpn();\r
- sprintf(tmpstr,"_fta_%d_%s",f,node_name.c_str());\r
- child_qpn->set_node_name(string(tmpstr));\r
- child_qpn->table_name = new tablevar_t(\r
- from[f]->get_interface().c_str(), from[f]->get_schema_name().c_str(), from[f]->get_ifq());\r
- child_qpn->table_name->set_range_var(from[f]->get_var_name());\r
-\r
- child_vec.push_back(child_qpn);\r
- select_vec.push_back(&(child_qpn->select_list));\r
-\r
-// Update the stream's FROM clause to read from this child\r
- stream_node->from[f]->set_interface("");\r
- stream_node->from[f]->set_schema(tmpstr);\r
- }else{\r
- child_vec.push_back(NULL);\r
- select_vec.push_back(NULL);\r
- }\r
- }\r
-\r
-// Push lfta-safe prefilter to the lfta\r
-// TODO: I'm not copying the preds, I dont *think* it will be a problem.\r
- predicate_t *pr_root;\r
-\r
- for(f=0;f<from.size();++f){\r
- vector<cnf_elem *> pred_vec = prefilter[f];\r
- if(child_vec[f] != NULL){\r
- for(p=0;p<pred_vec.size();++p){\r
- if(check_fta_forbidden_pr(pred_vec[p]->pr,NULL, Ext_fcns)){\r
- child_vec[f]->where.push_back(pred_vec[p]);\r
- }else{\r
- pr_root = split_ftavec_pr(pred_vec[p]->pr,select_vec,Ext_fcns);\r
- cnf_elem *cnf_root = new cnf_elem(pr_root);\r
- analyze_cnf(cnf_root);\r
- stream_node->prefilter[f].push_back(cnf_root);\r
- }\r
- }\r
- }else{\r
- for(p=0;p<pred_vec.size();++p){\r
- stream_node->prefilter[f].push_back(pred_vec[p]);\r
- }\r
- }\r
-\r
- }\r
-\r
-// Process the other predicates\r
- for(p=0;p<temporal_eq.size();++p){\r
- pr_root = split_ftavec_pr(temporal_eq[p]->pr,select_vec,Ext_fcns);\r
- cnf_elem *cnf_root = new cnf_elem(pr_root);\r
- analyze_cnf(cnf_root);\r
- stream_node->temporal_eq.push_back(cnf_root);\r
- }\r
- for(p=0;p<hash_eq.size();++p){\r
- pr_root = split_ftavec_pr(hash_eq[p]->pr,select_vec,Ext_fcns);\r
- cnf_elem *cnf_root = new cnf_elem(pr_root);\r
- analyze_cnf(cnf_root);\r
- stream_node->hash_eq.push_back(cnf_root);\r
- }\r
- for(p=0;p<postfilter.size();++p){\r
- pr_root = split_ftavec_pr(postfilter[p]->pr,select_vec,Ext_fcns);\r
- cnf_elem *cnf_root = new cnf_elem(pr_root);\r
- analyze_cnf(cnf_root);\r
- stream_node->postfilter.push_back(cnf_root);\r
- }\r
-\r
-// Process the SEs\r
- for(s=0;s<select_list.size();s++){\r
- bool fta_forbidden = false;\r
- int se_src = SPLIT_FTAVEC_NOTBLVAR;\r
- scalarexp_t *root_se = split_ftavec_se( select_list[s]->se,\r
- fta_forbidden, se_src, select_vec, Ext_fcns\r
- );\r
- if(fta_forbidden || !is_PROTOCOL_source(se_src, select_vec)){\r
- stream_node->select_list.push_back(\r
- new select_element(root_se, select_list[s]->name) );\r
- }else{\r
- scalarexp_t *new_se=make_fta_se_ref(select_vec,root_se,se_src);\r
- stream_node->select_list.push_back(\r
- new select_element(new_se, select_list[s]->name)\r
- );\r
- }\r
- }\r
-\r
-\r
-// I need to "rehome" the colrefs -- make the annotations in the colrefs\r
-// agree with their tablevars.\r
- for(f=0;f<child_vec.size();++f){\r
- if(child_vec[f]!=NULL){\r
- vector<tablevar_t *> fm; fm.push_back(child_vec[f]->table_name);\r
-\r
- for(s=0;s<child_vec[f]->select_list.size();++s)\r
- bind_colref_se(child_vec[f]->select_list[s]->se, fm,0,0);\r
- for(p=0;p<child_vec[f]->where.size();++p)\r
-// bind_colref_pr(child_vec[f]->where[p]->pr, fm,f,0);\r
- bind_colref_pr(child_vec[f]->where[p]->pr, fm,0,0);\r
- }\r
- }\r
-\r
-// rehome the colrefs in the hfta node.\r
- for(f=0;f<stream_node->from.size();++f){\r
- stream_node->where.clear();\r
- for(s=0;s<stream_node->from.size();++s){\r
- for(p=0;p<stream_node->prefilter[s].size();++p){\r
- bind_colref_pr((stream_node->prefilter[s])[p]->pr,stream_node->from,f,f);\r
- }\r
- }\r
- for(p=0;p<stream_node->temporal_eq.size();++p){\r
- bind_colref_pr(stream_node->temporal_eq[p]->pr,stream_node->from,f,f);\r
- }\r
- for(p=0;p<stream_node->hash_eq.size();++p){\r
- bind_colref_pr(stream_node->hash_eq[p]->pr,stream_node->from,f,f);\r
- }\r
- for(p=0;p<stream_node->postfilter.size();++p){\r
- bind_colref_pr(stream_node->postfilter[p]->pr,stream_node->from,f,f);\r
- }\r
- for(s=0;s<stream_node->select_list.size();++s){\r
- bind_colref_se(stream_node->select_list[s]->se,stream_node->from,f,f);\r
- }\r
- }\r
-\r
-// Rebuild the WHERE clause\r
- stream_node->where.clear();\r
- for(s=0;s<stream_node->from.size();++s){\r
- for(p=0;p<stream_node->prefilter[s].size();++p){\r
- stream_node->where.push_back((stream_node->prefilter[s])[p]);\r
- }\r
- }\r
- for(p=0;p<stream_node->temporal_eq.size();++p){\r
- stream_node->where.push_back(stream_node->temporal_eq[p]);\r
- }\r
- for(p=0;p<stream_node->hash_eq.size();++p){\r
- stream_node->where.push_back(stream_node->hash_eq[p]);\r
- }\r
- for(p=0;p<stream_node->postfilter.size();++p){\r
- stream_node->where.push_back(stream_node->postfilter[p]);\r
- }\r
-\r
-\r
-// Build the return list\r
- vector<qp_node *> hfta_nodes;\r
- hfta_returned = 1;\r
- for(f=0;f<from.size();++f){\r
- if(child_vec[f] != NULL){\r
- spx_qpn *c_node = child_vec[f];\r
- vector<pair<string, string> > ifaces = get_ifaces(c_node->table_name, ifdb, n_virtual_ifaces, hfta_parallelism, hfta_idx);\r
- if (ifaces.empty()) {\r
- fprintf(stderr,"INTERNAL ERROR in join_eq_hash_qpn::split_node_for_fta - empty interface set\n");\r
- exit(1);\r
- }\r
-\r
- if(ifaces.size() == 1){\r
- c_node->table_name->set_machine(ifaces[0].first);\r
- c_node->table_name->set_interface(ifaces[0].second);\r
- c_node->table_name->set_ifq(false);\r
- if(c_node->resolve_if_params(ifdb, this->err_str)){\r
- this->error_code = 3;\r
- return ret_vec;\r
- }\r
- ret_vec.push_back(c_node);\r
- }else{\r
- vector<string> sel_names;\r
- int si;\r
- for(si=0;si<ifaces.size();++si){\r
- spx_qpn *subq_node = new spx_qpn();\r
-\r
-// Name the subquery\r
- string new_name = "_"+c_node->node_name+"_"+ifaces[si].first+"_"+ifaces[si].second;\r
- untaboo(new_name);\r
- subq_node->set_node_name( new_name) ;\r
- sel_names.push_back(subq_node->get_node_name());\r
-\r
-// Assign the table\r
- subq_node->table_name = c_node->table_name->duplicate();\r
- subq_node->table_name->set_machine(ifaces[si].first);\r
- subq_node->table_name->set_interface(ifaces[si].second);\r
- subq_node->table_name->set_ifq(false);\r
-\r
- for(s=0;s<c_node->select_list.size();s++){\r
- subq_node->select_list.push_back(dup_select(c_node->select_list[s], NULL));\r
- }\r
- for(p=0;p<c_node->where.size();p++){\r
- predicate_t *new_pr = dup_pr(c_node->where[p]->pr, NULL);\r
- cnf_elem *new_cnf = new cnf_elem(new_pr);\r
- analyze_cnf(new_cnf);\r
-\r
-printf("table name is %s\n",subq_node->table_name->to_string().c_str());\r
- subq_node->where.push_back(new_cnf);\r
- }\r
-// Xfer all of the parameters.\r
-// Use existing handle annotations.\r
-// vector<string> param_names = param_tbl->get_param_names();\r
-// int pi;\r
-// for(pi=0;pi<param_names.size();pi++){\r
-// data_type *dt = param_tbl->get_data_type(param_names[pi]);\r
-// subq_node->param_tbl->add_param(param_names[pi],dt->duplicate(),\r
-// param_tbl->handle_access(param_names[pi]));\r
-// }\r
-// subq_node->definitions = definitions;\r
-\r
- if(subq_node->resolve_if_params(ifdb, this->err_str)){\r
- this->error_code = 3;\r
- return ret_vec;\r
- }\r
-\r
- ret_vec.push_back(subq_node);\r
- }\r
- int lpos = ret_vec.size()-1 ;\r
- mrg_qpn *mrg_node = new mrg_qpn((spx_qpn *)(ret_vec[lpos]),c_node->node_name,sel_names, ifaces, ifdb);\r
- /*\r
- Do not split sources until we are done with optimizations\r
- vector<mrg_qpn *> split_merge = mrg_node->split_sources();\r
- int i;\r
- for(i=0;i<split_merge.size();++i){\r
- hfta_nodes.push_back(split_merge[i]);\r
- }\r
- */\r
- hfta_nodes.push_back(mrg_node);\r
- }\r
- }\r
- }\r
- int i;\r
- for(i=0;i<hfta_nodes.size();++i) ret_vec.push_back(hfta_nodes[i]);\r
- ret_vec.push_back(stream_node);\r
- hfta_returned = hfta_nodes.size()+1;\r
-\r
-// Currently : assume that the stream receives all parameters\r
-// and parameter updates, incorporates them, then passes\r
-// all of the parameters to the FTA.\r
-// This will need to change (tables, fta-unsafe types. etc.)\r
-\r
-// I will pass on the use_handle_access marking, even\r
-// though the fcn call that requires handle access might\r
-// exist in only one of the parts of the query.\r
-// Parameter manipulation and handle access determination will\r
-// need to be revisited anyway.\r
- vector<string> param_names = param_tbl->get_param_names();\r
- int pi;\r
- for(pi=0;pi<param_names.size();pi++){\r
- int ri;\r
- data_type *dt = param_tbl->get_data_type(param_names[pi]);\r
- for(ri=0;ri<ret_vec.size();++ri){\r
- ret_vec[ri]->param_tbl->add_param(param_names[pi],dt->duplicate(),\r
- param_tbl->handle_access(param_names[pi]));\r
- ret_vec[ri]->definitions = definitions; ret_vec[ri]->definitions.erase("_referenced_ifaces");\r
- }\r
- }\r
-\r
-\r
-\r
- return(ret_vec);\r
-\r
-}\r
-\r
-\r
-/////////////////////////////////////////////////////////////\r
-//// extract_opview\r
-\r
-// Common processing\r
-int process_opview(tablevar_t *fmtbl, int pos, string node_name,\r
- table_list *Schema,\r
- vector<query_node *> &qnodes,\r
- opview_set &opviews,\r
- vector<table_exp_t *> &ret, string rootnm, string silo_nm){\r
-\r
- int s,f,q,m;\r
-\r
- int schref = fmtbl->get_schema_ref();\r
- if(schref <= 0)\r
- return 0;\r
-\r
- if(Schema->get_schema_type(schref) == OPERATOR_VIEW_SCHEMA){\r
- opview_entry *opv = new opview_entry();\r
- opv->parent_qname = node_name;\r
- opv->root_name = rootnm;\r
- opv->view_name = fmtbl->get_schema_name();\r
- opv->pos = pos;\r
- sprintf(tmpstr,"%s_UDOP%d_%s",node_name.c_str(),pos,opv->view_name.c_str());\r
- opv->udop_alias = tmpstr;\r
- fmtbl->set_udop_alias(opv->udop_alias);\r
-\r
- opv->exec_fl = Schema->get_op_prop(schref, string("file"));\r
- opv->liveness_timeout = atoi(Schema->get_op_prop(schref, string("liveness_timeout")).c_str());\r
-\r
- vector<subquery_spec *> subq = Schema->get_subqueryspecs(schref);\r
- for(s=0;s<subq.size();++s){\r
-// Validate that the fields match.\r
- subquery_spec *sqs = subq[s];\r
- vector<field_entry *> flds = Schema->get_fields(sqs->name+silo_nm);\r
- if(flds.size() == 0){\r
- fprintf(stderr,"INTERNAL ERROR: subquery %s of view %s not found in Schema.\n",sqs->name.c_str(), opv->view_name.c_str());\r
- return(1);\r
- }\r
- if(flds.size() < sqs->types.size()){\r
- fprintf(stderr,"ERROR: subquery %s of view %s does not have enough fields (%lu found, %lu expected).\n",sqs->name.c_str(), opv->view_name.c_str(),flds.size(), sqs->types.size());\r
- return(1);\r
- }\r
- bool failed = false;\r
- for(f=0;f<sqs->types.size();++f){\r
- data_type dte(sqs->types[f],sqs->modifiers[f]);\r
- data_type dtf(flds[f]->get_type(),flds[f]->get_modifier_list());\r
- if(! dte.subsumes_type(&dtf) ){\r
- fprintf(stderr,"ERROR: subquery %s of view %s does not have the correct type for field %d (%s found, %s expected).\n",sqs->name.c_str(), opv->view_name.c_str(),f,dtf.to_string().c_str(), dte.to_string().c_str());\r
- failed = true;\r
- }\r
-/*\r
- if(dte.is_temporal() && (dte.get_temporal() != dtf.get_temporal()) ){\r
- string pstr = dte.get_temporal_string();\r
- fprintf(stderr,"ERROR: subquery %s of view %s does not have the expected temporal value %s of field %d.\n",sqs->name.c_str(), opv->view_name.c_str(),pstr.c_str(),f);\r
- failed = true;\r
- }\r
-*/\r
- }\r
- if(failed)\r
- return(1);\r
-/// Validation done, find the subquery, make a copy of the\r
-/// parse tree, and add it to the return list.\r
- for(q=0;q<qnodes.size();++q)\r
- if(qnodes[q]->name == sqs->name)\r
- break;\r
- if(q==qnodes.size()){\r
- fprintf(stderr,"INTERNAL ERROR: subquery %s of view %s not found in list of query names.\n",sqs->name.c_str(), opv->view_name.c_str());\r
- return(1);\r
- }\r
-\r
- table_exp_t *newq = dup_table_exp(qnodes[q]->parse_tree);\r
- sprintf(tmpstr,"%s_OP%d_%s_SUBQ%d",node_name.c_str(),pos,opv->view_name.c_str(),s);\r
- string newq_name = tmpstr;\r
- newq->nmap["query_name"] = newq_name;\r
- ret.push_back(newq);\r
- opv->subq_names.push_back(newq_name);\r
- }\r
- fmtbl->set_opview_idx(opviews.append(opv));\r
- }\r
-\r
- return 0;\r
-}\r
-\r
-vector<table_exp_t *> spx_qpn::extract_opview(table_list *Schema, vector<query_node *> &qnodes, opview_set &opviews, string rootnm, string silo_name){\r
- vector<table_exp_t *> ret;\r
-\r
- int retval = process_opview(table_name,0,node_name,\r
- Schema,qnodes,opviews,ret, rootnm, silo_name);\r
- if(retval) exit(1);\r
- return(ret);\r
-}\r
-\r
-\r
-vector<table_exp_t *> sgah_qpn::extract_opview(table_list *Schema, vector<query_node *> &qnodes, opview_set &opviews, string rootnm, string silo_name){\r
- vector<table_exp_t *> ret;\r
-\r
- int retval = process_opview(table_name,0,node_name,\r
- Schema,qnodes,opviews,ret, rootnm, silo_name);\r
- if(retval) exit(1);\r
- return(ret);\r
-}\r
-\r
-vector<table_exp_t *> rsgah_qpn::extract_opview(table_list *Schema, vector<query_node *> &qnodes, opview_set &opviews, string rootnm, string silo_name){\r
- vector<table_exp_t *> ret;\r
-\r
- int retval = process_opview(table_name,0,node_name,\r
- Schema,qnodes,opviews,ret, rootnm, silo_name);\r
- if(retval) exit(1);\r
- return(ret);\r
-}\r
-\r
-\r
-vector<table_exp_t *> sgahcwcb_qpn::extract_opview(table_list *Schema, vector<query_node *> &qnodes, opview_set &opviews, string rootnm, string silo_name){\r
- vector<table_exp_t *> ret;\r
-\r
- int retval = process_opview(table_name,0,node_name,\r
- Schema,qnodes,opviews,ret, rootnm, silo_name);\r
- if(retval) exit(1);\r
- return(ret);\r
-}\r
-\r
-\r
-\r
-vector<table_exp_t *> mrg_qpn::extract_opview(table_list *Schema, vector<query_node *> &qnodes, opview_set &opviews, string rootnm, string silo_name){\r
- vector<table_exp_t *> ret;\r
- int f;\r
- for(f=0;f<fm.size();++f){\r
- int retval = process_opview(fm[f],f,node_name,\r
- Schema,qnodes,opviews,ret, rootnm, silo_name);\r
- if(retval) exit(1);\r
- }\r
- return(ret);\r
-}\r
-\r
-\r
-\r
-\r
-vector<table_exp_t *> join_eq_hash_qpn::extract_opview(table_list *Schema, vector<query_node *> &qnodes, opview_set &opviews, string rootnm, string silo_name){\r
- vector<table_exp_t *> ret;\r
- int f;\r
- for(f=0;f<from.size();++f){\r
- int retval = process_opview(from[f],f,node_name,\r
- Schema,qnodes,opviews,ret, rootnm, silo_name);\r
- if(retval) exit(1);\r
- }\r
- return(ret);\r
-}\r
-\r
-vector<table_exp_t *> filter_join_qpn::extract_opview(table_list *Schema, vector<query_node *> &qnodes, opview_set &opviews, string rootnm, string silo_name){\r
- vector<table_exp_t *> ret;\r
- int f;\r
- for(f=0;f<from.size();++f){\r
- int retval = process_opview(from[f],f,node_name,\r
- Schema,qnodes,opviews,ret, rootnm, silo_name);\r
- if(retval) exit(1);\r
- }\r
- return(ret);\r
-}\r
-\r
-\r
-\r
-//////////////////////////////////////////////////////////////////\r
-//////////////////////////////////////////////////////////////////\r
-/////// Additional methods\r
-\r
-\r
-\r
-//////////////////////////////////////////////////////////////////\r
-// Get schema of operator output\r
-\r
-table_def *mrg_qpn::get_fields(){\r
- return(table_layout);\r
-}\r
-\r
-\r
-table_def *spx_qpn::get_fields(){\r
- return(create_attributes(node_name, select_list));\r
-}\r
-\r
-table_def *sgah_qpn::get_fields(){\r
- return(create_attributes(node_name, select_list));\r
-}\r
-\r
-table_def *rsgah_qpn::get_fields(){\r
- return(create_attributes(node_name, select_list));\r
-}\r
-\r
-table_def *sgahcwcb_qpn::get_fields(){\r
- return(create_attributes(node_name, select_list));\r
-}\r
-\r
-table_def *filter_join_qpn::get_fields(){\r
- return(create_attributes(node_name, select_list));\r
-}\r
-\r
-\r
-table_def *join_eq_hash_qpn::get_fields(){\r
- int i, h, s, t;\r
-\r
-// First, gather temporal colrefs and SEs.\r
- map<col_id, temporal_type> temporal_cids;\r
- vector<scalarexp_t *> temporal_se;\r
- for(h=0;h<temporal_eq.size();++h){\r
- scalarexp_t *sel = temporal_eq[h]->pr->get_left_se();\r
- scalarexp_t *ser = temporal_eq[h]->pr->get_right_se();\r
-\r
- if(sel->get_operator_type() == SE_COLREF){\r
- col_id tcol(sel->get_colref());\r
- if(temporal_cids.count(tcol) == 0){\r
- temporal_cids[tcol] = sel->get_data_type()->get_temporal();\r
- }\r
- }else{\r
- temporal_se.push_back(sel);\r
- }\r
-\r
- if(ser->get_operator_type() == SE_COLREF){\r
- col_id tcol(ser->get_colref());\r
- if(temporal_cids.count(tcol) == 0){\r
- temporal_cids[tcol] = ser->get_data_type()->get_temporal();\r
- }\r
- }else{\r
- temporal_se.push_back(ser);\r
- }\r
- }\r
-\r
-// Mark select elements as nontemporal, then deduce which\r
-// ones are temporal.\r
- for(s=0;s<select_list.size();++s){\r
- select_list[s]->se->get_data_type()->set_temporal(\r
- compute_se_temporal(select_list[s]->se, temporal_cids)\r
- );\r
-// Second chance if it is an exact match to an SE.\r
-// for(s=0;s<select_list.size();++s){\r
- if(! select_list[s]->se->get_data_type()->is_temporal() ){\r
- for(t=0;t<temporal_se.size();++t){\r
- if(is_equivalent_se(temporal_se[t], select_list[s]->se)){\r
- select_list[s]->se->get_data_type()->set_temporal(\r
- temporal_se[t]->get_data_type()->get_temporal()\r
- );\r
- }\r
- }\r
- }\r
-// }\r
- }\r
-\r
-// If there is an outer join, verify that\r
-// the temporal attributes are actually temporal.\r
-// NOTE: this code must be synchronized with the\r
-// equivalence finding in join_eq_hash_qpn::generate_functor\r
-// (and also, the join_eq_hash_qpn constructor)\r
- if(from[0]->get_property() || from[1]->get_property()){\r
- set<string> l_equiv, r_equiv;\r
- for(i=0;i<temporal_eq.size();i++){\r
- scalarexp_t *lse = temporal_eq[i]->pr->get_left_se();\r
- scalarexp_t *rse = temporal_eq[i]->pr->get_right_se();\r
- if(lse->get_operator_type()==SE_COLREF){\r
- l_equiv.insert(lse->get_colref()->get_field());\r
- }\r
- if(rse->get_operator_type()==SE_COLREF){\r
- r_equiv.insert(rse->get_colref()->get_field());\r
- }\r
- }\r
-\r
- for(s=0;s<select_list.size();++s){\r
- if(select_list[s]->se->get_data_type()->is_temporal()){\r
- col_id_set cid_set;\r
- col_id_set::iterator ci;\r
- bool failed = false;\r
- gather_se_col_ids(select_list[s]->se,cid_set, NULL);\r
- for(ci=cid_set.begin();ci!=cid_set.end();++ci){\r
- if((*ci).tblvar_ref == 0){\r
- if(from[0]->get_property()){\r
- if(l_equiv.count((*ci).field) == 0){\r
- failed = true;\r
- }\r
- }\r
- }else{\r
- if(from[1]->get_property()){\r
- if(r_equiv.count((*ci).field) == 0){\r
- failed = true;\r
- }\r
- }\r
- }\r
- }\r
- if(failed){\r
- select_list[s]->se->get_data_type()->reset_temporal();\r
- }\r
- }\r
- }\r
- }\r
-\r
-\r
- return create_attributes(node_name, select_list);\r
-}\r
-\r
-\r
-\r
-//-----------------------------------------------------------------\r
-// get output tables\r
-\r
-\r
-// Get tablevar_t names of input and output tables\r
-\r
-// output_file_qpn::output_file_qpn(){source_op_name = ""; }\r
- vector<tablevar_t *> output_file_qpn::get_input_tbls(){\r
- return(fm);\r
- }\r
-\r
- vector<tablevar_t *> mrg_qpn::get_input_tbls(){\r
- return(fm);\r
- }\r
-\r
- vector<tablevar_t *> spx_qpn::get_input_tbls(){\r
- vector<tablevar_t *> retval(1,table_name);\r
- return(retval);\r
- }\r
-\r
- vector<tablevar_t *> sgah_qpn::get_input_tbls(){\r
- vector<tablevar_t *> retval(1,table_name);\r
- return(retval);\r
- }\r
-\r
- vector<tablevar_t *> rsgah_qpn::get_input_tbls(){\r
- vector<tablevar_t *> retval(1,table_name);\r
- return(retval);\r
- }\r
-\r
- vector<tablevar_t *> sgahcwcb_qpn::get_input_tbls(){\r
- vector<tablevar_t *> retval(1,table_name);\r
- return(retval);\r
- }\r
-\r
- vector<tablevar_t *> join_eq_hash_qpn::get_input_tbls(){\r
- return(from);\r
- }\r
-\r
- vector<tablevar_t *> filter_join_qpn::get_input_tbls(){\r
- return(from);\r
- }\r
-\r
-//-----------------------------------------------------------------\r
-// get output tables\r
-\r
-\r
-// This does not make sense, this fcn returns the output table *name*,\r
-// not its schema, and then there is another fcn to rturn the schema.\r
- vector<tablevar_t *> output_file_qpn::get_output_tbls(){\r
- vector<tablevar_t *> retval(1,new tablevar_t(node_name.c_str()));\r
- return(retval);\r
- }\r
-\r
- vector<tablevar_t *> mrg_qpn::get_output_tbls(){\r
- vector<tablevar_t *> retval(1,new tablevar_t(node_name.c_str()));\r
- return(retval);\r
- }\r
-\r
- vector<tablevar_t *> spx_qpn::get_output_tbls(){\r
- vector<tablevar_t *> retval(1,new tablevar_t(node_name.c_str()));\r
- return(retval);\r
- }\r
-\r
- vector<tablevar_t *> sgah_qpn::get_output_tbls(){\r
- vector<tablevar_t *> retval(1,new tablevar_t(node_name.c_str()));\r
- return(retval);\r
- }\r
-\r
- vector<tablevar_t *> rsgah_qpn::get_output_tbls(){\r
- vector<tablevar_t *> retval(1,new tablevar_t(node_name.c_str()));\r
- return(retval);\r
- }\r
-\r
- vector<tablevar_t *> sgahcwcb_qpn::get_output_tbls(){\r
- vector<tablevar_t *> retval(1,new tablevar_t(node_name.c_str()));\r
- return(retval);\r
- }\r
-\r
- vector<tablevar_t *> join_eq_hash_qpn::get_output_tbls(){\r
- vector<tablevar_t *> retval(1,new tablevar_t(node_name.c_str()));\r
- return(retval);\r
- }\r
-\r
- vector<tablevar_t *> filter_join_qpn::get_output_tbls(){\r
- vector<tablevar_t *> retval(1,new tablevar_t(node_name.c_str()));\r
- return(retval);\r
- }\r
-\r
-\r
-\r
-//-----------------------------------------------------------------\r
-// Bind to schema\r
-\r
-// Associate colrefs with this schema.\r
-// Also, use this opportunity to create table_layout (the output schema).\r
-// If the output schema is ever needed before\r
-void mrg_qpn::bind_to_schema(table_list *Schema){\r
- int t;\r
- for(t=0;t<fm.size();++t){\r
- int tblref = Schema->get_table_ref(fm[t]->get_schema_name());\r
- if(tblref>=0)\r
- fm[t]->set_schema_ref(tblref );\r
- }\r
-\r
-// Here I assume that the colrefs have been reorderd\r
-// during analysis so that mvars line up with fm.\r
- mvars[0]->set_schema_ref(fm[0]->get_schema_ref());\r
- mvars[1]->set_schema_ref(fm[1]->get_schema_ref());\r
-\r
-\r
-}\r
-\r
-\r
-\r
-// Associate colrefs in SEs with this schema.\r
-void spx_qpn::bind_to_schema(table_list *Schema){\r
-// Bind the tablevars in the From clause to the Schema\r
-// (it might have changed from analysis time)\r
- int t = Schema->get_table_ref(table_name->get_schema_name() );\r
- if(t>=0)\r
- table_name->set_schema_ref(t );\r
-\r
-// Get the "from" clause\r
- tablevar_list_t fm(table_name);\r
-\r
-// Bind all SEs to this schema\r
- int p;\r
- for(p=0;p<where.size();++p){\r
- bind_to_schema_pr(where[p]->pr, &fm, Schema);\r
- }\r
- int s;\r
- for(s=0;s<select_list.size();++s){\r
- bind_to_schema_se(select_list[s]->se, &fm, Schema);\r
- }\r
-\r
-// Collect set of tuples referenced in this HFTA\r
-// input, internal, or output.\r
-\r
-}\r
-\r
-col_id_set spx_qpn::get_colrefs(bool ext_fcns_only,table_list *Schema){\r
- col_id_set retval, tmp_cset;\r
- int p;\r
- for(p=0;p<where.size();++p){\r
- gather_pr_col_ids(where[p]->pr, tmp_cset, NULL);\r
- }\r
- int s;\r
- for(s=0;s<select_list.size();++s){\r
- gather_se_col_ids(select_list[s]->se, tmp_cset, NULL);\r
- }\r
- col_id_set::iterator cisi;\r
- if(ext_fcns_only){\r
- for(cisi=tmp_cset.begin();cisi!=tmp_cset.end();++cisi){\r
- field_entry *fe = Schema->get_field((*cisi).schema_ref, (*cisi).field);\r
- if(fe->get_unpack_fcns().size()>0)\r
- retval.insert((*cisi));\r
- }\r
- return retval;\r
- }\r
-\r
- return tmp_cset;\r
-}\r
-\r
-col_id_set filter_join_qpn::get_colrefs(bool ext_fcns_only,table_list *Schema){\r
- col_id_set retval, tmp_cset;\r
- int p;\r
- for(p=0;p<where.size();++p){\r
- gather_pr_col_ids(where[p]->pr, tmp_cset, NULL);\r
- }\r
- int s;\r
- for(s=0;s<select_list.size();++s){\r
- gather_se_col_ids(select_list[s]->se, tmp_cset, NULL);\r
- }\r
- col_id_set::iterator cisi;\r
- if(ext_fcns_only){\r
- for(cisi=tmp_cset.begin();cisi!=tmp_cset.end();++cisi){\r
- field_entry *fe = Schema->get_field((*cisi).schema_ref, (*cisi).field);\r
- if(fe->get_unpack_fcns().size()>0)\r
- retval.insert((*cisi));\r
- }\r
- return retval;\r
- }\r
-\r
- return tmp_cset;\r
-}\r
-\r
-\r
-\r
-// Associate colrefs in SEs with this schema.\r
-void join_eq_hash_qpn::bind_to_schema(table_list *Schema){\r
-// Bind the tablevars in the From clause to the Schema\r
-// (it might have changed from analysis time)\r
- int f;\r
- for(f=0;f<from.size();++f){\r
- string snm = from[f]->get_schema_name();\r
- int tbl_ref = Schema->get_table_ref(snm);\r
- if(tbl_ref >= 0)\r
- from[f]->set_schema_ref(tbl_ref);\r
- }\r
-\r
-// Bind all SEs to this schema\r
- tablevar_list_t fm(from);\r
-\r
- int p;\r
- for(p=0;p<where.size();++p){\r
- bind_to_schema_pr(where[p]->pr, &fm, Schema);\r
- }\r
- int s;\r
- for(s=0;s<select_list.size();++s){\r
- bind_to_schema_se(select_list[s]->se, &fm, Schema);\r
- }\r
-\r
-// Collect set of tuples referenced in this HFTA\r
-// input, internal, or output.\r
-\r
-}\r
-\r
-void filter_join_qpn::bind_to_schema(table_list *Schema){\r
-// Bind the tablevars in the From clause to the Schema\r
-// (it might have changed from analysis time)\r
- int f;\r
- for(f=0;f<from.size();++f){\r
- string snm = from[f]->get_schema_name();\r
- int tbl_ref = Schema->get_table_ref(snm);\r
- if(tbl_ref >= 0)\r
- from[f]->set_schema_ref(tbl_ref);\r
- }\r
-\r
-// Bind all SEs to this schema\r
- tablevar_list_t fm(from);\r
-\r
- int p;\r
- for(p=0;p<where.size();++p){\r
- bind_to_schema_pr(where[p]->pr, &fm, Schema);\r
- }\r
- int s;\r
- for(s=0;s<select_list.size();++s){\r
- bind_to_schema_se(select_list[s]->se, &fm, Schema);\r
- }\r
-\r
-// Collect set of tuples referenced in this HFTA\r
-// input, internal, or output.\r
-\r
-}\r
-\r
-\r
-\r
-\r
-void sgah_qpn::bind_to_schema(table_list *Schema){\r
-// Bind the tablevars in the From clause to the Schema\r
-// (it might have changed from analysis time)\r
-\r
-\r
- int t = Schema->get_table_ref(table_name->get_schema_name() );\r
- if(t>=0)\r
- table_name->set_schema_ref(t );\r
-\r
-// Get the "from" clause\r
- tablevar_list_t fm(table_name);\r
-\r
-\r
-\r
-// Bind all SEs to this schema\r
- int p;\r
- for(p=0;p<where.size();++p){\r
- bind_to_schema_pr(where[p]->pr, &fm, Schema);\r
- }\r
- for(p=0;p<having.size();++p){\r
- bind_to_schema_pr(having[p]->pr, &fm, Schema);\r
- }\r
- int s;\r
- for(s=0;s<select_list.size();++s){\r
- bind_to_schema_se(select_list[s]->se, &fm, Schema);\r
- }\r
- int g;\r
- for(g=0;g<gb_tbl.size();++g){\r
- bind_to_schema_se(gb_tbl.get_def(g), &fm, Schema);\r
- }\r
- int a;\r
- for(a=0;a<aggr_tbl.size();++a){\r
- if(aggr_tbl.is_builtin(a)){\r
- bind_to_schema_se(aggr_tbl.get_aggr_se(a), &fm, Schema);\r
- }else{\r
- vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(a);\r
- int o;\r
- for(o=0;o<opl.size();++o){\r
- bind_to_schema_se(opl[o],&fm,Schema);\r
- }\r
- }\r
- }\r
-}\r
-\r
-col_id_set sgah_qpn::get_colrefs(bool ext_fcns_only,table_list *Schema){\r
- col_id_set retval, tmp_cset;\r
- int p;\r
- for(p=0;p<where.size();++p){\r
- gather_pr_col_ids(where[p]->pr, tmp_cset, &gb_tbl);\r
- }\r
- int g;\r
- for(g=0;g<gb_tbl.size();++g){\r
- gather_se_col_ids(gb_tbl.get_def(g), tmp_cset, &gb_tbl);\r
- }\r
- int a;\r
- for(a=0;a<aggr_tbl.size();++a){\r
- if(aggr_tbl.is_builtin(a)){\r
- gather_se_col_ids(aggr_tbl.get_aggr_se(a), tmp_cset, &gb_tbl);\r
- }else{\r
- vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(a);\r
- int o;\r
- for(o=0;o<opl.size();++o){\r
- gather_se_col_ids(opl[o], tmp_cset, &gb_tbl);\r
- }\r
- }\r
- }\r
-\r
- col_id_set::iterator cisi;\r
- if(ext_fcns_only){\r
- for(cisi=tmp_cset.begin();cisi!=tmp_cset.end();++cisi){\r
- field_entry *fe = Schema->get_field((*cisi).schema_ref, (*cisi).field);\r
- if(fe->get_unpack_fcns().size()>0)\r
- retval.insert((*cisi));\r
- }\r
- return retval;\r
- }\r
-\r
- return tmp_cset;\r
-}\r
-\r
-\r
-void rsgah_qpn::bind_to_schema(table_list *Schema){\r
-// Bind the tablevars in the From clause to the Schema\r
-// (it might have changed from analysis time)\r
- int t = Schema->get_table_ref(table_name->get_schema_name() );\r
- if(t>=0)\r
- table_name->set_schema_ref(t );\r
-\r
-// Get the "from" clause\r
- tablevar_list_t fm(table_name);\r
-\r
-// Bind all SEs to this schema\r
- int p;\r
- for(p=0;p<where.size();++p){\r
- bind_to_schema_pr(where[p]->pr, &fm, Schema);\r
- }\r
- for(p=0;p<having.size();++p){\r
- bind_to_schema_pr(having[p]->pr, &fm, Schema);\r
- }\r
- for(p=0;p<closing_when.size();++p){\r
- bind_to_schema_pr(closing_when[p]->pr, &fm, Schema);\r
- }\r
- int s;\r
- for(s=0;s<select_list.size();++s){\r
- bind_to_schema_se(select_list[s]->se, &fm, Schema);\r
- }\r
- int g;\r
- for(g=0;g<gb_tbl.size();++g){\r
- bind_to_schema_se(gb_tbl.get_def(g), &fm, Schema);\r
- }\r
- int a;\r
- for(a=0;a<aggr_tbl.size();++a){\r
- if(aggr_tbl.is_builtin(a)){\r
- bind_to_schema_se(aggr_tbl.get_aggr_se(a), &fm, Schema);\r
- }else{\r
- vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(a);\r
- int o;\r
- for(o=0;o<opl.size();++o){\r
- bind_to_schema_se(opl[o],&fm,Schema);\r
- }\r
- }\r
- }\r
-}\r
-\r
-\r
-void sgahcwcb_qpn::bind_to_schema(table_list *Schema){\r
-// Bind the tablevars in the From clause to the Schema\r
-// (it might have changed from analysis time)\r
- int t = Schema->get_table_ref(table_name->get_schema_name() );\r
- if(t>=0)\r
- table_name->set_schema_ref(t );\r
-\r
-// Get the "from" clause\r
- tablevar_list_t fm(table_name);\r
-\r
-// Bind all SEs to this schema\r
- int p;\r
- for(p=0;p<where.size();++p){\r
- bind_to_schema_pr(where[p]->pr, &fm, Schema);\r
- }\r
- for(p=0;p<having.size();++p){\r
- bind_to_schema_pr(having[p]->pr, &fm, Schema);\r
- }\r
- for(p=0;p<having.size();++p){\r
- bind_to_schema_pr(cleanby[p]->pr, &fm, Schema);\r
- }\r
- for(p=0;p<having.size();++p){\r
- bind_to_schema_pr(cleanwhen[p]->pr, &fm, Schema);\r
- }\r
- int s;\r
- for(s=0;s<select_list.size();++s){\r
- bind_to_schema_se(select_list[s]->se, &fm, Schema);\r
- }\r
- int g;\r
- for(g=0;g<gb_tbl.size();++g){\r
- bind_to_schema_se(gb_tbl.get_def(g), &fm, Schema);\r
- }\r
- int a;\r
- for(a=0;a<aggr_tbl.size();++a){\r
- if(aggr_tbl.is_builtin(a)){\r
- bind_to_schema_se(aggr_tbl.get_aggr_se(a), &fm, Schema);\r
- }else{\r
- vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(a);\r
- int o;\r
- for(o=0;o<opl.size();++o){\r
- bind_to_schema_se(opl[o],&fm,Schema);\r
- }\r
- }\r
- }\r
-}\r
-\r
-\r
-\r
-\r
-\r
-\r
-///////////////////////////////////////////////////////////////\r
-///////////////////////////////////////////////////////////////\r
-/// Functions for code generation.\r
-\r
-\r
-//-----------------------------------------------------------------\r
-// get_cplx_lit_tbl\r
-\r
-cplx_lit_table *mrg_qpn::get_cplx_lit_tbl(ext_fcn_list *Ext_fcns){\r
- return(new cplx_lit_table());\r
-}\r
-\r
-cplx_lit_table *spx_qpn::get_cplx_lit_tbl(ext_fcn_list *Ext_fcns){\r
- int i;\r
- cplx_lit_table *complex_literals = new cplx_lit_table();\r
-\r
- for(i=0;i<select_list.size();i++){\r
- find_complex_literal_se(select_list[i]->se, Ext_fcns, complex_literals);\r
- }\r
- for(i=0;i<where.size();++i){\r
- find_complex_literal_pr(where[i]->pr,Ext_fcns, complex_literals);\r
- }\r
-\r
- return(complex_literals);\r
-}\r
-\r
-cplx_lit_table *sgah_qpn::get_cplx_lit_tbl(ext_fcn_list *Ext_fcns){\r
- int i,j;\r
- cplx_lit_table *complex_literals = new cplx_lit_table();\r
-\r
- for(i=0;i<aggr_tbl.size();++i){\r
- if(aggr_tbl.is_builtin(i) && !aggr_tbl.is_star_aggr(i)){\r
- find_complex_literal_se(aggr_tbl.get_aggr_se(i), Ext_fcns, complex_literals);\r
- }else{\r
- vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(i);\r
- for(j=0;j<opl.size();++j)\r
- find_complex_literal_se(opl[j], Ext_fcns, complex_literals);\r
- }\r
- }\r
-\r
- for(i=0;i<select_list.size();i++){\r
- find_complex_literal_se(select_list[i]->se, Ext_fcns, complex_literals);\r
- }\r
- for(i=0;i<gb_tbl.size();i++){\r
- find_complex_literal_se(gb_tbl.get_def(i), Ext_fcns, complex_literals);\r
- }\r
- for(i=0;i<where.size();++i){\r
- find_complex_literal_pr(where[i]->pr,Ext_fcns, complex_literals);\r
- }\r
- for(i=0;i<having.size();++i){\r
- find_complex_literal_pr(having[i]->pr,Ext_fcns, complex_literals);\r
- }\r
-\r
- return(complex_literals);\r
-}\r
-\r
-\r
-cplx_lit_table *rsgah_qpn::get_cplx_lit_tbl(ext_fcn_list *Ext_fcns){\r
- int i,j;\r
- cplx_lit_table *complex_literals = new cplx_lit_table();\r
-\r
- for(i=0;i<aggr_tbl.size();++i){\r
- if(aggr_tbl.is_builtin(i) && !aggr_tbl.is_star_aggr(i)){\r
- find_complex_literal_se(aggr_tbl.get_aggr_se(i), Ext_fcns, complex_literals);\r
- }else{\r
- vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(i);\r
- for(j=0;j<opl.size();++j)\r
- find_complex_literal_se(opl[j], Ext_fcns, complex_literals);\r
- }\r
- }\r
-\r
- for(i=0;i<select_list.size();i++){\r
- find_complex_literal_se(select_list[i]->se, Ext_fcns, complex_literals);\r
- }\r
- for(i=0;i<gb_tbl.size();i++){\r
- find_complex_literal_se(gb_tbl.get_def(i), Ext_fcns, complex_literals);\r
- }\r
- for(i=0;i<where.size();++i){\r
- find_complex_literal_pr(where[i]->pr,Ext_fcns, complex_literals);\r
- }\r
- for(i=0;i<having.size();++i){\r
- find_complex_literal_pr(having[i]->pr,Ext_fcns, complex_literals);\r
- }\r
- for(i=0;i<closing_when.size();++i){\r
- find_complex_literal_pr(closing_when[i]->pr,Ext_fcns, complex_literals);\r
- }\r
-\r
- return(complex_literals);\r
-}\r
-\r
-\r
-cplx_lit_table *sgahcwcb_qpn::get_cplx_lit_tbl(ext_fcn_list *Ext_fcns){\r
- int i,j;\r
- cplx_lit_table *complex_literals = new cplx_lit_table();\r
-\r
- for(i=0;i<aggr_tbl.size();++i){\r
- if(aggr_tbl.is_builtin(i) && !aggr_tbl.is_star_aggr(i)){\r
- find_complex_literal_se(aggr_tbl.get_aggr_se(i), Ext_fcns, complex_literals);\r
- }else{\r
- vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(i);\r
- for(j=0;j<opl.size();++j)\r
- find_complex_literal_se(opl[j], Ext_fcns, complex_literals);\r
- }\r
- }\r
-\r
- for(i=0;i<select_list.size();i++){\r
- find_complex_literal_se(select_list[i]->se, Ext_fcns, complex_literals);\r
- }\r
- for(i=0;i<gb_tbl.size();i++){\r
- find_complex_literal_se(gb_tbl.get_def(i), Ext_fcns, complex_literals);\r
- }\r
- for(i=0;i<where.size();++i){\r
- find_complex_literal_pr(where[i]->pr,Ext_fcns, complex_literals);\r
- }\r
- for(i=0;i<having.size();++i){\r
- find_complex_literal_pr(having[i]->pr,Ext_fcns, complex_literals);\r
- }\r
- for(i=0;i<cleanwhen.size();++i){\r
- find_complex_literal_pr(cleanwhen[i]->pr,Ext_fcns, complex_literals);\r
- }\r
- for(i=0;i<cleanby.size();++i){\r
- find_complex_literal_pr(cleanby[i]->pr,Ext_fcns, complex_literals);\r
- }\r
-\r
- return(complex_literals);\r
-}\r
-\r
-cplx_lit_table *join_eq_hash_qpn::get_cplx_lit_tbl(ext_fcn_list *Ext_fcns){\r
- int i;\r
- cplx_lit_table *complex_literals = new cplx_lit_table();\r
-\r
- for(i=0;i<select_list.size();i++){\r
- find_complex_literal_se(select_list[i]->se, Ext_fcns, complex_literals);\r
- }\r
- for(i=0;i<where.size();++i){\r
- find_complex_literal_pr(where[i]->pr,Ext_fcns, complex_literals);\r
- }\r
-\r
- return(complex_literals);\r
-}\r
-\r
-cplx_lit_table *filter_join_qpn::get_cplx_lit_tbl(ext_fcn_list *Ext_fcns){\r
- int i;\r
- cplx_lit_table *complex_literals = new cplx_lit_table();\r
-\r
- for(i=0;i<select_list.size();i++){\r
- find_complex_literal_se(select_list[i]->se, Ext_fcns, complex_literals);\r
- }\r
- for(i=0;i<where.size();++i){\r
- find_complex_literal_pr(where[i]->pr,Ext_fcns, complex_literals);\r
- }\r
-\r
- return(complex_literals);\r
-}\r
-\r
-\r
-\r
-\r
-//-----------------------------------------------------------------\r
-// get_handle_param_tbl\r
-\r
-vector<handle_param_tbl_entry *> mrg_qpn::get_handle_param_tbl(ext_fcn_list *Ext_fcns){\r
- vector<handle_param_tbl_entry *> retval;\r
- return(retval);\r
-}\r
-\r
-\r
-vector<handle_param_tbl_entry *> spx_qpn::get_handle_param_tbl(ext_fcn_list *Ext_fcns){\r
- int i;\r
- vector<handle_param_tbl_entry *> retval;\r
-\r
- for(i=0;i<select_list.size();i++){\r
- find_param_handles_se(select_list[i]->se, Ext_fcns, retval);\r
- }\r
- for(i=0;i<where.size();++i){\r
- find_param_handles_pr(where[i]->pr,Ext_fcns, retval);\r
- }\r
-\r
- return(retval);\r
-}\r
-\r
-\r
-vector<handle_param_tbl_entry *> sgah_qpn::get_handle_param_tbl(ext_fcn_list *Ext_fcns){\r
- int i,j;\r
- vector<handle_param_tbl_entry *> retval;\r
-\r
-\r
- for(i=0;i<aggr_tbl.size();++i){\r
- if(aggr_tbl.is_builtin(i) && !aggr_tbl.is_star_aggr(i)){\r
- find_param_handles_se(aggr_tbl.get_aggr_se(i), Ext_fcns, retval);\r
- }else{\r
- vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(i);\r
- for(j=0;j<opl.size();++j)\r
- find_param_handles_se(opl[j], Ext_fcns, retval);\r
- }\r
- }\r
- for(i=0;i<select_list.size();i++){\r
- find_param_handles_se(select_list[i]->se, Ext_fcns, retval);\r
- }\r
- for(i=0;i<gb_tbl.size();i++){\r
- find_param_handles_se(gb_tbl.get_def(i), Ext_fcns, retval);\r
- }\r
- for(i=0;i<where.size();++i){\r
- find_param_handles_pr(where[i]->pr,Ext_fcns, retval);\r
- }\r
- for(i=0;i<having.size();++i){\r
- find_param_handles_pr(having[i]->pr,Ext_fcns, retval);\r
- }\r
-\r
- return(retval);\r
-}\r
-\r
-\r
-vector<handle_param_tbl_entry *> rsgah_qpn::get_handle_param_tbl(ext_fcn_list *Ext_fcns){\r
- int i,j;\r
- vector<handle_param_tbl_entry *> retval;\r
-\r
-\r
- for(i=0;i<aggr_tbl.size();++i){\r
- if(aggr_tbl.is_builtin(i) && !aggr_tbl.is_star_aggr(i)){\r
- find_param_handles_se(aggr_tbl.get_aggr_se(i), Ext_fcns, retval);\r
- }else{\r
- vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(i);\r
- for(j=0;j<opl.size();++j)\r
- find_param_handles_se(opl[j], Ext_fcns, retval);\r
- }\r
- }\r
- for(i=0;i<select_list.size();i++){\r
- find_param_handles_se(select_list[i]->se, Ext_fcns, retval);\r
- }\r
- for(i=0;i<gb_tbl.size();i++){\r
- find_param_handles_se(gb_tbl.get_def(i), Ext_fcns, retval);\r
- }\r
- for(i=0;i<where.size();++i){\r
- find_param_handles_pr(where[i]->pr,Ext_fcns, retval);\r
- }\r
- for(i=0;i<having.size();++i){\r
- find_param_handles_pr(having[i]->pr,Ext_fcns, retval);\r
- }\r
- for(i=0;i<closing_when.size();++i){\r
- find_param_handles_pr(closing_when[i]->pr,Ext_fcns, retval);\r
- }\r
-\r
- return(retval);\r
-}\r
-\r
-\r
-vector<handle_param_tbl_entry *> sgahcwcb_qpn::get_handle_param_tbl(ext_fcn_list *Ext_fcns){\r
- int i,j;\r
- vector<handle_param_tbl_entry *> retval;\r
-\r
-\r
- for(i=0;i<aggr_tbl.size();++i){\r
- if(aggr_tbl.is_builtin(i) && !aggr_tbl.is_star_aggr(i)){\r
- find_param_handles_se(aggr_tbl.get_aggr_se(i), Ext_fcns, retval);\r
- }else{\r
- vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(i);\r
- for(j=0;j<opl.size();++j)\r
- find_param_handles_se(opl[j], Ext_fcns, retval);\r
- }\r
- }\r
- for(i=0;i<select_list.size();i++){\r
- find_param_handles_se(select_list[i]->se, Ext_fcns, retval);\r
- }\r
- for(i=0;i<gb_tbl.size();i++){\r
- find_param_handles_se(gb_tbl.get_def(i), Ext_fcns, retval);\r
- }\r
- for(i=0;i<where.size();++i){\r
- find_param_handles_pr(where[i]->pr,Ext_fcns, retval);\r
- }\r
- for(i=0;i<having.size();++i){\r
- find_param_handles_pr(having[i]->pr,Ext_fcns, retval);\r
- }\r
- for(i=0;i<cleanwhen.size();++i){\r
- find_param_handles_pr(cleanwhen[i]->pr,Ext_fcns, retval);\r
- }\r
- for(i=0;i<cleanby.size();++i){\r
- find_param_handles_pr(cleanby[i]->pr,Ext_fcns, retval);\r
- }\r
-\r
- return(retval);\r
-}\r
-\r
-vector<handle_param_tbl_entry *> join_eq_hash_qpn::get_handle_param_tbl(ext_fcn_list *Ext_fcns){\r
- int i;\r
- vector<handle_param_tbl_entry *> retval;\r
-\r
- for(i=0;i<select_list.size();i++){\r
- find_param_handles_se(select_list[i]->se, Ext_fcns, retval);\r
- }\r
- for(i=0;i<where.size();++i){\r
- find_param_handles_pr(where[i]->pr,Ext_fcns, retval);\r
- }\r
-\r
- return(retval);\r
-}\r
-\r
-\r
-vector<handle_param_tbl_entry *> filter_join_qpn::get_handle_param_tbl(ext_fcn_list *Ext_fcns){\r
- int i;\r
- vector<handle_param_tbl_entry *> retval;\r
-\r
- for(i=0;i<select_list.size();i++){\r
- find_param_handles_se(select_list[i]->se, Ext_fcns, retval);\r
- }\r
- for(i=0;i<where.size();++i){\r
- find_param_handles_pr(where[i]->pr,Ext_fcns, retval);\r
- }\r
-\r
- return(retval);\r
-}\r
-\r
-///////////////////////////////////////////////////////////////\r
-///////////////////////////////////////////////////////////////\r
-/// Functions for operator output rates estimations\r
-\r
-\r
-//-----------------------------------------------------------------\r
-// get_rate_estimate\r
-\r
-double spx_qpn::get_rate_estimate() {\r
-\r
- // dummy method for now\r
- return SPX_SELECTIVITY * DEFAULT_INTERFACE_RATE;\r
-}\r
-\r
-double sgah_qpn::get_rate_estimate() {\r
-\r
- // dummy method for now\r
- return SGAH_SELECTIVITY * DEFAULT_INTERFACE_RATE;\r
-}\r
-\r
-double rsgah_qpn::get_rate_estimate() {\r
-\r
- // dummy method for now\r
- return RSGAH_SELECTIVITY * DEFAULT_INTERFACE_RATE;\r
-}\r
-\r
-double sgahcwcb_qpn::get_rate_estimate() {\r
-\r
- // dummy method for now\r
- return SGAHCWCB_SELECTIVITY * DEFAULT_INTERFACE_RATE;\r
-}\r
-\r
-double mrg_qpn::get_rate_estimate() {\r
-\r
- // dummy method for now\r
- return MRG_SELECTIVITY * DEFAULT_INTERFACE_RATE;\r
-}\r
-\r
-double join_eq_hash_qpn::get_rate_estimate() {\r
-\r
- // dummy method for now\r
- return JOIN_EQ_HASH_SELECTIVITY * DEFAULT_INTERFACE_RATE;\r
-}\r
-\r
-\r
-//////////////////////////////////////////////////////////////////////////////\r
-//////////////////////////////////////////////////////////////////////////////\r
-///// Generate functors\r
-\r
-\r
-\r
-\r
-//-------------------------------------------------------------------------\r
-// Code generation utilities.\r
-//-------------------------------------------------------------------------\r
-\r
-// Globals referenced by generate utilities\r
-\r
-static gb_table *segen_gb_tbl; // Table of all group-by attributes.\r
-\r
-\r
-\r
-// Generate code that makes reference\r
-// to the tuple, and not to any aggregates.\r
-// NEW : it might reference a stateful function.\r
-static string generate_se_code(scalarexp_t *se,table_list *schema){\r
- string ret;\r
- data_type *ldt, *rdt;\r
- int o;\r
- vector<scalarexp_t *> operands;\r
-\r
-\r
- switch(se->get_operator_type()){\r
- case SE_LITERAL:\r
- if(se->is_handle_ref()){\r
- sprintf(tmpstr,"handle_param_%d",se->get_handle_ref() );\r
- ret = tmpstr;\r
- return(ret);\r
- }\r
- if(se->get_literal()->is_cpx_lit()){\r
- sprintf(tmpstr,"complex_literal_%d",se->get_literal()->get_cpx_lit_ref() );\r
- ret = tmpstr;\r
- return(ret);\r
- }\r
- return(se->get_literal()->to_hfta_C_code("")); // not complex no constr.\r
- case SE_PARAM:\r
- if(se->is_handle_ref()){\r
- sprintf(tmpstr,"handle_param_%d",se->get_handle_ref() );\r
- ret = tmpstr;\r
- return(ret);\r
- }\r
- ret.append("param_");\r
- ret.append(se->get_param_name());\r
- return(ret);\r
- case SE_UNARY_OP:\r
- ldt = se->get_left_se()->get_data_type();\r
- if(ldt->complex_operator(se->get_op()) ){\r
- ret.append( ldt->get_complex_operator(se->get_op()) );\r
- ret.append("(");\r
- ret.append(generate_se_code(se->get_left_se(),schema));\r
- ret.append(")");\r
- }else{\r
- ret.append("(");\r
- ret.append(se->get_op());\r
- ret.append(generate_se_code(se->get_left_se(),schema));\r
- ret.append(")");\r
- }\r
- return(ret);\r
- case SE_BINARY_OP:\r
- ldt = se->get_left_se()->get_data_type();\r
- rdt = se->get_right_se()->get_data_type();\r
-\r
- if(ldt->complex_operator(rdt, se->get_op()) ){\r
- ret.append( ldt->get_complex_operator(rdt, se->get_op()) );\r
- ret.append("(");\r
- ret.append(generate_se_code(se->get_left_se(),schema));\r
- ret.append(", ");\r
- ret.append(generate_se_code(se->get_right_se(),schema));\r
- ret.append(")");\r
- }else{\r
- ret.append("(");\r
- ret.append(generate_se_code(se->get_left_se(),schema));\r
- ret.append(se->get_op());\r
- ret.append(generate_se_code(se->get_right_se(),schema));\r
- ret.append(")");\r
- }\r
- return(ret);\r
- case SE_COLREF:\r
- if(se->is_gb()){ // OK to ref gb attrs, but they're not yet unpacked ...\r
- // so return the defining code.\r
- int gref = se->get_gb_ref();\r
- scalarexp_t *gdef_se = segen_gb_tbl->get_def(gref);\r
- ret = generate_se_code(gdef_se, schema );\r
-\r
- }else{\r
- sprintf(tmpstr,"unpack_var_%s_%d",\r
- se->get_colref()->get_field().c_str(), se->get_colref()->get_tablevar_ref() );\r
- ret = tmpstr;\r
- }\r
- return(ret);\r
- case SE_FUNC:\r
- if(se->is_partial()){\r
- sprintf(tmpstr,"partial_fcn_result_%d",se->get_partial_ref());\r
- ret = tmpstr;\r
- }else{\r
- ret += se->op + "(";\r
- operands = se->get_operands();\r
- bool first_elem = true;\r
- if(se->get_storage_state() != ""){\r
- ret += "&(stval->state_var_"+se->get_storage_state()+"),cd";\r
- first_elem = false;\r
- }\r
- for(o=0;o<operands.size();o++){\r
- if(first_elem) first_elem=false; else ret += ", ";\r
- if(operands[o]->get_data_type()->is_buffer_type() &&\r
- (! (operands[o]->is_handle_ref()) ) )\r
- ret.append("&");\r
- ret += generate_se_code(operands[o], schema);\r
- }\r
- ret += ")";\r
- }\r
- return(ret);\r
- default:\r
- fprintf(stderr,"INTERNAL ERROR in generate_se_code (hfta), line %d, character %d: unknown operator type %d\n",\r
- se->get_lineno(), se->get_charno(),se->get_operator_type());\r
- return("ERROR in generate_se_code");\r
- }\r
-}\r
-\r
-// generate code that refers only to aggregate data and constants.\r
-// NEW : modified to handle superaggregates and stateful fcn refs.\r
-// Assume that the state is in *stval\r
-static string generate_se_code_fm_aggr(scalarexp_t *se, string gbvar, string aggvar, table_list *schema){\r
-\r
- string ret;\r
- data_type *ldt, *rdt;\r
- int o;\r
- vector<scalarexp_t *> operands;\r
-\r
-\r
- switch(se->get_operator_type()){\r
- case SE_LITERAL:\r
- if(se->is_handle_ref()){\r
- sprintf(tmpstr,"handle_param_%d",se->get_handle_ref() );\r
- ret = tmpstr;\r
- return(ret);\r
- }\r
- if(se->get_literal()->is_cpx_lit()){\r
- sprintf(tmpstr,"complex_literal_%d",se->get_literal()->get_cpx_lit_ref() );\r
- ret = tmpstr;\r
- return(ret);\r
- }\r
- return(se->get_literal()->to_hfta_C_code("")); // not complex no constr.\r
- case SE_PARAM:\r
- if(se->is_handle_ref()){\r
- sprintf(tmpstr,"handle_param_%d",se->get_handle_ref() );\r
- ret = tmpstr;\r
- return(ret);\r
- }\r
- ret.append("param_");\r
- ret.append(se->get_param_name());\r
- return(ret);\r
- case SE_UNARY_OP:\r
- ldt = se->get_left_se()->get_data_type();\r
- if(ldt->complex_operator(se->get_op()) ){\r
- ret.append( ldt->get_complex_operator(se->get_op()) );\r
- ret.append("(");\r
- ret.append(generate_se_code_fm_aggr(se->get_left_se(),gbvar,aggvar,schema));\r
- ret.append(")");\r
- }else{\r
- ret.append("(");\r
- ret.append(se->get_op());\r
- ret.append(generate_se_code_fm_aggr(se->get_left_se(),gbvar,aggvar,schema));\r
- ret.append(")");\r
- }\r
- return(ret);\r
- case SE_BINARY_OP:\r
- ldt = se->get_left_se()->get_data_type();\r
- rdt = se->get_right_se()->get_data_type();\r
-\r
- if(ldt->complex_operator(rdt, se->get_op()) ){\r
- ret.append( ldt->get_complex_operator(rdt, se->get_op()) );\r
- ret.append("(");\r
- ret.append(generate_se_code_fm_aggr(se->get_left_se(),gbvar,aggvar,schema));\r
- ret.append(", ");\r
- ret.append(generate_se_code_fm_aggr(se->get_right_se(),gbvar,aggvar,schema));\r
- ret.append(")");\r
- }else{\r
- ret.append("(");\r
- ret.append(generate_se_code_fm_aggr(se->get_left_se(),gbvar,aggvar,schema));\r
- ret.append(se->get_op());\r
- ret.append(generate_se_code_fm_aggr(se->get_right_se(),gbvar,aggvar,schema));\r
- ret.append(")");\r
- }\r
- return(ret);\r
- case SE_COLREF:\r
- if(se->is_gb()){ // OK to ref gb attrs, but they're not yet unpacked ...\r
- // so return the defining code.\r
- sprintf(tmpstr,"%s%d",gbvar.c_str(),se->get_gb_ref());\r
- ret = tmpstr;\r
-\r
- }else{\r
- fprintf(stderr,"ERROR reference to non-GB column ref not permitted here,"\r
- "error in query_plan.cc:generate_se_code_fm_aggr, line %d, character %d.\n",\r
- se->get_lineno(), se->get_charno());\r
- ret = tmpstr;\r
- }\r
- return(ret);\r
- case SE_AGGR_STAR:\r
- case SE_AGGR_SE:\r
- if(se->is_superaggr()){\r
- sprintf(tmpstr,"stval->aggr_var%d",se->get_aggr_ref());\r
- }else{\r
- sprintf(tmpstr,"%saggr_var%d",aggvar.c_str(),se->get_aggr_ref());\r
- }\r
- ret = tmpstr;\r
- return(ret);\r
- case SE_FUNC:\r
-// Is it a UDAF?\r
- if(se->get_aggr_ref() >= 0){\r
- sprintf(tmpstr,"udaf_ret_%d",se->get_aggr_ref());\r
- ret = tmpstr;\r
- return(ret);\r
- }\r
-\r
- if(se->is_partial()){\r
- sprintf(tmpstr,"partial_fcn_result_%d",se->get_partial_ref());\r
- ret = tmpstr;\r
- }else{\r
- ret += se->op + "(";\r
- bool first_elem = true;\r
- if(se->get_storage_state() != ""){\r
- ret += "&(stval->state_var_"+se->get_storage_state()+"),cd";\r
- first_elem = false;\r
- }\r
- operands = se->get_operands();\r
- for(o=0;o<operands.size();o++){\r
- if(first_elem) first_elem=false; else ret += ", ";\r
- if(operands[o]->get_data_type()->is_buffer_type() &&\r
- (! (operands[o]->is_handle_ref()) ) )\r
- ret.append("&");\r
- ret += generate_se_code_fm_aggr(operands[o], gbvar,aggvar, schema);\r
- }\r
- ret += ")";\r
- }\r
- return(ret);\r
- default:\r
- fprintf(stderr,"INTERNAL ERROR in query_plan.cc::generate_se_code_fm_aggr, line %d, character %d: unknown operator type %d\n",\r
- se->get_lineno(), se->get_charno(),se->get_operator_type());\r
- return("ERROR in generate_se_code_fm_aggr");\r
- }\r
-\r
-}\r
-\r
-\r
-static string unpack_partial_fcn_fm_aggr(scalarexp_t *se, int pfn_id, string gbvar, string aggvar, table_list *schema){\r
- string ret;\r
- int o;\r
- vector<scalarexp_t *> operands;\r
-\r
-\r
- if(se->get_operator_type() != SE_FUNC){\r
- fprintf(stderr,"INTERNAL ERROR, non-function SE passed to unpack_partial_fcn_fm_aggr. line %d, character %d\n",\r
- se->get_lineno(), se->get_charno());\r
- return("ERROR in unpack_partial_fcn_fm_aggr");\r
- }\r
-\r
- ret = "\tretval = " + se->get_op() + "( ",\r
- sprintf(tmpstr, "&partial_fcn_result_%d",pfn_id);\r
- ret += tmpstr;\r
-\r
- if(se->get_storage_state() != ""){\r
- ret += ",&(stval->state_var_"+se->get_storage_state()+"),cd";\r
- }\r
-\r
- operands = se->get_operands();\r
- for(o=0;o<operands.size();o++){\r
- ret += ", ";\r
- if(operands[o]->get_data_type()->is_buffer_type() &&\r
- (! (operands[o]->is_handle_ref()) ) )\r
- ret.append("&");\r
- ret += generate_se_code_fm_aggr(operands[o], gbvar,aggvar, schema);\r
- }\r
- ret += ");\n";\r
-\r
- return(ret);\r
-}\r
-\r
-\r
-static string unpack_partial_fcn(scalarexp_t *se, int pfn_id, table_list *schema){\r
- string ret;\r
- int o;\r
- vector<scalarexp_t *> operands;\r
-\r
- if(se->get_operator_type() != SE_FUNC){\r
- fprintf(stderr,"INTERNAL ERROR, non-function SE passed to unpack_partial_fcn. line %d, character %d\n",\r
- se->get_lineno(), se->get_charno());\r
- return("ERROR in unpack_partial_fcn");\r
- }\r
-\r
- ret = "\tretval = " + se->get_op() + "( ",\r
- sprintf(tmpstr, "&partial_fcn_result_%d",pfn_id);\r
- ret += tmpstr;\r
-\r
- if(se->get_storage_state() != ""){\r
- ret += ",&(stval->state_var_"+se->get_storage_state()+"),cd";\r
- }\r
-\r
- operands = se->get_operands();\r
- for(o=0;o<operands.size();o++){\r
- ret += ", ";\r
- if(operands[o]->get_data_type()->is_buffer_type() &&\r
- (! (operands[o]->is_handle_ref()) ) )\r
- ret.append("&");\r
- ret += generate_se_code(operands[o], schema);\r
- }\r
- ret += ");\n";\r
-\r
- return(ret);\r
-}\r
-\r
-static string generate_cached_fcn(scalarexp_t *se, int pfn_id, table_list *schema){\r
- string ret;\r
- int o;\r
- vector<scalarexp_t *> operands;\r
-\r
- if(se->get_operator_type() != SE_FUNC){\r
- fprintf(stderr,"INTERNAL ERROR, non-function SE passed to generate_cached_fcn. line %d, character %d\n",\r
- se->get_lineno(), se->get_charno());\r
- return("ERROR in generate_cached_fcn");\r
- }\r
-\r
- ret = se->get_op()+"(";\r
-\r
- if(se->get_storage_state() != ""){\r
- ret += "&(stval->state_var_"+se->get_storage_state()+"),cd,";\r
- }\r
-\r
- operands = se->get_operands();\r
- for(o=0;o<operands.size();o++){\r
- if(o) ret += ", ";\r
- if(operands[o]->get_data_type()->is_buffer_type() &&\r
- (! (operands[o]->is_handle_ref()) ) )\r
- ret.append("&");\r
- ret += generate_se_code(operands[o], schema);\r
- }\r
- ret += ");\n";\r
-\r
- return(ret);\r
-}\r
-\r
-\r
-\r
-\r
-\r
-static string generate_C_comparison_op(string op){\r
- if(op == "=") return("==");\r
- if(op == "<>") return("!=");\r
- return(op);\r
-}\r
-\r
-static string generate_C_boolean_op(string op){\r
- if( (op == "AND") || (op == "And") || (op == "and") ){\r
- return("&&");\r
- }\r
- if( (op == "OR") || (op == "Or") || (op == "or") ){\r
- return("||");\r
- }\r
- if( (op == "NOT") || (op == "Not") || (op == "not") ){\r
- return("!");\r
- }\r
-\r
- return("ERROR UNKNOWN BOOLEAN OPERATOR");\r
-}\r
-\r
-\r
-static string generate_predicate_code(predicate_t *pr,table_list *schema){\r
- string ret;\r
- vector<literal_t *> litv;\r
- int i;\r
- data_type *ldt, *rdt;\r
- vector<scalarexp_t *> op_list;\r
- int o;\r
-\r
- switch(pr->get_operator_type()){\r
- case PRED_IN:\r
- ldt = pr->get_left_se()->get_data_type();\r
-\r
- ret.append("( ");\r
- litv = pr->get_lit_vec();\r
- for(i=0;i<litv.size();i++){\r
- if(i>0) ret.append(" || ");\r
- ret.append("( ");\r
-\r
- if(ldt->complex_comparison(ldt) ){\r
- ret.append( ldt->get_hfta_comparison_fcn(ldt) );\r
- ret.append("( ");\r
- if(ldt->is_buffer_type() )\r
- ret.append("&");\r
- ret.append(generate_se_code(pr->get_left_se(), schema));\r
- ret.append(", ");\r
- if(ldt->is_buffer_type() )\r
- ret.append("&");\r
- if(litv[i]->is_cpx_lit()){\r
- sprintf(tmpstr,"complex_literal_%d",litv[i]->get_cpx_lit_ref() );\r
- ret += tmpstr;\r
- }else{\r
- ret.append(litv[i]->to_C_code(""));\r
- }\r
- ret.append(") == 0");\r
- }else{\r
- ret.append(generate_se_code(pr->get_left_se(), schema));\r
- ret.append(" == ");\r
- ret.append(litv[i]->to_hfta_C_code(""));\r
- }\r
-\r
- ret.append(" )");\r
- }\r
- ret.append(" )");\r
- return(ret);\r
-\r
- case PRED_COMPARE:\r
- ldt = pr->get_left_se()->get_data_type();\r
- rdt = pr->get_right_se()->get_data_type();\r
-\r
- ret.append("( ");\r
- if(ldt->complex_comparison(rdt) ){\r
- ret.append(ldt->get_hfta_comparison_fcn(rdt));\r
- ret.append("(");\r
- if(ldt->is_buffer_type() )\r
- ret.append("&");\r
- ret.append(generate_se_code(pr->get_left_se(),schema) );\r
- ret.append(", ");\r
- if(rdt->is_buffer_type() )\r
- ret.append("&");\r
- ret.append(generate_se_code(pr->get_right_se(),schema) );\r
- ret.append(") ");\r
- ret.append( generate_C_comparison_op(pr->get_op()));\r
- ret.append("0");\r
- }else{\r
- ret.append(generate_se_code(pr->get_left_se(),schema) );\r
- ret.append( generate_C_comparison_op(pr->get_op()));\r
- ret.append(generate_se_code(pr->get_right_se(),schema) );\r
- }\r
- ret.append(" )");\r
- return(ret);\r
- case PRED_UNARY_OP:\r
- ret.append("( ");\r
- ret.append( generate_C_boolean_op(pr->get_op()) );\r
- ret.append(generate_predicate_code(pr->get_left_pr(),schema) );\r
- ret.append(" )");\r
- return(ret);\r
- case PRED_BINARY_OP:\r
- ret.append("( ");\r
- ret.append(generate_predicate_code(pr->get_left_pr(),schema) );\r
- ret.append( generate_C_boolean_op(pr->get_op()) );\r
- ret.append(generate_predicate_code(pr->get_right_pr(),schema) );\r
- ret.append(" )");\r
- return(ret);\r
- case PRED_FUNC:\r
- ret += pr->get_op() + "( ";\r
- op_list = pr->get_op_list();\r
- for(o=0;o<op_list.size();++o){\r
- if(o>0) ret += ", ";\r
- if(op_list[o]->get_data_type()->is_buffer_type() && (! (op_list[o]->is_handle_ref()) ) )\r
- ret.append("&");\r
- ret += generate_se_code(op_list[o], schema);\r
- }\r
- ret += " )";\r
- return(ret);\r
- default:\r
- fprintf(stderr,"INTERNAL ERROR in generate_predicate_code, line %d, character %d, unknown predicate operator type %d\n",\r
- pr->get_lineno(), pr->get_charno(), pr->get_operator_type() );\r
- return("ERROR in generate_predicate_code");\r
- }\r
-}\r
-\r
-static string generate_predicate_code_fm_aggr(predicate_t *pr, string gbvar, string aggvar,table_list *schema){\r
- string ret;\r
- vector<literal_t *> litv;\r
- int i;\r
- data_type *ldt, *rdt;\r
- vector<scalarexp_t *> op_list;\r
- int o;\r
-\r
- switch(pr->get_operator_type()){\r
- case PRED_IN:\r
- ldt = pr->get_left_se()->get_data_type();\r
-\r
- ret.append("( ");\r
- litv = pr->get_lit_vec();\r
- for(i=0;i<litv.size();i++){\r
- if(i>0) ret.append(" || ");\r
- ret.append("( ");\r
-\r
- if(ldt->complex_comparison(ldt) ){\r
- ret.append( ldt->get_hfta_comparison_fcn(ldt) );\r
- ret.append("( ");\r
- if(ldt->is_buffer_type() )\r
- ret.append("&");\r
- ret.append(generate_se_code_fm_aggr(pr->get_left_se(), gbvar, aggvar, schema));\r
- ret.append(", ");\r
- if(ldt->is_buffer_type() )\r
- ret.append("&");\r
- if(litv[i]->is_cpx_lit()){\r
- sprintf(tmpstr,"complex_literal_%d",litv[i]->get_cpx_lit_ref() );\r
- ret += tmpstr;\r
- }else{\r
- ret.append(litv[i]->to_C_code(""));\r
- }\r
- ret.append(") == 0");\r
- }else{\r
- ret.append(generate_se_code_fm_aggr(pr->get_left_se(), gbvar, aggvar, schema));\r
- ret.append(" == ");\r
- ret.append(litv[i]->to_hfta_C_code(""));\r
- }\r
-\r
- ret.append(" )");\r
- }\r
- ret.append(" )");\r
- return(ret);\r
-\r
- case PRED_COMPARE:\r
- ldt = pr->get_left_se()->get_data_type();\r
- rdt = pr->get_right_se()->get_data_type();\r
-\r
- ret.append("( ");\r
- if(ldt->complex_comparison(rdt) ){\r
- ret.append(ldt->get_hfta_comparison_fcn(rdt));\r
- ret.append("(");\r
- if(ldt->is_buffer_type() )\r
- ret.append("&");\r
- ret.append(generate_se_code_fm_aggr(pr->get_left_se(), gbvar, aggvar,schema) );\r
- ret.append(", ");\r
- if(rdt->is_buffer_type() )\r
- ret.append("&");\r
- ret.append(generate_se_code_fm_aggr(pr->get_right_se(), gbvar, aggvar,schema) );\r
- ret.append(") ");\r
- ret.append( generate_C_comparison_op(pr->get_op()));\r
- ret.append("0");\r
- }else{\r
- ret.append(generate_se_code_fm_aggr(pr->get_left_se(), gbvar, aggvar,schema) );\r
- ret.append( generate_C_comparison_op(pr->get_op()));\r
- ret.append(generate_se_code_fm_aggr(pr->get_right_se(), gbvar, aggvar,schema) );\r
- }\r
- ret.append(" )");\r
- return(ret);\r
- case PRED_UNARY_OP:\r
- ret.append("( ");\r
- ret.append( generate_C_boolean_op(pr->get_op()) );\r
- ret.append(generate_predicate_code_fm_aggr(pr->get_left_pr(), gbvar, aggvar,schema) );\r
- ret.append(" )");\r
- return(ret);\r
- case PRED_BINARY_OP:\r
- ret.append("( ");\r
- ret.append(generate_predicate_code_fm_aggr(pr->get_left_pr(), gbvar, aggvar,schema) );\r
- ret.append( generate_C_boolean_op(pr->get_op()) );\r
- ret.append(generate_predicate_code_fm_aggr(pr->get_right_pr(), gbvar, aggvar,schema) );\r
- ret.append(" )");\r
- return(ret);\r
- case PRED_FUNC:\r
- ret += pr->get_op() + "( ";\r
- op_list = pr->get_op_list();\r
- for(o=0;o<op_list.size();++o){\r
- if(o>0) ret += ", ";\r
- if(op_list[o]->get_data_type()->is_buffer_type() && (! (op_list[o]->is_handle_ref()) ) )\r
- ret.append("&");\r
- ret += generate_se_code_fm_aggr(op_list[o], gbvar, aggvar, schema);\r
- }\r
- ret += " )";\r
- return(ret);\r
- default:\r
- fprintf(stderr,"INTERNAL ERROR in generate_predicate_code, line %d, character %d, unknown predicate operator type %d\n",\r
- pr->get_lineno(), pr->get_charno(), pr->get_operator_type() );\r
- return("ERROR in generate_predicate_code");\r
- }\r
-}\r
-\r
-\r
-// Aggregation code\r
-\r
-\r
-static string generate_equality_test(string &lhs_op, string &rhs_op, data_type *dt){\r
- string ret;\r
-\r
- if(dt->complex_comparison(dt) ){\r
- ret.append(dt->get_hfta_comparison_fcn(dt));\r
- ret.append("(");\r
- if(dt->is_buffer_type() )\r
- ret.append("&");\r
- ret.append(lhs_op);\r
- ret.append(", ");\r
- if(dt->is_buffer_type() )\r
- ret.append("&");\r
- ret.append(rhs_op );\r
- ret.append(") == 0");\r
- }else{\r
- ret.append(lhs_op );\r
- ret.append(" == ");\r
- ret.append(rhs_op );\r
- }\r
-\r
- return(ret);\r
-}\r
-\r
-static string generate_comparison(string &lhs_op, string &rhs_op, data_type *dt){\r
- string ret;\r
-\r
- if(dt->complex_comparison(dt) ){\r
- ret.append(dt->get_hfta_comparison_fcn(dt));\r
- ret.append("(");\r
- if(dt->is_buffer_type() )\r
- ret.append("&");\r
- ret.append(lhs_op);\r
- ret.append(", ");\r
- if(dt->is_buffer_type() )\r
- ret.append("&");\r
- ret.append(rhs_op );\r
- ret.append(") == 0");\r
- }else{\r
- ret.append(lhs_op );\r
- ret.append(" == ");\r
- ret.append(rhs_op );\r
- }\r
-\r
- return(ret);\r
-}\r
-\r
-\r
-// Here I assume that only MIN and MAX aggregates can be computed\r
-// over BUFFER data types.\r
-\r
-static string generate_aggr_update(string var, aggregate_table *atbl,int aidx, table_list *schema){\r
- string retval = "\t\t";\r
- string op = atbl->get_op(aidx);\r
-\r
-// Is it a UDAF\r
- if(! atbl->is_builtin(aidx)) {\r
- int o;\r
- retval += op+"_HFTA_AGGR_UPDATE_(";\r
- if(atbl->get_storage_type(aidx)->get_type() != fstring_t) retval+="&";\r
- retval+="("+var+")";\r
- vector<scalarexp_t *> opl = atbl->get_operand_list(aidx);\r
- for(o=0;o<opl.size();++o){{\r
- retval += ",";\r
- if(opl[o]->get_data_type()->is_buffer_type() && (! (opl[o]->is_handle_ref()) ) )\r
- retval.append("&");\r
- retval += generate_se_code(opl[o], schema);\r
- }\r
- }\r
- retval += ");\n";\r
-\r
- return retval;\r
- }\r
-\r
-\r
-// builtin processing\r
- data_type *dt = atbl->get_data_type(aidx);\r
-\r
- if(op == "COUNT"){\r
- retval.append(var);\r
- retval.append("++;\n");\r
- return(retval);\r
- }\r
- if(op == "SUM"){\r
- retval.append(var);\r
- retval.append(" += ");\r
- retval.append(generate_se_code(atbl->get_aggr_se(aidx), schema) );\r
- retval.append(";\n");\r
- return(retval);\r
- }\r
- if(op == "MIN"){\r
- sprintf(tmpstr,"aggr_tmp_%d",aidx);\r
- retval += dt->make_host_cvar(tmpstr);\r
- retval += " = ";\r
- retval += generate_se_code(atbl->get_aggr_se(aidx), schema )+";\n";\r
- if(dt->complex_comparison(dt)){\r
- if(dt->is_buffer_type())\r
- sprintf(tmpstr,"\t\tif(%s(&aggr_tmp_%d,&(%s)) < 0)\n",dt->get_hfta_comparison_fcn(dt).c_str(), aidx, var.c_str());\r
- else\r
- sprintf(tmpstr,"\t\tif(%s(aggr_tmp_%d,%s) < 0)\n",dt->get_hfta_comparison_fcn(dt).c_str(), aidx, var.c_str());\r
- }else{\r
- sprintf(tmpstr,"\t\tif(aggr_tmp_%d < %s)\n",aidx,var.c_str());\r
- }\r
- retval.append(tmpstr);\r
- if(dt->is_buffer_type()){\r
- sprintf(tmpstr,"\t\t\t%s(&(%s),&aggr_tmp_%d);\n",dt->get_hfta_buffer_replace().c_str(),var.c_str(),aidx);\r
- }else{\r
- sprintf(tmpstr,"\t\t\t%s = aggr_tmp_%d;\n",var.c_str(),aidx);\r
- }\r
- retval.append(tmpstr);\r
-\r
- return(retval);\r
- }\r
- if(op == "MAX"){\r
- sprintf(tmpstr,"aggr_tmp_%d",aidx);\r
- retval+=dt->make_host_cvar(tmpstr);\r
- retval+=" = ";\r
- retval+=generate_se_code(atbl->get_aggr_se(aidx), schema )+";\n";\r
- if(dt->complex_comparison(dt)){\r
- if(dt->is_buffer_type())\r
- sprintf(tmpstr,"\t\tif(%s(&aggr_tmp_%d,&(%s)) > 0)\n",dt->get_hfta_comparison_fcn(dt).c_str(), aidx, var.c_str());\r
- else\r
- sprintf(tmpstr,"\t\tif(%s(aggr_tmp_%d,%s) > 0)\n",dt->get_hfta_comparison_fcn(dt).c_str(), aidx, var.c_str());\r
- }else{\r
- sprintf(tmpstr,"\t\tif(aggr_tmp_%d > %s)\n",aidx,var.c_str());\r
- }\r
- retval.append(tmpstr);\r
- if(dt->is_buffer_type()){\r
- sprintf(tmpstr,"\t\t\t%s(&(%s),&aggr_tmp_%d);\n",dt->get_hfta_buffer_replace().c_str(),var.c_str(),aidx);\r
- }else{\r
- sprintf(tmpstr,"\t\t\t%s = aggr_tmp_%d;\n",var.c_str(),aidx);\r
- }\r
- retval.append(tmpstr);\r
-\r
- return(retval);\r
-\r
- }\r
- if(op == "AND_AGGR"){\r
- retval.append(var);\r
- retval.append(" &= ");\r
- retval.append(generate_se_code(atbl->get_aggr_se(aidx), schema) );\r
- retval.append(";\n");\r
- return(retval);\r
- }\r
- if(op == "OR_AGGR"){\r
- retval.append(var);\r
- retval.append(" |= ");\r
- retval.append(generate_se_code(atbl->get_aggr_se(aidx), schema) );\r
- retval.append(";\n");\r
- return(retval);\r
- }\r
- if(op == "XOR_AGGR"){\r
- retval.append(var);\r
- retval.append(" ^= ");\r
- retval.append(generate_se_code(atbl->get_aggr_se(aidx), schema) );\r
- retval.append(";\n");\r
- return(retval);\r
- }\r
- if(op=="AVG"){\r
- retval += var+"_sum += "+generate_se_code(atbl->get_aggr_se(aidx), schema)+";\n";\r
- retval += "\t\t"+var+"_cnt += 1;\n";\r
- retval += "\t\t"+var+" = "+var+"_sum / "+var+"_cnt;\n";\r
- return retval;\r
- }\r
-\r
- fprintf(stderr,"INTERNAL ERROR : aggregate %s not recognized in query_plan::generate_aggr_update.\n",op.c_str());\r
- exit(1);\r
- return(retval);\r
-\r
-}\r
-\r
-\r
-// superaggr minus.\r
-\r
-static string generate_superaggr_minus(string var, string supervar, aggregate_table *atbl,int aidx, table_list *schema){\r
- string retval = "\t\t";\r
- string op = atbl->get_op(aidx);\r
-\r
-// Is it a UDAF\r
- if(! atbl->is_builtin(aidx)) {\r
- int o;\r
- retval += op+"_HFTA_AGGR_MINUS_(";\r
- if(atbl->get_storage_type(aidx)->get_type() != fstring_t) retval+="&";\r
- retval+="("+supervar+"),";\r
- if(atbl->get_storage_type(aidx)->get_type() != fstring_t) retval+="&";\r
- retval+="("+var+");\n";\r
-\r
- return retval;\r
- }\r
-\r
-\r
- if(op == "COUNT" || op == "SUM"){\r
- retval += supervar + "-=" +var + ";\n";\r
- return(retval);\r
- }\r
-\r
- if(op == "XOR_AGGR"){\r
- retval += supervar + "^=" +var + ";\n";\r
- return(retval);\r
- }\r
-\r
- if(op=="MIN" || op == "MAX")\r
- return "";\r
-\r
- fprintf(stderr,"INTERNAL ERROR : aggregate %s not recognized in generate_superaggr_minus.\n",op.c_str());\r
- exit(1);\r
- return(retval);\r
-\r
-}\r
-\r
-\r
-\r
-\r
-static string generate_aggr_init(string var, aggregate_table *atbl,int aidx, table_list *schema){\r
- string retval;\r
- string op = atbl->get_op(aidx);\r
-\r
-// UDAF processing\r
- if(! atbl->is_builtin(aidx)){\r
-// initialize\r
- retval += "\t"+atbl->get_op(aidx)+"_HFTA_AGGR_INIT_(";\r
- if(atbl->get_storage_type(aidx)->get_type() != fstring_t) retval+="&";\r
- retval+="("+var+"));\n";\r
-// Add 1st tupl\r
- retval += "\t"+atbl->get_op(aidx)+"_HFTA_AGGR_UPDATE_(";\r
- if(atbl->get_storage_type(aidx)->get_type() != fstring_t) retval+="&";\r
- retval+="("+var+")";\r
- vector<scalarexp_t *> opl = atbl->get_operand_list(aidx);\r
- int o;\r
- for(o=0;o<opl.size();++o){\r
- retval += ",";\r
- if(opl[o]->get_data_type()->is_buffer_type() && (! (opl[o]->is_handle_ref()) ) )\r
- retval.append("&");\r
- retval += generate_se_code(opl[o],schema);\r
- }\r
- retval += ");\n";\r
- return(retval);\r
- }\r
-\r
-// builtin aggregate processing\r
- data_type *dt = atbl->get_data_type(aidx);\r
-\r
- if(op == "COUNT"){\r
- retval = var;\r
- retval.append(" = 1;\n");\r
- return(retval);\r
- }\r
-\r
- if(op == "SUM" || op == "MIN" || op == "MAX" || op == "AND_AGGR" ||\r
- op=="AVG" || op == "OR_AGGR" || op == "XOR_AGGR"){\r
- if(dt->is_buffer_type()){\r
- sprintf(tmpstr,"\t\taggr_tmp_%d = %s;\n",aidx,generate_se_code(atbl->get_aggr_se(aidx), schema ).c_str() );\r
- retval.append(tmpstr);\r
- sprintf(tmpstr,"\t\t%s(&(%s),&aggr_tmp_%d);\n",dt->get_hfta_buffer_assign_copy().c_str(),var.c_str(),aidx);\r
- retval.append(tmpstr);\r
- }else{\r
- if(op=="AVG"){\r
- retval += var+"_sum = "+generate_se_code(atbl->get_aggr_se(aidx), schema)+";\n";\r
- retval += "\t"+var+"_cnt = 1;\n";\r
- retval += "\t"+var+" = "+var+"_sum;\n";\r
- }else{\r
- retval = var;\r
- retval += " = ";\r
- retval.append(generate_se_code(atbl->get_aggr_se(aidx), schema));\r
- retval.append(";\n");\r
- }\r
- }\r
- return(retval);\r
- }\r
-\r
- fprintf(stderr,"INTERNAL ERROR : aggregate %s not recognized in query_plan::generate_aggr_init.\n",op.c_str());\r
- exit(1);\r
- return(retval);\r
-\r
-}\r
-\r
-\r
-\r
-static string generate_aggr_reinitialize(string var, aggregate_table *atbl,int aidx, table_list *schema){\r
- string retval;\r
- string op = atbl->get_op(aidx);\r
-\r
-// UDAF processing\r
- if(! atbl->is_builtin(aidx)){\r
-// initialize\r
- retval += "\t"+atbl->get_op(aidx);\r
- if(atbl->is_running_aggr(aidx)){\r
- retval += "_HFTA_AGGR_REINIT_(";\r
- }else{\r
- retval += "_HFTA_AGGR_INIT_(";\r
- }\r
- if(atbl->get_storage_type(aidx)->get_type() != fstring_t) retval+="&";\r
- retval+="("+var+"));\n";\r
- return(retval);\r
- }\r
-\r
-// builtin aggregate processing\r
- data_type *dt = atbl->get_data_type(aidx);\r
-\r
- if(op == "COUNT"){\r
- retval = var;\r
- retval.append(" = 0;\n");\r
- return(retval);\r
- }\r
-\r
- if(op == "SUM" || op == "AND_AGGR" ||\r
- op == "OR_AGGR" || op == "XOR_AGGR"){\r
- if(dt->is_buffer_type()){\r
- return("ERROR, cannot yet handle reinitialization of builtin aggregates over strings.");\r
- }else{\r
- retval = var;\r
- retval += " = ";\r
- literal_t l(dt->type_indicator());\r
- retval.append(l.to_string());\r
- retval.append(";\n");\r
- }\r
- return(retval);\r
- }\r
-\r
- if(op == "MIN"){\r
- if(dt->is_buffer_type()){\r
- return("ERROR, cannot yet handle reinitialization of builtin aggregates over strings.");\r
- }else{\r
- retval = var;\r
- retval += " = ";\r
- retval.append(dt->get_max_literal());\r
- retval.append(";\n");\r
- }\r
- return(retval);\r
- }\r
-\r
- if(op == "MAX"){\r
- if(dt->is_buffer_type()){\r
- return("ERROR, cannot yet handle reinitialization of builtin aggregates over strings.");\r
- }else{\r
- retval = var;\r
- retval += " = ";\r
- retval.append(dt->get_min_literal());\r
- retval.append(";\n");\r
- }\r
- return(retval);\r
- }\r
-\r
- fprintf(stderr,"INTERNAL ERROR : aggregate %s not recognized in generate_aggr_reinitialize.\n",op.c_str());\r
- exit(1);\r
- return(retval);\r
-\r
-}\r
-\r
-\r
-// Generate parameter holding vars from a param table.\r
-static string generate_param_vars(param_table *param_tbl){\r
- string ret;\r
- int p;\r
- vector<string> param_vec = param_tbl->get_param_names();\r
- for(p=0;p<param_vec.size();p++){\r
- data_type *dt = param_tbl->get_data_type(param_vec[p]);\r
- sprintf(tmpstr,"param_%s;\n", param_vec[p].c_str());\r
- ret += "\t"+dt->make_host_cvar(tmpstr)+";\n";\r
- if(param_tbl->handle_access(param_vec[p])){\r
- ret += "\tstruct search_handle *param_handle_"+param_vec[p]+";\n";\r
- }\r
- }\r
- return(ret);\r
-}\r
-\r
-// Parameter manipulation routines\r
-static string generate_load_param_block(string functor_name,\r
- param_table *param_tbl,\r
- vector<handle_param_tbl_entry *> param_handle_table\r
- ){\r
- int p;\r
- vector<string> param_names = param_tbl->get_param_names();\r
-\r
- string ret = "int load_params_"+functor_name+"(gs_int32_t sz, void *value){\n";\r
- ret.append("\tint pos=0;\n");\r
- ret.append("\tint data_pos;\n");\r
-\r
- for(p=0;p<param_names.size();p++){\r
- data_type *dt = param_tbl->get_data_type(param_names[p]);\r
- if(dt->is_buffer_type()){\r
- sprintf(tmpstr,"tmp_var_%s;\n", param_names[p].c_str());\r
- ret += "\t"+dt->make_host_cvar(tmpstr)+";\n";\r
- }\r
- }\r
-\r
-\r
-// Verify that the block is of minimum size\r
- if(param_names.size() > 0){\r
- ret += "//\tVerify that the value block is large enough */\n";\r
- ret.append("\n\tdata_pos = ");\r
- for(p=0;p<param_names.size();p++){\r
- if(p>0) ret.append(" + ");\r
- data_type *dt = param_tbl->get_data_type(param_names[p]);\r
- ret.append("sizeof( ");\r
- ret.append( dt->get_host_cvar_type() );\r
- ret.append(" )");\r
- }\r
- ret.append(";\n");\r
- ret.append("\tif(data_pos > sz) return 1;\n\n");\r
- }\r
-\r
-///////////////////////\r
-/// Verify that all strings can be unpacked.\r
-\r
- ret += "//\tVerify that the strings can be unpacked */\n";\r
- for(p=0;p<param_names.size();p++){\r
- data_type *dt = param_tbl->get_data_type(param_names[p]);\r
- if(dt->is_buffer_type()){\r
- sprintf(tmpstr,"\ttmp_var_%s = *( (%s *)((gs_sp_t )value+pos) );\n",param_names[p].c_str(), dt->get_host_cvar_type().c_str() );\r
- ret.append(tmpstr);\r
- switch( dt->get_type() ){\r
- case v_str_t:\r
-// ret += "\ttmp_var_"+param_names[p]+".offset = ntohl( tmp_var_"+param_names[p]+".offset );\n"; // ntoh conversion\r
-// ret += "\ttmp_var_"+param_names[p]+".length = ntohl( tmp_var_"+param_names[p]+".length );\n"; // ntoh conversion\r
- sprintf(tmpstr,"\tif( (int)(tmp_var_%s.offset) + tmp_var_%s.length > sz) return 1;\n",param_names[p].c_str(), param_names[p].c_str() );\r
- ret.append(tmpstr);\r
- sprintf(tmpstr,"\ttmp_var_%s.offset = (gs_p_t)( (gs_sp_t )value + (gs_p_t)(tmp_var_%s.offset) );\n",param_names[p].c_str(), param_names[p].c_str() );\r
- ret.append(tmpstr);\r
- break;\r
- default:\r
- fprintf(stderr,"ERROR: parameter %s is of type %s, a buffered type, but I don't know how to unpack it as a parameter.\n",param_names[p].c_str(), dt->to_string().c_str() );\r
- exit(1);\r
- break;\r
- }\r
- }\r
- ret += "\tpos += sizeof( "+dt->get_host_cvar_type()+" );\n";\r
- }\r
-\r
-\r
-/////////////////////////\r
-\r
- ret += "/*\tThe block is OK, do the unpacking. */\n";\r
- ret += "\tpos = 0;\n";\r
-\r
- for(p=0;p<param_names.size();p++){\r
- data_type *dt = param_tbl->get_data_type(param_names[p]);\r
- if(dt->is_buffer_type()){\r
- sprintf(tmpstr,"\t%s(¶m_%s, &tmp_var_%s);\n", dt->get_hfta_buffer_assign_copy().c_str(),param_names[p].c_str(),param_names[p].c_str() );\r
- ret.append(tmpstr);\r
- }else{\r
-// if(dt->needs_hn_translation()){\r
-// sprintf(tmpstr,"\tparam_%s = %s( *( (%s *)( (gs_sp_t )value+pos) ) );\n",\r
-// param_names[p].c_str(), dt->ntoh_translation().c_str(), dt->get_host_cvar_type().c_str() );\r
-// }else{\r
- sprintf(tmpstr,"\tparam_%s = *( (%s *)( (gs_sp_t )value+pos) );\n",\r
- param_names[p].c_str(), dt->get_host_cvar_type().c_str() );\r
-// }\r
- ret.append(tmpstr);\r
- }\r
- ret += "\tpos += sizeof( "+dt->get_host_cvar_type()+" );\n";\r
- }\r
-\r
-// TODO: I think this method of handle registration is obsolete\r
-// and should be deleted.\r
-// some examination reveals that handle_access is always false.\r
- for(p=0;p<param_names.size();p++){\r
- if(param_tbl->handle_access(param_names[p]) ){\r
- data_type *pdt = param_tbl->get_data_type(param_names[p]);\r
-// create the new.\r
- ret += "\tt->param_handle_"+param_names[p]+" = " +\r
- pdt->handle_registration_name() +\r
- "((struct FTA *)t, &(t->param_"+param_names[p]+"));\n";\r
- }\r
- }\r
-// Register the pass-by-handle parameters\r
-\r
- ret += "/* register the pass-by-handle parameters */\n";\r
-\r
- int ph;\r
- for(ph=0;ph<param_handle_table.size();++ph){\r
- data_type pdt(param_handle_table[ph]->type_name);\r
- switch(param_handle_table[ph]->val_type){\r
- case cplx_lit_e:\r
- break;\r
- case litval_e:\r
- break;\r
- case param_e:\r
- sprintf(tmpstr,"\thandle_param_%d = %s(",ph,param_handle_table[ph]->lfta_registration_fcn().c_str());\r
- ret += tmpstr;\r
- if(pdt.is_buffer_type()) ret += "&(";\r
- ret += "param_"+param_handle_table[ph]->param_name;\r
- if(pdt.is_buffer_type()) ret += ")";\r
- ret += ");\n";\r
- break;\r
- default:\r
- fprintf(stderr, "INTERNAL ERROR unknown case found when processing pass-by-handle parameter table.\n");\r
- exit(1);\r
- }\r
- }\r
-\r
-\r
- ret += "\treturn(0);\n";\r
- ret.append("}\n\n");\r
-\r
- return(ret);\r
-\r
-}\r
-\r
-static string generate_delete_param_block(string functor_name,\r
- param_table *param_tbl,\r
- vector<handle_param_tbl_entry *> param_handle_table\r
- ){\r
-\r
- int p;\r
- vector<string> param_names = param_tbl->get_param_names();\r
-\r
- string ret = "void destroy_params_"+functor_name+"(){\n";\r
-\r
- for(p=0;p<param_names.size();p++){\r
- data_type *dt = param_tbl->get_data_type(param_names[p]);\r
- if(dt->is_buffer_type()){\r
- sprintf(tmpstr,"\t\t%s(¶m_%s);\n",dt->get_hfta_buffer_destroy().c_str(),param_names[p].c_str());\r
- ret.append(tmpstr);\r
- }\r
- if(param_tbl->handle_access(param_names[p]) ){\r
- ret += "\t\t" + dt->get_handle_destructor() +\r
- "(t->param_handle_" + param_names[p] + ");\n";\r
- }\r
- }\r
-\r
- ret += "//\t\tDeregister handles.\n";\r
- int ph;\r
- for(ph=0;ph<param_handle_table.size();++ph){\r
- if(param_handle_table[ph]->val_type == param_e){\r
- sprintf(tmpstr, "\t\t%s(handle_param_%d);\n",\r
- param_handle_table[ph]->lfta_deregistration_fcn().c_str(),ph);\r
- ret += tmpstr;\r
- }\r
- }\r
-\r
- ret += "}\n\n";\r
- return ret;\r
-}\r
-\r
-// ---------------------------------------------------------------------\r
-// functions for creating functor variables.\r
-\r
-static string generate_access_vars(col_id_set &cid_set, table_list *schema){\r
- string ret;\r
- col_id_set::iterator csi;\r
-\r
- for(csi=cid_set.begin(); csi!=cid_set.end();++csi){\r
- int schref = (*csi).schema_ref;\r
- int tblref = (*csi).tblvar_ref;\r
- string field = (*csi).field;\r
- data_type dt(schema->get_type_name(schref,field));\r
- sprintf(tmpstr,"unpack_var_%s_%d", field.c_str(), tblref);\r
- ret+="\t"+dt.make_host_cvar(tmpstr)+";\n";\r
- sprintf(tmpstr,"\tgs_int32_t unpack_offset_%s_%d;\n", field.c_str(), tblref);\r
- ret.append(tmpstr);\r
- }\r
- return(ret);\r
-}\r
-\r
-static string generate_partial_fcn_vars(vector<scalarexp_t *> &partial_fcns,\r
- vector<int> &ref_cnt, vector<bool> &is_partial, bool gen_fcn_cache){\r
- string ret;\r
- int p;\r
-\r
-\r
- for(p=0;p<partial_fcns.size();++p){\r
- if(!gen_fcn_cache || is_partial[p] || ref_cnt[p]>1){\r
- sprintf(tmpstr,"partial_fcn_result_%d", p);\r
- ret+="\t"+partial_fcns[p]->get_data_type()->make_host_cvar(tmpstr)+";\n";\r
- if(gen_fcn_cache && ref_cnt[p]>1){\r
- ret+="\tint fcn_ref_cnt_"+int_to_string(p)+";\n";\r
- }\r
- }\r
- }\r
- return(ret);\r
-}\r
-\r
-\r
-static string generate_complex_lit_vars(cplx_lit_table *complex_literals){\r
- string ret;\r
- int cl;\r
- for(cl=0;cl<complex_literals->size();cl++){\r
- literal_t *l = complex_literals->get_literal(cl);\r
- data_type *dtl = new data_type( l->get_type() );\r
- sprintf(tmpstr,"complex_literal_%d",cl);\r
- ret += "\t"+dtl->make_host_cvar(tmpstr)+";\n";\r
- if(complex_literals->is_handle_ref(cl)){\r
- sprintf(tmpstr,"\tstruct search_handle *lit_handle_%d;\n",cl);\r
- ret.append(tmpstr);\r
- }\r
- }\r
- return(ret);\r
-}\r
-\r
-\r
-static string generate_pass_by_handle_vars(\r
- vector<handle_param_tbl_entry *> ¶m_handle_table){\r
- string ret;\r
- int p;\r
-\r
- for(p=0;p<param_handle_table.size();++p){\r
- sprintf(tmpstr,"\tgs_param_handle_t handle_param_%d;\n",p);\r
- ret += tmpstr;\r
- }\r
-\r
- return(ret);\r
-}\r
-\r
-\r
-// ------------------------------------------------------------\r
-// functions for generating initialization code.\r
-\r
-static string gen_access_var_init(col_id_set &cid_set){\r
- string ret;\r
- col_id_set::iterator csi;\r
-\r
- for(csi=cid_set.begin(); csi!=cid_set.end();++csi){\r
- int tblref = (*csi).tblvar_ref;\r
- string field = (*csi).field;\r
- sprintf(tmpstr,"\tunpack_offset_%s_%d = ftaschema_get_field_offset_by_name(schema_handle%d, \"%s\");\n", field.c_str(),tblref,tblref,field.c_str());\r
- ret.append(tmpstr);\r
- }\r
- return ret;\r
-}\r
-\r
-\r
-static string gen_complex_lit_init(cplx_lit_table *complex_literals){\r
- string ret;\r
-\r
- int cl;\r
- for(cl=0;cl<complex_literals->size();cl++){\r
- literal_t *l = complex_literals->get_literal(cl);\r
-// sprintf(tmpstr,"\tcomplex_literal_%d = ",cl);\r
-// ret += tmpstr + l->to_hfta_C_code() + ";\n";\r
- sprintf(tmpstr,"&(complex_literal_%d)",cl);\r
- ret += "\t" + l->to_hfta_C_code(tmpstr) + ";\n";\r
-// I think that the code below is obsolete\r
-// TODO: it is obsolete. add_cpx_lit is always\r
-// called with the handle indicator being false.\r
-// This entire structure should be cleansed.\r
- if(complex_literals->is_handle_ref(cl)){\r
- data_type *dt = new data_type( l->get_type() );\r
- sprintf(tmpstr,"\tlit_handle_%d = %s(&(f->complex_literal_%d));\n",\r
- cl, dt->hfta_handle_registration_name().c_str(), cl);\r
- ret += tmpstr;\r
- delete dt;\r
- }\r
- }\r
- return(ret);\r
-}\r
-\r
-\r
-static string gen_partial_fcn_init(vector<scalarexp_t *> &partial_fcns){\r
- string ret;\r
-\r
- int p;\r
- for(p=0;p<partial_fcns.size();++p){\r
- data_type *pdt =partial_fcns[p]->get_data_type();\r
- literal_t empty_lit(pdt->type_indicator());\r
- if(pdt->is_buffer_type()){\r
-// sprintf(tmpstr,"\tpartial_fcn_result_%d = %s;\n",\r
-// p, empty_lit.to_hfta_C_code().c_str());\r
- sprintf(tmpstr,"&(partial_fcn_result_%d)",p);\r
- ret += "\t"+empty_lit.to_hfta_C_code(tmpstr)+";\n";\r
- }\r
- }\r
- return(ret);\r
-}\r
-\r
-static string gen_pass_by_handle_init(\r
- vector<handle_param_tbl_entry *> ¶m_handle_table){\r
- string ret;\r
-\r
- int ph;\r
- for(ph=0;ph<param_handle_table.size();++ph){\r
- data_type pdt(param_handle_table[ph]->type_name);\r
- sprintf(tmpstr,"\thandle_param_%d = %s(",ph,param_handle_table[ph]->lfta_registration_fcn().c_str());\r
- switch(param_handle_table[ph]->val_type){\r
- case cplx_lit_e:\r
- ret += tmpstr;\r
- if(pdt.is_buffer_type()) ret += "&(";\r
- sprintf(tmpstr,"complex_literal_%d",param_handle_table[ph]->complex_literal_idx);\r
- ret += tmpstr;\r
- if(pdt.is_buffer_type()) ret += ")";\r
- ret += ");\n";\r
- break;\r
- case litval_e:\r
- ret += tmpstr;\r
- ret += param_handle_table[ph]->litval->to_hfta_C_code("") + ");\n";\r
-// ret += ");\n";\r
- break;\r
- case param_e:\r
-// query parameter handles are regstered/deregistered in the\r
-// load_params function.\r
-// ret += "t->param_"+param_handle_table[ph]->param_name;\r
- break;\r
- default:\r
- fprintf(stderr, "INTERNAL ERROR unknown case found when processing pass-by-handle parameter table.\n");\r
- exit(1);\r
- }\r
- }\r
- return(ret);\r
-}\r
-\r
-//------------------------------------------------------------\r
-// functions for destructor and deregistration code\r
-\r
-static string gen_complex_lit_dtr(cplx_lit_table *complex_literals){\r
- string ret;\r
-\r
- int cl;\r
- for(cl=0;cl<complex_literals->size();cl++){\r
- literal_t *l = complex_literals->get_literal(cl);\r
- data_type ldt( l->get_type() );\r
- if(ldt.is_buffer_type()){\r
- sprintf(tmpstr,"\t\t%s(&complex_literal_%d);\n",\r
- ldt.get_hfta_buffer_destroy().c_str(), cl );\r
- ret += tmpstr;\r
- }\r
- }\r
- return(ret);\r
-}\r
-\r
-\r
-static string gen_pass_by_handle_dtr(\r
- vector<handle_param_tbl_entry *> ¶m_handle_table){\r
- string ret;\r
-\r
- int ph;\r
- for(ph=0;ph<param_handle_table.size();++ph){\r
- sprintf(tmpstr, "\t\t%s(handle_param_%d);\n",\r
- param_handle_table[ph]->lfta_deregistration_fcn().c_str(),ph);\r
- ret += tmpstr;\r
- }\r
- return(ret);\r
-}\r
-\r
-// Destroy all previous results\r
-static string gen_partial_fcn_dtr(vector<scalarexp_t *> &partial_fcns){\r
- string ret;\r
-\r
- int p;\r
- for(p=0;p<partial_fcns.size();++p){\r
- data_type *pdt =partial_fcns[p]->get_data_type();\r
- if(pdt->is_buffer_type()){\r
- sprintf(tmpstr,"\t\t%s(&partial_fcn_result_%d);\n",\r
- pdt->get_hfta_buffer_destroy().c_str(), p );\r
- ret += tmpstr;\r
- }\r
- }\r
- return(ret);\r
-}\r
-\r
-// Destroy previsou results of fcns in pfcn_set\r
-static string gen_partial_fcn_dtr(vector<scalarexp_t *> &partial_fcns, set<int> &pfcn_set){\r
- string ret;\r
- set<int>::iterator si;\r
-\r
- for(si=pfcn_set.begin(); si!=pfcn_set.end(); ++si){\r
- data_type *pdt =partial_fcns[(*si)]->get_data_type();\r
- if(pdt->is_buffer_type()){\r
- sprintf(tmpstr,"\t\t%s(&partial_fcn_result_%d);\n",\r
- pdt->get_hfta_buffer_destroy().c_str(), (*si) );\r
- ret += tmpstr;\r
- }\r
- }\r
- return(ret);\r
-}\r
-\r
-\r
-//-------------------------------------------------------------------------\r
-// Functions related to se generation bookkeeping.\r
-\r
-static void get_new_pred_cids(predicate_t *pr, col_id_set &found_cids,\r
- col_id_set &new_cids, gb_table *gtbl){\r
- col_id_set this_pred_cids;\r
- col_id_set::iterator csi;\r
-\r
-// get colrefs in predicate not already found.\r
- gather_pr_col_ids(pr,this_pred_cids,gtbl);\r
- set_difference(this_pred_cids.begin(), this_pred_cids.end(),\r
- found_cids.begin(), found_cids.end(),\r
- inserter(new_cids,new_cids.begin()) );\r
-\r
-// We've found these cids, so update found_cids\r
- for(csi=new_cids.begin(); csi!=new_cids.end(); ++csi)\r
- found_cids.insert((*csi));\r
-\r
-}\r
-\r
-// after the call, new_cids will have the colrefs in se but not found_cids.\r
-// update found_cids with the new cids.\r
-static void get_new_se_cids(scalarexp_t *se, col_id_set &found_cids,\r
- col_id_set &new_cids, gb_table *gtbl){\r
- col_id_set this_se_cids;\r
- col_id_set::iterator csi;\r
-\r
-// get colrefs in se not already found.\r
- gather_se_col_ids(se,this_se_cids,gtbl);\r
- set_difference(this_se_cids.begin(), this_se_cids.end(),\r
- found_cids.begin(), found_cids.end(),\r
- inserter(new_cids,new_cids.begin()) );\r
-\r
-// We've found these cids, so update found_cids\r
- for(csi=new_cids.begin(); csi!=new_cids.end(); ++csi)\r
- found_cids.insert((*csi));\r
-\r
-}\r
-\r
-static string gen_unpack_cids(table_list *schema, col_id_set &new_cids, string on_problem, vector<bool> &needs_xform){\r
- string ret;\r
- col_id_set::iterator csi;\r
-\r
- for(csi=new_cids.begin(); csi!=new_cids.end(); ++csi){\r
- int schref = (*csi).schema_ref;\r
- int tblref = (*csi).tblvar_ref;\r
- string field = (*csi).field;\r
- data_type dt(schema->get_type_name(schref,field));\r
- string unpack_fcn;\r
- if(needs_xform[tblref]){\r
- unpack_fcn = dt.get_hfta_unpack_fcn();\r
- }else{\r
- unpack_fcn = dt.get_hfta_unpack_fcn_noxf();\r
- }\r
- if(dt.is_buffer_type()){\r
- sprintf(tmpstr,"\t unpack_var_%s_%d = %s(tup%d.data, tup%d.tuple_size, unpack_offset_%s_%d, &problem);\n",field.c_str(), tblref, unpack_fcn.c_str(), tblref, tblref, field.c_str(), tblref);\r
- }else{\r
- sprintf(tmpstr,"\t unpack_var_%s_%d = %s_nocheck(tup%d.data, unpack_offset_%s_%d);\n",field.c_str(), tblref, unpack_fcn.c_str(), tblref, field.c_str(), tblref);\r
- }\r
- ret += tmpstr;\r
- if(dt.is_buffer_type()){\r
- ret += "\tif(problem) return "+on_problem+" ;\n";\r
- }\r
- }\r
- return(ret);\r
-}\r
-\r
-// generates the declaration of all the variables related to\r
-// temp tuples generation\r
-static string gen_decl_temp_vars(){\r
- string ret;\r
-\r
- ret += "\t// variables related to temp tuple generation\n";\r
- ret += "\tbool temp_tuple_received;\n";\r
-\r
- return(ret);\r
-}\r
-\r
-// generates initialization code for variables related to temp tuple processing\r
-static string gen_init_temp_vars(table_list *schema, vector<select_element *>& select_list, gb_table *gtbl){\r
- string ret;\r
- col_id_set::iterator csi;\r
- int s;\r
-\r
-// Initialize internal state\r
- ret += "\ttemp_tuple_received = false;\n";\r
-\r
- col_id_set temp_cids; // colrefs unpacked thus far.\r
-\r
- for(s=0;s<select_list.size();s++){\r
- if (select_list[s]->se->get_data_type()->is_temporal()) {\r
-// Find the set of attributes accessed in this SE\r
- col_id_set new_cids;\r
- get_new_se_cids(select_list[s]->se,temp_cids, new_cids, gtbl);\r
-\r
- // init these vars\r
- for(csi=new_cids.begin(); csi!=new_cids.end(); ++csi){\r
- int schref = (*csi).schema_ref;\r
- int tblref = (*csi).tblvar_ref;\r
- string field = (*csi).field;\r
- data_type dt(schema->get_type_name(schref,field), schema->get_modifier_list(schref,field));\r
-\r
- sprintf(tmpstr,"\t unpack_var_%s_%d = %s;\n", field.c_str(), tblref,\r
- dt.is_increasing() ? dt.get_min_literal().c_str() : dt.get_max_literal().c_str());\r
- ret += tmpstr;\r
- }\r
- }\r
- }\r
- return(ret);\r
-}\r
-\r
-\r
-\r
-// generates a check if tuple is temporal\r
-static string gen_temp_tuple_check(string node_name, int channel) {\r
- string ret;\r
-\r
- char tmpstr[256];\r
- sprintf(tmpstr, "tup%d", channel);\r
- string tup_name = tmpstr;\r
- sprintf(tmpstr, "schema_handle%d", channel);\r
- string schema_handle_name = tmpstr;\r
- string tuple_offset_name = "tuple_metadata_offset"+int_to_string(channel);\r
-\r
-// check if it is a temporary status tuple\r
- ret += "\t// check if tuple is temp status tuple\n";\r
-// ret += "\tif (ftaschema_is_temporal_tuple(" + schema_handle_name + ", " + tup_name + ".data)) {\n";\r
- ret += "\tif (ftaschema_is_temporal_tuple_offset(" + tuple_offset_name + ", " + tup_name + ".data)) {\n";\r
- ret += "\t\ttemp_tuple_received = true;\n";\r
- ret += "\t}\n";\r
- ret += "\telse\n\t\ttemp_tuple_received = false;\n\n";\r
-\r
- return(ret);\r
-}\r
-\r
-// generates unpacking code for all temporal attributes referenced in select\r
-static string gen_unpack_temp_vars(table_list *schema, col_id_set& found_cids, vector<select_element *>& select_list, gb_table *gtbl, vector<bool> &needs_xform) {\r
- string ret;\r
- int s;\r
-\r
-// Unpack all the temporal attributes references in select list\r
-// we need it to be able to generate temp status tuples\r
- for(s=0;s<select_list.size();s++){\r
- if (select_list[s]->se->get_data_type()->is_temporal()) {\r
-// Find the set of attributes accessed in this SE\r
- col_id_set new_cids;\r
- get_new_se_cids(select_list[s]->se,found_cids, new_cids, gtbl);\r
-// Unpack these values.\r
- ret += gen_unpack_cids(schema, new_cids, "false", needs_xform);\r
- }\r
- }\r
-\r
- return(ret);\r
-}\r
-\r
-\r
-// Generates temporal tuple generation code (except attribute packing)\r
-static string gen_init_temp_status_tuple(string node_name) {\r
- string ret;\r
-\r
- ret += "\t// create temp status tuple\n";\r
- ret += "\tresult.tuple_size = sizeof("+generate_tuple_name( node_name)+") + sizeof(gs_uint8_t);\n";\r
- ret += "\tresult.data = (gs_sp_t )malloc(result.tuple_size);\n";\r
- ret += "\tresult.heap_resident = true;\n";\r
- ret += "\t// Mark tuple as temporal\n";\r
- ret += "\t*((gs_sp_t )result.data + sizeof("+generate_tuple_name( node_name)+")) = TEMPORAL_TUPLE;\n";\r
-\r
- ret += "\t"+generate_tuple_name( node_name)+" *tuple = ("+\r
- generate_tuple_name( node_name) +" *)(result.data);\n";\r
-\r
- return(ret);\r
-}\r
-\r
-\r
-// Assume that all colrefs unpacked already ...\r
-static string gen_unpack_partial_fcn(table_list *schema,\r
- vector<scalarexp_t *> &partial_fcns,set<int> &pfcn_refs,\r
- string on_problem){\r
- string ret;\r
- set<int>::iterator si;\r
-\r
-// Since set<..> is a "Sorted Associative Container",\r
-// we can walk through it in sorted order by walking from\r
-// begin() to end(). (and the partial fcns must be\r
-// evaluated in this order).\r
- for(si=pfcn_refs.begin();si!=pfcn_refs.end();++si){\r
- ret += unpack_partial_fcn(partial_fcns[(*si)], (*si), schema);\r
- ret += "\tif(retval) return "+on_problem+" ;\n";\r
- }\r
- return(ret);\r
-}\r
-\r
-// Assume that all colrefs unpacked already ...\r
-// this time with cached functions.\r
-static string gen_unpack_partial_fcn(table_list *schema,\r
- vector<scalarexp_t *> &partial_fcns,set<int> &pfcn_refs,\r
- vector<int> &fcn_ref_cnt, vector<bool> &is_partial_fcn,\r
- string on_problem){\r
- string ret;\r
- set<int>::iterator si;\r
-\r
-// Since set<..> is a "Sorted Associative Container",\r
-// we can walk through it in sorted order by walking from\r
-// begin() to end(). (and the partial fcns must be\r
-// evaluated in this order).\r
- for(si=pfcn_refs.begin();si!=pfcn_refs.end();++si){\r
- if(fcn_ref_cnt[(*si)] > 1){\r
- ret += "\tif(fcn_ref_cnt_"+int_to_string((*si))+"==0){\n";\r
- }\r
- if(is_partial_fcn[(*si)]){\r
- ret += unpack_partial_fcn(partial_fcns[(*si)], (*si), schema);\r
- ret += "\tif(retval) return "+on_problem+" ;\n";\r
- }\r
- if(fcn_ref_cnt[(*si)] > 1){\r
- if(!is_partial_fcn[(*si)]){\r
- ret += "\t\tpartial_fcn_result_"+int_to_string((*si))+"="+generate_cached_fcn(partial_fcns[(*si)],(*si),schema)+";\n";\r
- }\r
- ret += "\t\tfcn_ref_cnt_"+int_to_string((*si))+"=1;\n";\r
- ret += "\t}\n";\r
- }\r
- }\r
-\r
- return(ret);\r
-}\r
-\r
-\r
-// This version finds and unpacks new colrefs.\r
-// found_cids gets updated with the newly unpacked cids.\r
-static string gen_full_unpack_partial_fcn(table_list *schema,\r
- vector<scalarexp_t *> &partial_fcns,set<int> &pfcn_refs,\r
- col_id_set &found_cids, gb_table *gtbl, string on_problem,\r
- vector<bool> &needs_xform){\r
- string ret;\r
- set<int>::iterator slsi;\r
-\r
- for(slsi=pfcn_refs.begin(); slsi!=pfcn_refs.end(); ++slsi){\r
-// find all new fields ref'd by this partial fcn.\r
- col_id_set new_cids;\r
- get_new_se_cids(partial_fcns[(*slsi)], found_cids, new_cids, gtbl);\r
-// Unpack these values.\r
- ret += gen_unpack_cids(schema, new_cids, on_problem, needs_xform);\r
-\r
-// Now evaluate the partial fcn.\r
- ret += unpack_partial_fcn(partial_fcns[(*slsi)], (*slsi), schema);\r
- ret += "\tif(retval) return "+on_problem+" ;\n";\r
- }\r
- return(ret);\r
-}\r
-\r
-// This version finds and unpacks new colrefs.\r
-// found_cids gets updated with the newly unpacked cids.\r
-// BUT : only for the partial functions.\r
-static string gen_full_unpack_partial_fcn(table_list *schema,\r
- vector<scalarexp_t *> &partial_fcns,set<int> &pfcn_refs,\r
- vector<int> &fcn_ref_cnt, vector<bool> &is_partial_fcn,\r
- col_id_set &found_cids, gb_table *gtbl, string on_problem,\r
- vector<bool> &needs_xform){\r
- string ret;\r
- set<int>::iterator slsi;\r
-\r
- for(slsi=pfcn_refs.begin(); slsi!=pfcn_refs.end(); ++slsi){\r
- if(is_partial_fcn[(*slsi)]){\r
-// find all new fields ref'd by this partial fcn.\r
- col_id_set new_cids;\r
- get_new_se_cids(partial_fcns[(*slsi)], found_cids, new_cids, gtbl);\r
-// Unpack these values.\r
- ret += gen_unpack_cids(schema, new_cids, on_problem, needs_xform);\r
-\r
-// Now evaluate the partial fcn.\r
- if(fcn_ref_cnt[(*slsi)] > 1){\r
- ret += "\tif(fcn_ref_cnt_"+int_to_string((*slsi))+"==0){\n";\r
- }\r
- if(is_partial_fcn[(*slsi)]){\r
- ret += unpack_partial_fcn(partial_fcns[(*slsi)], (*slsi), schema);\r
- ret += "\tif(retval) return "+on_problem+" ;\n";\r
- }\r
- if(fcn_ref_cnt[(*slsi)] > 1){\r
- ret += "\t\tfcn_ref_cnt_"+int_to_string((*slsi))+"=1;\n";\r
- ret += "\t}\n";\r
- }\r
-\r
- }\r
- }\r
- return(ret);\r
-}\r
-\r
-static string gen_remaining_cached_fcns(table_list *schema,\r
- vector<scalarexp_t *> &partial_fcns,set<int> &pfcn_refs,\r
- vector<int> &fcn_ref_cnt, vector<bool> &is_partial_fcn){\r
- string ret;\r
- set<int>::iterator slsi;\r
-\r
- for(slsi=pfcn_refs.begin(); slsi!=pfcn_refs.end(); ++slsi){\r
- if(!is_partial_fcn[(*slsi)] && fcn_ref_cnt[(*slsi)] > 1){\r
-\r
- if(fcn_ref_cnt[(*slsi)] > 1){\r
- ret += "\tif(fcn_ref_cnt_"+int_to_string((*slsi))+"==0){\n";\r
- ret += "\t\tpartial_fcn_result_"+int_to_string((*slsi))+"="+generate_cached_fcn(partial_fcns[(*slsi)],(*slsi),schema)+";\n";\r
- ret += "\t\tfcn_ref_cnt_"+int_to_string((*slsi))+"=1;\n";\r
- ret += "\t}\n";\r
- }\r
- }\r
- }\r
- return(ret);\r
-}\r
-\r
-\r
-// unpack the colrefs in cid_set not in found_cids\r
-static string gen_remaining_colrefs(table_list *schema,\r
- col_id_set &cid_set, col_id_set &found_cids, string on_problem,\r
- vector<bool> &needs_xform){\r
- string ret;\r
- col_id_set::iterator csi;\r
-\r
- for(csi=cid_set.begin(); csi!=cid_set.end();csi++){\r
- if(found_cids.count( (*csi) ) == 0){\r
- int schref = (*csi).schema_ref;\r
- int tblref = (*csi).tblvar_ref;\r
- string field = (*csi).field;\r
- data_type dt(schema->get_type_name(schref,field));\r
- string unpack_fcn;\r
- if(needs_xform[tblref]){\r
- unpack_fcn = dt.get_hfta_unpack_fcn();\r
- }else{\r
- unpack_fcn = dt.get_hfta_unpack_fcn_noxf();\r
- }\r
- if(dt.is_buffer_type()){\r
- sprintf(tmpstr,"\t unpack_var_%s_%d = %s(tup%d.data, tup%d.tuple_size, unpack_offset_%s_%d, &problem);\n",field.c_str(), tblref, unpack_fcn.c_str(), tblref, tblref, field.c_str(), tblref);\r
- }else{\r
- sprintf(tmpstr,"\t unpack_var_%s_%d = %s_nocheck(tup%d.data, unpack_offset_%s_%d);\n",field.c_str(), tblref, unpack_fcn.c_str(), tblref, field.c_str(), tblref);\r
- }\r
- ret += tmpstr;\r
- if(dt.is_buffer_type()){\r
- ret.append("\tif(problem) return "+on_problem+" ;\n");\r
- }\r
- }\r
- }\r
- return(ret);\r
-}\r
-\r
-static string gen_buffer_selvars(table_list *schema,\r
- vector<select_element *> &select_list){\r
- string ret;\r
- int s;\r
-\r
- for(s=0;s<select_list.size();s++){\r
- scalarexp_t *se = select_list[s]->se;\r
- data_type *sdt = se->get_data_type();\r
- if(sdt->is_buffer_type() &&\r
- !( (se->get_operator_type() == SE_COLREF) ||\r
- (se->get_operator_type() == SE_FUNC && se->is_partial()) ||\r
- (se->get_operator_type() == SE_FUNC && se->get_aggr_ref() >= 0))\r
- ){\r
- sprintf(tmpstr,"selvar_%d",s);\r
- ret+="\t"+sdt->make_host_cvar(tmpstr)+" = ";\r
- ret += generate_se_code(se,schema) +";\n";\r
- }\r
- }\r
- return(ret);\r
-}\r
-\r
-static string gen_buffer_selvars_size(vector<select_element *> &select_list,table_list *schema){\r
- string ret;\r
- int s;\r
-\r
- for(s=0;s<select_list.size();s++){\r
- scalarexp_t *se = select_list[s]->se;\r
- data_type *sdt = se->get_data_type();\r
- if(sdt->is_buffer_type()){\r
- if( !( (se->get_operator_type() == SE_COLREF) ||\r
- (se->get_operator_type() == SE_FUNC && se->is_partial()) ||\r
- (se->get_operator_type() == SE_FUNC && se->get_aggr_ref() >= 0))\r
- ){\r
- sprintf(tmpstr," + %s(&selvar_%d)", sdt->get_hfta_buffer_size().c_str(),s);\r
- ret.append(tmpstr);\r
- }else{\r
- sprintf(tmpstr," + %s(&%s)", sdt->get_hfta_buffer_size().c_str(),\r
- generate_se_code(se,schema).c_str());\r
- ret.append(tmpstr);\r
- }\r
- }\r
- }\r
- return(ret);\r
-}\r
-\r
-static string gen_buffer_selvars_dtr(vector<select_element *> &select_list){\r
- string ret;\r
- int s;\r
-\r
- for(s=0;s<select_list.size();s++){\r
- scalarexp_t *se = select_list[s]->se;\r
- data_type *sdt = se->get_data_type();\r
- if(sdt->is_buffer_type() &&\r
- !( (se->get_operator_type() == SE_COLREF) ||\r
- (se->get_operator_type() == SE_AGGR_STAR) ||\r
- (se->get_operator_type() == SE_AGGR_SE) ||\r
- (se->get_operator_type() == SE_FUNC && se->is_partial()) ||\r
- (se->get_operator_type() == SE_FUNC && se->get_aggr_ref() >= 0))\r
- ){\r
- sprintf(tmpstr,"\t\t%s(&selvar_%d);\n",\r
- sdt->get_hfta_buffer_destroy().c_str(), s );\r
- ret += tmpstr;\r
- }\r
- }\r
- return(ret);\r
-}\r
-\r
-\r
-static string gen_pack_tuple(table_list *schema, vector<select_element *> &select_list, string node_name, bool temporal_only){\r
- string ret;\r
- int s;\r
-\r
- ret += "\tint tuple_pos = sizeof("+generate_tuple_name(node_name)+") + sizeof(gs_uint8_t);\n";\r
- for(s=0;s<select_list.size();s++){\r
- scalarexp_t *se = select_list[s]->se;\r
- data_type *sdt = se->get_data_type();\r
-\r
- if(!temporal_only && sdt->is_buffer_type()){\r
- if( !( (se->get_operator_type() == SE_COLREF) ||\r
- (se->get_operator_type() == SE_FUNC && se->is_partial()))\r
- ){\r
- sprintf(tmpstr,"\t%s(&(tuple->tuple_var%d), &selvar_%d, ((gs_sp_t )tuple)+tuple_pos, tuple_pos);\n", sdt->get_hfta_buffer_tuple_copy().c_str(),s, s);\r
- ret.append(tmpstr);\r
- sprintf(tmpstr,"\ttuple_pos += %s(&selvar_%d);\n", sdt->get_hfta_buffer_size().c_str(), s);\r
- ret.append(tmpstr);\r
- }else{\r
- sprintf(tmpstr,"\t%s(&(tuple->tuple_var%d), &%s, ((gs_sp_t )tuple)+tuple_pos, tuple_pos);\n", sdt->get_hfta_buffer_tuple_copy().c_str(),s, generate_se_code(se,schema).c_str());\r
- ret.append(tmpstr);\r
- sprintf(tmpstr,"\ttuple_pos += %s(&%s);\n", sdt->get_hfta_buffer_size().c_str(), generate_se_code(se,schema).c_str());\r
- ret.append(tmpstr);\r
- }\r
- }else if (!temporal_only || sdt->is_temporal()) {\r
- sprintf(tmpstr,"\ttuple->tuple_var%d = ",s);\r
- ret.append(tmpstr);\r
- ret.append(generate_se_code(se,schema) );\r
- ret.append(";\n");\r
- }\r
- }\r
- return(ret);\r
-}\r
-\r
-\r
-//-------------------------------------------------------------------------\r
-// functor generation methods\r
-//-------------------------------------------------------------------------\r
-\r
-/////////////////////////////////////////////////////////\r
-//// File Output Operator\r
-string output_file_qpn::generate_functor_name(){\r
- return("output_file_functor_" + normalize_name(get_node_name()));\r
-}\r
-\r
-\r
-string output_file_qpn::generate_functor(table_list *schema, ext_fcn_list *Ext_fcns, vector<bool> &needs_xform){\r
- string ret = "class " + this->generate_functor_name() + "{\n";\r
-\r
-// Find the temporal field\r
- int temporal_field_idx;\r
- data_type *tdt = NULL;\r
- for(temporal_field_idx=0;temporal_field_idx<fields.size();temporal_field_idx++){\r
- tdt = new data_type(fields[temporal_field_idx]->get_type(), fields[temporal_field_idx]->get_modifier_list());\r
- if(tdt->is_temporal()){\r
- break;\r
- }else{\r
- delete tdt;\r
- }\r
- }\r
-\r
- if(temporal_field_idx == fields.size()){\r
- fprintf(stderr,"ERROR, no temporal field for file output operator %s\n",node_name.c_str());\r
- exit(1);\r
- }\r
-\r
- ret += "private:\n";\r
-\r
- // var to save the schema handle\r
- ret += "\tint schema_handle0;\n";\r
-// tuple metadata offset\r
- ret += "\tint tuple_metadata_offset0;\n";\r
- sprintf(tmpstr,"\tgs_int32_t unpack_offset_%s_0;\n", fields[temporal_field_idx]->get_name().c_str());\r
- ret.append(tmpstr);\r
-\r
-// For unpacking the hashing fields, if any\r
- int h;\r
- for(h=0;h<hash_flds.size();++h){\r
- sprintf(tmpstr,"unpack_var_%s", fields[hash_flds[h]]->get_name().c_str());\r
- data_type *hdt = new data_type(fields[hash_flds[h]]->get_type(), fields[hash_flds[h]]->get_modifier_list());\r
- ret+="\t"+hdt->make_host_cvar(tmpstr)+";\n";\r
- if(hash_flds[h]!=temporal_field_idx){\r
- sprintf(tmpstr,"\tgs_int32_t unpack_offset_%s_0;\n", fields[hash_flds[h]]->get_name().c_str());\r
- ret.append(tmpstr);\r
- }\r
- }\r
-// Specail case for output file hashing\r
- if(n_streams>1 && hash_flds.size()==0){\r
- ret+="\tgs_uint32_t outfl_cnt;\n";\r
- }\r
-\r
- ret += "//\t\tRemember the last posted timestamp.\n";\r
- ret+="\t"+tdt->make_host_cvar("timestamp")+";\n";\r
- ret+="\t"+tdt->make_host_cvar("last_bucket")+";\n";\r
- ret+="\t"+tdt->make_host_cvar("slack")+";\n";\r
- ret += "\tbool first_execution;\n";\r
- ret += "\tbool temp_tuple_received;\n";\r
- ret += "\tbool is_eof;\n";\r
-\r
- ret += "\tgs_int32_t bucketwidth;\n";\r
-\r
- ret += "public:\n";\r
-//-------------------\r
-// The functor constructor\r
-// pass in a schema handle (e.g. for the 1st input stream),\r
-// use it to determine how to unpack the merge variable.\r
-// ASSUME that both streams have the same layout,\r
-// just duplicate it.\r
-\r
-// unpack vars\r
- ret += "//\t\tFunctor constructor.\n";\r
- ret += this->generate_functor_name()+"(int schema_hndl){\n";\r
-\r
- ret += "\tschema_handle0 = schema_hndl;\n";\r
-// tuple metadata offset\r
- ret += "\ttuple_metadata_offset0 = ftaschema_get_tuple_metadata_offset(schema_handle0);\n";\r
-\r
- if(output_spec->bucketwidth == 0)\r
- ret += "\tbucketwidth = 60;\n";\r
- else\r
- ret += "\tbucketwidth = "+int_to_string(output_spec->bucketwidth)+";\n";\r
- ret += "//\t\tGet offsets for unpacking fields from input tuple.\n";\r
-\r
- sprintf(tmpstr,"\tunpack_offset_%s_0 = ftaschema_get_field_offset_by_name(schema_handle0, \"%s\");\n", fields[temporal_field_idx]->get_name().c_str(), fields[temporal_field_idx]->get_name().c_str());\r
- ret.append(tmpstr);\r
-// Hashing field unpacking, if any\r
- for(h=0;h<hash_flds.size();++h){\r
- if(hash_flds[h]!=temporal_field_idx){\r
- sprintf(tmpstr,"\tunpack_offset_%s_0 = ftaschema_get_field_offset_by_name(schema_handle0, \"%s\");\n", fields[hash_flds[h]]->get_name().c_str(),fields[hash_flds[h]]->get_name().c_str());\r
- ret.append(tmpstr);\r
- }\r
- }\r
-\r
- ret+="\tfirst_execution = true;\n";\r
-\r
-// Initialize internal state\r
- ret += "\ttemp_tuple_received = false;\n";\r
-\r
- // Init last timestamp values to minimum value for their type\r
- if (tdt->is_increasing()){\r
- ret+="\ttimestamp = " + tdt->get_min_literal() + ";\n";\r
- ret+="\tlast_bucket = " + tdt->get_min_literal() + ";\n";\r
- }else{\r
- ret+="\ttimestamp = " + tdt->get_max_literal() + ";\n";\r
- ret+="\tlast_bucket = " + tdt->get_max_literal() + ";\n";\r
- }\r
-\r
-\r
- ret += "};\n\n";\r
-\r
- ret += "//\t\tFunctor destructor.\n";\r
- ret += "~"+this->generate_functor_name()+"(){\n";\r
- ret+="};\n\n";\r
-\r
-\r
- ret += "int load_params_"+this->generate_functor_name()+"(gs_int32_t sz, void *value){return 0;}\n";\r
- ret += "void destroy_params_"+this->generate_functor_name()+"(){}\n";\r
-\r
-// Register new parameter block\r
- ret += "int set_param_block(gs_int32_t sz, void* value){\n";\r
- ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";\r
- ret += "\treturn this->load_params_"+this->generate_functor_name()+\r
- "(sz, value);\n";\r
- ret += "};\n\n";\r
-\r
- ret+="\nbool temp_status_received(const host_tuple& tup0)/* const*/ {\n";\r
- ret+="\tgs_int32_t problem;\n";\r
-\r
- ret += "\tvoid *tup_ptr = (void *)(&tup0);\n";\r
- ret += "\tis_eof = ftaschema_is_eof_tuple(schema_handle0,tup_ptr);\n";\r
-\r
- ret += gen_temp_tuple_check(this->node_name, 0);\r
-\r
- sprintf(tmpstr,"\ttimestamp = %s_nocheck(tup0.data, unpack_offset_%s_%d);\n", tdt->get_hfta_unpack_fcn_noxf().c_str(), fields[temporal_field_idx]->get_name().c_str(), 0);\r
- ret += tmpstr;\r
-\r
- for(h=0;h<hash_flds.size();++h){\r
- data_type *hdt = new data_type(fields[hash_flds[h]]->get_type(), fields[hash_flds[h]]->get_modifier_list());\r
- sprintf(tmpstr,"\tunpack_var_%s = %s_nocheck(tup0.data, unpack_offset_%s_%d);\n", fields[hash_flds[h]]->get_name().c_str(), hdt->get_hfta_unpack_fcn_noxf().c_str(), fields[hash_flds[h]]->get_name().c_str(), 0);\r
- ret += tmpstr;\r
- }\r
- ret +=\r
-" return temp_tuple_received;\n"\r
-"}\n"\r
-"\n"\r
-;\r
-\r
- ret +=\r
-"bool new_epoch(){\n"\r
-" if(first_execution || (last_bucket + 1) * bucketwidth <= timestamp){\n"\r
-" last_bucket = timestamp / bucketwidth;\n"\r
-" first_execution = false;\n"\r
-" return true;\n"\r
-" }\n"\r
-" return false;\n"\r
-"}\n"\r
-"\n"\r
-;\r
-\r
- if(n_streams <= 1){\r
- ret+=\r
-"inline gs_uint32_t output_hash(){return 0;}\n\n";\r
- }else{\r
- if(hash_flds.size()==0){\r
- ret +=\r
-"gs_uint32_t output_hash(){\n"\r
-" outfl_cnt++;\n"\r
-" if(outfl_cnt >= "+int_to_string(n_streams)+")\n"\r
-" outfl_cnt = 0;\n"\r
-" return outfl_cnt;\n"\r
-"}\n"\r
-"\n"\r
-;\r
- }else{\r
- ret +=\r
-"gs_uint32_t output_hash(){\n"\r
-" gs_uint32_t ret = "\r
-;\r
- for(h=0;h<hash_flds.size();++h){\r
- if(h>0) ret += "^";\r
- data_type *hdt = new data_type(fields[hash_flds[h]]->get_type(), fields[hash_flds[h]]->get_modifier_list());\r
- if(hdt->use_hashfunc()){\r
- sprintf(tmpstr,"%s(&(unpack_var_%s))",hdt->get_hfta_hashfunc().c_str(),fields[hash_flds[h]]->get_name().c_str());\r
- }else{\r
- sprintf(tmpstr,"unpack_var_%s",fields[hash_flds[h]]->get_name().c_str());\r
- }\r
- ret += tmpstr;\r
- }\r
- ret +=\r
-";\n"\r
-" return ret % "+int_to_string(hash_flds.size())+";\n"\r
-"}\n\n"\r
-;\r
- }\r
- }\r
-\r
-ret +=\r
-"gs_uint32_t num_file_streams(){\n"\r
-" return("+int_to_string(n_streams)+");\n"\r
-"}\n\n"\r
-;\r
-\r
- ret +=\r
-"string get_filename_base(){\n"\r
-" char tmp_fname[500];\n";\r
-\r
- string output_filename_base = hfta_query_name+filestream_id;\r
-/*\r
- if(n_hfta_clones > 1){\r
- output_filename_base += "_"+int_to_string(parallel_idx);\r
- }\r
-*/\r
-\r
-\r
-\r
- if(output_spec->output_directory == "")\r
- ret +=\r
-" sprintf(tmp_fname,\""+output_filename_base+"_%lld\",(gs_int64_t)(last_bucket*bucketwidth));\n";\r
- else ret +=\r
-" sprintf(tmp_fname,\""+output_spec->output_directory+"/"+output_filename_base+"_%lld\",(gs_int64_t)(last_bucket*bucketwidth));\n";\r
-ret +=\r
-" return (string)(tmp_fname);\n"\r
-"}\n"\r
-"\n";\r
-\r
-\r
-ret+=\r
-"bool do_compression(){\n";\r
- if(do_gzip)\r
- ret += " return true;\n";\r
- else\r
- ret += " return false;\n";\r
-ret+=\r
-"}\n"\r
-"\n"\r
-"bool is_eof_tuple(){\n"\r
-" return is_eof;\n"\r
-"}\n"\r
-"\n"\r
-"bool propagate_tuple(){\n"\r
-;\r
-if(eat_input)\r
- ret+="\treturn false;\n";\r
-else\r
- ret+="\treturn true;\n";\r
-ret+="}\n\n";\r
-// create a temp status tuple\r
- ret += "int create_temp_status_tuple(host_tuple& result) {\n\n";\r
-\r
- ret += gen_init_temp_status_tuple(this->hfta_query_name);\r
-\r
- sprintf(tmpstr,"\ttuple->tuple_var%d = timestamp;\n",temporal_field_idx);\r
-\r
-\r
- ret += tmpstr;\r
-\r
- ret += "\treturn 0;\n";\r
- ret += "}\n\n";\r
- ret += "};\n\n";\r
-\r
- return ret;\r
-}\r
-\r
-\r
-string output_file_qpn::generate_operator(int i, string params){\r
- string optype = "file_output_operator";\r
- switch(compression_type){\r
- case regular:\r
- optype = "file_output_operator";\r
- break;\r
- case gzip:\r
- optype = "zfile_output_operator";\r
- break;\r
- case bzip:\r
- optype = "bfile_output_operator";\r
- break;\r
- }\r
-\r
- return(" "+optype+"<" +\r
- generate_functor_name() +\r
- "> *op"+int_to_string(i)+" = new "+optype+"<"+\r
- generate_functor_name() +">("+params+", \"" + hfta_query_name + "\""\r
- + "," + hfta_query_name + "_schema_definition);\n");\r
-}\r
-\r
-/////////////////////////////////////////////////////////\r
-////// SPX functor\r
-\r
-\r
-string spx_qpn::generate_functor_name(){\r
- return("spx_functor_" + normalize_name(normalize_name(this->get_node_name())));\r
-}\r
-\r
-string spx_qpn::generate_functor(table_list *schema, ext_fcn_list *Ext_fcns, vector<bool> &needs_xform){\r
-// Initialize generate utility globals\r
- segen_gb_tbl = NULL;\r
-\r
- string ret = "class " + this->generate_functor_name() + "{\n";\r
-\r
-// Find variables referenced in this query node.\r
-\r
- col_id_set cid_set;\r
- col_id_set::iterator csi;\r
-\r
- int w, s, p;\r
- for(w=0;w<where.size();++w)\r
- gather_pr_col_ids(where[w]->pr,cid_set,NULL);\r
- for(s=0;s<select_list.size();s++){\r
- gather_se_col_ids(select_list[s]->se,cid_set,NULL);\r
- }\r
-\r
-\r
-// Private variables : store the state of the functor.\r
-// 1) variables for unpacked attributes\r
-// 2) offsets of the upacked attributes\r
-// 3) storage of partial functions\r
-// 4) storage of complex literals (i.e., require a constructor)\r
-\r
- ret += "private:\n";\r
- ret += "\tbool first_execution;\t// internal processing state \n";\r
- ret += "\tint schema_handle0;\n";\r
-\r
- // generate the declaration of all the variables related to\r
- // temp tuples generation\r
- ret += gen_decl_temp_vars();\r
-\r
-\r
-// unpacked attribute storage, offsets\r
- ret += "//\t\tstorage and offsets of accessed fields.\n";\r
- ret += generate_access_vars(cid_set,schema);\r
-// tuple metadata management\r
- ret += "\tint tuple_metadata_offset0;\n";\r
-\r
-// Variables to store results of partial functions.\r
-// WARNING find_partial_functions modifies the SE\r
-// (it marks the partial function id).\r
- ret += "//\t\tParital function result storage\n";\r
- vector<scalarexp_t *> partial_fcns;\r
- vector<int> fcn_ref_cnt;\r
- vector<bool> is_partial_fcn;\r
- for(s=0;s<select_list.size();s++){\r
- find_partial_fcns(select_list[s]->se, &partial_fcns,&fcn_ref_cnt,&is_partial_fcn, Ext_fcns);\r
- }\r
- for(w=0;w<where.size();w++){\r
- find_partial_fcns_pr(where[w]->pr, &partial_fcns, &fcn_ref_cnt,&is_partial_fcn,Ext_fcns);\r
- }\r
-// Unmark non-partial expensive functions referenced only once.\r
- for(p=0; p<partial_fcns.size();p++){\r
- if(!is_partial_fcn[p] && fcn_ref_cnt[p] <= 1){\r
- partial_fcns[p]->set_partial_ref(-1);\r
- }\r
- }\r
- if(partial_fcns.size()>0){\r
- ret += generate_partial_fcn_vars(partial_fcns,fcn_ref_cnt,is_partial_fcn,true);\r
- }\r
-\r
-// Complex literals (i.e., they need constructors)\r
- ret += "//\t\tComplex literal storage.\n";\r
- cplx_lit_table *complex_literals = this->get_cplx_lit_tbl(Ext_fcns);\r
- ret += generate_complex_lit_vars(complex_literals);\r
-\r
-// Pass-by-handle parameters\r
- ret += "//\t\tPass-by-handle storage.\n";\r
- vector<handle_param_tbl_entry *> param_handle_table = this->get_handle_param_tbl(Ext_fcns);\r
- ret += generate_pass_by_handle_vars(param_handle_table);\r
-\r
-// Variables to hold parameters\r
- ret += "//\tfor query parameters\n";\r
- ret += generate_param_vars(param_tbl);\r
-\r
-\r
-// The publicly exposed functions\r
-\r
- ret += "\npublic:\n";\r
-\r
-\r
-//-------------------\r
-// The functor constructor\r
-// pass in the schema handle.\r
-// 1) make assignments to the unpack offset variables\r
-// 2) initialize the complex literals\r
-// 3) Set the initial values of the temporal attributes\r
-// referenced in select clause (in case we need to emit\r
-// temporal tuple before receiving first tuple )\r
-\r
- ret += "//\t\tFunctor constructor.\n";\r
- ret += this->generate_functor_name()+"(int schema_handle0){\n";\r
-\r
-// save schema handle\r
- ret += "this->schema_handle0 = schema_handle0;\n";\r
-\r
-// unpack vars\r
- ret += "//\t\tGet offsets for unpacking fields from input tuple.\n";\r
- ret += gen_access_var_init(cid_set);\r
-// tuple metadata\r
- ret += "\ttuple_metadata_offset0 = ftaschema_get_tuple_metadata_offset(schema_handle0);\n";\r
-\r
-// complex literals\r
- ret += "//\t\tInitialize complex literals.\n";\r
- ret += gen_complex_lit_init(complex_literals);\r
-\r
-// Initialize partial function results so they can be safely GC'd\r
- ret += gen_partial_fcn_init(partial_fcns);\r
-\r
-// Initialize non-query-parameter parameter handles\r
- ret += gen_pass_by_handle_init(param_handle_table);\r
-\r
-// Init temporal attributes referenced in select list\r
- ret += gen_init_temp_vars(schema, select_list, NULL);\r
-\r
- ret += "};\n\n";\r
-\r
-\r
-//-------------------\r
-// Functor destructor\r
- ret += "//\t\tFunctor destructor.\n";\r
- ret += "~"+this->generate_functor_name()+"(){\n";\r
-\r
-// clean up buffer-type complex literals.\r
- ret += gen_complex_lit_dtr(complex_literals);\r
-\r
-// Deregister the pass-by-handle parameters\r
- ret += "/* register and de-register the pass-by-handle parameters */\n";\r
- ret += gen_pass_by_handle_dtr(param_handle_table);\r
-\r
-// Reclaim buffer space for partial fucntion results\r
- ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";\r
- ret += gen_partial_fcn_dtr(partial_fcns);\r
-\r
-\r
-// Destroy the parameters, if any need to be destroyed\r
- ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";\r
-\r
- ret += "};\n\n";\r
-\r
-\r
-//-------------------\r
-// Parameter manipulation routines\r
- ret += generate_load_param_block(this->generate_functor_name(),\r
- this->param_tbl,param_handle_table );\r
- ret += generate_delete_param_block(this->generate_functor_name(),\r
- this->param_tbl,param_handle_table);\r
-\r
-\r
-//-------------------\r
-// Register new parameter block\r
- ret += "int set_param_block(gs_int32_t sz, void* value){\n";\r
- ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";\r
- ret += "\treturn this->load_params_"+this->generate_functor_name()+\r
- "(sz, value);\n";\r
- ret += "};\n\n";\r
-\r
-\r
-//-------------------\r
-// The selection predicate.\r
-// Unpack variables for 1 cnf element\r
-// at a time, return false immediately if the\r
-// predicate fails.\r
-// optimization : evaluate the cheap cnf elements\r
-// first, the expensive ones last.\r
-\r
- ret += "bool predicate(host_tuple &tup0){\n";\r
- // Variables for execution of the function.\r
- ret += "\tgs_int32_t problem = 0;\n"; // return unpack failure\r
-// Initialize cached function indicators.\r
- for(p=0;p<partial_fcns.size();++p){\r
- if(fcn_ref_cnt[p]>1){\r
- ret+="\tfcn_ref_cnt_"+int_to_string(p)+"=0;\n";\r
- }\r
- }\r
-\r
-\r
- ret += gen_temp_tuple_check(this->node_name, 0);\r
-\r
- if(partial_fcns.size()>0){ // partial fcn access failure\r
- ret += "\tgs_retval_t retval = 0;\n";\r
- ret += "\n";\r
- }\r
-\r
-// Reclaim buffer space for partial fucntion results\r
- ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";\r
- ret += gen_partial_fcn_dtr(partial_fcns);\r
-\r
- col_id_set found_cids; // colrefs unpacked thus far.\r
- ret += gen_unpack_temp_vars(schema, found_cids, select_list, NULL, needs_xform);\r
-\r
-// For temporal status tuple we don't need to do anything else\r
- ret += "\tif (temp_tuple_received) return false;\n\n";\r
-\r
-\r
- for(w=0;w<where.size();++w){\r
- sprintf(tmpstr,"//\t\tPredicate clause %d.\n",w);\r
- ret += tmpstr;\r
-// Find the set of variables accessed in this CNF elem,\r
-// but in no previous element.\r
- col_id_set new_cids;\r
- get_new_pred_cids(where[w]->pr,found_cids, new_cids, NULL);\r
-// Unpack these values.\r
- ret += gen_unpack_cids(schema, new_cids, "false", needs_xform);\r
-// Find partial fcns ref'd in this cnf element\r
- set<int> pfcn_refs;\r
- collect_partial_fcns_pr(where[w]->pr, pfcn_refs);\r
- ret += gen_unpack_partial_fcn(schema,partial_fcns,pfcn_refs,fcn_ref_cnt, is_partial_fcn, "false");\r
-\r
- ret += "\tif( !("+generate_predicate_code(where[w]->pr,schema)+\r
- +") ) return(false);\n";\r
- }\r
-\r
-// The partial functions ref'd in the select list\r
-// must also be evaluated. If one returns false,\r
-// then implicitly the predicate is false.\r
- set<int> sl_pfcns;\r
- for(s=0;s<select_list.size();s++){\r
- collect_partial_fcns(select_list[s]->se, sl_pfcns);\r
- }\r
- if(sl_pfcns.size() > 0)\r
- ret += "//\t\tUnpack remaining partial fcns.\n";\r
- ret += gen_full_unpack_partial_fcn(schema, partial_fcns, sl_pfcns,\r
- fcn_ref_cnt, is_partial_fcn,\r
- found_cids, NULL, "false", needs_xform);\r
-\r
-// Unpack remaining fields\r
- ret += "//\t\tunpack any remaining fields from the input tuple.\n";\r
- ret += gen_remaining_colrefs(schema, cid_set, found_cids, "false", needs_xform);\r
-\r
-\r
- ret += "\treturn(true);\n";\r
- ret += "};\n\n";\r
-\r
-\r
-//-------------------\r
-// The output tuple function.\r
-// Unpack the remaining attributes into\r
-// the placeholder variables, unpack the\r
-// partial fcn refs, then pack up the tuple.\r
-\r
- ret += "host_tuple create_output_tuple() {\n";\r
- ret += "\thost_tuple tup;\n";\r
- ret += "\tgs_retval_t retval = 0;\n";\r
-\r
-// Unpack any remaining cached functions.\r
- ret += gen_remaining_cached_fcns(schema, partial_fcns, sl_pfcns,\r
- fcn_ref_cnt, is_partial_fcn);\r
-\r
-\r
-// Now, compute the size of the tuple.\r
-\r
-// Unpack any BUFFER type selections into temporaries\r
-// so that I can compute their size and not have\r
-// to recompute their value during tuple packing.\r
-// I can use regular assignment here because\r
-// these temporaries are non-persistent.\r
-\r
- ret += "//\t\tCompute the size of the tuple.\n";\r
- ret += "//\t\t\tNote: buffer storage packed at the end of the tuple.\n";\r
-\r
-// Unpack all buffer type selections, to be able to compute their size\r
- ret += gen_buffer_selvars(schema, select_list);\r
-\r
-// The size of the tuple is the size of the tuple struct plus the\r
-// size of the buffers to be copied in.\r
-\r
-\r
- ret+="\ttup.tuple_size = sizeof(" + generate_tuple_name( this->get_node_name()) +") + sizeof(gs_uint8_t)";\r
- ret += gen_buffer_selvars_size(select_list,schema);\r
- ret.append(";\n");\r
-\r
-// Allocate tuple data block.\r
- ret += "//\t\tCreate the tuple block.\n";\r
- ret += "\ttup.data = malloc(tup.tuple_size);\n";\r
- ret += "\ttup.heap_resident = true;\n";\r
-// Mark tuple as regular\r
- ret += "\t*((gs_sp_t )tup.data + sizeof(" + generate_tuple_name( this->get_node_name()) +")) = REGULAR_TUPLE;\n";\r
-\r
-// ret += "\ttup.channel = 0;\n";\r
- ret += "\t"+generate_tuple_name( this->get_node_name())+" *tuple = ("+\r
- generate_tuple_name( this->get_node_name())+" *)(tup.data);\n";\r
-\r
-// Start packing.\r
-// (Here, offsets are hard-wired. is this a problem?)\r
-\r
- ret += "//\t\tPack the fields into the tuple.\n";\r
- ret += gen_pack_tuple(schema,select_list,this->get_node_name(), false );\r
-\r
-// Delete string temporaries\r
- ret += gen_buffer_selvars_dtr(select_list);\r
-\r
- ret += "\treturn tup;\n";\r
- ret += "};\n";\r
-\r
-//-------------------------------------------------------------------\r
-// Temporal update functions\r
-\r
- ret += "bool temp_status_received(){return temp_tuple_received;};\n\n";\r
-\r
-\r
-// create a temp status tuple\r
- ret += "int create_temp_status_tuple(host_tuple& result) {\n\n";\r
-\r
- ret += gen_init_temp_status_tuple(this->get_node_name());\r
-\r
-// Start packing.\r
-// (Here, offsets are hard-wired. is this a problem?)\r
-\r
- ret += "//\t\tPack the fields into the tuple.\n";\r
- ret += gen_pack_tuple(schema,select_list,this->get_node_name(), true );\r
-\r
- ret += "\treturn 0;\n";\r
- ret += "};};\n\n";\r
-\r
- return(ret);\r
-}\r
-\r
-\r
-string spx_qpn::generate_operator(int i, string params){\r
-\r
- return(" select_project_operator<" +\r
- generate_functor_name() +\r
- "> *op"+int_to_string(i)+" = new select_project_operator<"+\r
- generate_functor_name() +">("+params+", \"" + get_node_name() + "\");\n");\r
-}\r
-\r
-\r
-////////////////////////////////////////////////////////////////\r
-//// SGAH functor\r
-\r
-\r
-\r
-string sgah_qpn::generate_functor_name(){\r
- return("sgah_functor_" + normalize_name(this->get_node_name()));\r
-}\r
-\r
-\r
-string sgah_qpn::generate_functor(table_list *schema, ext_fcn_list *Ext_fcns, vector<bool> &needs_xform){\r
- int a,g,w,s;\r
-\r
-\r
-// Initialize generate utility globals\r
- segen_gb_tbl = &(gb_tbl);\r
-\r
-// Might need to generate empty values for cube processing.\r
- map<int, string> structured_types;\r
- for(g=0;g<gb_tbl.size();++g){\r
- if(gb_tbl.get_data_type(g)->is_structured_type()){\r
- structured_types[gb_tbl.get_data_type(g)->type_indicator()] = gb_tbl.get_data_type(g)->get_type_str();\r
- }\r
- }\r
-\r
-//--------------------------------\r
-// group definition class\r
- string ret = "class " + generate_functor_name() + "_groupdef{\n";\r
- ret += "public:\n";\r
- for(g=0;g<this->gb_tbl.size();g++){\r
- sprintf(tmpstr,"gb_var%d",g);\r
- ret+="\t"+this->gb_tbl.get_data_type(g)->make_host_cvar(tmpstr)+";\n";\r
- }\r
-// empty strucutred literals\r
- map<int, string>::iterator sii;\r
- for(sii=structured_types.begin();sii!=structured_types.end();++sii){\r
- data_type dt(sii->second);\r
- literal_t empty_lit(sii->first);\r
- ret += "\t"+dt.make_host_cvar(empty_lit.hfta_empty_literal_name())+";\n";\r
- }\r
-// Constructors\r
- if(structured_types.size()==0){\r
- ret += "\t"+generate_functor_name() + "_groupdef(){};\n";\r
- }else{\r
- ret += "\t"+generate_functor_name() + "_groupdef(){}\n";\r
- }\r
-\r
-\r
- ret += "\t"+generate_functor_name() + "_groupdef("+\r
- this->generate_functor_name() + "_groupdef *gd){\n";\r
- for(g=0;g<gb_tbl.size();g++){\r
- data_type *gdt = gb_tbl.get_data_type(g);\r
- if(gdt->is_buffer_type()){\r
- sprintf(tmpstr,"\t\t%s(&gb_var%d, &(gd->gb_var%d));\n",\r
- gdt->get_hfta_buffer_assign_copy().c_str(),g,g );\r
- ret += tmpstr;\r
- }else{\r
- sprintf(tmpstr,"\t\tgb_var%d = gd->gb_var%d;\n",g,g);\r
- ret += tmpstr;\r
- }\r
- }\r
- ret += "\t}\n";\r
- ret += "\t"+generate_functor_name() + "_groupdef("+\r
- this->generate_functor_name() + "_groupdef *gd, bool *pattern){\n";\r
- for(sii=structured_types.begin();sii!=structured_types.end();++sii){\r
- literal_t empty_lit(sii->first);\r
- ret += "\t\t"+empty_lit.to_hfta_C_code("&"+empty_lit.hfta_empty_literal_name())+";\n";\r
- }\r
- for(g=0;g<gb_tbl.size();g++){\r
- data_type *gdt = gb_tbl.get_data_type(g);\r
- ret += "\t\tif(pattern["+int_to_string(g)+"]){\n";\r
- if(gdt->is_buffer_type()){\r
- sprintf(tmpstr,"\t\t\t%s(&gb_var%d, &(gd->gb_var%d));\n",\r
- gdt->get_hfta_buffer_assign_copy().c_str(),g,g );\r
- ret += tmpstr;\r
- }else{\r
- sprintf(tmpstr,"\t\t\tgb_var%d = gd->gb_var%d;\n",g,g);\r
- ret += tmpstr;\r
- }\r
- ret += "\t\t}else{\n";\r
- literal_t empty_lit(gdt->type_indicator());\r
- if(empty_lit.is_cpx_lit()){\r
- ret +="\t\t\tgb_var"+int_to_string(g)+"= "+empty_lit.hfta_empty_literal_name()+";\n";\r
- }else{\r
- ret +="\t\t\tgb_var"+int_to_string(g)+"="+empty_lit.to_hfta_C_code("")+";\n";\r
- }\r
- ret += "\t\t}\n";\r
- }\r
- ret += "\t};\n";\r
-// destructor\r
- ret += "\t~"+ generate_functor_name() + "_groupdef(){\n";\r
- for(g=0;g<gb_tbl.size();g++){\r
- data_type *gdt = gb_tbl.get_data_type(g);\r
- if(gdt->is_buffer_type()){\r
- sprintf(tmpstr,"\t\t%s(&gb_var%d);\n",\r
- gdt->get_hfta_buffer_destroy().c_str(), g );\r
- ret += tmpstr;\r
- }\r
- }\r
- ret += "\t};\n";\r
-\r
- data_type *tgdt;\r
- for(g=0;g<gb_tbl.size();g++){\r
- data_type *gdt = gb_tbl.get_data_type(g);\r
- if(gdt->is_temporal()){\r
- tgdt = gdt;\r
- break;\r
- }\r
- }\r
- ret += tgdt->get_host_cvar_type()+" get_curr_gb(){\n";\r
- ret+="\treturn gb_var"+int_to_string(g)+";\n";\r
- ret+="}\n";\r
-\r
- ret +="};\n\n";\r
-\r
-//--------------------------------\r
-// aggr definition class\r
- ret += "class " + this->generate_functor_name() + "_aggrdef{\n";\r
- ret += "public:\n";\r
- for(a=0;a<aggr_tbl.size();a++){\r
- aggr_table_entry *ate = aggr_tbl.agr_tbl[a];\r
- sprintf(tmpstr,"aggr_var%d",a);\r
- if(aggr_tbl.is_builtin(a)){\r
- ret+="\t"+ aggr_tbl.get_data_type(a)->make_host_cvar(tmpstr)+";\n";\r
- if(aggr_tbl.get_op(a) == "AVG"){ // HACK!\r
- data_type cnt_type = data_type("ullong");\r
- ret+="\t"+cnt_type.make_host_cvar(string(tmpstr)+"_cnt")+";\n";\r
- ret+="\t"+ aggr_tbl.get_data_type(a)->make_host_cvar(string(tmpstr)+"_sum")+";\n";\r
- }\r
- }else{\r
- ret+="\t"+ aggr_tbl.get_storage_type(a)->make_host_cvar(tmpstr)+";\n";\r
- }\r
- }\r
-// Constructors\r
- ret += "\t"+this->generate_functor_name() + "_aggrdef(){};\n";\r
-// destructor\r
- ret += "\t~"+this->generate_functor_name() + "_aggrdef(){\n";\r
- for(a=0;a<aggr_tbl.size();a++){\r
- if(aggr_tbl.is_builtin(a)){\r
- data_type *adt = aggr_tbl.get_data_type(a);\r
- if(adt->is_buffer_type()){\r
- sprintf(tmpstr,"\t\t%s(&aggr_var%d);\n",\r
- adt->get_hfta_buffer_destroy().c_str(), a );\r
- ret += tmpstr;\r
- }\r
- }else{\r
- ret+="\t\t"+aggr_tbl.get_op(a)+"_HFTA_AGGR_DESTROY_(";\r
- if(aggr_tbl.get_storage_type(a)->get_type() != fstring_t) ret+="&";\r
- ret+="(aggr_var"+int_to_string(a)+"));\n";\r
- }\r
- }\r
- ret += "\t};\n";\r
- ret +="};\n\n";\r
-\r
-//-------------------------------------------\r
-// group-by patterns for the functor,\r
-// initialization within the class is cumbersome.\r
- int n_patterns = gb_tbl.gb_patterns.size();\r
- int i,j;\r
- ret += "bool "+this->generate_functor_name()+"_gb_patterns["+int_to_string(n_patterns)+\r
- "]["+int_to_string(gb_tbl.size())+"] = {\n";\r
- if(n_patterns == 0){\r
- for(i=0;i<gb_tbl.size();++i){\r
- if(i>0) ret += ",";\r
- ret += "true";\r
- }\r
- }else{\r
- for(i=0;i<n_patterns;++i){\r
- if(i>0) ret += ",\n";\r
- ret += "\t{";\r
- for(j=0;j<gb_tbl.size();j++){\r
- if(j>0) ret += ", ";\r
- if(gb_tbl.gb_patterns[i][j]){\r
- ret += "true";\r
- }else{\r
- ret += "false";\r
- }\r
- }\r
- ret += "}";\r
- }\r
- ret += "\n";\r
- }\r
- ret += "};\n";\r
-\r
-\r
-//--------------------------------\r
-// gb functor class\r
- ret += "class " + this->generate_functor_name() + "{\n";\r
-\r
-// Find variables referenced in this query node.\r
-\r
- col_id_set cid_set;\r
- col_id_set::iterator csi;\r
-\r
- for(w=0;w<where.size();++w)\r
- gather_pr_col_ids(where[w]->pr,cid_set,segen_gb_tbl);\r
- for(w=0;w<having.size();++w)\r
- gather_pr_col_ids(having[w]->pr,cid_set,segen_gb_tbl);\r
- for(g=0;g<gb_tbl.size();g++)\r
- gather_se_col_ids(gb_tbl.get_def(g),cid_set,segen_gb_tbl);\r
-\r
- for(s=0;s<select_list.size();s++){\r
- gather_se_col_ids(select_list[s]->se,cid_set,segen_gb_tbl); // descends into aggregates\r
- }\r
-\r
-\r
-// Private variables : store the state of the functor.\r
-// 1) variables for unpacked attributes\r
-// 2) offsets of the upacked attributes\r
-// 3) storage of partial functions\r
-// 4) storage of complex literals (i.e., require a constructor)\r
-\r
- ret += "private:\n";\r
-\r
- // var to save the schema handle\r
- ret += "\tint schema_handle0;\n";\r
- // metadata from schema handle\r
- ret += "\tint tuple_metadata_offset0;\n";\r
-\r
- // generate the declaration of all the variables related to\r
- // temp tuples generation\r
- ret += gen_decl_temp_vars();\r
-\r
-// unpacked attribute storage, offsets\r
- ret += "//\t\tstorage and offsets of accessed fields.\n";\r
- ret += generate_access_vars(cid_set, schema);\r
-\r
-// Variables to store results of partial functions.\r
-// WARNING find_partial_functions modifies the SE\r
-// (it marks the partial function id).\r
- ret += "//\t\tParital function result storage\n";\r
- vector<scalarexp_t *> partial_fcns;\r
- vector<int> fcn_ref_cnt;\r
- vector<bool> is_partial_fcn;\r
- for(s=0;s<select_list.size();s++){\r
- find_partial_fcns(select_list[s]->se, &partial_fcns,NULL,NULL, Ext_fcns);\r
- }\r
- for(w=0;w<where.size();w++){\r
- find_partial_fcns_pr(where[w]->pr, &partial_fcns,NULL,NULL, Ext_fcns);\r
- }\r
- for(w=0;w<having.size();w++){\r
- find_partial_fcns_pr(having[w]->pr, &partial_fcns,NULL,NULL, Ext_fcns);\r
- }\r
- for(g=0;g<gb_tbl.size();g++){\r
- find_partial_fcns(gb_tbl.get_def(g), &partial_fcns,NULL,NULL, Ext_fcns);\r
- }\r
- for(a=0;a<aggr_tbl.size();a++){\r
- find_partial_fcns(aggr_tbl.get_aggr_se(a), &partial_fcns,NULL,NULL, Ext_fcns);\r
- }\r
- if(partial_fcns.size()>0){\r
- ret += "/*\t\tVariables for storing results of partial functions. \t*/\n";\r
- ret += generate_partial_fcn_vars(partial_fcns,fcn_ref_cnt,is_partial_fcn,false);\r
- }\r
-\r
-// Complex literals (i.e., they need constructors)\r
- ret += "//\t\tComplex literal storage.\n";\r
- cplx_lit_table *complex_literals = this->get_cplx_lit_tbl(Ext_fcns);\r
- ret += generate_complex_lit_vars(complex_literals);\r
-\r
-// Pass-by-handle parameters\r
- ret += "//\t\tPass-by-handle storage.\n";\r
- vector<handle_param_tbl_entry *> param_handle_table = this->get_handle_param_tbl(Ext_fcns);\r
- ret += generate_pass_by_handle_vars(param_handle_table);\r
-\r
-\r
-// variables to hold parameters.\r
- ret += "//\tfor query parameters\n";\r
- ret += generate_param_vars(param_tbl);\r
-\r
-// Is there a temporal flush? If so create flush temporaries,\r
-// create flush indicator.\r
- bool uses_temporal_flush = false;\r
- for(g=0;g<gb_tbl.size();g++){\r
- data_type *gdt = gb_tbl.get_data_type(g);\r
- if(gdt->is_temporal())\r
- uses_temporal_flush = true;\r
- }\r
-\r
- if(uses_temporal_flush){\r
- ret += "//\t\tFor temporal flush\n";\r
- for(g=0;g<gb_tbl.size();g++){\r
- data_type *gdt = gb_tbl.get_data_type(g);\r
- if(gdt->is_temporal()){\r
- sprintf(tmpstr,"last_gb%d",g);\r
- ret+="\t"+gb_tbl.get_data_type(g)->make_host_cvar(tmpstr)+";\n";\r
- sprintf(tmpstr,"last_flushed_gb%d",g);\r
- ret+="\t"+gb_tbl.get_data_type(g)->make_host_cvar(tmpstr)+";\n";\r
- }\r
- }\r
- ret += "\tbool needs_temporal_flush;\n";\r
- }\r
-\r
-\r
-// The publicly exposed functions\r
-\r
- ret += "\npublic:\n";\r
-\r
-\r
-//-------------------\r
-// The functor constructor\r
-// pass in the schema handle.\r
-// 1) make assignments to the unpack offset variables\r
-// 2) initialize the complex literals\r
-\r
- ret += "//\t\tFunctor constructor.\n";\r
- ret += this->generate_functor_name()+"(int schema_handle0){\n";\r
-\r
- // save the schema handle\r
- ret += "\t\tthis->schema_handle0 = schema_handle0;\n";\r
-\r
-// unpack vars\r
- ret += "//\t\tGet offsets for unpacking fields from input tuple.\n";\r
- ret += gen_access_var_init(cid_set);\r
-// tuple metadata\r
- ret += "tuple_metadata_offset0 = ftaschema_get_tuple_metadata_offset(schema_handle0);\n";\r
-\r
-// complex literals\r
- ret += "//\t\tInitialize complex literals.\n";\r
- ret += gen_complex_lit_init(complex_literals);\r
-\r
-// Initialize partial function results so they can be safely GC'd\r
- ret += gen_partial_fcn_init(partial_fcns);\r
-\r
-// Initialize non-query-parameter parameter handles\r
- ret += gen_pass_by_handle_init(param_handle_table);\r
-\r
-// temporal flush variables\r
-// ASSUME that structured values won't be temporal.\r
- if(uses_temporal_flush){\r
- ret += "//\t\tInitialize temporal flush variables.\n";\r
- for(g=0;g<gb_tbl.size();g++){\r
- data_type *gdt = gb_tbl.get_data_type(g);\r
- if(gdt->is_temporal()){\r
- literal_t gl(gdt->type_indicator());\r
- sprintf(tmpstr,"\tlast_gb%d = %s;\n",g, gl.to_hfta_C_code("").c_str());\r
- ret.append(tmpstr);\r
- sprintf(tmpstr,"\tlast_flushed_gb%d = %s;\n",g, gl.to_hfta_C_code("").c_str());\r
- ret.append(tmpstr);\r
- }\r
- }\r
- ret += "\tneeds_temporal_flush = false;\n";\r
- }\r
-\r
- // Init temporal attributes referenced in select list\r
- ret += gen_init_temp_vars(schema, select_list, segen_gb_tbl);\r
-\r
- ret += "}\n\n";\r
-\r
-//-------------------\r
-// Functor destructor\r
- ret += "//\t\tFunctor destructor.\n";\r
- ret += "~"+this->generate_functor_name()+"(){\n";\r
-\r
-// clean up buffer type complex literals\r
- ret += gen_complex_lit_dtr(complex_literals);\r
-\r
-// Deregister the pass-by-handle parameters\r
- ret += "/* register and de-register the pass-by-handle parameters */\n";\r
- ret += gen_pass_by_handle_dtr(param_handle_table);\r
-\r
-// clean up partial function results.\r
- ret += "/* clean up partial function storage */\n";\r
- ret += gen_partial_fcn_dtr(partial_fcns);\r
-\r
-// Destroy the parameters, if any need to be destroyed\r
- ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";\r
-\r
- ret += "};\n\n";\r
-\r
-\r
-//-------------------\r
-// Parameter manipulation routines\r
- ret += generate_load_param_block(this->generate_functor_name(),\r
- this->param_tbl,param_handle_table);\r
- ret += generate_delete_param_block(this->generate_functor_name(),\r
- this->param_tbl,param_handle_table);\r
-\r
-//-------------------\r
-// Register new parameter block\r
-\r
- ret += "int set_param_block(gs_int32_t sz, void* value){\n";\r
- ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";\r
- ret += "\treturn this->load_params_"+this->generate_functor_name()+\r
- "(sz, value);\n";\r
- ret += "};\n\n";\r
-\r
-// -----------------------------------\r
-// group-by pattern support\r
-\r
- ret +=\r
-"int n_groupby_patterns(){\n"\r
-" return "+int_to_string(gb_tbl.gb_patterns.size())+";\n"\r
-"}\n"\r
-"bool *get_pattern(int p){\n"\r
-" return "+this->generate_functor_name()+"_gb_patterns[p];\n"\r
-"}\n\n"\r
-;\r
-\r
-\r
-\r
-\r
-//-------------------\r
-// the create_group method.\r
-// This method creates a group in a buffer passed in\r
-// (to allow for creation on the stack).\r
-// There are also a couple of side effects:\r
-// 1) evaluate the WHERE clause (and therefore, unpack all partial fcns)\r
-// 2) determine if a temporal flush is required.\r
-\r
- ret += this->generate_functor_name()+"_groupdef *create_group(host_tuple &tup0, gs_sp_t buffer){\n";\r
- // Variables for execution of the function.\r
- ret += "\tgs_int32_t problem = 0;\n"; // return unpack failure\r
-\r
- if(partial_fcns.size()>0){ // partial fcn access failure\r
- ret += "\tgs_retval_t retval = 0;\n";\r
- ret += "\n";\r
- }\r
-// return value\r
- ret += "\t"+generate_functor_name()+"_groupdef *gbval = ("+generate_functor_name()+\r
- "_groupdef *) buffer;\n";\r
-\r
-// Start by cleaning up partial function results\r
- ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";\r
- set<int> w_pfcns; // partial fcns in where clause\r
- for(w=0;w<where.size();++w)\r
- collect_partial_fcns_pr(where[w]->pr, w_pfcns);\r
-\r
- set<int> ag_gb_pfcns; // partial fcns in gbdefs, aggr se's\r
- for(g=0;g<gb_tbl.size();g++){\r
- collect_partial_fcns(gb_tbl.get_def(g), ag_gb_pfcns);\r
- }\r
- for(a=0;a<aggr_tbl.size();a++){\r
- collect_partial_fcns(aggr_tbl.get_aggr_se(a), ag_gb_pfcns);\r
- }\r
- ret += gen_partial_fcn_dtr(partial_fcns,w_pfcns);\r
- ret += gen_partial_fcn_dtr(partial_fcns,ag_gb_pfcns);\r
-// ret += gen_partial_fcn_dtr(partial_fcns);\r
-\r
-\r
- ret += gen_temp_tuple_check(this->node_name, 0);\r
- col_id_set found_cids; // colrefs unpacked thus far.\r
- ret += gen_unpack_temp_vars(schema, found_cids, select_list, segen_gb_tbl, needs_xform);\r
-\r
-\r
-// Save temporal group-by variables\r
-\r
-\r
- ret.append("\n\t//\t\tCompute temporal groupby attributes\n\n");\r
-\r
- for(g=0;g<gb_tbl.size();g++){\r
-\r
- data_type *gdt = gb_tbl.get_data_type(g);\r
-\r
- if(gdt->is_temporal()){\r
- sprintf(tmpstr,"\tgbval->gb_var%d = %s;\n",\r
- g, generate_se_code(gb_tbl.get_def(g),schema).c_str() );\r
- ret.append(tmpstr);\r
- }\r
- }\r
- ret.append("\n");\r
-\r
-\r
-\r
-// Compare the temporal GB vars with the stored ones,\r
-// set flush indicator and update stored GB vars if there is any change.\r
-\r
-ret += "// hfta_disorder = "+int_to_string(hfta_disorder)+"\n";\r
- if(hfta_disorder < 2){\r
- if(uses_temporal_flush){\r
- ret+= "\tif( !( (";\r
- bool first_one = true;\r
- for(g=0;g<gb_tbl.size();g++){\r
- data_type *gdt = gb_tbl.get_data_type(g);\r
-\r
- if(gdt->is_temporal()){\r
- sprintf(tmpstr,"last_gb%d",g); string lhs_op = tmpstr;\r
- sprintf(tmpstr,"gbval->gb_var%d",g); string rhs_op = tmpstr;\r
- if(first_one){first_one = false;} else {ret += ") && (";}\r
- ret += generate_equality_test(lhs_op, rhs_op, gdt);\r
- }\r
- }\r
- ret += ") ) ){\n";\r
- for(g=0;g<gb_tbl.size();g++){\r
- data_type *gdt = gb_tbl.get_data_type(g);\r
- if(gdt->is_temporal()){\r
- if(gdt->is_buffer_type()){\r
- sprintf(tmpstr,"\t\t%s(&(gbval->gb_var%d),&last_gb%d);\n",gdt->get_hfta_buffer_replace().c_str(),g,g);\r
- }else{\r
- sprintf(tmpstr,"\t\tlast_flushed_gb%d = last_gb%d;\n",g,g);\r
- ret += tmpstr;\r
- sprintf(tmpstr,"\t\tlast_gb%d = gbval->gb_var%d;\n",g,g);\r
- }\r
- ret += tmpstr;\r
- }\r
- }\r
- ret += "\t\tneeds_temporal_flush=true;\n";\r
- ret += "\t\t}else{\n"\r
- "\t\t\tneeds_temporal_flush=false;\n"\r
- "\t\t}\n";\r
- }\r
- }else{\r
- ret+= "\tif(temp_tuple_received && !( (";\r
- bool first_one = true;\r
- for(g=0;g<gb_tbl.size();g++){\r
- data_type *gdt = gb_tbl.get_data_type(g);\r
-\r
- if(gdt->is_temporal()){\r
- sprintf(tmpstr,"last_gb%d",g); string lhs_op = tmpstr;\r
- sprintf(tmpstr,"gbval->gb_var%d",g); string rhs_op = tmpstr;\r
- if(first_one){first_one = false;} else {ret += ") && (";}\r
- ret += generate_equality_test(lhs_op, rhs_op, gdt);\r
- break;\r
- }\r
- }\r
- ret += ") ) ){\n";\r
- int temporal_g = 0;\r
- for(g=0;g<gb_tbl.size();g++){\r
- data_type *gdt = gb_tbl.get_data_type(g);\r
- if(gdt->is_temporal()){\r
- temporal_g = g;\r
- if(gdt->is_buffer_type()){\r
- sprintf(tmpstr,"\t\t%s(&(gbval->gb_var%d),&last_gb%d);\n",gdt->get_hfta_buffer_replace().c_str(),g,g);\r
- }else{\r
- sprintf(tmpstr,"\t\tlast_flushed_gb%d = last_gb%d;\n",g,g);\r
- ret += tmpstr;\r
- sprintf(tmpstr,"\t\tlast_gb%d = gbval->gb_var%d;\n",g,g);\r
- }\r
- ret += tmpstr;\r
- break;\r
- }\r
- }\r
- data_type *tgdt = gb_tbl.get_data_type(temporal_g);\r
- literal_t gl(tgdt->type_indicator());\r
- ret += "\t\tif(last_flushed_gb"+int_to_string(temporal_g)+">"+gl.to_hfta_C_code("")+")\n";\r
- ret += "\t\t\tneeds_temporal_flush=true;\n";\r
- ret += "\t\t}else{\n"\r
- "\t\t\tneeds_temporal_flush=false;\n"\r
- "\t\t}\n";\r
- }\r
-\r
-\r
-// For temporal status tuple we don't need to do anything else\r
- ret += "\tif (temp_tuple_received) return NULL;\n\n";\r
-\r
- for(w=0;w<where.size();++w){\r
- sprintf(tmpstr,"//\t\tPredicate clause %d.\n",w);\r
- ret += tmpstr;\r
-// Find the set of variables accessed in this CNF elem,\r
-// but in no previous element.\r
- col_id_set new_cids;\r
- get_new_pred_cids(where[w]->pr, found_cids, new_cids, segen_gb_tbl);\r
-\r
-// Unpack these values.\r
- ret += gen_unpack_cids(schema, new_cids, "NULL", needs_xform);\r
-// Find partial fcns ref'd in this cnf element\r
- set<int> pfcn_refs;\r
- collect_partial_fcns_pr(where[w]->pr, pfcn_refs);\r
- ret += gen_unpack_partial_fcn(schema, partial_fcns, pfcn_refs,"NULL");\r
-\r
- ret += "\tif( !("+generate_predicate_code(where[w]->pr,schema)+\r
- +") ) return(NULL);\n";\r
- }\r
-\r
-// The partial functions ref'd in the group-by var and aggregate\r
-// definitions must also be evaluated. If one returns false,\r
-// then implicitly the predicate is false.\r
- set<int>::iterator pfsi;\r
-\r
- if(ag_gb_pfcns.size() > 0)\r
- ret += "//\t\tUnpack remaining partial fcns.\n";\r
- ret += gen_full_unpack_partial_fcn(schema, partial_fcns, ag_gb_pfcns,\r
- found_cids, segen_gb_tbl, "NULL", needs_xform);\r
-\r
-// Unpack the group-by variables\r
-\r
- for(g=0;g<gb_tbl.size();g++){\r
- data_type *gdt = gb_tbl.get_data_type(g);\r
-\r
- if(!gdt->is_temporal()){\r
-// Find the new fields ref'd by this GBvar def.\r
- col_id_set new_cids;\r
- get_new_se_cids(gb_tbl.get_def(g), found_cids, new_cids, segen_gb_tbl);\r
-// Unpack these values.\r
- ret += gen_unpack_cids(schema, new_cids, "NULL", needs_xform);\r
-\r
- sprintf(tmpstr,"\tgbval->gb_var%d = %s;\n",\r
- g, generate_se_code(gb_tbl.get_def(g),schema).c_str() );\r
-/*\r
-// There seems to be no difference between the two\r
-// branches of the IF statement.\r
- data_type *gdt = gb_tbl.get_data_type(g);\r
- if(gdt->is_buffer_type()){\r
-// Create temporary copy.\r
- sprintf(tmpstr,"\tgbval->gb_var%d = %s;\n",\r
- g, generate_se_code(gb_tbl.get_def(g),schema).c_str() );\r
- }else{\r
- scalarexp_t *gse = gb_tbl.get_def(g);\r
- sprintf(tmpstr,"\tgbval->gb_var%d = %s;\n",\r
- g,generate_se_code(gse,schema).c_str());\r
- }\r
-*/\r
-\r
- ret.append(tmpstr);\r
- }\r
- }\r
- ret.append("\n");\r
-\r
- ret+= "\treturn gbval;\n";\r
- ret += "};\n\n\n";\r
-\r
-//--------------------------------------------------------\r
-// Create and initialize an aggregate object\r
-\r
- ret += this->generate_functor_name()+"_aggrdef *create_aggregate(host_tuple &tup0, gs_sp_t buffer){\n";\r
- // Variables for execution of the function.\r
- ret += "\tgs_int32_t problem = 0;\n"; // return unpack failure\r
-\r
-// return value\r
- ret += "\t"+generate_functor_name()+"_aggrdef *aggval = ("+generate_functor_name()+\r
- "_aggrdef *)buffer;\n";\r
-\r
- for(a=0;a<aggr_tbl.size();a++){\r
- if(aggr_tbl.is_builtin(a)){\r
-// Create temporaries for buffer return values\r
- data_type *adt = aggr_tbl.get_data_type(a);\r
- if(adt->is_buffer_type()){\r
- sprintf(tmpstr,"aggr_tmp_%d", a);\r
- ret+=adt->make_host_cvar(tmpstr)+";\n";\r
- }\r
- }\r
- }\r
-\r
-// Unpack all remaining attributes\r
- ret += gen_remaining_colrefs(schema, cid_set, found_cids, "NULL", needs_xform);\r
- for(a=0;a<aggr_tbl.size();a++){\r
- sprintf(tmpstr,"aggval->aggr_var%d",a);\r
- string assignto_var = tmpstr;\r
- ret += "\t"+generate_aggr_init(assignto_var,&aggr_tbl,a, schema);\r
- }\r
-\r
- ret += "\treturn aggval;\n";\r
- ret += "};\n\n";\r
-\r
-//--------------------------------------------------------\r
-// update an aggregate object\r
-\r
- ret += "void update_aggregate(host_tuple &tup0, "\r
- +generate_functor_name()+"_groupdef *gbval, "+\r
- generate_functor_name()+"_aggrdef *aggval){\n";\r
- // Variables for execution of the function.\r
- ret += "\tgs_int32_t problem = 0;\n"; // return unpack failure\r
-\r
-// use of temporaries depends on the aggregate,\r
-// generate them in generate_aggr_update\r
-\r
-\r
-// Unpack all remaining attributes\r
- ret += gen_remaining_colrefs(schema, cid_set, found_cids, "", needs_xform);\r
- for(a=0;a<aggr_tbl.size();a++){\r
- sprintf(tmpstr,"aggval->aggr_var%d",a);\r
- string varname = tmpstr;\r
- ret.append(generate_aggr_update(varname,&aggr_tbl,a, schema));\r
- }\r
-\r
- ret += "\treturn;\n";\r
- ret += "};\n";\r
-\r
-//---------------------------------------------------\r
-// Flush test\r
-\r
- ret += "\tbool flush_needed(){\n";\r
- if(uses_temporal_flush){\r
- ret += "\t\treturn needs_temporal_flush;\n";\r
- }else{\r
- ret += "\t\treturn false;\n";\r
- }\r
- ret += "\t};\n";\r
-\r
-//---------------------------------------------------\r
-// create output tuple\r
-// Unpack the partial functions ref'd in the where clause,\r
-// select clause. Evaluate the where clause.\r
-// Finally, pack the tuple.\r
-\r
-// I need to use special code generation here,\r
-// so I'll leave it in longhand.\r
-\r
- ret += "host_tuple create_output_tuple("\r
- +generate_functor_name()+"_groupdef *gbval, "+\r
- generate_functor_name()+"_aggrdef *aggval, bool &failed){\n";\r
-\r
- ret += "\thost_tuple tup;\n";\r
- ret += "\tfailed = false;\n";\r
- ret += "\tgs_retval_t retval = 0;\n";\r
-\r
- string gbvar = "gbval->gb_var";\r
- string aggvar = "aggval->";\r
-\r
-// Create cached temporaries for UDAF return values.\r
- for(a=0;a<aggr_tbl.size();a++){\r
- if(! aggr_tbl.is_builtin(a)){\r
- int afcn_id = aggr_tbl.get_fcn_id(a);\r
- data_type *adt = Ext_fcns->get_fcn_dt(afcn_id);\r
- sprintf(tmpstr,"udaf_ret_%d", a);\r
- ret+="\t"+adt->make_host_cvar(tmpstr)+";\n";\r
- }\r
- }\r
-\r
-\r
-// First, get the return values from the UDAFS\r
- for(a=0;a<aggr_tbl.size();a++){\r
- if(! aggr_tbl.is_builtin(a)){\r
- ret += "\t"+aggr_tbl.get_op(a)+"_HFTA_AGGR_OUTPUT_(&(udaf_ret_"+int_to_string(a)+"),";\r
- if(aggr_tbl.get_storage_type(a)->get_type() != fstring_t) ret+="&";\r
- ret+="("+aggvar+"aggr_var"+int_to_string(a)+"));\n";\r
- }\r
- }\r
-\r
- set<int> hv_sl_pfcns;\r
- for(w=0;w<having.size();w++){\r
- collect_partial_fcns_pr(having[w]->pr, hv_sl_pfcns);\r
- }\r
- for(s=0;s<select_list.size();s++){\r
- collect_partial_fcns(select_list[s]->se, hv_sl_pfcns);\r
- }\r
-\r
-// clean up the partial fcn results from any previous execution\r
- ret += gen_partial_fcn_dtr(partial_fcns,hv_sl_pfcns);\r
-\r
-// Unpack them now\r
- for(pfsi=hv_sl_pfcns.begin();pfsi!=hv_sl_pfcns.end();++pfsi){\r
- ret += unpack_partial_fcn_fm_aggr(partial_fcns[(*pfsi)], (*pfsi), gbvar, aggvar, schema);\r
- ret += "\tif(retval){ failed = true; return(tup);}\n";\r
- }\r
-\r
-// Evalaute the HAVING clause\r
-// TODO: this seems to have a ++ operator rather than a + operator.\r
- for(w=0;w<having.size();++w){\r
- ret += "\tif( !("+generate_predicate_code_fm_aggr(having[w]->pr,gbvar, aggvar, schema) +") ) { failed = true; return(tup);}\n";\r
- }\r
-\r
-// Now, compute the size of the tuple.\r
-\r
-// Unpack any BUFFER type selections into temporaries\r
-// so that I can compute their size and not have\r
-// to recompute their value during tuple packing.\r
-// I can use regular assignment here because\r
-// these temporaries are non-persistent.\r
-// TODO: should I be using the selvar generation routine?\r
-\r
- ret += "//\t\tCompute the size of the tuple.\n";\r
- ret += "//\t\t\tNote: buffer storage packed at the end of the tuple.\n";\r
- for(s=0;s<select_list.size();s++){\r
- scalarexp_t *se = select_list[s]->se;\r
- data_type *sdt = se->get_data_type();\r
- if(sdt->is_buffer_type() &&\r
- !( (se->get_operator_type() == SE_COLREF) ||\r
- (se->get_operator_type() == SE_AGGR_STAR) ||\r
- (se->get_operator_type() == SE_AGGR_SE) ||\r
- (se->get_operator_type() == SE_FUNC && se->is_partial()) ||\r
- (se->get_operator_type() == SE_FUNC && se->get_aggr_ref() >= 0))\r
- ){\r
- sprintf(tmpstr,"selvar_%d",s);\r
- ret+="\t"+sdt->make_host_cvar(tmpstr)+" = ";\r
- ret += generate_se_code_fm_aggr(se,gbvar, aggvar, schema) +";\n";\r
- }\r
- }\r
-\r
-// The size of the tuple is the size of the tuple struct plus the\r
-// size of the buffers to be copied in.\r
-\r
- ret+="\ttup.tuple_size = sizeof(" + generate_tuple_name( this->get_node_name()) +") + sizeof(gs_uint8_t)";\r
- for(s=0;s<select_list.size();s++){\r
-// if(s>0) ret += "+";\r
- scalarexp_t *se = select_list[s]->se;\r
- data_type *sdt = select_list[s]->se->get_data_type();\r
- if(sdt->is_buffer_type()){\r
- if(!( (se->get_operator_type() == SE_COLREF) ||\r
- (se->get_operator_type() == SE_AGGR_STAR) ||\r
- (se->get_operator_type() == SE_AGGR_SE) ||\r
- (se->get_operator_type() == SE_FUNC && se->is_partial()) ||\r
- (se->get_operator_type() == SE_FUNC && se->get_aggr_ref() >= 0))\r
- ){\r
- sprintf(tmpstr," + %s(&selvar_%d)", sdt->get_hfta_buffer_size().c_str(),s);\r
- ret.append(tmpstr);\r
- }else{\r
- sprintf(tmpstr," + %s(&%s)", sdt->get_hfta_buffer_size().c_str(),generate_se_code_fm_aggr(se,gbvar, aggvar, schema).c_str());\r
- ret.append(tmpstr);\r
- }\r
- }\r
- }\r
- ret.append(";\n");\r
-\r
-// Allocate tuple data block.\r
- ret += "//\t\tCreate the tuple block.\n";\r
- ret += "\ttup.data = malloc(tup.tuple_size);\n";\r
- ret += "\ttup.heap_resident = true;\n";\r
-\r
-// Mark tuple as regular\r
- ret += "\t*((gs_sp_t )tup.data + sizeof(" + generate_tuple_name( this->get_node_name()) +")) = REGULAR_TUPLE;\n";\r
-\r
-// ret += "\ttup.channel = 0;\n";\r
- ret += "\t"+generate_tuple_name( this->get_node_name())+" *tuple = ("+\r
- generate_tuple_name( this->get_node_name())+" *)(tup.data);\n";\r
-\r
-// Start packing.\r
-// (Here, offsets are hard-wired. is this a problem?)\r
-\r
- ret += "//\t\tPack the fields into the tuple.\n";\r
- ret += "\tint tuple_pos = sizeof("+generate_tuple_name( this->get_node_name()) +") + sizeof(gs_uint8_t);\n";\r
- for(s=0;s<select_list.size();s++){\r
- scalarexp_t *se = select_list[s]->se;\r
- data_type *sdt = se->get_data_type();\r
- if(sdt->is_buffer_type()){\r
- if(!( (se->get_operator_type() == SE_COLREF) ||\r
- (se->get_operator_type() == SE_AGGR_STAR) ||\r
- (se->get_operator_type() == SE_AGGR_SE) ||\r
- (se->get_operator_type() == SE_FUNC && se->is_partial()) ||\r
- (se->get_operator_type() == SE_FUNC && se->get_aggr_ref() >= 0))\r
- ){\r
- sprintf(tmpstr,"\t%s(&(tuple->tuple_var%d), &selvar_%d, ((gs_sp_t)tuple)+tuple_pos, tuple_pos);\n", sdt->get_hfta_buffer_tuple_copy().c_str(),s, s);\r
- ret.append(tmpstr);\r
- sprintf(tmpstr,"\ttuple_pos += %s(&selvar_%d);\n", sdt->get_hfta_buffer_size().c_str(), s);\r
- ret.append(tmpstr);\r
- }else{\r
- sprintf(tmpstr,"\t%s(&(tuple->tuple_var%d), &%s, ((gs_sp_t)tuple)+tuple_pos, tuple_pos);\n", sdt->get_hfta_buffer_tuple_copy().c_str(),s, generate_se_code_fm_aggr(se,gbvar, aggvar, schema).c_str());\r
- ret.append(tmpstr);\r
- sprintf(tmpstr,"\ttuple_pos += %s(&%s);\n", sdt->get_hfta_buffer_size().c_str(), generate_se_code_fm_aggr(se,gbvar, aggvar, schema).c_str());\r
- ret.append(tmpstr);\r
- }\r
- }else{\r
- sprintf(tmpstr,"\ttuple->tuple_var%d = ",s);\r
- ret.append(tmpstr);\r
- ret.append(generate_se_code_fm_aggr(se,gbvar, aggvar, schema) );\r
- ret.append(";\n");\r
- }\r
- }\r
-\r
-// Destroy string temporaries\r
- ret += gen_buffer_selvars_dtr(select_list);\r
-// Destroy string return vals of UDAFs\r
- for(a=0;a<aggr_tbl.size();a++){\r
- if(! aggr_tbl.is_builtin(a)){\r
- int afcn_id = aggr_tbl.get_fcn_id(a);\r
- data_type *adt = Ext_fcns->get_fcn_dt(afcn_id);\r
- if(adt->is_buffer_type()){\r
- sprintf(tmpstr,"\t%s(&udaf_ret_%d);\n",\r
- adt->get_hfta_buffer_destroy().c_str(), a );\r
- ret += tmpstr;\r
- }\r
- }\r
- }\r
-\r
-\r
- ret += "\treturn tup;\n";\r
- ret += "};\n";\r
-\r
-\r
-//-------------------------------------------------------------------\r
-// Temporal update functions\r
-\r
- ret+="bool temp_status_received(){return temp_tuple_received;};\n\n";\r
-\r
- for(g=0;g<gb_tbl.size();g++){\r
- data_type *gdt = gb_tbl.get_data_type(g);\r
- if(gdt->is_temporal()){\r
- tgdt = gdt;\r
- break;\r
- }\r
- }\r
- ret += tgdt->get_host_cvar_type()+" get_last_flushed_gb(){\n";\r
- ret+="\treturn last_flushed_gb"+int_to_string(g)+";\n";\r
- ret+="}\n";\r
- ret += tgdt->get_host_cvar_type()+" get_last_gb(){\n";\r
- ret+="\treturn last_gb"+int_to_string(g)+";\n";\r
- ret+="}\n";\r
-\r
-\r
-\r
-\r
-// create a temp status tuple\r
- ret += "int create_temp_status_tuple(host_tuple& result, bool flush_finished) {\n\n";\r
-\r
- ret += gen_init_temp_status_tuple(this->get_node_name());\r
-\r
-// Start packing.\r
-// (Here, offsets are hard-wired. is this a problem?)\r
-\r
- ret += "//\t\tPack the fields into the tuple.\n";\r
- for(s=0;s<select_list.size();s++){\r
- data_type *sdt = select_list[s]->se->get_data_type();\r
- if(sdt->is_temporal()){\r
- sprintf(tmpstr,"\ttuple->tuple_var%d = ",s);\r
- ret += tmpstr;\r
-\r
- sprintf(tmpstr,"(flush_finished) ? %s : %s ", generate_se_code(select_list[s]->se,schema).c_str(), generate_se_code_fm_aggr(select_list[s]->se,"last_flushed_gb", "", schema).c_str());\r
- ret += tmpstr;\r
- ret += ";\n";\r
- }\r
- }\r
-\r
-\r
- ret += "\treturn 0;\n";\r
- ret += "};};\n\n\n";\r
-\r
-\r
-//----------------------------------------------------------\r
-// The hash function\r
-\r
- ret += "struct "+generate_functor_name()+"_hash_func{\n";\r
- ret += "\tgs_uint32_t operator()(const "+generate_functor_name()+\r
- "_groupdef *grp) const{\n";\r
- ret += "\t\treturn( (";\r
- for(g=0;g<gb_tbl.size();g++){\r
- if(g>0) ret += "^";\r
- data_type *gdt = gb_tbl.get_data_type(g);\r
- if(gdt->use_hashfunc()){\r
- if(gdt->is_buffer_type())\r
- sprintf(tmpstr,"(%s*%s(&(grp->gb_var%d)))",hash_nums[g%NRANDS].c_str(),gdt->get_hfta_hashfunc().c_str(),g);\r
- else\r
- sprintf(tmpstr,"(%s*%s(grp->gb_var%d))",hash_nums[g%NRANDS].c_str(),gdt->get_hfta_hashfunc().c_str(),g);\r
- }else{\r
- sprintf(tmpstr,"(%s*grp->gb_var%d)",hash_nums[g%NRANDS].c_str(),g);\r
- }\r
- ret += tmpstr;\r
- }\r
- ret += ") >> 32);\n";\r
- ret += "\t}\n";\r
- ret += "};\n\n";\r
-\r
-//----------------------------------------------------------\r
-// The comparison function\r
-\r
- ret += "struct "+generate_functor_name()+"_equal_func{\n";\r
- ret += "\tbool operator()(const "+generate_functor_name()+"_groupdef *grp1, "+\r
- generate_functor_name()+"_groupdef *grp2) const{\n";\r
- ret += "\t\treturn( (";\r
-\r
- for(g=0;g<gb_tbl.size();g++){\r
- if(g>0) ret += ") && (";\r
- data_type *gdt = gb_tbl.get_data_type(g);\r
- if(gdt->complex_comparison(gdt)){\r
- if(gdt->is_buffer_type())\r
- sprintf(tmpstr,"(%s(&(grp1->gb_var%d), &(grp2->gb_var%d))==0)",\r
- gdt->get_hfta_comparison_fcn(gdt).c_str(),g,g);\r
- else\r
- sprintf(tmpstr,"(%s((grp1->gb_var%d), (grp2->gb_var%d))==0)",\r
- gdt->get_hfta_comparison_fcn(gdt).c_str(),g,g);\r
- }else{\r
- sprintf(tmpstr,"grp1->gb_var%d == grp2->gb_var%d",g,g);\r
- }\r
- ret += tmpstr;\r
- }\r
- ret += ") );\n";\r
- ret += "\t}\n";\r
- ret += "};\n\n";\r
-\r
-\r
- return(ret);\r
-}\r
-\r
-string sgah_qpn::generate_operator(int i, string params){\r
-\r
- if(hfta_disorder < 2){\r
- return(\r
- " groupby_operator<" +\r
- generate_functor_name()+","+\r
- generate_functor_name() + "_groupdef, " +\r
- generate_functor_name() + "_aggrdef, " +\r
- generate_functor_name()+"_hash_func, "+\r
- generate_functor_name()+"_equal_func "\r
- "> *op"+int_to_string(i)+" = new groupby_operator<"+\r
- generate_functor_name()+","+\r
- generate_functor_name() + "_groupdef, " +\r
- generate_functor_name() + "_aggrdef, " +\r
- generate_functor_name()+"_hash_func, "+\r
- generate_functor_name()+"_equal_func "\r
- ">("+params+", \"" + get_node_name() +\r
-"\");\n"\r
- );\r
- }\r
- data_type *tgdt;\r
- for(int g=0;g<gb_tbl.size();g++){\r
- data_type *gdt = gb_tbl.get_data_type(g);\r
- if(gdt->is_temporal()){\r
- tgdt = gdt;\r
- break;\r
- }\r
- }\r
-\r
- return(\r
- " groupby_operator_oop<" +\r
- generate_functor_name()+","+\r
- generate_functor_name() + "_groupdef, " +\r
- generate_functor_name() + "_aggrdef, " +\r
- generate_functor_name()+"_hash_func, "+\r
- generate_functor_name()+"_equal_func, " +\r
- tgdt->get_host_cvar_type() +\r
- "> *op"+int_to_string(i)+" = new groupby_operator_oop<"+\r
- generate_functor_name()+","+\r
- generate_functor_name() + "_groupdef, " +\r
- generate_functor_name() + "_aggrdef, " +\r
- generate_functor_name()+"_hash_func, "+\r
- generate_functor_name()+"_equal_func, " +\r
- tgdt->get_host_cvar_type() +\r
- ">("+params+", \"" + get_node_name() +\r
-"\");\n"\r
- );\r
-}\r
-\r
-\r
-////////////////////////////////////////////////\r
-/// MERGE operator\r
-/// MRG functor\r
-////////////////////////////////////////////\r
-\r
-string mrg_qpn::generate_functor_name(){\r
- return("mrg_functor_" + normalize_name(this->get_node_name()));\r
-}\r
-\r
-string mrg_qpn::generate_functor(table_list *schema, ext_fcn_list *Ext_fcns, vector<bool> &needs_xform){\r
- int tblref;\r
-\r
-\r
-// Sanity check\r
- if(fm.size() != mvars.size()){\r
- fprintf(stderr,"INTERNAL ERROR in mrg_qpn::generate_functor fm.size=%lu, mvars.size=%lu\n",fm.size(),mvars.size());\r
- exit(1);\r
- }\r
- if(fm.size() != 2){\r
- fprintf(stderr,"INTERNAL ERROR in mrg_qpn::generate_functor fm.size=mvars.size=%lu\n",fm.size());\r
- exit(1);\r
- }\r
-\r
-\r
-// Initialize generate utility globals\r
- segen_gb_tbl = NULL;\r
-\r
- string ret = "class " + this->generate_functor_name() + "{\n";\r
-\r
-// Private variable:\r
-// 1) Vars for unpacked attrs.\r
-// 2) offsets ofthe unpakced attrs\r
-// 3) last_posted_timestamp\r
-\r
- data_type dta(\r
- schema->get_type_name(mvars[0]->get_schema_ref(), mvars[0]->get_field()),\r
- schema->get_modifier_list(mvars[0]->get_schema_ref(), mvars[0]->get_field())\r
- );\r
- data_type dtb(\r
- schema->get_type_name(mvars[1]->get_schema_ref(), mvars[1]->get_field()),\r
- schema->get_modifier_list(mvars[1]->get_schema_ref(), mvars[1]->get_field())\r
- );\r
-\r
- ret += "private:\n";\r
-\r
- // var to save the schema handle\r
- ret += "\tint schema_handle0;\n";\r
-\r
- // generate the declaration of all the variables related to\r
- // temp tuples generation\r
- ret += gen_decl_temp_vars();\r
-\r
-// unpacked attribute storage, offsets\r
- ret += "//\t\tstorage and offsets of accessed fields.\n";\r
- ret += "\tint tuple_metadata_offset0, tuple_metadata_offset1;\n";\r
- tblref = 0;\r
- sprintf(tmpstr,"unpack_var_%s_%d", mvars[0]->get_field().c_str(), tblref);\r
- ret+="\t"+dta.make_host_cvar(tmpstr)+";\n";\r
- sprintf(tmpstr,"\tgs_int32_t unpack_offset_%s_%d;\n", mvars[0]->get_field().c_str(), tblref);\r
- ret.append(tmpstr);\r
- tblref = 1;\r
- sprintf(tmpstr,"unpack_var_%s_%d", mvars[1]->get_field().c_str(), tblref);\r
- ret+="\t"+dtb.make_host_cvar(tmpstr)+";\n";\r
- sprintf(tmpstr,"\tgs_int32_t unpack_offset_%s_%d;\n", mvars[1]->get_field().c_str(), tblref);\r
- ret.append(tmpstr);\r
-\r
- ret += "//\t\tRemember the last posted timestamp.\n";\r
- ret+="\t"+dta.make_host_cvar("last_posted_timestamp_0")+";\n";\r
- ret+="\t"+dta.make_host_cvar("last_posted_timestamp_1")+";\n";\r
- ret+="\t"+dta.make_host_cvar("timestamp")+";\n";\r
- ret+="\t"+dta.make_host_cvar("slack")+";\n";\r
-// ret += "\t bool first_execution_0, first_execution_1;\n";\r
-\r
-// variables to hold parameters.\r
- ret += "//\tfor query parameters\n";\r
- ret += generate_param_vars(param_tbl);\r
-\r
- ret += "public:\n";\r
-//-------------------\r
-// The functor constructor\r
-// pass in a schema handle (e.g. for the 1st input stream),\r
-// use it to determine how to unpack the merge variable.\r
-// ASSUME that both streams have the same layout,\r
-// just duplicate it.\r
-\r
-// unpack vars\r
- ret += "//\t\tFunctor constructor.\n";\r
- ret += this->generate_functor_name()+"(int schema_handle0){\n";\r
-\r
- // var to save the schema handle\r
- ret += "\tthis->schema_handle0 = schema_handle0;\n";\r
- ret += "\ttuple_metadata_offset0=ftaschema_get_tuple_metadata_offset(schema_handle0);\n";\r
- ret += "\ttuple_metadata_offset1=ftaschema_get_tuple_metadata_offset(schema_handle0);\n";\r
-\r
- ret += "//\t\tGet offsets for unpacking fields from input tuple.\n";\r
-\r
- sprintf(tmpstr,"\tunpack_offset_%s_%d = ftaschema_get_field_offset_by_name(schema_handle0, \"%s\");\n", mvars[0]->get_field().c_str(), 0,mvars[0]->get_field().c_str());\r
- ret.append(tmpstr);\r
- sprintf(tmpstr,"\tunpack_offset_%s_%d = unpack_offset_%s_%d;\n",mvars[1]->get_field().c_str(), 1,mvars[0]->get_field().c_str(), 0);\r
- ret.append(tmpstr);\r
-// ret+="\tfirst_execution_0 = first_execution_1 = true;\n";\r
- if(slack)\r
- ret+="\tslack = "+generate_se_code(slack,schema)+";\n";\r
- else\r
- ret+="\tslack = 0;\n";\r
-\r
-// Initialize internal state\r
- ret += "\ttemp_tuple_received = false;\n";\r
-\r
- // Init last timestamp values to minimum value for their type\r
- if (dta.is_increasing())\r
- ret+="\tlast_posted_timestamp_0 = last_posted_timestamp_1 = " + dta.get_min_literal() + ";\n";\r
- else\r
- ret+="\tlast_posted_timestamp_0 = last_posted_timestamp_1 = " + dta.get_max_literal() + ";\n";\r
-\r
-\r
- ret += "};\n\n";\r
-\r
- ret += "//\t\tFunctor destructor.\n";\r
- ret += "~"+this->generate_functor_name()+"(){\n";\r
-\r
-// Destroy the parameters, if any need to be destroyed\r
- ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";\r
-\r
- ret+="};\n\n";\r
-\r
-\r
-// no pass-by-handle params.\r
- vector<handle_param_tbl_entry *> param_handle_table;\r
-\r
-// Parameter manipulation routines\r
- ret += generate_load_param_block(this->generate_functor_name(),\r
- this->param_tbl,param_handle_table);\r
- ret += generate_delete_param_block(this->generate_functor_name(),\r
- this->param_tbl,param_handle_table);\r
-\r
-// Register new parameter block\r
-\r
- ret += "int set_param_block(gs_int32_t sz, void* value){\n";\r
- ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";\r
- ret += "\treturn this->load_params_"+this->generate_functor_name()+\r
- "(sz, value);\n";\r
- ret += "};\n\n";\r
-\r
-\r
-// -----------------------------------\r
-// Compare method\r
-\r
- string unpack_fcna;\r
- if(needs_xform[0]) unpack_fcna = dta.get_hfta_unpack_fcn();\r
- else unpack_fcna = dta.get_hfta_unpack_fcn_noxf();\r
- string unpack_fcnb;\r
- if(needs_xform[1]) unpack_fcnb = dtb.get_hfta_unpack_fcn();\r
- else unpack_fcnb = dtb.get_hfta_unpack_fcn_noxf();\r
-\r
-/*\r
- ret+="\tint compare(const host_tuple& tup1, const host_tuple& tup2) const{ \n";\r
- ret+="\t"+dta.make_host_cvar("timestamp1")+";\n";\r
- ret+="\t"+dta.make_host_cvar("timestamp2")+";\n";\r
- ret+="\tgs_int32_t problem;\n";\r
- ret+="\tif (tup1.channel == 0) {\n";\r
- sprintf(tmpstr,"\t\ttimestamp1 = %s(tup1.data, tup1.tuple_size, unpack_offset_%s_%d, &problem);\n", unpack_fcna.c_str(), mvars[0]->get_field().c_str(), 0);\r
- ret += tmpstr;\r
- sprintf(tmpstr,"\t\ttimestamp2 = %s(tup2.data, tup2.tuple_size, unpack_offset_%s_%d, &problem);\n", unpack_fcnb.c_str(), mvars[1]->get_field().c_str(), 1);\r
- ret += tmpstr;\r
- ret+="\t}else{\n";\r
- sprintf(tmpstr,"\t\ttimestamp1 = %s(tup1.data, tup1.tuple_size, unpack_offset_%s_%d, &problem);\n", unpack_fcna.c_str(), mvars[0]->get_field().c_str(), 1);\r
- ret += tmpstr;\r
- sprintf(tmpstr,"\t\ttimestamp2 = %s(tup2.data, tup2.tuple_size, unpack_offset_%s_%d, &problem);\n", unpack_fcnb.c_str(), mvars[1]->get_field().c_str(), 0);\r
- ret += tmpstr;\r
- ret+="\t}\n";\r
- ret+=\r
-" if (timestamp1 > timestamp2+slack)\n"\r
-" return 1;\n"\r
-" else if (timestamp1 < timestamp2)\n"\r
-" return -1;\n"\r
-" else\n"\r
-" return 0;\n"\r
-"\n"\r
-" }\n\n";\r
-*/\r
-\r
-ret +=\r
-" void get_timestamp(const host_tuple& tup0){\n"\r
-" gs_int32_t problem;\n"\r
-;\r
- sprintf(tmpstr,"\t\ttimestamp = %s_nocheck(tup0.data, unpack_offset_%s_%d);\n", unpack_fcna.c_str(), mvars[0]->get_field().c_str(), 0);\r
- ret += tmpstr;\r
-ret +=\r
-" }\n"\r
-"\n"\r
-;\r
-\r
-\r
-\r
-// Compare to temp status.\r
- ret+=\r
-" int compare_with_temp_status(int channel) {\n"\r
-" // check if tuple is temp status tuple\n"\r
-"\n"\r
-" if (channel == 0) {\n"\r
-//" if(first_execution_0) return 1;\n"\r
-" if (timestamp == last_posted_timestamp_0)\n"\r
-" return 0;\n"\r
-" else if (timestamp < last_posted_timestamp_0)\n"\r
-" return -1;\n"\r
-" else\n"\r
-" return 1;\n"\r
-" }\n"\r
-//" if(first_execution_1) return 1;\n"\r
-" if (timestamp == last_posted_timestamp_1)\n"\r
-" return 0;\n"\r
-" else if (timestamp < last_posted_timestamp_1)\n"\r
-" return -1;\n"\r
-" else\n"\r
-" return 1;\n"\r
-"\n"\r
-" }\n"\r
-;\r
-\r
- ret +=\r
-" int compare_stored_with_temp_status(const host_tuple& tup0, int channel)/* const*/ {\n"\r
-;\r
- ret+="\t"+dta.make_host_cvar("l_timestamp")+";\n";\r
- ret+="\tgs_int32_t problem;\n";\r
-\r
- sprintf(tmpstr,"\t\tl_timestamp = %s_nocheck(tup0.data, unpack_offset_%s_%d);\n", unpack_fcna.c_str(), mvars[0]->get_field().c_str(), 0);\r
- ret += tmpstr;\r
- ret+="\tif (channel == 0) {\n";\r
-// ret+="\tif(first_execution_0) return 1;\n";\r
- ret+=\r
-" if (l_timestamp == last_posted_timestamp_0)\n"\r
-" return 0;\n"\r
-" else if (l_timestamp < last_posted_timestamp_0)\n"\r
-" return -1;\n"\r
-" else\n"\r
-" return 1;\n"\r
-" }\n";\r
-// ret+="\tif(first_execution_1) return 1;\n";\r
- ret+=\r
-" if (l_timestamp == last_posted_timestamp_1)\n"\r
-" return 0;\n"\r
-" else if (l_timestamp < last_posted_timestamp_1)\n"\r
-" return -1;\n"\r
-" else\n"\r
-" return 1;\n"\r
-"\n"\r
-" }\n\n";\r
-\r
-\r
-// update temp status.\r
- ret+=\r
-" int update_temp_status(const host_tuple& tup) {\n"\r
-" if (tup.channel == 0) {\n"\r
-" last_posted_timestamp_0=timestamp;\n"\r
-//" first_execution_0 = false;\n"\r
-" }else{\n"\r
-" last_posted_timestamp_1=timestamp;\n"\r
-//" first_execution_1 = false;\n"\r
-" }\n"\r
-" return 0;\n"\r
-" }\n"\r
-;\r
- ret+=\r
-" int update_stored_temp_status(const host_tuple& tup, int channel) {\n"\r
-;\r
- ret+="\t"+dta.make_host_cvar("l_timestamp")+";\n";\r
- ret+="\tgs_int32_t problem;\n";\r
- sprintf(tmpstr,"\t\tl_timestamp = %s_nocheck(tup.data, unpack_offset_%s_%d);\n", unpack_fcna.c_str(), mvars[0]->get_field().c_str(), 0);\r
- ret += tmpstr;\r
-ret+=\r
-" if (tup.channel == 0) {\n"\r
-" last_posted_timestamp_0=l_timestamp;\n"\r
-//" first_execution_0 = false;\n"\r
-" }else{\n"\r
-" last_posted_timestamp_1=l_timestamp;\n"\r
-//" first_execution_1 = false;\n"\r
-" }\n"\r
-" return 0;\n"\r
-" }\n"\r
-;\r
-/*\r
- ret+="\t"+dta.make_host_cvar("timestamp")+";\n";\r
- ret+="\tgs_int32_t problem;\n";\r
- ret+="\tif (tup.channel == 0) {\n";\r
- sprintf(tmpstr,"\t\ttimestamp = %s(tup.data, tup.tuple_size, unpack_offset_%s_%d, &problem);\n", unpack_fcna.c_str(), mvars[0]->get_field().c_str(), 0);\r
- ret += tmpstr;\r
- ret+="\t}else{\n";\r
- sprintf(tmpstr,"\t\ttimestamp = %s(tup.data, tup.tuple_size, unpack_offset_%s_%d, &problem);\n", unpack_fcnb.c_str(), mvars[1]->get_field().c_str(), 1);\r
- ret += tmpstr;\r
- ret+="\t}\n";\r
- ret+="\tif (tup.channel == 0) {\n";\r
- ret+="\tlast_posted_timestamp_0=timestamp;\n";\r
- ret +="\tfirst_execution_0 = false;\n";\r
- ret+="\t}else{\n";\r
- ret+="\tlast_posted_timestamp_1=timestamp;\n";\r
- ret +="\tfirst_execution_1 = false;\n";\r
- ret+="\t}\n";\r
- ret+=\r
-" }\n\n";\r
-*/\r
-\r
-\r
-// update temp status modulo slack.\r
- ret+="\tint update_temp_status_by_slack(const host_tuple& tup, int channel) {\n";\r
- if(slack){\r
- ret+="\t"+dta.make_host_cvar("timestamp")+";\n";\r
- ret+="\tgs_int32_t problem;\n";\r
- ret+="\tif (tup.channel == 0) {\n";\r
- sprintf(tmpstr,"\t\ttimestamp = %s_nocheck(tup.data, unpack_offset_%s_%d);\n", unpack_fcna.c_str(), mvars[0]->get_field().c_str(), 0);\r
- ret += tmpstr;\r
- ret+="\t}else{\n";\r
- sprintf(tmpstr,"\t\ttimestamp = %s_nocheck(tup.data, unpack_offset_%s_%d);\n", unpack_fcnb.c_str(), mvars[1]->get_field().c_str(), 1);\r
- ret += tmpstr;\r
- ret+="\t}\n";\r
-ret +=\r
-" if (channel == 0) {\n"\r
-" if(first_execution_0){\n"\r
-" last_posted_timestamp_0=timestamp - slack;\n"\r
-" first_execution_0 = false;\n"\r
-" }else{\n"\r
-" if(last_posted_timestamp_0 < timestamp-slack)\n"\r
-" last_posted_timestamp_0 = timestamp-slack;\n"\r
-" }\n"\r
-" }else{\n"\r
-" if(first_execution_1){\n"\r
-" last_posted_timestamp_1=timestamp - slack;\n"\r
-" first_execution_1 = false;\n"\r
-" }else{\n"\r
-" if(last_posted_timestamp_1 < timestamp-slack)\n"\r
-" last_posted_timestamp_1 = timestamp-slack;\n"\r
-" }\n"\r
-" }\n"\r
-" return 0;\n"\r
-" }\n\n";\r
- }else{\r
- ret +=\r
-" return 0;\n"\r
-" }\n\n";\r
- }\r
-\r
-\r
-//\r
- ret+=\r
-"bool temp_status_received(const host_tuple& tup0){\n"\r
-" return ftaschema_is_temporal_tuple_offset(tuple_metadata_offset0, tup0.data);\n"\r
-"};\n"\r
-;\r
-//"bool temp_status_received(){return temp_tuple_received;};\n\n";\r
-\r
-\r
-// create a temp status tuple\r
- ret += "int create_temp_status_tuple(host_tuple& result) {\n\n";\r
-\r
- ret += gen_init_temp_status_tuple(this->get_node_name());\r
-\r
-// Start packing.\r
- ret += "//\t\tPack the fields into the tuple.\n";\r
-\r
- string fld_name = mvars[0]->get_field();\r
- int idx = table_layout->get_field_idx(fld_name);\r
- field_entry* fld = table_layout->get_field(idx);\r
- data_type dt(fld->get_type());\r
-\r
-// if (needs_xform[0] && needs_xform[1] && dt.needs_hn_translation())\r
-// sprintf(tmpstr,"\ttuple->tuple_var%d = %s((last_posted_timestamp_0 < last_posted_timestamp_1) ? last_posted_timestamp_0 : last_posted_timestamp_1);\n",idx, dt.hton_translation().c_str());\r
-// else\r
- sprintf(tmpstr,"\ttuple->tuple_var%d = (last_posted_timestamp_0 < last_posted_timestamp_1 ? last_posted_timestamp_0 : last_posted_timestamp_1);\n",idx);\r
-\r
- ret += tmpstr;\r
-\r
- ret += "\treturn 0;\n";\r
- ret += "}\n\n";\r
-\r
-// Transform tuple (before output)\r
-\r
-\r
- ret += "void xform_tuple(host_tuple &tup){\n";\r
- if((needs_xform[0] && !needs_xform[1]) || (needs_xform[1] && !needs_xform[0])){\r
- ret += "\tstruct "+generate_tuple_name(this->get_node_name())+" *tuple = ("+\r
- generate_tuple_name(this->get_node_name())+" *)(tup.data);\n";\r
-\r
- vector<field_entry *> flds = table_layout->get_fields();\r
-\r
- ret+="\tif(tup.channel == 0){\n";\r
- if(needs_xform[0] && !needs_xform[1]){\r
- int f;\r
- for(f=0;f<flds.size();f++){\r
- ret.append("\t");\r
- data_type dt(flds[f]->get_type());\r
- if(dt.get_type() == v_str_t){\r
-// sprintf(tmpstr,"\ttuple->tuple_var%d.offset = htonl(tuple->tuple_var%d.offset);\n",f,f);\r
-// ret += tmpstr;\r
-// sprintf(tmpstr,"\ttuple->tuple_var%d.length = htonl(tuple->tuple_var%d.length);\n",f,f);\r
-// ret += tmpstr;\r
-// sprintf(tmpstr,"\ttuple->tuple_var%d.reserved = htonl(tuple->tuple_var%d.reserved);\n",f,f);\r
-// ret += tmpstr;\r
- }else{\r
- if(dt.needs_hn_translation()){\r
-// sprintf(tmpstr,"\ttuple->tuple_var%d = %s(tuple->tuple_var%d);\n",\r
-// f, dt.hton_translation().c_str(), f);\r
-// ret += tmpstr;\r
- }\r
- }\r
- }\r
- }else{\r
- ret += "\t\treturn;\n";\r
- }\r
- ret.append("\t}\n");\r
-\r
-\r
- ret+="\tif(tup.channel == 1){\n";\r
- if(needs_xform[1] && !needs_xform[0]){\r
- int f;\r
- for(f=0;f<flds.size();f++){\r
- ret.append("\t");\r
- data_type dt(flds[f]->get_type());\r
- if(dt.get_type() == v_str_t){\r
-// sprintf(tmpstr,"\ttuple->tuple_var%d.offset = htonl(tuple->tuple_var%d.offset);\n",f,f);\r
-// ret += tmpstr;\r
-// sprintf(tmpstr,"\ttuple->tuple_var%d.length = htonl(tuple->tuple_var%d.length);\n",f,f);\r
-// ret += tmpstr;\r
-// sprintf(tmpstr,"\ttuple->tuple_var%d.reserved = htonl(tuple->tuple_var%d.reserved);\n",f,f);\r
-// ret += tmpstr;\r
- }else{\r
- if(dt.needs_hn_translation()){\r
-// sprintf(tmpstr,"\ttuple->tuple_var%d = %s(tuple->tuple_var%d);\n",\r
-// f, dt.hton_translation().c_str(), f);\r
-// ret += tmpstr;\r
- }\r
- }\r
- }\r
- }else{\r
- ret += "\t\treturn;\n";\r
- }\r
- ret.append("\t}\n");\r
- }\r
-\r
- ret.append("};\n\n");\r
-\r
-// print_warnings() : tell the functor if the user wants to print warnings.\r
- ret += "bool print_warnings(){\n";\r
- if(definitions.count("print_warnings") && (\r
- definitions["print_warnings"] == "yes" ||\r
- definitions["print_warnings"] == "Yes" ||\r
- definitions["print_warnings"] == "YES" )) {\r
- ret += "return true;\n";\r
- }else{\r
- ret += "return false;\n";\r
- }\r
- ret.append("};\n\n");\r
-\r
-\r
-// Done with methods.\r
- ret+="\n};\n\n";\r
-\r
-\r
- return(ret);\r
-}\r
-\r
-string mrg_qpn::generate_operator(int i, string params){\r
-\r
- if(disorder < 2){\r
- return(\r
- " merge_operator<" +\r
- generate_functor_name()+\r
- "> *op"+int_to_string(i)+" = new merge_operator<"+\r
- generate_functor_name()+\r
- ">("+params+",10000,\"" + get_node_name() + "\");\n"\r
- );\r
- }\r
- return(\r
- " merge_operator_oop<" +\r
- generate_functor_name()+\r
- "> *op"+int_to_string(i)+" = new merge_operator_oop<"+\r
- generate_functor_name()+\r
- ">("+params+",10000,\"" + get_node_name() + "\");\n"\r
- );\r
-}\r
-\r
-\r
-/////////////////////////////////////////////////////////\r
-////// JOIN_EQ_HASH functor\r
-\r
-\r
-string join_eq_hash_qpn::generate_functor_name(){\r
- return("join_eq_hash_functor_" + normalize_name(this->get_node_name()));\r
-}\r
-\r
-string join_eq_hash_qpn::generate_functor(table_list *schema, ext_fcn_list *Ext_fcns, vector<bool> &needs_xform){\r
- int p,s;\r
- vector<data_type *> hashkey_dt; // data types in the hash key\r
- vector<data_type *> temporal_dt; // data types in the temporal key\r
- map<string,scalarexp_t *> l_equiv, r_equiv; // field equivalences\r
- set<int> pfcn_refs;\r
- col_id_set new_cids, local_cids;\r
-\r
-//--------------------------------\r
-// Global init\r
-\r
- string plus_op = "+";\r
-\r
-//--------------------------------\r
-// key definition class\r
- string ret = "class " + generate_functor_name() + "_keydef{\n";\r
- ret += "public:\n";\r
-// Collect attributes from hash join predicates.\r
-// ASSUME equality predicate.\r
-// Use the upwardly compatible data type\r
-// (infer from '+' operator if possible, else use left type)\r
- for(p=0;p<this->hash_eq.size();++p){\r
- scalarexp_t *lse = hash_eq[p]->pr->get_left_se();\r
- scalarexp_t *rse = hash_eq[p]->pr->get_right_se();\r
- data_type *hdt = new data_type(\r
- lse->get_data_type(), rse->get_data_type(), plus_op );\r
- if(hdt->get_type() == undefined_t){\r
- hashkey_dt.push_back(lse->get_data_type()->duplicate());\r
- delete hdt;\r
- }else{\r
- hashkey_dt.push_back(hdt);\r
- }\r
- sprintf(tmpstr,"hashkey_var%d",p);\r
- ret+="\t"+hashkey_dt[p]->make_host_cvar(tmpstr)+";\n";\r
-\r
-// find equivalences\r
-// NOTE: this code needs to be synched with the temporality\r
-// checking done at join_eq_hash_qpn::get_fields\r
- if(lse->get_operator_type()==SE_COLREF){\r
- l_equiv[lse->get_colref()->get_field()] = rse;\r
- }\r
- if(rse->get_operator_type()==SE_COLREF){\r
- r_equiv[rse->get_colref()->get_field()] = lse;\r
- }\r
- }\r
- ret += "\tbool touched;\n";\r
-\r
-// Constructors\r
- ret += "\t"+generate_functor_name() + "_keydef(){touched=false;};\n";\r
-// destructor\r
- ret += "\t~"+ generate_functor_name() + "_keydef(){\n";\r
- for(p=0;p<hashkey_dt.size();p++){\r
- if(hashkey_dt[p]->is_buffer_type()){\r
- sprintf(tmpstr,"\t\t%s(&hashkey_var%d);\n",\r
- hashkey_dt[p]->get_hfta_buffer_destroy().c_str(), p );\r
- ret += tmpstr;\r
- }\r
- }\r
- ret += "\t};\n";\r
- ret+="\tvoid touch(){touched = true;};\n";\r
- ret+="\tbool is_touched(){return touched;};\n";\r
- ret +="};\n\n";\r
-\r
-\r
-//--------------------------------\r
-// temporal equality definition class\r
- ret += "class " + generate_functor_name() + "_tempeqdef{\n";\r
- ret += "public:\n";\r
-// Collect attributes from hash join predicates.\r
-// ASSUME equality predicate.\r
-// Use the upwardly compatible date type\r
-// (infer from '+' operator if possible, else use left type)\r
- for(p=0;p<this->temporal_eq.size();++p){\r
- scalarexp_t *lse = temporal_eq[p]->pr->get_left_se();\r
- scalarexp_t *rse = temporal_eq[p]->pr->get_right_se();\r
- data_type *hdt = new data_type(\r
- lse->get_data_type(), rse->get_data_type(), plus_op );\r
- if(hdt->get_type() == undefined_t){\r
- temporal_dt.push_back(hash_eq[p]->pr->get_left_se()->get_data_type()->duplicate());\r
- delete hdt;\r
- }else{\r
- temporal_dt.push_back(hdt);\r
- }\r
- sprintf(tmpstr,"tempeq_var%d",p);\r
- ret+="\t"+temporal_dt[p]->make_host_cvar(tmpstr)+";\n";\r
-// find equivalences\r
- if(lse->get_operator_type()==SE_COLREF){\r
- l_equiv[lse->get_colref()->get_field()] = rse;\r
- }\r
- if(rse->get_operator_type()==SE_COLREF){\r
- r_equiv[rse->get_colref()->get_field()] = lse;\r
- }\r
- }\r
-\r
-// Constructors\r
- ret += "\t"+generate_functor_name() + "_tempeqdef(){};\n";\r
-// destructor\r
- ret += "\t~"+ generate_functor_name() + "_tempeqdef(){\n";\r
- for(p=0;p<temporal_dt.size();p++){\r
- if(temporal_dt[p]->is_buffer_type()){\r
- sprintf(tmpstr,"\t\t%s(&tempeq_var%d);\n",\r
- temporal_dt[p]->get_hfta_buffer_destroy().c_str(), p );\r
- ret += tmpstr;\r
- }\r
- }\r
- ret += "\t};\n";\r
- ret +="};\n\n";\r
-\r
-\r
-//--------------------------------\r
-// temporal eq, hash join functor class\r
- ret += "class " + this->generate_functor_name() + "{\n";\r
-\r
-// Find variables referenced in this query node.\r
-\r
- col_id_set cid_set;\r
- col_id_set::iterator csi;\r
-\r
- for(p=0;p<where.size();++p)\r
- gather_pr_col_ids(where[p]->pr,cid_set,NULL);\r
- for(s=0;s<select_list.size();s++)\r
- gather_se_col_ids(select_list[s]->se,cid_set,NULL);\r
-\r
-// Private variables : store the state of the functor.\r
-// 1) variables for unpacked attributes\r
-// 2) offsets of the upacked attributes\r
-// 3) storage of partial functions\r
-// 4) storage of complex literals (i.e., require a constructor)\r
-\r
- ret += "private:\n";\r
-\r
- // var to save the schema handles\r
- ret += "\tint schema_handle0;\n";\r
- ret += "\tint schema_handle1;\n";\r
-\r
- // generate the declaration of all the variables related to\r
- // temp tuples generation\r
- ret += gen_decl_temp_vars();\r
- // tuple metadata offsets\r
- ret += "\tint tuple_metadata_offset0, tuple_metadata_offset1;\n";\r
-\r
-// unpacked attribute storage, offsets\r
- ret += "//\t\tstorage and offsets of accessed fields.\n";\r
- ret += generate_access_vars(cid_set, schema);\r
-\r
-\r
-// Variables to store results of partial functions.\r
-// WARNING find_partial_functions modifies the SE\r
-// (it marks the partial function id).\r
- ret += "//\t\tParital function result storage\n";\r
- vector<scalarexp_t *> partial_fcns;\r
- vector<int> fcn_ref_cnt;\r
- vector<bool> is_partial_fcn;\r
- for(s=0;s<select_list.size();s++){\r
- find_partial_fcns(select_list[s]->se, &partial_fcns,NULL,NULL, Ext_fcns);\r
- }\r
- for(p=0;p<where.size();p++){\r
- find_partial_fcns_pr(where[p]->pr, &partial_fcns,NULL,NULL, Ext_fcns);\r
- }\r
- if(partial_fcns.size()>0){\r
- ret += "/*\t\tVariables for storing results of partial functions. \t*/\n";\r
- ret += generate_partial_fcn_vars(partial_fcns,fcn_ref_cnt,is_partial_fcn,false);\r
- }\r
-\r
-// Complex literals (i.e., they need constructors)\r
- ret += "//\t\tComplex literal storage.\n";\r
- cplx_lit_table *complex_literals = this->get_cplx_lit_tbl(Ext_fcns);\r
- ret += generate_complex_lit_vars(complex_literals);\r
-// We need the following to handle strings in outer joins.\r
-// NEED AN EMPTY LITERAL FOR EAcH STRUCTURED LITERAL\r
- ret += "\tstruct vstring EmptyString;\n";\r
- ret += "\tstruct hfta_ipv6_str EmptyIp6;\n";\r
-\r
-// Pass-by-handle parameters\r
- ret += "//\t\tPass-by-handle storage.\n";\r
- vector<handle_param_tbl_entry *> param_handle_table = this->get_handle_param_tbl(Ext_fcns);\r
- ret += generate_pass_by_handle_vars(param_handle_table);\r
-\r
-\r
-// variables to hold parameters.\r
- ret += "//\tfor query parameters\n";\r
- ret += generate_param_vars(param_tbl);\r
-\r
-\r
- ret += "\npublic:\n";\r
-//-------------------\r
-// The functor constructor\r
-// pass in the schema handle.\r
-// 1) make assignments to the unpack offset variables\r
-// 2) initialize the complex literals\r
-\r
- ret += "//\t\tFunctor constructor.\n";\r
- ret += this->generate_functor_name()+"(int schema_handle0, int schema_handle1){\n";\r
-\r
- ret += "\t\tthis->schema_handle0 = schema_handle0;\n";\r
- ret += "\t\tthis->schema_handle1 = schema_handle1;\n";\r
-// metadata offsets\r
- ret += "\ttuple_metadata_offset0 = ftaschema_get_tuple_metadata_offset(schema_handle0);\n";\r
- ret += "\ttuple_metadata_offset1 = ftaschema_get_tuple_metadata_offset(schema_handle1);\n";\r
-\r
-// unpack vars\r
- ret += "//\t\tGet offsets for unpacking fields from input tuple.\n";\r
- ret += gen_access_var_init(cid_set);\r
-\r
-// complex literals\r
- ret += "//\t\tInitialize complex literals.\n";\r
- ret += gen_complex_lit_init(complex_literals);\r
-// Initialize EmptyString to the ... empty string\r
-// NEED AN EMPTY LITERAL FOR EAcH STRUCTURED LITERAL\r
- literal_t mtstr_lit("");\r
- ret += "\t" + mtstr_lit.to_hfta_C_code("&EmptyString")+";\n";\r
- literal_t mip6_lit("0:0:0:0:0:0:0:0",LITERAL_IPV6);\r
- ret += "\t" + mip6_lit.to_hfta_C_code("&EmptyIp6")+";\n";\r
-\r
-// Initialize partial function results so they can be safely GC'd\r
- ret += gen_partial_fcn_init(partial_fcns);\r
-\r
-// Initialize non-query-parameter parameter handles\r
- ret += gen_pass_by_handle_init(param_handle_table);\r
-\r
-// Init temporal attributes referenced in select list\r
- ret += gen_init_temp_vars(schema, select_list, NULL);\r
-\r
-\r
- ret += "};\n";\r
-\r
-\r
-\r
-//-------------------\r
-// Functor destructor\r
- ret += "//\t\tFunctor destructor.\n";\r
- ret += "~"+this->generate_functor_name()+"(){\n";\r
-\r
-// clean up buffer type complex literals\r
- ret += gen_complex_lit_dtr(complex_literals);\r
-\r
-// Deregister the pass-by-handle parameters\r
- ret += "/* register and de-register the pass-by-handle parameters */\n";\r
- ret += gen_pass_by_handle_dtr(param_handle_table);\r
-\r
-// clean up partial function results.\r
- ret += "/* clean up partial function storage */\n";\r
- ret += gen_partial_fcn_dtr(partial_fcns);\r
-\r
-// Destroy the parameters, if any need to be destroyed\r
- ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";\r
-\r
- ret += "};\n\n";\r
-\r
-\r
-//-------------------\r
-// Parameter manipulation routines\r
- ret += generate_load_param_block(this->generate_functor_name(),\r
- this->param_tbl,param_handle_table);\r
- ret += generate_delete_param_block(this->generate_functor_name(),\r
- this->param_tbl,param_handle_table);\r
-\r
-//-------------------\r
-// Register new parameter block\r
-\r
- ret += "int set_param_block(gs_int32_t sz, void* value){\n";\r
- ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";\r
- ret += "\treturn this->load_params_"+this->generate_functor_name()+\r
- "(sz, value);\n";\r
- ret += "};\n\n";\r
-\r
-\r
-//-------------------\r
-// The create_key method.\r
-// Perform heap allocation.\r
-// ASSUME : the LHS of the preds reference channel 0 attributes\r
-// NOTE : it may fail if a partial function fails.\r
-\r
- ret += this->generate_functor_name()+"_keydef *create_key(host_tuple &tup, bool &failed){\n";\r
-// Variables for execution of the function.\r
- ret+="\t"+this->generate_functor_name()+"_keydef *retval = NULL;\n";\r
- ret+="\tgs_int32_t problem = 0;\n";\r
-\r
-// Assume unsuccessful completion\r
- ret+= "\tfailed = true;\n";\r
-\r
-// Switch the processing based on the channel\r
- ret+="\tif(tup.channel == 0){\n";\r
- ret+="// ------------ processing for channel 0\n";\r
- ret+="\t\thost_tuple &tup0 = tup;\n";\r
-// Gather partial fcns and colids ref'd by this branch\r
- pfcn_refs.clear();\r
- new_cids.clear(); local_cids.clear();\r
- for(p=0;p<hash_eq.size();p++){\r
- collect_partial_fcns(hash_eq[p]->pr->get_left_se(), pfcn_refs);\r
- gather_se_col_ids(hash_eq[p]->pr->get_left_se(),local_cids,NULL);\r
- }\r
-\r
-// Start by cleaning up partial function results\r
- ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";\r
- ret += gen_partial_fcn_dtr(partial_fcns,pfcn_refs);\r
-\r
-// Evaluate the partial functions\r
- ret += gen_full_unpack_partial_fcn(schema, partial_fcns, pfcn_refs,\r
- new_cids, NULL, "NULL", needs_xform);\r
-// test passed -- unpack remaining cids.\r
- ret += gen_remaining_colrefs(schema, local_cids, new_cids, "NULL", needs_xform);\r
-\r
-// Alloc and load a key object\r
- ret += "\t\tretval = new "+this->generate_functor_name()+"_keydef();\n";\r
- for(p=0;p<hash_eq.size();p++){\r
- data_type *hdt = hash_eq[p]->pr->get_left_se()->get_data_type();\r
- if(hdt->is_buffer_type()){\r
- string vname = "tmp_keyvar"+int_to_string(p);\r
- ret += "\t\t"+hdt->make_host_cvar(vname)+" = "+generate_se_code(hash_eq[p]->pr->get_left_se(),schema)+";\n";\r
- ret += "\t\t"+hdt->get_hfta_buffer_assign_copy()+"(&(retval->hashkey_var"+int_to_string(p)+"),&"+vname+");\n";\r
- }else{\r
- sprintf(tmpstr,"\t\tretval->hashkey_var%d = %s;\n",\r
- p,generate_se_code(hash_eq[p]->pr->get_left_se(),schema).c_str() );\r
- ret += tmpstr;\r
- }\r
- }\r
- ret += "\t}else{\n";\r
-\r
- ret+="// ------------ processing for channel 1\n";\r
- ret+="\t\thost_tuple &tup1 = tup;\n";\r
-// Gather partial fcns and colids ref'd by this branch\r
- pfcn_refs.clear();\r
- new_cids.clear(); local_cids.clear();\r
- for(p=0;p<hash_eq.size();p++){\r
- collect_partial_fcns(hash_eq[p]->pr->get_right_se(), pfcn_refs);\r
- gather_se_col_ids(hash_eq[p]->pr->get_right_se(),local_cids,NULL);\r
- }\r
-\r
-// Start by cleaning up partial function results\r
- ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";\r
- ret += gen_partial_fcn_dtr(partial_fcns,pfcn_refs);\r
-\r
-// Evaluate the partial functions\r
- ret += gen_full_unpack_partial_fcn(schema, partial_fcns, pfcn_refs,\r
- new_cids, NULL, "NULL", needs_xform);\r
-\r
-// test passed -- unpack remaining cids.\r
- ret += gen_remaining_colrefs(schema, local_cids, new_cids, "NULL", needs_xform);\r
-\r
-// Alloc and load a key object\r
- ret += "\t\tretval = new "+this->generate_functor_name()+"_keydef();\n";\r
- for(p=0;p<hash_eq.size();p++){\r
- data_type *hdt = hash_eq[p]->pr->get_right_se()->get_data_type();\r
- if(hdt->is_buffer_type()){\r
- string vname = "tmp_keyvar"+int_to_string(p);\r
- ret += "\t\t"+hdt->make_host_cvar(vname)+" = "+generate_se_code(hash_eq[p]->pr->get_right_se(),schema)+";\n";\r
- ret += "\t\t"+hdt->get_hfta_buffer_assign_copy()+"(&(retval->hashkey_var"+int_to_string(p)+"),&"+vname+");\n";\r
- }else{\r
- sprintf(tmpstr,"\t\tretval->hashkey_var%d = %s;\n",\r
- p,generate_se_code(hash_eq[p]->pr->get_right_se(),schema).c_str() );\r
- ret += tmpstr;\r
- }\r
- }\r
- ret += "\t}\n";\r
-\r
- ret += "\tfailed = false;\n";\r
- ret += "\t return retval;\n";\r
- ret += "}\n";\r
-\r
-\r
-//-------------------\r
-// The load_ts method.\r
-// load into an allocated buffer.\r
-// ASSUME : the LHS of the preds reference channel 0 attributes\r
-// NOTE : it may fail if a partial function fails.\r
-// NOTE : cann't handle buffer attributes\r
-\r
- ret += "bool load_ts_from_tup("+this->generate_functor_name()+"_tempeqdef *ts, host_tuple &tup){\n";\r
-// Variables for execution of the function.\r
- ret+="\tgs_int32_t problem = 0;\n";\r
-\r
-// Switch the processing based on the channel\r
- ret+="\tif(tup.channel == 0){\n";\r
- ret+="// ------------ processing for channel 0\n";\r
- ret+="\t\thost_tuple &tup0 = tup;\n";\r
-\r
-// Gather partial fcns and colids ref'd by this branch\r
- pfcn_refs.clear();\r
- new_cids.clear(); local_cids.clear();\r
- for(p=0;p<temporal_eq.size();p++){\r
- collect_partial_fcns(temporal_eq[p]->pr->get_left_se(), pfcn_refs);\r
- gather_se_col_ids(temporal_eq[p]->pr->get_left_se(),local_cids,NULL);\r
- }\r
-\r
-// Start by cleaning up partial function results\r
- ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";\r
- ret += gen_partial_fcn_dtr(partial_fcns,pfcn_refs);\r
-\r
-// Evaluate the partial functions\r
- ret += gen_full_unpack_partial_fcn(schema, partial_fcns, pfcn_refs,\r
- new_cids, NULL, "false", needs_xform);\r
-\r
-// test passed -- unpack remaining cids.\r
- ret += gen_remaining_colrefs(schema, local_cids, new_cids, "false", needs_xform);\r
-\r
-// load the temporal key object\r
- for(p=0;p<temporal_eq.size();p++){\r
- sprintf(tmpstr,"\t\tts->tempeq_var%d = %s;\n",\r
- p,generate_se_code(temporal_eq[p]->pr->get_left_se(),schema).c_str() );\r
- ret += tmpstr;\r
- }\r
-\r
- ret += "\t}else{\n";\r
-\r
- ret+="// ------------ processing for channel 1\n";\r
- ret+="\t\thost_tuple &tup1 = tup;\n";\r
-\r
-// Gather partial fcns and colids ref'd by this branch\r
- pfcn_refs.clear();\r
- new_cids.clear(); local_cids.clear();\r
- for(p=0;p<temporal_eq.size();p++){\r
- collect_partial_fcns(temporal_eq[p]->pr->get_right_se(), pfcn_refs);\r
- gather_se_col_ids(temporal_eq[p]->pr->get_right_se(),local_cids,NULL);\r
- }\r
-\r
-// Start by cleaning up partial function results\r
- ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";\r
- ret += gen_partial_fcn_dtr(partial_fcns,pfcn_refs);\r
-\r
-// Evaluate the partial functions\r
- ret += gen_full_unpack_partial_fcn(schema, partial_fcns, pfcn_refs,\r
- new_cids, NULL, "false", needs_xform);\r
-\r
-// test passed -- unpack remaining cids.\r
- ret += gen_remaining_colrefs(schema, local_cids, new_cids, "false", needs_xform);\r
-\r
-// load the key object\r
- for(p=0;p<temporal_eq.size();p++){\r
- sprintf(tmpstr,"\t\tts->tempeq_var%d = %s;\n",\r
- p,generate_se_code(temporal_eq[p]->pr->get_right_se(),schema).c_str() );\r
- ret += tmpstr;\r
- }\r
-\r
- ret += "\t}\n";\r
-\r
- ret += "\t return true;\n";\r
- ret += "}\n";\r
-\r
-\r
-// ------------------------------\r
-// Load ts from ts\r
-// (i.e make a copy)\r
-\r
- ret += "bool load_ts_from_ts("+this->generate_functor_name()+"_tempeqdef *lts,"+this->generate_functor_name()+"_tempeqdef *rts){\n";\r
- for(p=0;p<temporal_eq.size();p++){\r
- sprintf(tmpstr,"\tlts->tempeq_var%d = rts->tempeq_var%d;\n",p,p);\r
- ret += tmpstr;\r
- }\r
- ret += "}\n";\r
-\r
-// -------------------------------------\r
-// compare_ts_to_ts\r
-// There should be only one variable to compare.\r
-// If there is more, assume an arbitrary lexicographic order.\r
-\r
- ret += "int compare_ts_with_ts("+this->generate_functor_name()+"_tempeqdef *lts,"+this->generate_functor_name()+"_tempeqdef *rts){\n";\r
- for(p=0;p<temporal_eq.size();p++){\r
- sprintf(tmpstr,"\tif(lts->tempeq_var%d < rts->tempeq_var%d) return(-1);\n",p,p);\r
- ret += tmpstr;\r
- sprintf(tmpstr,"\tif(lts->tempeq_var%d > rts->tempeq_var%d) return(1);\n",p,p);\r
- ret += tmpstr;\r
- }\r
- ret += "\treturn(0);\n";\r
- ret += "}\n";\r
-\r
-// ------------------------------------------\r
-// apply_prefilter\r
-// apply the prefilter\r
-\r
- ret += "bool apply_prefilter(host_tuple &tup){\n";\r
-\r
-// Variables for this procedure\r
- ret+="\tgs_int32_t problem = 0;\n";\r
- ret+="\tgs_retval_t retval;\n";\r
-\r
-// Switch the processing based on the channel\r
- ret+="\tif(tup.channel == 0){\n";\r
- ret+="// ------------ processing for channel 0\n";\r
- ret+="\t\thost_tuple &tup0 = tup;\n";\r
-// Gather partial fcns and colids ref'd by this branch\r
- pfcn_refs.clear();\r
- new_cids.clear(); local_cids.clear();\r
- for(p=0;p<prefilter[0].size();p++){\r
- collect_partial_fcns_pr((prefilter[0])[p]->pr, pfcn_refs);\r
- }\r
-\r
-// Start by cleaning up partial function results\r
- ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";\r
- ret += gen_partial_fcn_dtr(partial_fcns,pfcn_refs);\r
-\r
- for(p=0;p<(prefilter[0]).size();++p){\r
- sprintf(tmpstr,"//\t\tPredicate clause %d.\n",p);\r
- ret += tmpstr;\r
-// Find the set of variables accessed in this CNF elem,\r
-// but in no previous element.\r
- col_id_set new_pr_cids;\r
- get_new_pred_cids((prefilter[0])[p]->pr,local_cids,new_pr_cids, NULL);\r
-// Unpack these values.\r
- ret += gen_unpack_cids(schema, new_pr_cids, "false", needs_xform);\r
-// Find partial fcns ref'd in this cnf element\r
- set<int> pr_pfcn_refs;\r
- collect_partial_fcns_pr((prefilter[0])[p]->pr, pr_pfcn_refs);\r
- ret += gen_unpack_partial_fcn(schema,partial_fcns,pr_pfcn_refs,"false");\r
-\r
- ret += "\t\tif( !("+generate_predicate_code((prefilter[0])[p]->pr,schema)+") ) return(false);\n";\r
- }\r
- ret += "\t}else{\n";\r
- ret+="// ------------ processing for channel 1\n";\r
- ret+="\t\thost_tuple &tup1 = tup;\n";\r
-// Gather partial fcns and colids ref'd by this branch\r
- pfcn_refs.clear();\r
- new_cids.clear(); local_cids.clear();\r
- for(p=0;p<prefilter[1].size();p++){\r
- collect_partial_fcns_pr((prefilter[1])[p]->pr, pfcn_refs);\r
- }\r
-\r
-// Start by cleaning up partial function results\r
- ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";\r
- ret += gen_partial_fcn_dtr(partial_fcns,pfcn_refs);\r
-\r
- for(p=0;p<(prefilter[1]).size();++p){\r
- sprintf(tmpstr,"//\t\tPredicate clause %d.\n",p);\r
- ret += tmpstr;\r
-// Find the set of variables accessed in this CNF elem,\r
-// but in no previous element.\r
- col_id_set pr_new_cids;\r
- get_new_pred_cids((prefilter[1])[p]->pr,local_cids, pr_new_cids, NULL);\r
-// Unpack these values.\r
- ret += gen_unpack_cids(schema, pr_new_cids, "false", needs_xform);\r
-// Find partial fcns ref'd in this cnf element\r
- set<int> pr_pfcn_refs;\r
- collect_partial_fcns_pr((prefilter[1])[p]->pr, pr_pfcn_refs);\r
- ret += gen_unpack_partial_fcn(schema,partial_fcns,pr_pfcn_refs,"false");\r
-\r
- ret += "\t\tif( !("+generate_predicate_code((prefilter[1])[p]->pr,schema)+ ") ) return(false);\n";\r
- }\r
-\r
- ret += "\t}\n";\r
- ret+="\treturn true;\n";\r
- ret += "}\n";\r
-\r
-\r
-// -------------------------------------\r
-// create_output_tuple\r
-// If the postfilter on the pair of tuples passes,\r
-// create an output tuple from the combined information.\r
-// (Plus, outer join processing)\r
-\r
- ret += "host_tuple create_output_tuple(const host_tuple &tup0, const host_tuple &tup1, bool &failed){\n";\r
-\r
- ret += "\thost_tuple tup;\n";\r
- ret += "\tfailed = true;\n";\r
- ret += "\tgs_retval_t retval = 0;\n";\r
- ret += "\tgs_int32_t problem = 0;\n";\r
-\r
-// Start by cleaning up partial function results\r
- ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";\r
- pfcn_refs.clear();\r
- new_cids.clear(); local_cids.clear();\r
- for(p=0;p<postfilter.size();p++){\r
- collect_partial_fcns_pr(postfilter[p]->pr, pfcn_refs);\r
- }\r
- for(s=0;s<select_list.size();s++){\r
- collect_partial_fcns(select_list[s]->se, pfcn_refs);\r
- }\r
- ret += gen_partial_fcn_dtr(partial_fcns,pfcn_refs);\r
-\r
-\r
- ret+="\tif(tup0.data && tup1.data){\n";\r
-// Evaluate the postfilter\r
- new_cids.clear(); local_cids.clear();\r
- for(p=0;p<postfilter.size();p++){\r
- sprintf(tmpstr,"//\t\tPredicate clause %d.\n",p);\r
- ret += tmpstr;\r
-// Find the set of variables accessed in this CNF elem,\r
-// but in no previous element.\r
- col_id_set pr_new_cids;\r
- get_new_pred_cids(postfilter[p]->pr,local_cids, pr_new_cids, NULL);\r
-// Unpack these values.\r
- ret += gen_unpack_cids(schema, pr_new_cids, "tup", needs_xform);\r
-// Find partial fcns ref'd in this cnf element\r
- set<int> pr_pfcn_refs;\r
- collect_partial_fcns_pr(postfilter[p]->pr, pr_pfcn_refs);\r
- ret += gen_unpack_partial_fcn(schema,partial_fcns,pr_pfcn_refs,"tup");\r
-\r
- ret += "\t\tif( !("+generate_predicate_code(postfilter[p]->pr,schema)+ ") ) return(tup);\n";\r
- }\r
-\r
-\r
-// postfilter passed, evaluate partial functions for select list\r
-\r
- set<int> sl_pfcns;\r
- col_id_set se_cids;\r
- for(s=0;s<select_list.size();s++){\r
- collect_partial_fcns(select_list[s]->se, sl_pfcns);\r
- }\r
-\r
- if(sl_pfcns.size() > 0)\r
- ret += "//\t\tUnpack remaining partial fcns.\n";\r
- ret += gen_full_unpack_partial_fcn(schema, partial_fcns, sl_pfcns,\r
- local_cids, NULL, "tup", needs_xform);\r
-\r
-// Unpack remaining fields\r
- ret += "//\t\tunpack any remaining fields from the input tuples.\n";\r
- for(s=0;s<select_list.size();s++)\r
- get_new_se_cids(select_list[s]->se, local_cids,se_cids,NULL);\r
- ret += gen_unpack_cids(schema, se_cids,"tup", needs_xform);\r
-\r
-\r
-// Deal with outer join stuff\r
- col_id_set l_cids, r_cids;\r
- col_id_set::iterator ocsi;\r
- for(ocsi=local_cids.begin();ocsi!=local_cids.end();++ocsi){\r
- if((*ocsi).tblvar_ref == 0) l_cids.insert((*ocsi));\r
- else r_cids.insert((*ocsi));\r
- }\r
- for(ocsi=se_cids.begin();ocsi!=se_cids.end();++ocsi){\r
- if((*ocsi).tblvar_ref == 0) l_cids.insert((*ocsi));\r
- else r_cids.insert((*ocsi));\r
- }\r
-\r
- ret += "\t}else if(tup0.data){\n";\r
- string unpack_null = ""; col_id_set extra_cids;\r
- for(ocsi=r_cids.begin();ocsi!=r_cids.end();++ocsi){\r
- string field = (*ocsi).field;\r
- if(r_equiv.count(field)){\r
- unpack_null+="\t\tunpack_var_"+field+"_1="+generate_se_code(r_equiv[field],schema)+";\n";\r
- get_new_se_cids(r_equiv[field],l_cids,new_cids,NULL);\r
- }else{\r
- int schref = (*ocsi).schema_ref;\r
- data_type dt(schema->get_type_name(schref,field));\r
- literal_t empty_lit(dt.type_indicator());\r
- if(empty_lit.is_cpx_lit()){\r
-// sprintf(tmpstr,"&(unpack_var_%s_1)",field.c_str());\r
-// unpack_null += "\t"+empty_lit.to_hfta_C_code(tmpstr)+";\n";\r
-// NB : works for string type only\r
-// NNB: installed fix for ipv6, more of this should be pushed\r
-// into the literal_t code.\r
- unpack_null+="\tunpack_var_"+field+"_1= "+empty_lit.hfta_empty_literal_name()+";\n";\r
- }else{\r
- unpack_null+="\tunpack_var_"+field+"_1="+empty_lit.to_hfta_C_code("")+";\n";\r
- }\r
- }\r
- }\r
- ret += gen_unpack_cids(schema, l_cids, "tup", needs_xform);\r
- ret += gen_unpack_cids(schema, extra_cids, "tup", needs_xform);\r
- ret += unpack_null;\r
- ret += gen_unpack_partial_fcn(schema, partial_fcns, sl_pfcns, "tup");\r
-\r
- ret+="\t}else{\n";\r
- unpack_null = ""; extra_cids.clear();\r
- for(ocsi=l_cids.begin();ocsi!=l_cids.end();++ocsi){\r
- string field = (*ocsi).field;\r
- if(l_equiv.count(field)){\r
- unpack_null+="\t\tunpack_var_"+field+"_0="+generate_se_code(l_equiv[field],schema)+";\n";\r
- get_new_se_cids(l_equiv[field],r_cids,new_cids,NULL);\r
- }else{\r
- int schref = (*ocsi).schema_ref;\r
- data_type dt(schema->get_type_name(schref,field));\r
- literal_t empty_lit(dt.type_indicator());\r
- if(empty_lit.is_cpx_lit()){\r
-// sprintf(tmpstr,"&(unpack_var_%s_0)",field.c_str());\r
-// unpack_null += "\t"+empty_lit.to_hfta_C_code(tmpstr)+";\n";\r
-// NB : works for string type only\r
-// NNB: installed fix for ipv6, more of this should be pushed\r
-// into the literal_t code.\r
- unpack_null+="\tunpack_var_"+field+"_0= "+empty_lit.hfta_empty_literal_name()+";\n";\r
- }else{\r
- unpack_null+="\tunpack_var_"+field+"_0="+empty_lit.to_hfta_C_code("")+";\n";\r
- }\r
- }\r
- }\r
- ret += gen_unpack_cids(schema, r_cids, "tup", needs_xform);\r
- ret += gen_unpack_cids(schema, extra_cids, "tup", needs_xform);\r
- ret += unpack_null;\r
- ret += gen_unpack_partial_fcn(schema, partial_fcns, sl_pfcns, "tup");\r
- ret+="\t}\n";\r
-\r
-\r
-\r
-// Unpack any BUFFER type selections into temporaries\r
-// so that I can compute their size and not have\r
-// to recompute their value during tuple packing.\r
-// I can use regular assignment here because\r
-// these temporaries are non-persistent.\r
-\r
- ret += "//\t\tCompute the size of the tuple.\n";\r
- ret += "//\t\t\tNote: buffer storage packed at the end of the tuple.\n";\r
-\r
-// Unpack all buffer type selections, to be able to compute their size\r
- ret += gen_buffer_selvars(schema, select_list);\r
-\r
-// The size of the tuple is the size of the tuple struct plus the\r
-// size of the buffers to be copied in.\r
-\r
- ret+="\ttup.tuple_size = sizeof(" + generate_tuple_name( this->get_node_name()) +") + sizeof(gs_uint8_t)";\r
- ret += gen_buffer_selvars_size(select_list,schema);\r
- ret.append(";\n");\r
-\r
-// Allocate tuple data block.\r
- ret += "//\t\tCreate the tuple block.\n";\r
- ret += "\ttup.data = malloc(tup.tuple_size);\n";\r
- ret += "\ttup.heap_resident = true;\n";\r
-// ret += "\ttup.channel = 0;\n";\r
-\r
-// Mark tuple as regular\r
- ret += "\t*((gs_sp_t )tup.data + sizeof(" + generate_tuple_name( this->get_node_name()) +")) = REGULAR_TUPLE;\n";\r
-\r
-\r
- ret += "\t"+generate_tuple_name( this->get_node_name())+" *tuple = ("+\r
- generate_tuple_name( this->get_node_name())+" *)(tup.data);\n";\r
-\r
-// Start packing.\r
-// (Here, offsets are hard-wired. is this a problem?)\r
-\r
- ret += "//\t\tPack the fields into the tuple.\n";\r
- ret += gen_pack_tuple(schema,select_list,this->get_node_name(), false );\r
-\r
-// Delete string temporaries\r
- ret += gen_buffer_selvars_dtr(select_list);\r
-\r
- ret += "\tfailed = false;\n";\r
- ret += "\treturn tup;\n";\r
- ret += "};\n";\r
-\r
-\r
-\r
-//-----------------------------\r
-// Method for checking whether tuple is temporal\r
-\r
- ret += "bool temp_status_received(host_tuple &tup){\n";\r
-\r
-// Switch the processing based on the channel\r
- ret+="\tif(tup.channel == 0){\n";\r
- ret+="\t\thost_tuple &tup0 = tup;\n";\r
- ret += gen_temp_tuple_check(this->node_name, 0);\r
- ret += "\t}else{\n";\r
- ret+="\t\thost_tuple &tup1 = tup;\n";\r
- ret += gen_temp_tuple_check(this->node_name, 1);\r
- ret += "\t}\n";\r
- ret += "\treturn temp_tuple_received;\n};\n\n";\r
-\r
-\r
-//-------------------------------------------------------------------\r
-// Temporal update functions\r
-\r
-\r
-// create a temp status tuple\r
- ret += "int create_temp_status_tuple(const host_tuple &tup0, const host_tuple &tup1, host_tuple& result) {\n\n";\r
-\r
- ret += "\tgs_retval_t retval = 0;\n";\r
- ret += "\tgs_int32_t problem = 0;\n";\r
-\r
- ret += "\tif(tup0.data){\n";\r
-\r
-// Unpack all the temporal attributes references in select list\r
- col_id_set found_cids;\r
-\r
- for(s=0;s<select_list.size();s++){\r
- if (select_list[s]->se->get_data_type()->is_temporal()) {\r
-// Find the set of attributes accessed in this SE\r
- col_id_set new_cids;\r
- get_new_se_cids(select_list[s]->se,found_cids, new_cids, NULL);\r
- }\r
- }\r
-\r
- // Deal with outer join stuff\r
- l_cids.clear(), r_cids.clear();\r
- for(ocsi=found_cids.begin();ocsi!=found_cids.end();++ocsi){\r
- if((*ocsi).tblvar_ref == 0) l_cids.insert((*ocsi));\r
- else r_cids.insert((*ocsi));\r
- }\r
- unpack_null = "";\r
- extra_cids.clear();\r
- for(ocsi=r_cids.begin();ocsi!=r_cids.end();++ocsi){\r
- string field = (*ocsi).field;\r
- if(r_equiv.count(field)){\r
- unpack_null+="\t\tunpack_var_"+field+"_1="+generate_se_code(r_equiv[field],schema)+";\n";\r
- col_id_set addnl_cids;\r
- get_new_se_cids(r_equiv[field],l_cids,addnl_cids,NULL);\r
- }else{\r
- int schref = (*ocsi).schema_ref;\r
- data_type dt(schema->get_type_name(schref,field));\r
- literal_t empty_lit(dt.type_indicator());\r
- if(empty_lit.is_cpx_lit()){\r
- sprintf(tmpstr,"&(unpack_var_%s_1)",field.c_str());\r
- unpack_null += "\t"+empty_lit.to_hfta_C_code(tmpstr)+";\n";\r
- }else{\r
- unpack_null+="\tunpack_var_"+field+"_1="+empty_lit.to_hfta_C_code("")+";\n";\r
- }\r
- }\r
- }\r
- ret += gen_unpack_cids(schema, l_cids, "1", needs_xform);\r
- ret += gen_unpack_cids(schema, extra_cids, "1", needs_xform);\r
- ret += unpack_null;\r
-\r
- ret+="\t}else if (tup1.data) {\n";\r
- unpack_null = ""; extra_cids.clear();\r
- for(ocsi=l_cids.begin();ocsi!=l_cids.end();++ocsi){\r
- string field = (*ocsi).field;\r
- if(l_equiv.count(field)){\r
- unpack_null+="\t\tunpack_var_"+field+"_0="+generate_se_code(l_equiv[field],schema)+";\n";\r
- col_id_set addnl_cids;\r
- get_new_se_cids(l_equiv[field],r_cids,addnl_cids,NULL);\r
- }else{\r
- int schref = (*ocsi).schema_ref;\r
- data_type dt(schema->get_type_name(schref,field));\r
- literal_t empty_lit(dt.type_indicator());\r
- if(empty_lit.is_cpx_lit()){\r
- sprintf(tmpstr,"&(unpack_var_%s_0)",field.c_str());\r
- unpack_null += "\t"+empty_lit.to_hfta_C_code(tmpstr)+";\n";\r
- }else{\r
- unpack_null+="\tunpack_var_"+field+"_0="+empty_lit.to_hfta_C_code("")+";\n";\r
- }\r
- }\r
- }\r
- ret += gen_unpack_cids(schema, r_cids, "1", needs_xform);\r
- ret += gen_unpack_cids(schema, extra_cids, "1", needs_xform);\r
- ret += unpack_null;\r
- ret+="\t}\n";\r
-\r
- ret += gen_init_temp_status_tuple(this->get_node_name());\r
-\r
-// Start packing.\r
- ret += "//\t\tPack the fields into the tuple.\n";\r
- ret += gen_pack_tuple(schema,select_list,this->get_node_name(), true );\r
-\r
-\r
- ret += "\treturn 0;\n";\r
- ret += "};\n\n";\r
-\r
-\r
- ret += "};\n\n\n";\r
-\r
-//----------------------------------------------------------\r
-// The hash function\r
-\r
- ret += "struct "+generate_functor_name()+"_hash_func{\n";\r
- ret += "\tgs_uint32_t operator()(const "+generate_functor_name()+\r
- "_keydef *key) const{\n";\r
- ret += "\t\treturn( (";\r
- if(hashkey_dt.size() > 0){\r
- for(p=0;p<hashkey_dt.size();p++){\r
- if(p>0) ret += "^";\r
- if(hashkey_dt[p]->use_hashfunc()){\r
-// sprintf(tmpstr,"%s(&(key->hashkey_var%d))",hashkey_dt[p]->get_hfta_hashfunc().c_str(),p);\r
- if(hashkey_dt[p]->is_buffer_type())\r
- sprintf(tmpstr,"(%s*%s(&(key->hashkey_var%d)))",hash_nums[p%NRANDS].c_str(),hashkey_dt[p]->get_hfta_hashfunc().c_str(),p);\r
- else\r
- sprintf(tmpstr,"(%s*%s(key->hashkey_var%d))",hash_nums[p%NRANDS].c_str(),hashkey_dt[p]->get_hfta_hashfunc().c_str(),p);\r
- }else{\r
- sprintf(tmpstr,"(%s*key->hashkey_var%d)",hash_nums[p%NRANDS].c_str(),p);\r
- }\r
- ret += tmpstr;\r
- }\r
- }else{\r
- ret += "0";\r
- }\r
- ret += ") >> 32);\n";\r
- ret += "\t}\n";\r
- ret += "};\n\n";\r
-\r
-//----------------------------------------------------------\r
-// The comparison function\r
-\r
- ret += "struct "+generate_functor_name()+"_equal_func{\n";\r
- ret += "\tbool operator()(const "+generate_functor_name()+"_keydef *key1, "+\r
- generate_functor_name()+"_keydef *key2) const{\n";\r
- ret += "\t\treturn( (";\r
- if(hashkey_dt.size() > 0){\r
- for(p=0;p<hashkey_dt.size();p++){\r
- if(p>0) ret += ") && (";\r
- if(hashkey_dt[p]->complex_comparison(hashkey_dt[p])){\r
- if(hashkey_dt[p]->is_buffer_type())\r
- sprintf(tmpstr,"(%s(&(key1->hashkey_var%d), &(key2->hashkey_var%d))==0)",\r
- hashkey_dt[p]->get_hfta_comparison_fcn(hashkey_dt[p]).c_str(),p,p);\r
- else\r
- sprintf(tmpstr,"(%s((key1->hashkey_var%d), (key2->hashkey_var%d))==0)",\r
- hashkey_dt[p]->get_hfta_comparison_fcn(hashkey_dt[p]).c_str(),p,p);\r
- }else{\r
- sprintf(tmpstr,"key1->hashkey_var%d == key2->hashkey_var%d",p,p);\r
- }\r
- ret += tmpstr;\r
- }\r
- }else{\r
- ret += "1";\r
- }\r
- ret += ") );\n";\r
- ret += "\t}\n";\r
- ret += "};\n\n";\r
-\r
-\r
- return(ret);\r
-}\r
-\r
-\r
-\r
-string join_eq_hash_qpn::generate_operator(int i, string params){\r
-\r
- return(\r
- " join_eq_hash_operator<" +\r
- generate_functor_name()+ ","+\r
- generate_functor_name() + "_tempeqdef,"+\r
- generate_functor_name() + "_keydef,"+\r
- generate_functor_name()+"_hash_func,"+\r
- generate_functor_name()+"_equal_func"\r
- "> *op"+int_to_string(i)+" = new join_eq_hash_operator<"+\r
- generate_functor_name()+","+\r
- generate_functor_name() + "_tempeqdef,"+\r
- generate_functor_name() + "_keydef,"+\r
- generate_functor_name()+"_hash_func,"+\r
- generate_functor_name()+"_equal_func"\r
- ">("+params+", "+\r
- int_to_string(from[0]->get_property()+2*from[1]->get_property())+", \"" + get_node_name() +\r
-"\");\n"\r
- );\r
-}\r
-\r
-\r
-\r
-////////////////////////////////////////////////////////////////\r
-//// SGAHCWCB functor\r
-\r
-\r
-\r
-string sgahcwcb_qpn::generate_functor_name(){\r
- return("sgahcwcb_functor_" + normalize_name(this->get_node_name()));\r
-}\r
-\r
-\r
-string sgahcwcb_qpn::generate_functor(table_list *schema, ext_fcn_list *Ext_fcns, vector<bool> &needs_xform){\r
- int a,g,w,s;\r
-\r
-\r
-// Initialize generate utility globals\r
- segen_gb_tbl = &(gb_tbl);\r
-\r
-\r
-//--------------------------------\r
-// group definition class\r
- string ret = "class " + generate_functor_name() + "_groupdef{\n";\r
- ret += "public:\n";\r
- ret += "\tbool valid;\n";\r
- for(g=0;g<this->gb_tbl.size();g++){\r
- sprintf(tmpstr,"gb_var%d",g);\r
- ret+="\t"+this->gb_tbl.get_data_type(g)->make_host_cvar(tmpstr)+";\n";\r
- }\r
-// Constructors\r
- ret += "\t"+generate_functor_name() + "_groupdef(){valid=true;};\n";\r
- ret += "\t"+generate_functor_name() + "_groupdef("+\r
- this->generate_functor_name() + "_groupdef *gd){\n";\r
- for(g=0;g<gb_tbl.size();g++){\r
- data_type *gdt = gb_tbl.get_data_type(g);\r
- if(gdt->is_buffer_type()){\r
- sprintf(tmpstr,"\t\t%s(&gb_var%d, &(gd->gb_var%d));\n",\r
- gdt->get_hfta_buffer_assign_copy().c_str(),g,g );\r
- ret += tmpstr;\r
- }else{\r
- sprintf(tmpstr,"\t\tgb_var%d = gd->gb_var%d;\n",g,g);\r
- ret += tmpstr;\r
- }\r
- }\r
- ret += "\tvalid=true;\n";\r
- ret += "\t};\n";\r
-// destructor\r
- ret += "\t~"+ generate_functor_name() + "_groupdef(){\n";\r
- for(g=0;g<gb_tbl.size();g++){\r
- data_type *gdt = gb_tbl.get_data_type(g);\r
- if(gdt->is_buffer_type()){\r
- sprintf(tmpstr,"\t\t%s(&gb_var%d);\n",\r
- gdt->get_hfta_buffer_destroy().c_str(), g );\r
- ret += tmpstr;\r
- }\r
- }\r
- ret += "\t};\n";\r
- ret +="};\n\n";\r
-\r
-//--------------------------------\r
-// aggr definition class\r
- ret += "class " + this->generate_functor_name() + "_aggrdef{\n";\r
- ret += "public:\n";\r
- for(a=0;a<aggr_tbl.size();a++){\r
-aggr_table_entry *ate = aggr_tbl.agr_tbl[a];\r
- sprintf(tmpstr,"aggr_var%d",a);\r
- if(aggr_tbl.is_builtin(a))\r
- ret+="\t"+ aggr_tbl.get_data_type(a)->make_host_cvar(tmpstr)+";\n";\r
- else\r
- ret+="\t"+ aggr_tbl.get_storage_type(a)->make_host_cvar(tmpstr)+";\n";\r
- }\r
-// Constructors\r
- ret += "\t"+this->generate_functor_name() + "_aggrdef(){};\n";\r
-// destructor\r
- ret += "\t~"+this->generate_functor_name() + "_aggrdef(){\n";\r
- for(a=0;a<aggr_tbl.size();a++){\r
-aggr_table_entry *ate = aggr_tbl.agr_tbl[a];\r
- if(aggr_tbl.is_builtin(a)){\r
- data_type *adt = aggr_tbl.get_data_type(a);\r
- if(adt->is_buffer_type()){\r
- sprintf(tmpstr,"\t\t%s(&aggr_var%d);\n",\r
- adt->get_hfta_buffer_destroy().c_str(), a );\r
- ret += tmpstr;\r
- }\r
- }else{\r
- ret+="\t\t"+aggr_tbl.get_op(a)+"_HFTA_AGGR_DESTROY_(";\r
- if(aggr_tbl.get_storage_type(a)->get_type() != fstring_t) ret+="&";\r
- ret+="(aggr_var"+int_to_string(a)+"));\n";\r
- }\r
- }\r
- ret += "\t};\n";\r
- ret +="};\n\n";\r
-\r
-//--------------------------------\r
-// superaggr definition class\r
- ret += "class " + this->generate_functor_name() + "_statedef{\n";\r
- ret += "public:\n";\r
- for(a=0;a<aggr_tbl.size();a++){\r
-aggr_table_entry *ate = aggr_tbl.agr_tbl[a];\r
- if(ate->is_superaggr()){\r
- sprintf(tmpstr,"aggr_var%d",a);\r
- if(aggr_tbl.is_builtin(a))\r
- ret+="\t"+ aggr_tbl.get_data_type(a)->make_host_cvar(tmpstr)+";\n";\r
- else\r
- ret+="\t"+ aggr_tbl.get_storage_type(a)->make_host_cvar(tmpstr)+";\n";\r
- }\r
- }\r
- set<string>::iterator ssi;\r
- for(ssi=states_refd.begin(); ssi!=states_refd.end(); ++ssi){\r
- string state_nm = (*ssi);\r
- int state_id = Ext_fcns->lookup_state(state_nm);\r
- data_type *dt = Ext_fcns->get_storage_dt(state_id);\r
- string state_var = "state_var_"+state_nm;\r
- ret += "\t"+dt->make_host_cvar(state_var)+";\n";\r
- }\r
-// Constructors\r
- ret += "\t"+this->generate_functor_name() + "_statedef(){};\n";\r
-// destructor\r
- ret += "\t~"+this->generate_functor_name() + "_statedef(){\n";\r
- for(a=0;a<aggr_tbl.size();a++){\r
-aggr_table_entry *ate = aggr_tbl.agr_tbl[a];\r
- if(ate->is_superaggr()){\r
- if(aggr_tbl.is_builtin(a)){\r
- data_type *adt = aggr_tbl.get_data_type(a);\r
- if(adt->is_buffer_type()){\r
- sprintf(tmpstr,"\t\t%s(&aggr_var%d);\n",\r
- adt->get_hfta_buffer_destroy().c_str(), a );\r
- ret += tmpstr;\r
- }\r
- }else{\r
- ret+="\t\t"+aggr_tbl.get_op(a)+"_HFTA_AGGR_DESTROY_(";\r
- if(aggr_tbl.get_storage_type(a)->get_type() != fstring_t) ret+="&";\r
- ret+="(aggr_var"+int_to_string(a)+"));\n";\r
- }\r
- }\r
- }\r
- for(ssi=states_refd.begin(); ssi!=states_refd.end(); ++ssi){\r
- string state_nm = (*ssi);\r
- int state_id = Ext_fcns->lookup_state(state_nm);\r
- string state_var = "state_var_"+state_nm;\r
- ret += "\t_sfun_state_destroy_"+state_nm+"(&"+state_var+");\n";\r
- }\r
-\r
- ret += "\t};\n";\r
- ret +="};\n\n";\r
-\r
-\r
-//--------------------------------\r
-// gb functor class\r
- ret += "class " + this->generate_functor_name() + "{\n";\r
-\r
-// Find variables referenced in this query node.\r
-\r
- col_id_set cid_set;\r
- col_id_set::iterator csi;\r
-\r
- for(w=0;w<where.size();++w)\r
- gather_pr_col_ids(where[w]->pr,cid_set,segen_gb_tbl);\r
- for(w=0;w<having.size();++w)\r
- gather_pr_col_ids(having[w]->pr,cid_set,segen_gb_tbl);\r
- for(w=0;w<cleanby.size();++w)\r
- gather_pr_col_ids(cleanby[w]->pr,cid_set,segen_gb_tbl);\r
- for(w=0;w<cleanwhen.size();++w)\r
- gather_pr_col_ids(cleanwhen[w]->pr,cid_set,segen_gb_tbl);\r
- for(g=0;g<gb_tbl.size();g++)\r
- gather_se_col_ids(gb_tbl.get_def(g),cid_set,segen_gb_tbl);\r
-\r
- for(s=0;s<select_list.size();s++){\r
- gather_se_col_ids(select_list[s]->se,cid_set,segen_gb_tbl); // descends into aggregates\r
- }\r
-\r
-\r
-// Private variables : store the state of the functor.\r
-// 1) variables for unpacked attributes\r
-// 2) offsets of the upacked attributes\r
-// 3) storage of partial functions\r
-// 4) storage of complex literals (i.e., require a constructor)\r
-\r
- ret += "private:\n";\r
-\r
- // var to save the schema handle\r
- ret += "\tint schema_handle0;\n";\r
-\r
- // generate the declaration of all the variables related to\r
- // temp tuples generation\r
- ret += gen_decl_temp_vars();\r
-\r
-// unpacked attribute storage, offsets\r
- ret += "//\t\tstorage and offsets of accessed fields.\n";\r
- ret += generate_access_vars(cid_set, schema);\r
-// tuple metadata offset\r
- ret += "\ttuple_metadata_offset0;\n";\r
-\r
-// Variables to store results of partial functions.\r
-// WARNING find_partial_functions modifies the SE\r
-// (it marks the partial function id).\r
- ret += "//\t\tParital function result storage\n";\r
- vector<scalarexp_t *> partial_fcns;\r
- vector<int> fcn_ref_cnt;\r
- vector<bool> is_partial_fcn;\r
- for(s=0;s<select_list.size();s++){\r
- find_partial_fcns(select_list[s]->se, &partial_fcns, NULL,NULL, Ext_fcns);\r
- }\r
- for(w=0;w<where.size();w++){\r
- find_partial_fcns_pr(where[w]->pr, &partial_fcns, NULL,NULL, Ext_fcns);\r
- }\r
- for(w=0;w<having.size();w++){\r
- find_partial_fcns_pr(having[w]->pr, &partial_fcns, NULL,NULL, Ext_fcns);\r
- }\r
- for(w=0;w<cleanby.size();w++){\r
- find_partial_fcns_pr(cleanby[w]->pr, &partial_fcns, NULL,NULL, Ext_fcns);\r
- }\r
- for(w=0;w<cleanwhen.size();w++){\r
- find_partial_fcns_pr(cleanwhen[w]->pr, &partial_fcns, NULL,NULL, Ext_fcns);\r
- }\r
- for(g=0;g<gb_tbl.size();g++){\r
- find_partial_fcns(gb_tbl.get_def(g), &partial_fcns, NULL,NULL, Ext_fcns);\r
- }\r
- for(a=0;a<aggr_tbl.size();a++){\r
- find_partial_fcns(aggr_tbl.get_aggr_se(a), &partial_fcns, NULL,NULL, Ext_fcns);\r
- }\r
- if(partial_fcns.size()>0){\r
- ret += "/*\t\tVariables for storing results of partial functions. \t*/\n";\r
- ret += generate_partial_fcn_vars(partial_fcns,fcn_ref_cnt,is_partial_fcn,false);\r
- }\r
-\r
-// Complex literals (i.e., they need constructors)\r
- ret += "//\t\tComplex literal storage.\n";\r
- cplx_lit_table *complex_literals = this->get_cplx_lit_tbl(Ext_fcns);\r
- ret += generate_complex_lit_vars(complex_literals);\r
-\r
-// Pass-by-handle parameters\r
- ret += "//\t\tPass-by-handle storage.\n";\r
- vector<handle_param_tbl_entry *> param_handle_table = this->get_handle_param_tbl(Ext_fcns);\r
- ret += generate_pass_by_handle_vars(param_handle_table);\r
-\r
-// Create cached temporaries for UDAF return values.\r
- ret += "//\t\tTemporaries for UDAF return values.\n";\r
- for(a=0;a<aggr_tbl.size();a++){\r
- if(! aggr_tbl.is_builtin(a)){\r
- int afcn_id = aggr_tbl.get_fcn_id(a);\r
- data_type *adt = Ext_fcns->get_fcn_dt(afcn_id);\r
- sprintf(tmpstr,"udaf_ret_%d", a);\r
- ret+="\t"+adt->make_host_cvar(tmpstr)+";\n";\r
- }\r
- }\r
-\r
-\r
-\r
-// variables to hold parameters.\r
- ret += "//\tfor query parameters\n";\r
- ret += generate_param_vars(param_tbl);\r
-\r
-// Is there a temporal flush? If so create flush temporaries,\r
-// create flush indicator.\r
- bool uses_temporal_flush = false;\r
- for(g=0;g<gb_tbl.size();g++){\r
- data_type *gdt = gb_tbl.get_data_type(g);\r
- if(gdt->is_temporal())\r
- uses_temporal_flush = true;\r
- }\r
-\r
- if(uses_temporal_flush){\r
- ret += "//\t\tFor temporal flush\n";\r
- for(g=0;g<gb_tbl.size();g++){\r
- data_type *gdt = gb_tbl.get_data_type(g);\r
- if(gdt->is_temporal()){\r
- sprintf(tmpstr,"last_gb%d",g);\r
- ret+="\t"+gb_tbl.get_data_type(g)->make_host_cvar(tmpstr)+";\n";\r
- sprintf(tmpstr,"last_flushed_gb%d",g);\r
- ret+="\t"+gb_tbl.get_data_type(g)->make_host_cvar(tmpstr)+";\n";\r
- }\r
- }\r
- ret += "\tbool needs_temporal_flush;\n";\r
- }\r
-\r
-// The publicly exposed functions\r
-\r
- ret += "\npublic:\n";\r
-\r
-\r
-//-------------------\r
-// The functor constructor\r
-// pass in the schema handle.\r
-// 1) make assignments to the unpack offset variables\r
-// 2) initialize the complex literals\r
-\r
- ret += "//\t\tFunctor constructor.\n";\r
- ret += this->generate_functor_name()+"(int schema_handle0){\n";\r
-\r
- // save the schema handle\r
- ret += "\t\tthis->schema_handle0 = schema_handle0;\n";\r
-// tuple metadata offset\r
- ret += "\ttuple_metadata_offset0 = ftaschema_get_tuple_metadata_offset(schema_handle0);\n";\r
-\r
-// unpack vars\r
- ret += "//\t\tGet offsets for unpacking fields from input tuple.\n";\r
- ret += gen_access_var_init(cid_set);\r
-\r
-// aggregate return vals : refd in both final_sample\r
-// and create_output_tuple\r
-// Create cached temporaries for UDAF return values.\r
- for(a=0;a<aggr_tbl.size();a++){\r
- if(! aggr_tbl.is_builtin(a)){\r
- int afcn_id = aggr_tbl.get_fcn_id(a);\r
- data_type *adt = Ext_fcns->get_fcn_dt(afcn_id);\r
- sprintf(tmpstr,"udaf_ret_%d", a);\r
- ret+="\t"+adt->make_host_cvar(tmpstr)+";\n";\r
- }\r
- }\r
-\r
-// complex literals\r
- ret += "//\t\tInitialize complex literals.\n";\r
- ret += gen_complex_lit_init(complex_literals);\r
-\r
-// Initialize partial function results so they can be safely GC'd\r
- ret += gen_partial_fcn_init(partial_fcns);\r
-\r
-// Initialize non-query-parameter parameter handles\r
- ret += gen_pass_by_handle_init(param_handle_table);\r
-\r
-// temporal flush variables\r
-// ASSUME that structured values won't be temporal.\r
- if(uses_temporal_flush){\r
- ret += "//\t\tInitialize temporal flush variables.\n";\r
- for(g=0;g<gb_tbl.size();g++){\r
- data_type *gdt = gb_tbl.get_data_type(g);\r
- if(gdt->is_temporal()){\r
- literal_t gl(gdt->type_indicator());\r
- sprintf(tmpstr,"\tlast_gb%d = %s;\n",g, gl.to_hfta_C_code("").c_str());\r
- ret.append(tmpstr);\r
- }\r
- }\r
- ret += "\tneeds_temporal_flush = false;\n";\r
- }\r
-\r
- // Init temporal attributes referenced in select list\r
- ret += gen_init_temp_vars(schema, select_list, segen_gb_tbl);\r
-\r
- ret += "};\n";\r
-\r
-\r
-//-------------------\r
-// Functor destructor\r
- ret += "//\t\tFunctor destructor.\n";\r
- ret += "~"+this->generate_functor_name()+"(){\n";\r
-\r
-// clean up buffer type complex literals\r
- ret += gen_complex_lit_dtr(complex_literals);\r
-\r
-// Deregister the pass-by-handle parameters\r
- ret += "/* register and de-register the pass-by-handle parameters */\n";\r
- ret += gen_pass_by_handle_dtr(param_handle_table);\r
-\r
-// clean up partial function results.\r
- ret += "/* clean up partial function storage */\n";\r
- ret += gen_partial_fcn_dtr(partial_fcns);\r
-\r
-// Destroy the parameters, if any need to be destroyed\r
- ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";\r
-\r
- ret += "};\n\n";\r
-\r
-\r
-//-------------------\r
-// Parameter manipulation routines\r
- ret += generate_load_param_block(this->generate_functor_name(),\r
- this->param_tbl,param_handle_table);\r
- ret += generate_delete_param_block(this->generate_functor_name(),\r
- this->param_tbl,param_handle_table);\r
-\r
-//-------------------\r
-// Register new parameter block\r
-\r
- ret += "int set_param_block(gs_int32_t sz, void* value){\n";\r
- ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";\r
- ret += "\treturn this->load_params_"+this->generate_functor_name()+\r
- "(sz, value);\n";\r
- ret += "};\n\n";\r
-\r
-//-------------------\r
-// the create_group method.\r
-// This method creates a group in a buffer passed in\r
-// (to allow for creation on the stack).\r
-// There are also a couple of side effects:\r
-// 1) evaluate the WHERE clause (and therefore, unpack all partial fcns)\r
-// 2) determine if a temporal flush is required.\r
-\r
- ret += this->generate_functor_name()+"_groupdef *create_group(host_tuple &tup0, gs_sp_t buffer){\n";\r
- // Variables for execution of the function.\r
- ret += "\tgs_int32_t problem = 0;\n"; // return unpack failure\r
-\r
- if(partial_fcns.size()>0){ // partial fcn access failure\r
- ret += "\tgs_retval_t retval = 0;\n";\r
- ret += "\n";\r
- }\r
-// return value\r
- ret += "\t"+generate_functor_name()+"_groupdef *gbval = ("+generate_functor_name()+\r
- "_groupdef *) buffer;\n";\r
-\r
-// Start by cleaning up partial function results\r
- ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";\r
-\r
- set<int> gb_pfcns; // partial fcns in gbdefs, aggr se's\r
- for(g=0;g<gb_tbl.size();g++){\r
- collect_partial_fcns(gb_tbl.get_def(g), gb_pfcns);\r
- }\r
- ret += gen_partial_fcn_dtr(partial_fcns,gb_pfcns);\r
-// ret += gen_partial_fcn_dtr(partial_fcns);\r
-\r
-\r
- ret += gen_temp_tuple_check(this->node_name, 0);\r
- col_id_set found_cids; // colrefs unpacked thus far.\r
- ret += gen_unpack_temp_vars(schema, found_cids, select_list, segen_gb_tbl, needs_xform);\r
-\r
-\r
-\r
-// Save temporal group-by variables\r
-\r
-\r
- ret.append("\n\t//\t\tCompute temporal groupby attributes\n\n");\r
-\r
- for(g=0;g<gb_tbl.size();g++){\r
-\r
- data_type *gdt = gb_tbl.get_data_type(g);\r
-\r
- if(gdt->is_temporal()){\r
- sprintf(tmpstr,"\tgbval->gb_var%d = %s;\n",\r
- g, generate_se_code(gb_tbl.get_def(g),schema).c_str() );\r
- ret.append(tmpstr);\r
- }\r
- }\r
- ret.append("\n");\r
-\r
-\r
-\r
-// Compare the temporal GB vars with the stored ones,\r
-// set flush indicator and update stored GB vars if there is any change.\r
-\r
- if(uses_temporal_flush){\r
- ret+= "\tif( !( (";\r
- bool first_one = true;\r
- for(g=0;g<gb_tbl.size();g++){\r
- data_type *gdt = gb_tbl.get_data_type(g);\r
-\r
- if(gdt->is_temporal()){\r
- sprintf(tmpstr,"last_gb%d",g); string lhs_op = tmpstr;\r
- sprintf(tmpstr,"gbval->gb_var%d",g); string rhs_op = tmpstr;\r
- if(first_one){first_one = false;} else {ret += ") && (";}\r
- ret += generate_equality_test(lhs_op, rhs_op, gdt);\r
- }\r
- }\r
- ret += ") ) ){\n";\r
- for(g=0;g<gb_tbl.size();g++){\r
- data_type *gdt = gb_tbl.get_data_type(g);\r
- if(gdt->is_temporal()){\r
- if(gdt->is_buffer_type()){\r
- sprintf(tmpstr,"\t\t%s(&(gbval->gb_var%d),&last_gb%d);\n",gdt->get_hfta_buffer_replace().c_str(),g,g);\r
- }else{\r
- sprintf(tmpstr,"\t\tlast_flushed_gb%d = last_gb%d;\n",g,g);\r
- ret += tmpstr;\r
- sprintf(tmpstr,"\t\tlast_gb%d = gbval->gb_var%d;\n",g,g);\r
- }\r
- ret += tmpstr;\r
- }\r
- }\r
-/*\r
- if(uses_temporal_flush){\r
- for(g=0;g<gb_tbl.size();g++){\r
- data_type *gdt = gb_tbl.get_data_type(g);\r
- if(gdt->is_temporal()){\r
- ret+="if(last_flushed_gb"+int_to_string(g)+">0)\n";\r
- break;\r
- }\r
- }\r
- }\r
-*/\r
- ret += "\t\tneeds_temporal_flush=true;\n";\r
- ret += "\t\t}else{\n"\r
- "\t\t\tneeds_temporal_flush=false;\n"\r
- "\t\t}\n";\r
- }\r
-\r
-\r
-// For temporal status tuple we don't need to do anything else\r
- ret += "\tif (temp_tuple_received) return NULL;\n\n";\r
-\r
-\r
-// The partial functions ref'd in the group-by var\r
-// definitions must be evaluated. If one returns false,\r
-// then implicitly the predicate is false.\r
- set<int>::iterator pfsi;\r
-\r
- if(gb_pfcns.size() > 0)\r
- ret += "//\t\tUnpack partial fcns.\n";\r
- ret += gen_full_unpack_partial_fcn(schema, partial_fcns, gb_pfcns,\r
- found_cids, segen_gb_tbl, "NULL", needs_xform);\r
-\r
-// Unpack the group-by variables\r
-\r
- for(g=0;g<gb_tbl.size();g++){\r
-// Find the new fields ref'd by this GBvar def.\r
- col_id_set new_cids;\r
- get_new_se_cids(gb_tbl.get_def(g), found_cids, new_cids, segen_gb_tbl);\r
-// Unpack these values.\r
- ret += gen_unpack_cids(schema, new_cids, "NULL", needs_xform);\r
-\r
- sprintf(tmpstr,"\tgbval->gb_var%d = %s;\n",\r
- g, generate_se_code(gb_tbl.get_def(g),schema).c_str() );\r
-/*\r
-// There seems to be no difference between the two\r
-// branches of the IF statement.\r
- data_type *gdt = gb_tbl.get_data_type(g);\r
- if(gdt->is_buffer_type()){\r
-// Create temporary copy.\r
- sprintf(tmpstr,"\tgbval->gb_var%d = %s;\n",\r
- g, generate_se_code(gb_tbl.get_def(g),schema).c_str() );\r
- }else{\r
- scalarexp_t *gse = gb_tbl.get_def(g);\r
- sprintf(tmpstr,"\tgbval->gb_var%d = %s;\n",\r
- g,generate_se_code(gse,schema).c_str());\r
- }\r
-*/\r
- ret.append(tmpstr);\r
- }\r
- ret.append("\n");\r
-\r
-\r
- ret+= "\treturn gbval;\n";\r
- ret += "};\n\n\n";\r
-\r
-\r
-\r
-//-------------------\r
-// the create_group method.\r
-// This method creates a group in a buffer passed in\r
-// (to allow for creation on the stack).\r
-// There are also a couple of side effects:\r
-// 1) evaluate the WHERE clause (and therefore, unpack all partial fcns)\r
-// 2) determine if a temporal flush is required.\r
-\r
- ret += "bool evaluate_predicate(host_tuple &tup0, "+generate_functor_name()+"_groupdef *gbval, "+generate_functor_name()+"_statedef *stval, int cd){\n";\r
- // Variables for execution of the function.\r
- ret += "\tgs_int32_t problem = 0;\n"; // return unpack failure\r
-\r
- if(partial_fcns.size()>0){ // partial fcn access failure\r
- ret += "\tgs_retval_t retval = 0;\n";\r
- ret += "\n";\r
- }\r
-\r
-// Start by cleaning up partial function results\r
- ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";\r
- set<int> w_pfcns; // partial fcns in where clause\r
- for(w=0;w<where.size();++w)\r
- collect_partial_fcns_pr(where[w]->pr, w_pfcns);\r
-\r
- set<int> ag_pfcns; // partial fcns in gbdefs, aggr se's\r
- for(a=0;a<aggr_tbl.size();a++){\r
- collect_partial_fcns(aggr_tbl.get_aggr_se(a), ag_pfcns);\r
- }\r
- ret += gen_partial_fcn_dtr(partial_fcns,w_pfcns);\r
- ret += gen_partial_fcn_dtr(partial_fcns,ag_pfcns);\r
-\r
- ret+="//\t\tEvaluate clauses which don't reference stateful fcns first \n";\r
- for(w=0;w<where.size();++w){\r
- if(! pred_refs_sfun(where[w]->pr)){\r
- sprintf(tmpstr,"//\t\tPredicate clause %d.\n",w);\r
- ret += tmpstr;\r
-// Find the set of variables accessed in this CNF elem,\r
-// but in no previous element.\r
- col_id_set new_cids;\r
- get_new_pred_cids(where[w]->pr, found_cids, new_cids, segen_gb_tbl);\r
-\r
-// Unpack these values.\r
- ret += gen_unpack_cids(schema, new_cids, "false", needs_xform);\r
-// Find partial fcns ref'd in this cnf element\r
- set<int> pfcn_refs;\r
- collect_partial_fcns_pr(where[w]->pr, pfcn_refs);\r
- ret += gen_unpack_partial_fcn(schema, partial_fcns, pfcn_refs,"false");\r
-\r
- ret += "\tif( !("+generate_predicate_code(where[w]->pr,schema)+\r
- +") ) return(false);\n";\r
- }\r
- }\r
-\r
-\r
-// The partial functions ref'd in the and aggregate\r
-// definitions must also be evaluated. If one returns false,\r
-// then implicitly the predicate is false.\r
-// ASSUME that aggregates cannot reference stateful fcns.\r
-\r
- if(ag_pfcns.size() > 0)\r
- ret += "//\t\tUnpack remaining partial fcns.\n";\r
- ret += gen_full_unpack_partial_fcn(schema, partial_fcns, ag_pfcns,\r
- found_cids, segen_gb_tbl, "false", needs_xform);\r
-\r
- ret+="//\t\tEvaluate all remaining where clauses.\n";\r
- ret+="\tbool retval = true;\n";\r
- for(w=0;w<where.size();++w){\r
- if( pred_refs_sfun(where[w]->pr)){\r
- sprintf(tmpstr,"//\t\tPredicate clause %d.\n",w);\r
- ret += tmpstr;\r
-// Find the set of variables accessed in this CNF elem,\r
-// but in no previous element.\r
- col_id_set new_cids;\r
- get_new_pred_cids(where[w]->pr, found_cids, new_cids, segen_gb_tbl);\r
-\r
-// Unpack these values.\r
- ret += gen_unpack_cids(schema, new_cids, "false", needs_xform);\r
-// Find partial fcns ref'd in this cnf element\r
- set<int> pfcn_refs;\r
- collect_partial_fcns_pr(where[w]->pr, pfcn_refs);\r
- ret += gen_unpack_partial_fcn(schema, partial_fcns, pfcn_refs,"false");\r
-\r
- ret += "\tif( !("+generate_predicate_code(where[w]->pr,schema)+\r
- +") ) retval = false;\n";\r
- }\r
- }\r
-\r
- ret+="// Unpack all remaining attributes\n";\r
- ret += gen_remaining_colrefs(schema, cid_set, found_cids, "false", needs_xform);\r
-\r
- ret += "\n\treturn retval;\n";\r
- ret += "};\n\n\n";\r
-\r
-//--------------------------------------------------------\r
-// Create and initialize an aggregate object\r
-\r
- ret += this->generate_functor_name()+"_aggrdef *create_aggregate(host_tuple &tup0, "+generate_functor_name()+"_groupdef *gbval, gs_sp_t a,"+generate_functor_name()+"_statedef *stval, int cd){\n";\r
- // Variables for execution of the function.\r
- ret += "\tgs_int32_t problem = 0;\n"; // return unpack failure\r
-\r
-// return value\r
- ret += "\t"+generate_functor_name()+"_aggrdef *aggval = ("+generate_functor_name()+ "_aggrdef *)a;\n";\r
-\r
- for(a=0;a<aggr_tbl.size();a++){\r
- if(aggr_tbl.is_builtin(a)){\r
-// Create temporaries for buffer return values\r
- data_type *adt = aggr_tbl.get_data_type(a);\r
- if(adt->is_buffer_type()){\r
- sprintf(tmpstr,"aggr_tmp_%d", a);\r
- ret+=adt->make_host_cvar(tmpstr)+";\n";\r
- }\r
- }\r
- }\r
-\r
- for(a=0;a<aggr_tbl.size();a++){\r
- sprintf(tmpstr,"aggval->aggr_var%d",a);\r
- string assignto_var = tmpstr;\r
- ret += "\t"+generate_aggr_init(assignto_var,&aggr_tbl,a, schema);\r
- }\r
-\r
- ret += "\treturn aggval;\n";\r
- ret += "};\n\n";\r
-\r
-\r
-//--------------------------------------------------------\r
-// initialize an aggregate object inplace\r
-\r
- ret += "void create_aggregate(host_tuple &tup0, "+this->generate_functor_name()+"_aggrdef *aggval,"+generate_functor_name()+"_statedef *stval, int cd){\n";\r
- // Variables for execution of the function.\r
- ret += "\tgs_int32_t problem = 0;\n"; // return unpack failure\r
-\r
-// return value\r
-\r
- for(a=0;a<aggr_tbl.size();a++){\r
- if(aggr_tbl.is_builtin(a)){\r
-// Create temporaries for buffer return values\r
- data_type *adt = aggr_tbl.get_data_type(a);\r
- if(adt->is_buffer_type()){\r
- sprintf(tmpstr,"aggr_tmp_%d", a);\r
- ret+=adt->make_host_cvar(tmpstr)+";\n";\r
- }\r
- }\r
- }\r
-\r
- for(a=0;a<aggr_tbl.size();a++){\r
- sprintf(tmpstr,"aggval->aggr_var%d",a);\r
- string assignto_var = tmpstr;\r
- ret += "\t"+generate_aggr_init(assignto_var,&aggr_tbl,a, schema);\r
- }\r
-\r
- ret += "};\n\n";\r
-\r
-\r
-//--------------------------------------------------------\r
-// Create and clean-initialize an state object\r
-\r
- ret += "void initialize_state(host_tuple &tup0, "+generate_functor_name()+"_groupdef *gbval, "+generate_functor_name()+"_statedef *stval){\n";\r
- // Variables for execution of the function.\r
- ret += "\tgs_int32_t problem = 0;\n"; // return unpack failure\r
-\r
-// return value\r
-// ret += "\t"+generate_functor_name()+"_statedef *stval = ("+generate_functor_name()+ "_statedef *)s;\n";\r
-\r
- for(a=0;a<aggr_tbl.size();a++){\r
- if( aggr_tbl.is_superaggr(a)){\r
- if(aggr_tbl.is_builtin(a)){\r
-// Create temporaries for buffer return values\r
- data_type *adt = aggr_tbl.get_data_type(a);\r
- if(adt->is_buffer_type()){\r
- sprintf(tmpstr,"aggr_tmp_%d", a);\r
- ret+=adt->make_host_cvar(tmpstr)+";\n";\r
- }\r
- }\r
- }\r
- }\r
-\r
- for(a=0;a<aggr_tbl.size();a++){\r
- if( aggr_tbl.is_superaggr(a)){\r
- sprintf(tmpstr,"stval->aggr_var%d",a);\r
- string assignto_var = tmpstr;\r
- ret += "\t"+generate_aggr_init(assignto_var,&aggr_tbl,a, schema);\r
- }\r
- }\r
-\r
- for(ssi=states_refd.begin(); ssi!=states_refd.end();++ssi){\r
- string state_nm = (*ssi);\r
- ret += "_sfun_state_clean_init_"+state_nm+"(&(stval->state_var_"+state_nm+"));\n";\r
- }\r
-\r
- ret += "};\n\n";\r
-\r
-\r
-//--------------------------------------------------------\r
-// Create and dirty-initialize an state object\r
-\r
- ret += "void reinitialize_state(host_tuple &tup0, "+generate_functor_name()+"_groupdef *gbval, "+generate_functor_name()+"_statedef *stval, "+generate_functor_name()+"_statedef *old_stval, int cd){\n";\r
- // Variables for execution of the function.\r
- ret += "\tgs_int32_t problem = 0;\n"; // return unpack failure\r
-\r
-// return value\r
-// ret += "\t"+generate_functor_name()+"_statedef *stval = ("+generate_functor_name()+ "_statedef *)s;\n";\r
-\r
- for(a=0;a<aggr_tbl.size();a++){\r
- if( aggr_tbl.is_superaggr(a)){\r
- if(aggr_tbl.is_builtin(a)){\r
-// Create temporaries for buffer return values\r
- data_type *adt = aggr_tbl.get_data_type(a);\r
- if(adt->is_buffer_type()){\r
- sprintf(tmpstr,"aggr_tmp_%d", a);\r
- ret+=adt->make_host_cvar(tmpstr)+";\n";\r
- }\r
- }\r
- }\r
- }\r
-\r
-// initialize superaggregates\r
- for(a=0;a<aggr_tbl.size();a++){\r
- if( aggr_tbl.is_superaggr(a)){\r
- sprintf(tmpstr,"stval->aggr_var%d",a);\r
- string assignto_var = tmpstr;\r
- ret += "\t"+generate_aggr_init(assignto_var,&aggr_tbl,a, schema);\r
- }\r
- }\r
-\r
- for(ssi=states_refd.begin(); ssi!=states_refd.end();++ssi){\r
- string state_nm = (*ssi);\r
- ret += "_sfun_state_dirty_init_"+state_nm+"(&(stval->state_var_"+state_nm+"),&(old_stval->state_var_"+state_nm+"), cd );\n";\r
- }\r
-\r
- ret += "};\n\n";\r
-\r
-//--------------------------------------------------------\r
-// Finalize_state : call the finalize fcn on all states\r
-\r
-\r
- ret += "void finalize_state( "+generate_functor_name()+"_statedef *stval, int cd){\n";\r
-\r
- for(ssi=states_refd.begin(); ssi!=states_refd.end();++ssi){\r
- string state_nm = (*ssi);\r
- ret += "_sfun_state_final_init_"+state_nm+"(&(stval->state_var_"+state_nm+"), cd);\n";\r
- }\r
-\r
- ret += "};\n\n";\r
-\r
-\r
-\r
-\r
-//--------------------------------------------------------\r
-// update (plus) a superaggregate object\r
-\r
- ret += "void update_plus_superaggr(host_tuple &tup0, " +\r
- generate_functor_name()+"_groupdef *gbval, "+\r
- generate_functor_name()+"_statedef *stval){\n";\r
- // Variables for execution of the function.\r
- ret += "\tgs_int32_t problem = 0;\n"; // return unpack failure\r
-\r
-// use of temporaries depends on the aggregate,\r
-// generate them in generate_aggr_update\r
-\r
-\r
- for(a=0;a<aggr_tbl.size();a++){\r
- if(aggr_tbl.is_superaggr(a)){\r
- sprintf(tmpstr,"stval->aggr_var%d",a);\r
- string varname = tmpstr;\r
- ret.append(generate_aggr_update(varname,&aggr_tbl,a, schema));\r
- }\r
- }\r
-\r
- ret += "\treturn;\n";\r
- ret += "};\n";\r
-\r
-\r
-\r
-//--------------------------------------------------------\r
-// update (minus) a superaggregate object\r
-\r
- ret += "void update_minus_superaggr( "+\r
- generate_functor_name()+"_groupdef *gbval, "+\r
- generate_functor_name()+"_aggrdef *aggval,"+\r
- generate_functor_name()+"_statedef *stval"+\r
- "){\n";\r
- // Variables for execution of the function.\r
- ret += "\tgs_int32_t problem = 0;\n"; // return unpack failure\r
-\r
-// use of temporaries depends on the aggregate,\r
-// generate them in generate_aggr_update\r
-\r
-\r
- for(a=0;a<aggr_tbl.size();a++){\r
- if(aggr_tbl.is_superaggr(a)){\r
- sprintf(tmpstr,"stval->aggr_var%d",a);\r
- string super_varname = tmpstr;\r
- sprintf(tmpstr,"aggval->aggr_var%d",a);\r
- string sub_varname = tmpstr;\r
- ret.append(generate_superaggr_minus(sub_varname, super_varname,&aggr_tbl,a, schema));\r
- }\r
- }\r
-\r
- ret += "\treturn;\n";\r
- ret += "};\n";\r
-\r
-\r
-//--------------------------------------------------------\r
-// update an aggregate object\r
-\r
- ret += "void update_aggregate(host_tuple &tup0, "\r
- +generate_functor_name()+"_groupdef *gbval, "+\r
- generate_functor_name()+"_aggrdef *aggval,"+generate_functor_name()+"_statedef *stval, int cd){\n";\r
- // Variables for execution of the function.\r
- ret += "\tgs_int32_t problem = 0;\n"; // return unpack failure\r
-\r
-// use of temporaries depends on the aggregate,\r
-// generate them in generate_aggr_update\r
-\r
-\r
- for(a=0;a<aggr_tbl.size();a++){\r
- sprintf(tmpstr,"aggval->aggr_var%d",a);\r
- string varname = tmpstr;\r
- ret.append(generate_aggr_update(varname,&aggr_tbl,a, schema));\r
- }\r
-\r
- ret += "\treturn;\n";\r
- ret += "};\n";\r
-\r
-//---------------------------------------------------\r
-// Flush test\r
-\r
- ret += "\tbool flush_needed(){\n";\r
- if(uses_temporal_flush){\r
- ret += "\t\treturn needs_temporal_flush;\n";\r
- }else{\r
- ret += "\t\treturn false;\n";\r
- }\r
- ret += "\t};\n";\r
-\r
-\r
-//------------------------------------------------------\r
-// THe cleaning_when predicate\r
-\r
- string gbvar = "gbval->gb_var";\r
- string aggvar = "aggval->";\r
-\r
- ret += "bool need_to_clean( "\r
- +generate_functor_name()+"_groupdef *gbval, "+\r
- generate_functor_name()+"_statedef *stval, int cd"+\r
- "){\n";\r
-\r
- if(cleanwhen.size()>0)\r
- ret += "\tbool predval = true;\n";\r
- else\r
- ret += "\tbool predval = false;\n";\r
-\r
-// Find the udafs ref'd in the having clause\r
- set<int> cw_aggs;\r
- for(w=0;w<cleanwhen.size();++w)\r
- collect_aggr_refs_pr(cleanwhen[w]->pr, cw_aggs);\r
-\r
-\r
-// get the return values from the UDAFS\r
- for(a=0;a<aggr_tbl.size();a++){\r
- if(! aggr_tbl.is_builtin(a) && cw_aggs.count(a)){\r
- ret += "\t"+aggr_tbl.get_op(a)+"_HFTA_AGGR_OUTPUT_(&(udaf_ret_"+int_to_string(a)+"),";\r
- if(aggr_tbl.get_storage_type(a)->get_type() != fstring_t) ret+="&";\r
- ret+="("+aggvar+"aggr_var"+int_to_string(a)+"));\n";\r
- }\r
- }\r
-\r
-\r
-// Start by cleaning up partial function results\r
- ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";\r
- set<int> cw_pfcns; // partial fcns in where clause\r
- for(w=0;w<cleanwhen.size();++w)\r
- collect_partial_fcns_pr(cleanwhen[w]->pr, cw_pfcns);\r
-\r
- ret += gen_partial_fcn_dtr(partial_fcns,cw_pfcns);\r
-\r
-\r
- for(w=0;w<cleanwhen.size();++w){\r
- sprintf(tmpstr,"//\t\tPredicate clause %d.\n",w);\r
- ret += tmpstr;\r
-// Find partial fcns ref'd in this cnf element\r
- set<int> pfcn_refs;\r
- collect_partial_fcns_pr(cleanwhen[w]->pr, pfcn_refs);\r
- for(pfsi=pfcn_refs.begin();pfsi!=pfcn_refs.end();++pfsi){\r
- ret += unpack_partial_fcn_fm_aggr(partial_fcns[(*pfsi)], (*pfsi), gbvar, aggvar, schema);\r
- ret += "\tif(retval){ return false;}\n";\r
- }\r
-// ret += unpack_partial_fcn_fm_aggr(schema, partial_fcns, pfcn_refs,"false");\r
-\r
- ret += "\tif( !("+generate_predicate_code_fm_aggr(cleanwhen[w]->pr,gbvar, aggvar, schema)+\r
- ") ) predval = false;\n";\r
- }\r
-\r
- ret += "\treturn predval;\n";\r
- ret += "\t};\n";\r
-\r
-//------------------------------------------------------\r
-// THe cleaning_by predicate\r
-\r
- ret += "bool sample_group("\r
- +generate_functor_name()+"_groupdef *gbval, "+\r
- generate_functor_name()+"_aggrdef *aggval,"+\r
- generate_functor_name()+"_statedef *stval, int cd"+\r
- "){\n";\r
-\r
- if(cleanby.size()>0)\r
- ret += "\tbool retval = true;\n";\r
- else\r
- ret += "\tbool retval = false;\n";\r
-\r
-// Find the udafs ref'd in the having clause\r
- set<int> cb_aggs;\r
- for(w=0;w<cleanby.size();++w)\r
- collect_aggr_refs_pr(cleanby[w]->pr, cb_aggs);\r
-\r
-\r
-// get the return values from the UDAFS\r
- for(a=0;a<aggr_tbl.size();a++){\r
- if(! aggr_tbl.is_builtin(a) && cb_aggs.count(a)){\r
- ret += "\t"+aggr_tbl.get_op(a)+"_HFTA_AGGR_OUTPUT_(&(udaf_ret_"+int_to_string(a)+"),";\r
- if(aggr_tbl.get_storage_type(a)->get_type() != fstring_t) ret+="&";\r
- ret+="("+aggvar+"aggr_var"+int_to_string(a)+"));\n";\r
- }\r
- }\r
-\r
-\r
-// Start by cleaning up partial function results\r
- ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";\r
- set<int> cb_pfcns; // partial fcns in where clause\r
- for(w=0;w<cleanby.size();++w)\r
- collect_partial_fcns_pr(cleanby[w]->pr, cb_pfcns);\r
-\r
- ret += gen_partial_fcn_dtr(partial_fcns,cb_pfcns);\r
-\r
-\r
- for(w=0;w<cleanwhen.size();++w){\r
- sprintf(tmpstr,"//\t\tPredicate clause %d.\n",w);\r
- ret += tmpstr;\r
-\r
-/*\r
-// Find the set of variables accessed in this CNF elem,\r
-// but in no previous element.\r
- col_id_set new_cids;\r
- get_new_pred_cids(cleanby[w]->pr, found_cids, new_cids, segen_gb_tbl);\r
-\r
-// Unpack these values.\r
- ret += gen_unpack_cids(schema, new_cids, "false", needs_xform);\r
-*/\r
-\r
-// Find partial fcns ref'd in this cnf element\r
- set<int> pfcn_refs;\r
- collect_partial_fcns_pr(cleanby[w]->pr, pfcn_refs);\r
- for(pfsi=pfcn_refs.begin();pfsi!=pfcn_refs.end();++pfsi){\r
- ret += unpack_partial_fcn_fm_aggr(partial_fcns[(*pfsi)], (*pfsi), gbvar, aggvar, schema);\r
- ret += "\tif(retval){ return false;}\n";\r
- }\r
-// ret += gen_unpack_partial_fcn(schema, partial_fcns, pfcn_refs,"false");\r
-\r
- ret += "\tif( !("+generate_predicate_code_fm_aggr(cleanby[w]->pr,gbvar, aggvar, schema)+\r
- +") ) retval = false;\n";\r
- }\r
-\r
- ret += "\treturn retval;\n";\r
- ret += "\t};\n";\r
-\r
-\r
-//-----------------------------------------------------\r
-//\r
- ret += "bool final_sample_group("\r
- +generate_functor_name()+"_groupdef *gbval, "+\r
- generate_functor_name()+"_aggrdef *aggval,"+\r
- generate_functor_name()+"_statedef *stval,"+\r
- "int cd){\n";\r
-\r
- ret += "\tgs_retval_t retval = 0;\n";\r
-\r
-// Find the udafs ref'd in the having clause\r
- set<int> hv_aggs;\r
- for(w=0;w<having.size();++w)\r
- collect_aggr_refs_pr(having[w]->pr, hv_aggs);\r
-\r
-\r
-// get the return values from the UDAFS\r
- for(a=0;a<aggr_tbl.size();a++){\r
- if(! aggr_tbl.is_builtin(a) && hv_aggs.count(a)){\r
- ret += "\t"+aggr_tbl.get_op(a)+"_HFTA_AGGR_OUTPUT_(&(udaf_ret_"+int_to_string(a)+"),";\r
- if(aggr_tbl.get_storage_type(a)->get_type() != fstring_t) ret+="&";\r
- ret+="("+aggvar+"aggr_var"+int_to_string(a)+"));\n";\r
- }\r
- }\r
-\r
-\r
- set<int> hv_sl_pfcns;\r
- for(w=0;w<having.size();w++){\r
- collect_partial_fcns_pr(having[w]->pr, hv_sl_pfcns);\r
- }\r
-\r
-// clean up the partial fcn results from any previous execution\r
- ret += gen_partial_fcn_dtr(partial_fcns,hv_sl_pfcns);\r
-\r
-// Unpack them now\r
- for(pfsi=hv_sl_pfcns.begin();pfsi!=hv_sl_pfcns.end();++pfsi){\r
- ret += unpack_partial_fcn_fm_aggr(partial_fcns[(*pfsi)], (*pfsi), gbvar, aggvar, schema);\r
- ret += "\tif(retval){ return false;}\n";\r
- }\r
-\r
-// Evalaute the HAVING clause\r
-// TODO: this seems to have a ++ operator rather than a + operator.\r
- for(w=0;w<having.size();++w){\r
- ret += "\tif( !("+generate_predicate_code_fm_aggr(having[w]->pr,gbvar, aggvar, schema) +") ) { return false;}\n";\r
- }\r
-\r
- ret += "\treturn true;\n";\r
- ret+="}\n\n";\r
-\r
-//---------------------------------------------------\r
-// create output tuple\r
-// Unpack the partial functions ref'd in the where clause,\r
-// select clause. Evaluate the where clause.\r
-// Finally, pack the tuple.\r
-\r
-// I need to use special code generation here,\r
-// so I'll leave it in longhand.\r
-\r
- ret += "host_tuple create_output_tuple("\r
- +generate_functor_name()+"_groupdef *gbval, "+\r
- generate_functor_name()+"_aggrdef *aggval,"+\r
- generate_functor_name()+"_statedef *stval,"+\r
- "int cd, bool &failed){\n";\r
-\r
- ret += "\thost_tuple tup;\n";\r
- ret += "\tfailed = false;\n";\r
- ret += "\tgs_retval_t retval = 0;\n";\r
-\r
-\r
-// Find the udafs ref'd in the select clause\r
- set<int> sl_aggs;\r
- for(s=0;s<select_list.size();s++)\r
- collect_agg_refs(select_list[s]->se, sl_aggs);\r
-\r
-\r
-// get the return values from the UDAFS\r
- for(a=0;a<aggr_tbl.size();a++){\r
- if(! aggr_tbl.is_builtin(a) && sl_aggs.count(a)){\r
- ret += "\t"+aggr_tbl.get_op(a)+"_HFTA_AGGR_OUTPUT_(&(udaf_ret_"+int_to_string(a)+"),";\r
- if(aggr_tbl.get_storage_type(a)->get_type() != fstring_t) ret+="&";\r
- ret+="("+aggvar+"aggr_var"+int_to_string(a)+"));\n";\r
- }\r
- }\r
-\r
-\r
-// I can't cache partial fcn results from the having\r
-// clause because evaluation is separated.\r
- set<int> sl_pfcns;\r
- for(s=0;s<select_list.size();s++){\r
- collect_partial_fcns(select_list[s]->se, sl_pfcns);\r
- }\r
-// Unpack them now\r
- for(pfsi=sl_pfcns.begin();pfsi!=sl_pfcns.end();++pfsi){\r
- ret += unpack_partial_fcn_fm_aggr(partial_fcns[(*pfsi)], (*pfsi), gbvar, aggvar, schema);\r
- ret += "\tif(retval){ failed=true; return tup;}\n";\r
- }\r
-\r
-\r
-// Now, compute the size of the tuple.\r
-\r
-// Unpack any BUFFER type selections into temporaries\r
-// so that I can compute their size and not have\r
-// to recompute their value during tuple packing.\r
-// I can use regular assignment here because\r
-// these temporaries are non-persistent.\r
-// TODO: should I be using the selvar generation routine?\r
-\r
- ret += "//\t\tCompute the size of the tuple.\n";\r
- ret += "//\t\t\tNote: buffer storage packed at the end of the tuple.\n";\r
- for(s=0;s<select_list.size();s++){\r
- scalarexp_t *se = select_list[s]->se;\r
- data_type *sdt = se->get_data_type();\r
- if(sdt->is_buffer_type() &&\r
- !( (se->get_operator_type() == SE_COLREF) ||\r
- (se->get_operator_type() == SE_AGGR_STAR) ||\r
- (se->get_operator_type() == SE_AGGR_SE) ||\r
- (se->get_operator_type() == SE_FUNC && se->is_partial()) ||\r
- (se->get_operator_type() == SE_FUNC && se->get_aggr_ref() >= 0))\r
- ){\r
- sprintf(tmpstr,"selvar_%d",s);\r
- ret+="\t"+sdt->make_host_cvar(tmpstr)+" = ";\r
- ret += generate_se_code_fm_aggr(se,gbvar, aggvar, schema) +";\n";\r
- }\r
- }\r
-\r
-// The size of the tuple is the size of the tuple struct plus the\r
-// size of the buffers to be copied in.\r
-\r
- ret+="\ttup.tuple_size = sizeof(" + generate_tuple_name( this->get_node_name()) +") + sizeof(gs_uint8_t)";\r
- for(s=0;s<select_list.size();s++){\r
-// if(s>0) ret += "+";\r
- scalarexp_t *se = select_list[s]->se;\r
- data_type *sdt = select_list[s]->se->get_data_type();\r
- if(sdt->is_buffer_type()){\r
- if(!( (se->get_operator_type() == SE_COLREF) ||\r
- (se->get_operator_type() == SE_AGGR_STAR) ||\r
- (se->get_operator_type() == SE_AGGR_SE) ||\r
- (se->get_operator_type() == SE_FUNC && se->is_partial()) ||\r
- (se->get_operator_type() == SE_FUNC && se->get_aggr_ref() >= 0))\r
- ){\r
- sprintf(tmpstr," + %s(&selvar_%d)", sdt->get_hfta_buffer_size().c_str(),s);\r
- ret.append(tmpstr);\r
- }else{\r
- sprintf(tmpstr," + %s(&%s)", sdt->get_hfta_buffer_size().c_str(),generate_se_code_fm_aggr(se,gbvar, aggvar, schema).c_str());\r
- ret.append(tmpstr);\r
- }\r
- }\r
- }\r
- ret.append(";\n");\r
-\r
-// Allocate tuple data block.\r
- ret += "//\t\tCreate the tuple block.\n";\r
- ret += "\ttup.data = malloc(tup.tuple_size);\n";\r
- ret += "\ttup.heap_resident = true;\n";\r
-\r
-// Mark tuple as regular\r
- ret += "\t*((gs_sp_t )tup.data + sizeof(" + generate_tuple_name( this->get_node_name()) +")) = REGULAR_TUPLE;\n";\r
-\r
-// ret += "\ttup.channel = 0;\n";\r
- ret += "\t"+generate_tuple_name( this->get_node_name())+" *tuple = ("+\r
- generate_tuple_name( this->get_node_name())+" *)(tup.data);\n";\r
-\r
-// Start packing.\r
-// (Here, offsets are hard-wired. is this a problem?)\r
-\r
- ret += "//\t\tPack the fields into the tuple.\n";\r
- ret += "\tint tuple_pos = sizeof("+generate_tuple_name( this->get_node_name()) +") + sizeof(gs_uint8_t);\n";\r
- for(s=0;s<select_list.size();s++){\r
- scalarexp_t *se = select_list[s]->se;\r
- data_type *sdt = se->get_data_type();\r
- if(sdt->is_buffer_type()){\r
- if(!( (se->get_operator_type() == SE_COLREF) ||\r
- (se->get_operator_type() == SE_AGGR_STAR) ||\r
- (se->get_operator_type() == SE_AGGR_SE) ||\r
- (se->get_operator_type() == SE_FUNC && se->is_partial()) ||\r
- (se->get_operator_type() == SE_FUNC && se->get_aggr_ref() >= 0))\r
- ){\r
- sprintf(tmpstr,"\t%s(&(tuple->tuple_var%d), &selvar_%d, ((gs_sp_t )tuple)+tuple_pos, tuple_pos);\n", sdt->get_hfta_buffer_tuple_copy().c_str(),s, s);\r
- ret.append(tmpstr);\r
- sprintf(tmpstr,"\ttuple_pos += %s(&selvar_%d);\n", sdt->get_hfta_buffer_size().c_str(), s);\r
- ret.append(tmpstr);\r
- }else{\r
- sprintf(tmpstr,"\t%s(&(tuple->tuple_var%d), &%s, ((gs_sp_t )tuple)+tuple_pos, tuple_pos);\n", sdt->get_hfta_buffer_tuple_copy().c_str(),s, generate_se_code_fm_aggr(se,gbvar, aggvar, schema).c_str());\r
- ret.append(tmpstr);\r
- sprintf(tmpstr,"\ttuple_pos += %s(&%s);\n", sdt->get_hfta_buffer_size().c_str(), generate_se_code_fm_aggr(se,gbvar, aggvar, schema).c_str());\r
- ret.append(tmpstr);\r
- }\r
- }else{\r
- sprintf(tmpstr,"\ttuple->tuple_var%d = ",s);\r
- ret.append(tmpstr);\r
- ret.append(generate_se_code_fm_aggr(se,gbvar, aggvar, schema) );\r
- ret.append(";\n");\r
- }\r
- }\r
-\r
-// Destroy string temporaries\r
- ret += gen_buffer_selvars_dtr(select_list);\r
-// Destroy string return vals of UDAFs\r
- for(a=0;a<aggr_tbl.size();a++){\r
- if(! aggr_tbl.is_builtin(a)){\r
- int afcn_id = aggr_tbl.get_fcn_id(a);\r
- data_type *adt = Ext_fcns->get_fcn_dt(afcn_id);\r
- if(adt->is_buffer_type()){\r
- sprintf(tmpstr,"\t%s(&udaf_ret_%d);\n",\r
- adt->get_hfta_buffer_destroy().c_str(), a );\r
- ret += tmpstr;\r
- }\r
- }\r
- }\r
-\r
-\r
- ret += "\treturn tup;\n";\r
- ret += "};\n";\r
-\r
-\r
-//-------------------------------------------------------------------\r
-// Temporal update functions\r
-\r
- ret+="bool temp_status_received(){return temp_tuple_received;};\n\n";\r
-\r
-// create a temp status tuple\r
- ret += "int create_temp_status_tuple(host_tuple& result, bool flush_finished) {\n\n";\r
-\r
- ret += gen_init_temp_status_tuple(this->get_node_name());\r
-\r
-// Start packing.\r
-// (Here, offsets are hard-wired. is this a problem?)\r
-\r
- ret += "//\t\tPack the fields into the tuple.\n";\r
- for(s=0;s<select_list.size();s++){\r
- data_type *sdt = select_list[s]->se->get_data_type();\r
- if(sdt->is_temporal()){\r
- sprintf(tmpstr,"\ttuple->tuple_var%d = ",s);\r
- ret += tmpstr;\r
- sprintf(tmpstr,"(flush_finished) ? %s : %s ", generate_se_code(select_list[s]->se,schema).c_str(), generate_se_code_fm_aggr(select_list[s]->se,"last_flushed_gb", "", schema).c_str());\r
- ret += tmpstr;\r
- ret += ";\n";\r
- }\r
- }\r
-\r
- ret += "\treturn 0;\n";\r
- ret += "};};\n\n\n";\r
-\r
-\r
-//----------------------------------------------------------\r
-// The hash function\r
-\r
- ret += "struct "+generate_functor_name()+"_hash_func{\n";\r
- ret += "\tgs_uint32_t operator()(const "+generate_functor_name()+\r
- "_groupdef *grp) const{\n";\r
- ret += "\t\treturn(";\r
- for(g=0;g<gb_tbl.size();g++){\r
- if(g>0) ret += "^";\r
- data_type *gdt = gb_tbl.get_data_type(g);\r
- if(gdt->use_hashfunc()){\r
- if(gdt->is_buffer_type())\r
- sprintf(tmpstr,"(%s*%s(&)grp->gb_var%d)))",hash_nums[g%NRANDS].c_str(),gdt->get_hfta_hashfunc().c_str(),g);\r
- else\r
- sprintf(tmpstr,"(%s*%s(grp->gb_var%d))",hash_nums[g%NRANDS].c_str(),gdt->get_hfta_hashfunc().c_str(),g);\r
- }else{\r
- sprintf(tmpstr,"(%s*grp->gb_var%d)",hash_nums[g%NRANDS].c_str(),g);\r
- }\r
- ret += tmpstr;\r
- }\r
- ret += ") >> 32);\n";\r
- ret += "\t}\n";\r
- ret += "};\n\n";\r
-\r
-//----------------------------------------------------------\r
-// The superhash function\r
-\r
- ret += "struct "+generate_functor_name()+"_superhash_func{\n";\r
- ret += "\tgs_uint32_t operator()(const "+generate_functor_name()+\r
- "_groupdef *grp) const{\n";\r
- ret += "\t\treturn(0";\r
-\r
- for(g=0;g<gb_tbl.size();g++){\r
- if(sg_tbl.count(g)>0){\r
- ret += "^";\r
- data_type *gdt = gb_tbl.get_data_type(g);\r
- if(gdt->use_hashfunc()){\r
- sprintf(tmpstr,"(%s*%s(&(grp->gb_var%d)))",hash_nums[g%NRANDS].c_str(),gdt->get_hfta_hashfunc().c_str(),g);\r
- }else{\r
- sprintf(tmpstr,"(%s*grp->gb_var%d)",hash_nums[g%NRANDS].c_str(),g);\r
- }\r
- ret += tmpstr;\r
- }\r
- }\r
- ret += ") >> 32);\n";\r
-\r
- ret += "\t}\n";\r
- ret += "};\n\n";\r
-\r
-//----------------------------------------------------------\r
-// The comparison function\r
-\r
- ret += "struct "+generate_functor_name()+"_equal_func{\n";\r
- ret += "\tbool operator()(const "+generate_functor_name()+"_groupdef *grp1, "+\r
- generate_functor_name()+"_groupdef *grp2) const{\n";\r
- ret += "\t\treturn( (";\r
- for(g=0;g<gb_tbl.size();g++){\r
- if(g>0) ret += ") && (";\r
- data_type *gdt = gb_tbl.get_data_type(g);\r
- if(gdt->complex_comparison(gdt)){\r
- if(gdt->is_buffer_type())\r
- sprintf(tmpstr,"(%s(&(grp1->gb_var%d), &(grp2->gb_var%d))==0)",\r
- gdt->get_hfta_comparison_fcn(gdt).c_str(),g,g);\r
- else\r
- sprintf(tmpstr,"(%s((grp1->gb_var%d), (grp2->gb_var%d))==0)",\r
- gdt->get_hfta_comparison_fcn(gdt).c_str(),g,g);\r
- }else{\r
- sprintf(tmpstr,"grp1->gb_var%d == grp2->gb_var%d",g,g);\r
- }\r
- ret += tmpstr;\r
- }\r
- ret += ") );\n";\r
- ret += "\t}\n";\r
- ret += "};\n\n";\r
-\r
-\r
-//----------------------------------------------------------\r
-// The superhashcomparison function\r
-\r
- ret += "struct "+generate_functor_name()+"_superequal_func{\n";\r
- ret += "\tbool operator()(const "+generate_functor_name()+"_groupdef *grp1, "+\r
- generate_functor_name()+"_groupdef *grp2) const{\n";\r
- ret += "\t\treturn( (";\r
- if(sg_tbl.size()){\r
- bool first_elem = true;\r
- for(g=0;g<gb_tbl.size();g++){\r
- if(sg_tbl.count(g)){\r
- if(first_elem) first_elem=false; else ret += ") && (";\r
- data_type *gdt = gb_tbl.get_data_type(g);\r
- if(gdt->complex_comparison(gdt)){\r
- if(gdt->is_buffer_type())\r
- sprintf(tmpstr,"(%s(&(grp1->gb_var%d), &(grp2->gb_var%d))==0)",\r
- gdt->get_hfta_comparison_fcn(gdt).c_str(),g,g);\r
- else\r
- sprintf(tmpstr,"(%s((grp1->gb_var%d), (grp2->gb_var%d))==0)",\r
- gdt->get_hfta_comparison_fcn(gdt).c_str(),g,g);\r
- }else{\r
- sprintf(tmpstr,"grp1->gb_var%d == grp2->gb_var%d",g,g);\r
- }\r
- ret += tmpstr;\r
- }\r
- }\r
- }else{\r
- ret += "true";\r
- }\r
-\r
- ret += ") );\n";\r
- ret += "\t}\n";\r
-\r
-\r
- ret += "};\n\n";\r
- return(ret);\r
-}\r
-\r
-string sgahcwcb_qpn::generate_operator(int i, string params){\r
-\r
- return(\r
- " clean_operator<" +\r
- generate_functor_name()+",\n\t"+\r
- generate_functor_name() + "_groupdef, \n\t" +\r
- generate_functor_name() + "_aggrdef, \n\t" +\r
- generate_functor_name() + "_statedef, \n\t" +\r
- generate_functor_name()+"_hash_func, \n\t"+\r
- generate_functor_name()+"_equal_func ,\n\t"+\r
- generate_functor_name()+"_superhash_func,\n\t "+\r
- generate_functor_name()+"_superequal_func \n\t"+\r
- "> *op"+int_to_string(i)+" = new clean_operator<"+\r
- generate_functor_name()+",\n\t"+\r
- generate_functor_name() + "_groupdef,\n\t " +\r
- generate_functor_name() + "_aggrdef, \n\t" +\r
- generate_functor_name() + "_statedef, \n\t" +\r
- generate_functor_name()+"_hash_func, \n\t"+\r
- generate_functor_name()+"_equal_func, \n\t"+\r
- generate_functor_name()+"_superhash_func, \n\t"+\r
- generate_functor_name()+"_superequal_func\n\t "\r
- ">("+params+", \"" + get_node_name() + "\");\n"\r
- );\r
-}\r
-\r
-////////////////////////////////////////////////////////////////\r
-//// RSGAH functor\r
-\r
-\r
-\r
-string rsgah_qpn::generate_functor_name(){\r
- return("rsgah_functor_" + normalize_name(this->get_node_name()));\r
-}\r
-\r
-\r
-string rsgah_qpn::generate_functor(table_list *schema, ext_fcn_list *Ext_fcns, vector<bool> &needs_xform){\r
- int a,g,w,s;\r
-\r
-\r
-// Initialize generate utility globals\r
- segen_gb_tbl = &(gb_tbl);\r
-\r
-\r
-//--------------------------------\r
-// group definition class\r
- string ret = "class " + generate_functor_name() + "_groupdef{\n";\r
- ret += "public:\n";\r
- for(g=0;g<this->gb_tbl.size();g++){\r
- sprintf(tmpstr,"gb_var%d",g);\r
- ret+="\t"+this->gb_tbl.get_data_type(g)->make_host_cvar(tmpstr)+";\n";\r
- }\r
-// Constructors\r
- ret += "\t"+generate_functor_name() + "_groupdef(){};\n";\r
- ret += "\t"+generate_functor_name() + "_groupdef("+\r
- this->generate_functor_name() + "_groupdef *gd){\n";\r
- for(g=0;g<gb_tbl.size();g++){\r
- data_type *gdt = gb_tbl.get_data_type(g);\r
- if(gdt->is_buffer_type()){\r
- sprintf(tmpstr,"\t\t%s(&gb_var%d, &(gd->gb_var%d));\n",\r
- gdt->get_hfta_buffer_assign_copy().c_str(),g,g );\r
- ret += tmpstr;\r
- }else{\r
- sprintf(tmpstr,"\t\tgb_var%d = gd->gb_var%d;\n",g,g);\r
- ret += tmpstr;\r
- }\r
- }\r
- ret += "\t};\n";\r
-// destructor\r
- ret += "\t~"+ generate_functor_name() + "_groupdef(){\n";\r
- for(g=0;g<gb_tbl.size();g++){\r
- data_type *gdt = gb_tbl.get_data_type(g);\r
- if(gdt->is_buffer_type()){\r
- sprintf(tmpstr,"\t\t%s(&gb_var%d);\n",\r
- gdt->get_hfta_buffer_destroy().c_str(), g );\r
- ret += tmpstr;\r
- }\r
- }\r
- ret += "\t};\n";\r
- ret +="};\n\n";\r
-\r
-//--------------------------------\r
-// aggr definition class\r
- ret += "class " + this->generate_functor_name() + "_aggrdef{\n";\r
- ret += "public:\n";\r
- for(a=0;a<aggr_tbl.size();a++){\r
-aggr_table_entry *ate = aggr_tbl.agr_tbl[a];\r
- sprintf(tmpstr,"aggr_var%d",a);\r
- if(aggr_tbl.is_builtin(a))\r
- ret+="\t"+ aggr_tbl.get_data_type(a)->make_host_cvar(tmpstr)+";\n";\r
- else\r
- ret+="\t"+ aggr_tbl.get_storage_type(a)->make_host_cvar(tmpstr)+";\n";\r
- }\r
-// Constructors\r
- ret += "\t"+this->generate_functor_name() + "_aggrdef(){};\n";\r
-// destructor\r
- ret += "\t~"+this->generate_functor_name() + "_aggrdef(){\n";\r
- for(a=0;a<aggr_tbl.size();a++){\r
- if(aggr_tbl.is_builtin(a)){\r
- data_type *adt = aggr_tbl.get_data_type(a);\r
- if(adt->is_buffer_type()){\r
- sprintf(tmpstr,"\t\t%s(&aggr_var%d);\n",\r
- adt->get_hfta_buffer_destroy().c_str(), a );\r
- ret += tmpstr;\r
- }\r
- }else{\r
- ret+="\t\t"+aggr_tbl.get_op(a)+"_HFTA_AGGR_DESTROY_(";\r
- if(aggr_tbl.get_storage_type(a)->get_type() != fstring_t) ret+="&";\r
- ret+="(aggr_var"+int_to_string(a)+"));\n";\r
- }\r
- }\r
- ret += "\t};\n";\r
- ret +="};\n\n";\r
-\r
-//--------------------------------\r
-// gb functor class\r
- ret += "class " + this->generate_functor_name() + "{\n";\r
-\r
-// Find variables referenced in this query node.\r
-\r
- col_id_set cid_set;\r
- col_id_set::iterator csi;\r
-\r
- for(w=0;w<where.size();++w)\r
- gather_pr_col_ids(where[w]->pr,cid_set,segen_gb_tbl);\r
- for(w=0;w<having.size();++w)\r
- gather_pr_col_ids(having[w]->pr,cid_set,segen_gb_tbl);\r
- for(w=0;w<closing_when.size();++w)\r
- gather_pr_col_ids(closing_when[w]->pr,cid_set,segen_gb_tbl);\r
- for(g=0;g<gb_tbl.size();g++)\r
- gather_se_col_ids(gb_tbl.get_def(g),cid_set,segen_gb_tbl);\r
-\r
- for(s=0;s<select_list.size();s++){\r
- gather_se_col_ids(select_list[s]->se,cid_set,segen_gb_tbl); // descends into aggregates\r
- }\r
-\r
-\r
-// Private variables : store the state of the functor.\r
-// 1) variables for unpacked attributes\r
-// 2) offsets of the upacked attributes\r
-// 3) storage of partial functions\r
-// 4) storage of complex literals (i.e., require a constructor)\r
-\r
- ret += "private:\n";\r
-\r
- // var to save the schema handle\r
- ret += "\tint schema_handle0;\n";\r
-\r
- // generate the declaration of all the variables related to\r
- // temp tuples generation\r
- ret += gen_decl_temp_vars();\r
-\r
-// unpacked attribute storage, offsets\r
- ret += "//\t\tstorage and offsets of accessed fields.\n";\r
- ret += generate_access_vars(cid_set, schema);\r
-// tuple metadata offset\r
- ret += "\tint tuple_metadata_offset0;\n";\r
-\r
-// Variables to store results of partial functions.\r
-// WARNING find_partial_functions modifies the SE\r
-// (it marks the partial function id).\r
- ret += "//\t\tParital function result storage\n";\r
- vector<scalarexp_t *> partial_fcns;\r
- vector<int> fcn_ref_cnt;\r
- vector<bool> is_partial_fcn;\r
- for(s=0;s<select_list.size();s++){\r
- find_partial_fcns(select_list[s]->se, &partial_fcns, NULL,NULL, Ext_fcns);\r
- }\r
- for(w=0;w<where.size();w++){\r
- find_partial_fcns_pr(where[w]->pr, &partial_fcns, NULL,NULL, Ext_fcns);\r
- }\r
- for(w=0;w<having.size();w++){\r
- find_partial_fcns_pr(having[w]->pr, &partial_fcns, NULL,NULL, Ext_fcns);\r
- }\r
- for(w=0;w<closing_when.size();w++){\r
- find_partial_fcns_pr(closing_when[w]->pr, &partial_fcns, NULL,NULL, Ext_fcns);\r
- }\r
- for(g=0;g<gb_tbl.size();g++){\r
- find_partial_fcns(gb_tbl.get_def(g), &partial_fcns, NULL,NULL, Ext_fcns);\r
- }\r
- for(a=0;a<aggr_tbl.size();a++){\r
- find_partial_fcns(aggr_tbl.get_aggr_se(a), &partial_fcns, NULL,NULL, Ext_fcns);\r
- }\r
- if(partial_fcns.size()>0){\r
- ret += "/*\t\tVariables for storing results of partial functions. \t*/\n";\r
- ret += generate_partial_fcn_vars(partial_fcns,fcn_ref_cnt,is_partial_fcn,false);\r
- }\r
-\r
-// Create cached temporaries for UDAF return values.\r
- for(a=0;a<aggr_tbl.size();a++){\r
- if(! aggr_tbl.is_builtin(a)){\r
- int afcn_id = aggr_tbl.get_fcn_id(a);\r
- data_type *adt = Ext_fcns->get_fcn_dt(afcn_id);\r
- sprintf(tmpstr,"udaf_ret_%d", a);\r
- ret+="\t"+adt->make_host_cvar(tmpstr)+";\n";\r
- }\r
- }\r
-\r
-\r
-// Complex literals (i.e., they need constructors)\r
- ret += "//\t\tComplex literal storage.\n";\r
- cplx_lit_table *complex_literals = this->get_cplx_lit_tbl(Ext_fcns);\r
- ret += generate_complex_lit_vars(complex_literals);\r
-\r
-// Pass-by-handle parameters\r
- ret += "//\t\tPass-by-handle storage.\n";\r
- vector<handle_param_tbl_entry *> param_handle_table = this->get_handle_param_tbl(Ext_fcns);\r
- ret += generate_pass_by_handle_vars(param_handle_table);\r
-\r
-\r
-// variables to hold parameters.\r
- ret += "//\tfor query parameters\n";\r
- ret += generate_param_vars(param_tbl);\r
-\r
-// Is there a temporal flush? If so create flush temporaries,\r
-// create flush indicator.\r
- bool uses_temporal_flush = false;\r
- for(g=0;g<gb_tbl.size();g++){\r
- data_type *gdt = gb_tbl.get_data_type(g);\r
- if(gdt->is_temporal())\r
- uses_temporal_flush = true;\r
- }\r
-\r
- if(uses_temporal_flush){\r
- ret += "//\t\tFor temporal flush\n";\r
- for(g=0;g<gb_tbl.size();g++){\r
- data_type *gdt = gb_tbl.get_data_type(g);\r
- if(gdt->is_temporal()){\r
- sprintf(tmpstr,"last_gb%d",g);\r
- ret+="\t"+gb_tbl.get_data_type(g)->make_host_cvar(tmpstr)+";\n";\r
- sprintf(tmpstr,"last_flushed_gb%d",g);\r
- ret+="\t"+gb_tbl.get_data_type(g)->make_host_cvar(tmpstr)+";\n";\r
- }\r
- }\r
- ret += "\tbool needs_temporal_flush;\n";\r
- }\r
-\r
-// The publicly exposed functions\r
-\r
- ret += "\npublic:\n";\r
-\r
-\r
-//-------------------\r
-// The functor constructor\r
-// pass in the schema handle.\r
-// 1) make assignments to the unpack offset variables\r
-// 2) initialize the complex literals\r
-\r
- ret += "//\t\tFunctor constructor.\n";\r
- ret += this->generate_functor_name()+"(int schema_handle0){\n";\r
-\r
- // save the schema handle\r
- ret += "\t\tthis->schema_handle0 = schema_handle0;\n";\r
-// metadata offset\r
- ret += "\ttuple_metadata_offset0 = ftaschema_get_tuple_metadata_offset(schema_handle0);\n";\r
-\r
-// unpack vars\r
- ret += "//\t\tGet offsets for unpacking fields from input tuple.\n";\r
- ret += gen_access_var_init(cid_set);\r
-\r
-// complex literals\r
- ret += "//\t\tInitialize complex literals.\n";\r
- ret += gen_complex_lit_init(complex_literals);\r
-\r
-// Initialize partial function results so they can be safely GC'd\r
- ret += gen_partial_fcn_init(partial_fcns);\r
-\r
-// Initialize non-query-parameter parameter handles\r
- ret += gen_pass_by_handle_init(param_handle_table);\r
-\r
-// temporal flush variables\r
-// ASSUME that structured values won't be temporal.\r
- if(uses_temporal_flush){\r
- ret += "//\t\tInitialize temporal flush variables.\n";\r
- for(g=0;g<gb_tbl.size();g++){\r
- data_type *gdt = gb_tbl.get_data_type(g);\r
- if(gdt->is_temporal()){\r
- literal_t gl(gdt->type_indicator());\r
- sprintf(tmpstr,"\tlast_gb%d = %s;\n",g, gl.to_hfta_C_code("").c_str());\r
- ret.append(tmpstr);\r
- }\r
- }\r
- ret += "\tneeds_temporal_flush = false;\n";\r
- }\r
-\r
- // Init temporal attributes referenced in select list\r
- ret += gen_init_temp_vars(schema, select_list, segen_gb_tbl);\r
-\r
- ret += "};\n";\r
-\r
-\r
-//-------------------\r
-// Functor destructor\r
- ret += "//\t\tFunctor destructor.\n";\r
- ret += "~"+this->generate_functor_name()+"(){\n";\r
-\r
-// clean up buffer type complex literals\r
- ret += gen_complex_lit_dtr(complex_literals);\r
-\r
-// Deregister the pass-by-handle parameters\r
- ret += "/* register and de-register the pass-by-handle parameters */\n";\r
- ret += gen_pass_by_handle_dtr(param_handle_table);\r
-\r
-// clean up partial function results.\r
- ret += "/* clean up partial function storage */\n";\r
- ret += gen_partial_fcn_dtr(partial_fcns);\r
-\r
-// Destroy the parameters, if any need to be destroyed\r
- ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";\r
-\r
- ret += "};\n\n";\r
-\r
-\r
-//-------------------\r
-// Parameter manipulation routines\r
- ret += generate_load_param_block(this->generate_functor_name(),\r
- this->param_tbl,param_handle_table);\r
- ret += generate_delete_param_block(this->generate_functor_name(),\r
- this->param_tbl,param_handle_table);\r
-\r
-//-------------------\r
-// Register new parameter block\r
-\r
- ret += "int set_param_block(gs_int32_t sz, void* value){\n";\r
- ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";\r
- ret += "\treturn this->load_params_"+this->generate_functor_name()+\r
- "(sz, value);\n";\r
- ret += "};\n\n";\r
-\r
-\r
-//-------------------\r
-// the create_group method.\r
-// This method creates a group in a buffer passed in\r
-// (to allow for creation on the stack).\r
-// There are also a couple of side effects:\r
-// 1) evaluate the WHERE clause (and therefore, unpack all partial fcns)\r
-// 2) determine if a temporal flush is required.\r
-\r
- ret += this->generate_functor_name()+"_groupdef *create_group(host_tuple &tup0, gs_sp_t buffer){\n";\r
- // Variables for execution of the function.\r
- ret += "\tgs_int32_t problem = 0;\n"; // return unpack failure\r
-\r
- if(partial_fcns.size()>0){ // partial fcn access failure\r
- ret += "\tgs_retval_t retval = 0;\n";\r
- ret += "\n";\r
- }\r
-// return value\r
- ret += "\t"+generate_functor_name()+"_groupdef *gbval = ("+generate_functor_name()+\r
- "_groupdef *) buffer;\n";\r
-\r
-// Start by cleaning up partial function results\r
- ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";\r
- set<int> w_pfcns; // partial fcns in where clause\r
- for(w=0;w<where.size();++w)\r
- collect_partial_fcns_pr(where[w]->pr, w_pfcns);\r
-\r
- set<int> ag_gb_pfcns; // partial fcns in gbdefs, aggr se's\r
- for(g=0;g<gb_tbl.size();g++){\r
- collect_partial_fcns(gb_tbl.get_def(g), ag_gb_pfcns);\r
- }\r
- for(a=0;a<aggr_tbl.size();a++){\r
- collect_partial_fcns(aggr_tbl.get_aggr_se(a), ag_gb_pfcns);\r
- }\r
- ret += gen_partial_fcn_dtr(partial_fcns,w_pfcns);\r
- ret += gen_partial_fcn_dtr(partial_fcns,ag_gb_pfcns);\r
-// ret += gen_partial_fcn_dtr(partial_fcns);\r
-\r
-\r
- ret += gen_temp_tuple_check(this->node_name, 0);\r
- col_id_set found_cids; // colrefs unpacked thus far.\r
- ret += gen_unpack_temp_vars(schema, found_cids, select_list, segen_gb_tbl, needs_xform);\r
-\r
-\r
-// Save temporal group-by variables\r
-\r
-\r
- ret.append("\n\t//\t\tCompute temporal groupby attributes\n\n");\r
-\r
- for(g=0;g<gb_tbl.size();g++){\r
-\r
- data_type *gdt = gb_tbl.get_data_type(g);\r
-\r
- if(gdt->is_temporal()){\r
- sprintf(tmpstr,"\tgbval->gb_var%d = %s;\n",\r
- g, generate_se_code(gb_tbl.get_def(g),schema).c_str() );\r
- ret.append(tmpstr);\r
- }\r
- }\r
- ret.append("\n");\r
-\r
-\r
-\r
-// Compare the temporal GB vars with the stored ones,\r
-// set flush indicator and update stored GB vars if there is any change.\r
-\r
- if(uses_temporal_flush){\r
- ret+= "\tif( !( (";\r
- bool first_one = true;\r
- for(g=0;g<gb_tbl.size();g++){\r
- data_type *gdt = gb_tbl.get_data_type(g);\r
-\r
- if(gdt->is_temporal()){\r
- sprintf(tmpstr,"last_gb%d",g); string lhs_op = tmpstr;\r
- sprintf(tmpstr,"gbval->gb_var%d",g); string rhs_op = tmpstr;\r
- if(first_one){first_one = false;} else {ret += ") && (";}\r
- ret += generate_equality_test(lhs_op, rhs_op, gdt);\r
- }\r
- }\r
- ret += ") ) ){\n";\r
- for(g=0;g<gb_tbl.size();g++){\r
- data_type *gdt = gb_tbl.get_data_type(g);\r
- if(gdt->is_temporal()){\r
- if(gdt->is_buffer_type()){\r
- sprintf(tmpstr,"\t\t%s(&(gbval->gb_var%d),&last_gb%d);\n",gdt->get_hfta_buffer_replace().c_str(),g,g);\r
- }else{\r
- sprintf(tmpstr,"\t\tlast_flushed_gb%d = last_gb%d;\n",g,g);\r
- ret += tmpstr;\r
- sprintf(tmpstr,"\t\tlast_gb%d = gbval->gb_var%d;\n",g,g);\r
- }\r
- ret += tmpstr;\r
- }\r
- }\r
- ret += "\t\tneeds_temporal_flush=true;\n";\r
- ret += "\t\t}else{\n"\r
- "\t\t\tneeds_temporal_flush=false;\n"\r
- "\t\t}\n";\r
- }\r
-\r
-\r
-// For temporal status tuple we don't need to do anything else\r
- ret += "\tif (temp_tuple_received) return NULL;\n\n";\r
-\r
- for(w=0;w<where.size();++w){\r
- sprintf(tmpstr,"//\t\tPredicate clause %d.\n",w);\r
- ret += tmpstr;\r
-// Find the set of variables accessed in this CNF elem,\r
-// but in no previous element.\r
- col_id_set new_cids;\r
- get_new_pred_cids(where[w]->pr, found_cids, new_cids, segen_gb_tbl);\r
-\r
-// Unpack these values.\r
- ret += gen_unpack_cids(schema, new_cids, "NULL", needs_xform);\r
-// Find partial fcns ref'd in this cnf element\r
- set<int> pfcn_refs;\r
- collect_partial_fcns_pr(where[w]->pr, pfcn_refs);\r
- ret += gen_unpack_partial_fcn(schema, partial_fcns, pfcn_refs,"NULL");\r
-\r
- ret += "\tif( !("+generate_predicate_code(where[w]->pr,schema)+\r
- +") ) return(NULL);\n";\r
- }\r
-\r
-// The partial functions ref'd in the group-by var and aggregate\r
-// definitions must also be evaluated. If one returns false,\r
-// then implicitly the predicate is false.\r
- set<int>::iterator pfsi;\r
-\r
- if(ag_gb_pfcns.size() > 0)\r
- ret += "//\t\tUnpack remaining partial fcns.\n";\r
- ret += gen_full_unpack_partial_fcn(schema, partial_fcns, ag_gb_pfcns,\r
- found_cids, segen_gb_tbl, "NULL", needs_xform);\r
-\r
-// Unpack the group-by variables\r
-\r
- for(g=0;g<gb_tbl.size();g++){\r
- data_type *gdt = gb_tbl.get_data_type(g);\r
- if(!gdt->is_temporal()){ // temproal gbs already computed\r
-// Find the new fields ref'd by this GBvar def.\r
- col_id_set new_cids;\r
- get_new_se_cids(gb_tbl.get_def(g), found_cids, new_cids, segen_gb_tbl);\r
-// Unpack these values.\r
- ret += gen_unpack_cids(schema, new_cids, "NULL", needs_xform);\r
-\r
- sprintf(tmpstr,"\tgbval->gb_var%d = %s;\n",\r
- g, generate_se_code(gb_tbl.get_def(g),schema).c_str() );\r
-/*\r
-// There seems to be no difference between the two\r
-// branches of the IF statement.\r
- data_type *gdt = gb_tbl.get_data_type(g);\r
- if(gdt->is_buffer_type()){\r
-// Create temporary copy.\r
- sprintf(tmpstr,"\tgbval->gb_var%d = %s;\n",\r
- g, generate_se_code(gb_tbl.get_def(g),schema).c_str() );\r
- }else{\r
- scalarexp_t *gse = gb_tbl.get_def(g);\r
- sprintf(tmpstr,"\tgbval->gb_var%d = %s;\n",\r
- g,generate_se_code(gse,schema).c_str());\r
- }\r
-*/\r
- ret.append(tmpstr);\r
- }\r
- }\r
- ret.append("\n");\r
-\r
-\r
- ret+= "\treturn gbval;\n";\r
- ret += "};\n\n\n";\r
-\r
-//--------------------------------------------------------\r
-// Create and initialize an aggregate object\r
-\r
- ret += this->generate_functor_name()+"_aggrdef *create_aggregate(host_tuple &tup0, gs_sp_t buffer){\n";\r
- // Variables for execution of the function.\r
- ret += "\tgs_int32_t problem = 0;\n"; // return unpack failure\r
-\r
-// return value\r
- ret += "\t"+generate_functor_name()+"_aggrdef *aggval = ("+generate_functor_name()+\r
- "_aggrdef *)buffer;\n";\r
-\r
- for(a=0;a<aggr_tbl.size();a++){\r
- if(aggr_tbl.is_builtin(a)){\r
-// Create temporaries for buffer return values\r
- data_type *adt = aggr_tbl.get_data_type(a);\r
- if(adt->is_buffer_type()){\r
- sprintf(tmpstr,"aggr_tmp_%d", a);\r
- ret+=adt->make_host_cvar(tmpstr)+";\n";\r
- }\r
- }\r
- }\r
-\r
-// Unpack all remaining attributes\r
- ret += gen_remaining_colrefs(schema, cid_set, found_cids, "NULL", needs_xform);\r
- for(a=0;a<aggr_tbl.size();a++){\r
- sprintf(tmpstr,"aggval->aggr_var%d",a);\r
- string assignto_var = tmpstr;\r
- ret += "\t"+generate_aggr_init(assignto_var,&aggr_tbl,a, schema);\r
- }\r
-\r
- ret += "\treturn aggval;\n";\r
- ret += "};\n\n";\r
-\r
-//--------------------------------------------------------\r
-// update an aggregate object\r
-\r
- ret += "void update_aggregate(host_tuple &tup0, "\r
- +generate_functor_name()+"_groupdef *gbval, "+\r
- generate_functor_name()+"_aggrdef *aggval){\n";\r
- // Variables for execution of the function.\r
- ret += "\tgs_int32_t problem = 0;\n"; // return unpack failure\r
-\r
-// use of temporaries depends on the aggregate,\r
-// generate them in generate_aggr_update\r
-\r
-\r
-// Unpack all remaining attributes\r
- ret += gen_remaining_colrefs(schema, cid_set, found_cids, "", needs_xform);\r
- for(a=0;a<aggr_tbl.size();a++){\r
- sprintf(tmpstr,"aggval->aggr_var%d",a);\r
- string varname = tmpstr;\r
- ret.append(generate_aggr_update(varname,&aggr_tbl,a, schema));\r
- }\r
-\r
- ret += "\treturn;\n";\r
- ret += "};\n";\r
-\r
-//--------------------------------------------------------\r
-// reinitialize an aggregate object\r
-\r
- ret += "void reinit_aggregates( "+\r
- generate_functor_name()+"_groupdef *gbval, "+\r
- generate_functor_name()+"_aggrdef *aggval){\n";\r
- // Variables for execution of the function.\r
- ret += "\tgs_int32_t problem = 0;\n"; // return unpack failure\r
-\r
-// use of temporaries depends on the aggregate,\r
-// generate them in generate_aggr_update\r
-\r
- for(g=0;g<gb_tbl.size();g++){\r
- data_type *gdt = gb_tbl.get_data_type(g);\r
- if(gdt->is_temporal()){\r
- if(gdt->is_buffer_type()){\r
- sprintf(tmpstr,"\t\t%s(&(gbval->gb_var%d),&last_gb%d);\n",gdt->get_hfta_buffer_replace().c_str(),g,g);\r
- }else{\r
- sprintf(tmpstr,"\t\t gbval->gb_var%d =last_gb%d;\n",g,g);\r
- }\r
- ret += tmpstr;\r
- }\r
- }\r
-\r
-// Unpack all remaining attributes\r
- for(a=0;a<aggr_tbl.size();a++){\r
- sprintf(tmpstr,"aggval->aggr_var%d",a);\r
- string varname = tmpstr;\r
- ret.append(generate_aggr_reinitialize(varname,&aggr_tbl,a, schema));\r
- }\r
-\r
- ret += "\treturn;\n";\r
- ret += "};\n";\r
-\r
-\r
-\r
-\r
-\r
-//---------------------------------------------------\r
-// Flush test\r
-\r
- ret += "\tbool flush_needed(){\n";\r
- if(uses_temporal_flush){\r
- ret += "\t\treturn needs_temporal_flush;\n";\r
- }else{\r
- ret += "\t\treturn false;\n";\r
- }\r
- ret += "\t};\n";\r
-\r
-//---------------------------------------------------\r
-// create output tuple\r
-// Unpack the partial functions ref'd in the where clause,\r
-// select clause. Evaluate the where clause.\r
-// Finally, pack the tuple.\r
-\r
-// I need to use special code generation here,\r
-// so I'll leave it in longhand.\r
-\r
- ret += "host_tuple create_output_tuple("\r
- +generate_functor_name()+"_groupdef *gbval, "+\r
- generate_functor_name()+"_aggrdef *aggval, bool &failed){\n";\r
-\r
- ret += "\thost_tuple tup;\n";\r
- ret += "\tfailed = false;\n";\r
- ret += "\tgs_retval_t retval = 0;\n";\r
-\r
- string gbvar = "gbval->gb_var";\r
- string aggvar = "aggval->";\r
-\r
-\r
-// First, get the return values from the UDAFS\r
- for(a=0;a<aggr_tbl.size();a++){\r
- if(! aggr_tbl.is_builtin(a)){\r
- ret += "\t"+aggr_tbl.get_op(a)+"_HFTA_AGGR_OUTPUT_(&(udaf_ret_"+int_to_string(a)+"),";\r
- if(aggr_tbl.get_storage_type(a)->get_type() != fstring_t) ret+="&";\r
- ret+="("+aggvar+"aggr_var"+int_to_string(a)+"));\n";\r
- }\r
- }\r
-\r
- set<int> hv_sl_pfcns;\r
- for(w=0;w<having.size();w++){\r
- collect_partial_fcns_pr(having[w]->pr, hv_sl_pfcns);\r
- }\r
- for(s=0;s<select_list.size();s++){\r
- collect_partial_fcns(select_list[s]->se, hv_sl_pfcns);\r
- }\r
-\r
-// clean up the partial fcn results from any previous execution\r
- ret += gen_partial_fcn_dtr(partial_fcns,hv_sl_pfcns);\r
-\r
-// Unpack them now\r
- for(pfsi=hv_sl_pfcns.begin();pfsi!=hv_sl_pfcns.end();++pfsi){\r
- ret += unpack_partial_fcn_fm_aggr(partial_fcns[(*pfsi)], (*pfsi), gbvar, aggvar, schema);\r
- ret += "\tif(retval){ failed = true; return(tup);}\n";\r
- }\r
-\r
-// Evalaute the HAVING clause\r
-// TODO: this seems to have a ++ operator rather than a + operator.\r
- for(w=0;w<having.size();++w){\r
- ret += "\tif( !("+generate_predicate_code_fm_aggr(having[w]->pr,gbvar, aggvar, schema) +") ) { failed = true; return(tup);}\n";\r
- }\r
-\r
-// Now, compute the size of the tuple.\r
-\r
-// Unpack any BUFFER type selections into temporaries\r
-// so that I can compute their size and not have\r
-// to recompute their value during tuple packing.\r
-// I can use regular assignment here because\r
-// these temporaries are non-persistent.\r
-// TODO: should I be using the selvar generation routine?\r
-\r
- ret += "//\t\tCompute the size of the tuple.\n";\r
- ret += "//\t\t\tNote: buffer storage packed at the end of the tuple.\n";\r
- for(s=0;s<select_list.size();s++){\r
- scalarexp_t *se = select_list[s]->se;\r
- data_type *sdt = se->get_data_type();\r
- if(sdt->is_buffer_type() &&\r
- !( (se->get_operator_type() == SE_COLREF) ||\r
- (se->get_operator_type() == SE_AGGR_STAR) ||\r
- (se->get_operator_type() == SE_AGGR_SE) ||\r
- (se->get_operator_type() == SE_FUNC && se->is_partial()) ||\r
- (se->get_operator_type() == SE_FUNC && se->get_aggr_ref() >= 0))\r
- ){\r
- sprintf(tmpstr,"selvar_%d",s);\r
- ret+="\t"+sdt->make_host_cvar(tmpstr)+" = ";\r
- ret += generate_se_code_fm_aggr(se,gbvar, aggvar, schema) +";\n";\r
- }\r
- }\r
-\r
-// The size of the tuple is the size of the tuple struct plus the\r
-// size of the buffers to be copied in.\r
-\r
- ret+="\ttup.tuple_size = sizeof(" + generate_tuple_name( this->get_node_name()) +") + sizeof(gs_uint8_t)";\r
- for(s=0;s<select_list.size();s++){\r
-// if(s>0) ret += "+";\r
- scalarexp_t *se = select_list[s]->se;\r
- data_type *sdt = select_list[s]->se->get_data_type();\r
- if(sdt->is_buffer_type()){\r
- if(!( (se->get_operator_type() == SE_COLREF) ||\r
- (se->get_operator_type() == SE_AGGR_STAR) ||\r
- (se->get_operator_type() == SE_AGGR_SE) ||\r
- (se->get_operator_type() == SE_FUNC && se->is_partial()) ||\r
- (se->get_operator_type() == SE_FUNC && se->get_aggr_ref() >= 0))\r
- ){\r
- sprintf(tmpstr," + %s(&selvar_%d)", sdt->get_hfta_buffer_size().c_str(),s);\r
- ret.append(tmpstr);\r
- }else{\r
- sprintf(tmpstr," + %s(&%s)", sdt->get_hfta_buffer_size().c_str(),generate_se_code_fm_aggr(se,gbvar, aggvar, schema).c_str());\r
- ret.append(tmpstr);\r
- }\r
- }\r
- }\r
- ret.append(";\n");\r
-\r
-// Allocate tuple data block.\r
- ret += "//\t\tCreate the tuple block.\n";\r
- ret += "\ttup.data = malloc(tup.tuple_size);\n";\r
- ret += "\ttup.heap_resident = true;\n";\r
-\r
-// Mark tuple as regular\r
- ret += "\t*((gs_sp_t )tup.data + sizeof(" + generate_tuple_name( this->get_node_name()) +")) = REGULAR_TUPLE;\n";\r
-\r
-// ret += "\ttup.channel = 0;\n";\r
- ret += "\t"+generate_tuple_name( this->get_node_name())+" *tuple = ("+\r
- generate_tuple_name( this->get_node_name())+" *)(tup.data);\n";\r
-\r
-// Start packing.\r
-// (Here, offsets are hard-wired. is this a problem?)\r
-\r
- ret += "//\t\tPack the fields into the tuple.\n";\r
- ret += "\tint tuple_pos = sizeof("+generate_tuple_name( this->get_node_name()) +") + sizeof(gs_uint8_t);\n";\r
- for(s=0;s<select_list.size();s++){\r
- scalarexp_t *se = select_list[s]->se;\r
- data_type *sdt = se->get_data_type();\r
- if(sdt->is_buffer_type()){\r
- if(!( (se->get_operator_type() == SE_COLREF) ||\r
- (se->get_operator_type() == SE_AGGR_STAR) ||\r
- (se->get_operator_type() == SE_AGGR_SE) ||\r
- (se->get_operator_type() == SE_FUNC && se->is_partial()) ||\r
- (se->get_operator_type() == SE_FUNC && se->get_aggr_ref() >= 0))\r
- ){\r
- sprintf(tmpstr,"\t%s(&(tuple->tuple_var%d), &selvar_%d, ((gs_sp_t )tuple)+tuple_pos, tuple_pos);\n", sdt->get_hfta_buffer_tuple_copy().c_str(),s, s);\r
- ret.append(tmpstr);\r
- sprintf(tmpstr,"\ttuple_pos += %s(&selvar_%d);\n", sdt->get_hfta_buffer_size().c_str(), s);\r
- ret.append(tmpstr);\r
- }else{\r
- sprintf(tmpstr,"\t%s(&(tuple->tuple_var%d), &%s, ((gs_sp_t )tuple)+tuple_pos, tuple_pos);\n", sdt->get_hfta_buffer_tuple_copy().c_str(),s, generate_se_code_fm_aggr(se,gbvar, aggvar, schema).c_str());\r
- ret.append(tmpstr);\r
- sprintf(tmpstr,"\ttuple_pos += %s(&%s);\n", sdt->get_hfta_buffer_size().c_str(), generate_se_code_fm_aggr(se,gbvar, aggvar, schema).c_str());\r
- ret.append(tmpstr);\r
- }\r
- }else{\r
- sprintf(tmpstr,"\ttuple->tuple_var%d = ",s);\r
- ret.append(tmpstr);\r
- ret.append(generate_se_code_fm_aggr(se,gbvar, aggvar, schema) );\r
- ret.append(";\n");\r
- }\r
- }\r
-\r
-// Destroy string temporaries\r
- ret += gen_buffer_selvars_dtr(select_list);\r
-\r
- ret += "\treturn tup;\n";\r
- ret += "};\n";\r
-\r
-//------------------------------------------------------------------\r
-// Cleaning_when : evaluate the cleaning_when clause.\r
-// ASSUME that the udaf return values have already\r
-// been unpacked. delete the string udaf return values at the end.\r
-\r
- ret += "bool cleaning_when("\r
- +generate_functor_name()+"_groupdef *gbval, "+\r
- generate_functor_name()+"_aggrdef *aggval){\n";\r
-\r
- ret += "\tbool retval = true;\n";\r
-\r
-\r
- gbvar = "gbval->gb_var";\r
- aggvar = "aggval->";\r
-\r
-\r
- set<int> clw_pfcns;\r
- for(w=0;w<closing_when.size();w++){\r
- collect_partial_fcns_pr(closing_when[w]->pr, clw_pfcns);\r
- }\r
-\r
-// clean up the partial fcn results from any previous execution\r
- ret += gen_partial_fcn_dtr(partial_fcns,clw_pfcns);\r
-\r
-// Unpack them now\r
- for(pfsi=clw_pfcns.begin();pfsi!=clw_pfcns.end();++pfsi){\r
- ret += unpack_partial_fcn_fm_aggr(partial_fcns[(*pfsi)], (*pfsi), gbvar, aggvar, schema);\r
- ret += "\tif(retval){ return false;}\n";\r
- }\r
-\r
-// Evalaute the Closing When clause\r
-// TODO: this seems to have a ++ operator rather than a + operator.\r
- for(w=0;w<closing_when.size();++w){\r
- ret += "\tif( !("+generate_predicate_code_fm_aggr(closing_when[w]->pr,gbvar, aggvar, schema) +") ) { return false;}\n";\r
- }\r
-\r
-\r
-// Destroy string return vals of UDAFs\r
- for(a=0;a<aggr_tbl.size();a++){\r
- if(! aggr_tbl.is_builtin(a)){\r
- int afcn_id = aggr_tbl.get_fcn_id(a);\r
- data_type *adt = Ext_fcns->get_fcn_dt(afcn_id);\r
- if(adt->is_buffer_type()){\r
- sprintf(tmpstr,"\t%s(&udaf_ret_%d);\n",\r
- adt->get_hfta_buffer_destroy().c_str(), a );\r
- ret += tmpstr;\r
- }\r
- }\r
- }\r
-\r
- ret += "\treturn retval;\n";\r
- ret += "};\n";\r
-\r
-\r
-\r
-\r
-//-------------------------------------------------------------------\r
-// Temporal update functions\r
-\r
- ret+="bool temp_status_received(){return temp_tuple_received;};\n\n";\r
-\r
-// create a temp status tuple\r
- ret += "int create_temp_status_tuple(host_tuple& result, bool flush_finished) {\n\n";\r
-\r
- ret += gen_init_temp_status_tuple(this->get_node_name());\r
-\r
-// Start packing.\r
-// (Here, offsets are hard-wired. is this a problem?)\r
-\r
- ret += "//\t\tPack the fields into the tuple.\n";\r
- for(s=0;s<select_list.size();s++){\r
- data_type *sdt = select_list[s]->se->get_data_type();\r
- if(sdt->is_temporal()){\r
- sprintf(tmpstr,"\ttuple->tuple_var%d = ",s);\r
- ret += tmpstr;\r
- sprintf(tmpstr,"(flush_finished) ? %s : %s ", generate_se_code(select_list[s]->se,schema).c_str(), generate_se_code_fm_aggr(select_list[s]->se,"last_flushed_gb", "", schema).c_str());\r
- ret += tmpstr;\r
- ret += ";\n";\r
- }\r
- }\r
-\r
- ret += "\treturn 0;\n";\r
- ret += "};};\n\n\n";\r
-\r
-\r
-//----------------------------------------------------------\r
-// The hash function\r
-\r
- ret += "struct "+generate_functor_name()+"_hash_func{\n";\r
- ret += "\tgs_uint32_t operator()(const "+generate_functor_name()+\r
- "_groupdef *grp) const{\n";\r
- ret += "\t\treturn(0";\r
- for(g=0;g<gb_tbl.size();g++){\r
- data_type *gdt = gb_tbl.get_data_type(g);\r
- if(! gdt->is_temporal()){\r
- ret += "^";\r
- if(gdt->use_hashfunc()){\r
- if(gdt->is_buffer_type())\r
- sprintf(tmpstr,"(%s*%s(&(grp->gb_var%d)))",hash_nums[g%NRANDS].c_str(),gdt->get_hfta_hashfunc().c_str(),g);\r
- else\r
- sprintf(tmpstr,"(%s*%s(grp->gb_var%d))",hash_nums[g%NRANDS].c_str(),gdt->get_hfta_hashfunc().c_str(),g);\r
- }else{\r
- sprintf(tmpstr,"(%s*grp->gb_var%d)",hash_nums[g%NRANDS].c_str(),g);\r
- }\r
- ret += tmpstr;\r
- }\r
- }\r
- ret += " >> 32);\n";\r
- ret += "\t}\n";\r
- ret += "};\n\n";\r
-\r
-//----------------------------------------------------------\r
-// The comparison function\r
-\r
- ret += "struct "+generate_functor_name()+"_equal_func{\n";\r
- ret += "\tbool operator()(const "+generate_functor_name()+"_groupdef *grp1, "+\r
- generate_functor_name()+"_groupdef *grp2) const{\n";\r
- ret += "\t\treturn( (";\r
-\r
- string hcmpr = "";\r
- bool first_exec = true;\r
- for(g=0;g<gb_tbl.size();g++){\r
- data_type *gdt = gb_tbl.get_data_type(g);\r
- if(! gdt->is_temporal()){\r
- if(first_exec){first_exec=false;}else{ hcmpr += ") && (";}\r
- if(gdt->complex_comparison(gdt)){\r
- if(gdt->is_buffer_type())\r
- sprintf(tmpstr,"(%s(&(grp1->gb_var%d), &(grp2->gb_var%d))==0)",\r
- gdt->get_hfta_comparison_fcn(gdt).c_str(),g,g);\r
- else\r
- sprintf(tmpstr,"(%s((grp1->gb_var%d), (grp2->gb_var%d))==0)",\r
- gdt->get_hfta_comparison_fcn(gdt).c_str(),g,g);\r
- }else{\r
- sprintf(tmpstr,"grp1->gb_var%d == grp2->gb_var%d",g,g);\r
- }\r
- hcmpr += tmpstr;\r
- }\r
- }\r
- if(hcmpr == "")\r
- hcmpr = "true";\r
- ret += hcmpr;\r
-\r
- ret += ") );\n";\r
- ret += "\t}\n";\r
- ret += "};\n\n";\r
-\r
-\r
- return(ret);\r
-}\r
-\r
-string rsgah_qpn::generate_operator(int i, string params){\r
-\r
- return(\r
- " running_agg_operator<" +\r
- generate_functor_name()+","+\r
- generate_functor_name() + "_groupdef, " +\r
- generate_functor_name() + "_aggrdef, " +\r
- generate_functor_name()+"_hash_func, "+\r
- generate_functor_name()+"_equal_func "\r
- "> *op"+int_to_string(i)+" = new running_agg_operator<"+\r
- generate_functor_name()+","+\r
- generate_functor_name() + "_groupdef, " +\r
- generate_functor_name() + "_aggrdef, " +\r
- generate_functor_name()+"_hash_func, "+\r
- generate_functor_name()+"_equal_func "\r
- ">("+params+", \"" + get_node_name() + "\");\n"\r
- );\r
-}\r
-\r
-\r
-\r
-// Split aggregation into two HFTA components - sub and superaggregation\r
-// If unable to split the aggreagates, empty vector will be returned\r
-vector<qp_node *> sgah_qpn::split_node_for_hfta(ext_fcn_list *Ext_fcns, table_list *Schema){\r
-\r
- vector<qp_node *> ret_vec;\r
- int s, p, g, a, o, i;\r
- int si;\r
-\r
- vector<string> fta_flds, stream_flds;\r
- int t = table_name->get_schema_ref();\r
-\r
-// Get the set of interfaces it accesses.\r
- int ierr;\r
- vector<string> sel_names;\r
-\r
-// Verify that all of the ref'd UDAFs can be split.\r
-\r
- for(a=0;a<aggr_tbl.size();++a){\r
- if(! aggr_tbl.is_builtin(a)){\r
- int afcn = aggr_tbl.get_fcn_id(a);\r
- int hfta_super_id = Ext_fcns->get_hfta_superaggr_id(afcn);\r
- int hfta_sub_id = Ext_fcns->get_hfta_subaggr_id(afcn);\r
- if(hfta_super_id < 0 || hfta_sub_id < 0){\r
- return(ret_vec);\r
- }\r
- }\r
- }\r
-\r
-/////////////////////////////////////////////////////\r
-// Split into aggr/aggr.\r
-\r
-\r
- sgah_qpn *low_hfta_node = new sgah_qpn();\r
- low_hfta_node->table_name = table_name;\r
- low_hfta_node->set_node_name( "_"+node_name );\r
- low_hfta_node->table_name->set_range_var(table_name->get_var_name());\r
-\r
-\r
- sgah_qpn *hi_hfta_node = new sgah_qpn();\r
- hi_hfta_node->table_name = new tablevar_t( ("_"+node_name).c_str());\r
- hi_hfta_node->set_node_name( node_name );\r
- hi_hfta_node->table_name->set_range_var(table_name->get_var_name());\r
-\r
-// First, process the group-by variables.\r
-// both low and hi level queries duplicate group-by variables of original query\r
-\r
-\r
- for(g=0;g<gb_tbl.size();g++){\r
-// Insert the gbvar into both low- and hi level hfta.\r
- scalarexp_t *gbvar_def = dup_se(gb_tbl.get_def(g), &aggr_tbl);\r
- low_hfta_node->gb_tbl.add_gb_var(\r
- gb_tbl.get_name(g), gb_tbl.get_tblvar_ref(g), gbvar_def, gb_tbl.get_reftype(g)\r
- );\r
-\r
-// Insert a ref to the value of the gbvar into the low-level hfta select list.\r
- colref_t *new_cr = new colref_t(gb_tbl.get_name(g).c_str() );\r
- scalarexp_t *gbvar_fta = new scalarexp_t(new_cr);\r
- gbvar_fta->set_gb_ref(g);\r
- gbvar_fta->set_data_type( gb_tbl.get_def(g)->get_data_type() );\r
- scalarexp_t *gbvar_stream = make_fta_se_ref(low_hfta_node->select_list, gbvar_fta,0);\r
-\r
-// Insert the corresponding gbvar ref (gbvar_stream) into the stream.\r
- gbvar_stream->set_gb_ref(-1); // used as GBvar def\r
- hi_hfta_node->gb_tbl.add_gb_var(\r
- gbvar_stream->get_colref()->get_field(), -1, gbvar_stream, gb_tbl.get_reftype(g)\r
- );\r
-\r
- }\r
-// hi_hfta_node->gb_tbl.gb_patterns = gb_tbl.gb_patterns; // pattern processing at higtest level\r
- hi_hfta_node->gb_tbl.set_pattern_info( &gb_tbl); // pattern processing at higtest level\r
-\r
-// SEs in the aggregate definitions.\r
-// They are all safe, so split them up for later processing.\r
- map<int, scalarexp_t *> hfta_aggr_se;\r
- for(a=0;a<aggr_tbl.size();++a){\r
- split_hfta_aggr( &(aggr_tbl), a,\r
- &(hi_hfta_node->aggr_tbl), &(low_hfta_node->aggr_tbl) ,\r
- low_hfta_node->select_list,\r
- hfta_aggr_se,\r
- Ext_fcns\r
- );\r
- }\r
-\r
-\r
-// Next, the select list.\r
-\r
- for(s=0;s<select_list.size();s++){\r
- bool fta_forbidden = false;\r
- scalarexp_t *root_se = rehome_fta_se(select_list[s]->se, &hfta_aggr_se);\r
- hi_hfta_node->select_list.push_back(\r
- new select_element(root_se, select_list[s]->name));\r
- }\r
-\r
-\r
-\r
-// All the predicates in the where clause must execute\r
-// in the low-level hfta.\r
-\r
- for(p=0;p<where.size();p++){\r
- predicate_t *new_pr = dup_pr(where[p]->pr, &aggr_tbl);\r
- cnf_elem *new_cnf = new cnf_elem(new_pr);\r
- analyze_cnf(new_cnf);\r
-\r
- low_hfta_node->where.push_back(new_cnf);\r
- }\r
-\r
-// All of the predicates in the having clause must\r
-// execute in the high-level hfta node.\r
-\r
- for(p=0;p<having.size();p++){\r
- predicate_t *pr_root = rehome_fta_pr( having[p]->pr, &hfta_aggr_se);\r
- cnf_elem *cnf_root = new cnf_elem(pr_root);\r
- analyze_cnf(cnf_root);\r
-\r
- hi_hfta_node->having.push_back(cnf_root);\r
- }\r
-\r
-\r
-// Copy parameters to both nodes\r
- vector<string> param_names = param_tbl->get_param_names();\r
- int pi;\r
- for(pi=0;pi<param_names.size();pi++){\r
- data_type *dt = param_tbl->get_data_type(param_names[pi]);\r
- low_hfta_node->param_tbl->add_param(param_names[pi],dt->duplicate(),\r
- param_tbl->handle_access(param_names[pi]));\r
- hi_hfta_node->param_tbl->add_param(param_names[pi],dt->duplicate(),\r
- param_tbl->handle_access(param_names[pi]));\r
- }\r
- low_hfta_node->definitions = definitions;\r
- hi_hfta_node->definitions = definitions;\r
-\r
-\r
- low_hfta_node->table_name->set_machine(table_name->get_machine());\r
- low_hfta_node->table_name->set_interface(table_name->get_interface());\r
- low_hfta_node->table_name->set_ifq(false);\r
-\r
- hi_hfta_node->table_name->set_machine(table_name->get_machine());\r
- hi_hfta_node->table_name->set_interface(table_name->get_interface());\r
- hi_hfta_node->table_name->set_ifq(false);\r
-\r
- ret_vec.push_back(low_hfta_node);\r
- ret_vec.push_back(hi_hfta_node);\r
-\r
-\r
- return(ret_vec);\r
-\r
-\r
- // TODO: add splitting into selection/aggregation\r
-}\r
-\r
-\r
-// Split aggregation into two HFTA components - sub and superaggregation\r
-// If unable to split the aggreagates, empty vector will be returned\r
-// Similar to sgah, but super aggregate is rsgah, subaggr is sgah\r
-vector<qp_node *> rsgah_qpn::split_node_for_hfta(ext_fcn_list *Ext_fcns, table_list *Schema){\r
-\r
- vector<qp_node *> ret_vec;\r
- int s, p, g, a, o, i;\r
- int si;\r
-\r
- vector<string> fta_flds, stream_flds;\r
- int t = table_name->get_schema_ref();\r
-\r
-// Get the set of interfaces it accesses.\r
- int ierr;\r
- vector<string> sel_names;\r
-\r
-// Verify that all of the ref'd UDAFs can be split.\r
-\r
- for(a=0;a<aggr_tbl.size();++a){\r
- if(! aggr_tbl.is_builtin(a)){\r
- int afcn = aggr_tbl.get_fcn_id(a);\r
- int hfta_super_id = Ext_fcns->get_hfta_superaggr_id(afcn);\r
- int hfta_sub_id = Ext_fcns->get_hfta_subaggr_id(afcn);\r
- if(hfta_super_id < 0 || hfta_sub_id < 0){\r
- return(ret_vec);\r
- }\r
- }\r
- }\r
-\r
-/////////////////////////////////////////////////////\r
-// Split into aggr/aggr.\r
-\r
-\r
- sgah_qpn *low_hfta_node = new sgah_qpn();\r
- low_hfta_node->table_name = table_name;\r
- low_hfta_node->set_node_name( "_"+node_name );\r
- low_hfta_node->table_name->set_range_var(table_name->get_var_name());\r
-\r
-\r
- rsgah_qpn *hi_hfta_node = new rsgah_qpn();\r
- hi_hfta_node->table_name = new tablevar_t( ("_"+node_name).c_str());\r
- hi_hfta_node->set_node_name( node_name );\r
- hi_hfta_node->table_name->set_range_var(table_name->get_var_name());\r
-\r
-// First, process the group-by variables.\r
-// both low and hi level queries duplicate group-by variables of original query\r
-\r
-\r
- for(g=0;g<gb_tbl.size();g++){\r
-// Insert the gbvar into both low- and hi level hfta.\r
- scalarexp_t *gbvar_def = dup_se(gb_tbl.get_def(g), &aggr_tbl);\r
- low_hfta_node->gb_tbl.add_gb_var(\r
- gb_tbl.get_name(g), gb_tbl.get_tblvar_ref(g), gbvar_def, gb_tbl.get_reftype(g)\r
- );\r
-\r
-// Insert a ref to the value of the gbvar into the low-level hfta select list.\r
- colref_t *new_cr = new colref_t(gb_tbl.get_name(g).c_str() );\r
- scalarexp_t *gbvar_fta = new scalarexp_t(new_cr);\r
- gbvar_fta->set_gb_ref(g);\r
- gbvar_fta->set_data_type( gb_tbl.get_def(g)->get_data_type() );\r
- scalarexp_t *gbvar_stream = make_fta_se_ref(low_hfta_node->select_list, gbvar_fta,0);\r
-\r
-// Insert the corresponding gbvar ref (gbvar_stream) into the stream.\r
- gbvar_stream->set_gb_ref(-1); // used as GBvar def\r
- hi_hfta_node->gb_tbl.add_gb_var(\r
- gbvar_stream->get_colref()->get_field(), -1, gbvar_stream, gb_tbl.get_reftype(g)\r
- );\r
-\r
- }\r
-\r
-// SEs in the aggregate definitions.\r
-// They are all safe, so split them up for later processing.\r
- map<int, scalarexp_t *> hfta_aggr_se;\r
- for(a=0;a<aggr_tbl.size();++a){\r
- split_hfta_aggr( &(aggr_tbl), a,\r
- &(hi_hfta_node->aggr_tbl), &(low_hfta_node->aggr_tbl) ,\r
- low_hfta_node->select_list,\r
- hfta_aggr_se,\r
- Ext_fcns\r
- );\r
- }\r
-\r
-\r
-// Next, the select list.\r
-\r
- for(s=0;s<select_list.size();s++){\r
- bool fta_forbidden = false;\r
- scalarexp_t *root_se = rehome_fta_se(select_list[s]->se, &hfta_aggr_se);\r
- hi_hfta_node->select_list.push_back(\r
- new select_element(root_se, select_list[s]->name));\r
- }\r
-\r
-\r
-\r
-// All the predicates in the where clause must execute\r
-// in the low-level hfta.\r
-\r
- for(p=0;p<where.size();p++){\r
- predicate_t *new_pr = dup_pr(where[p]->pr, &aggr_tbl);\r
- cnf_elem *new_cnf = new cnf_elem(new_pr);\r
- analyze_cnf(new_cnf);\r
-\r
- low_hfta_node->where.push_back(new_cnf);\r
- }\r
-\r
-// All of the predicates in the having clause must\r
-// execute in the high-level hfta node.\r
-\r
- for(p=0;p<having.size();p++){\r
- predicate_t *pr_root = rehome_fta_pr( having[p]->pr, &hfta_aggr_se);\r
- cnf_elem *cnf_root = new cnf_elem(pr_root);\r
- analyze_cnf(cnf_root);\r
-\r
- hi_hfta_node->having.push_back(cnf_root);\r
- }\r
-\r
-// Similar for closing when\r
- for(p=0;p<closing_when.size();p++){\r
- predicate_t *pr_root = rehome_fta_pr( closing_when[p]->pr, &hfta_aggr_se);\r
- cnf_elem *cnf_root = new cnf_elem(pr_root);\r
- analyze_cnf(cnf_root);\r
-\r
- hi_hfta_node->closing_when.push_back(cnf_root);\r
- }\r
-\r
-\r
-// Copy parameters to both nodes\r
- vector<string> param_names = param_tbl->get_param_names();\r
- int pi;\r
- for(pi=0;pi<param_names.size();pi++){\r
- data_type *dt = param_tbl->get_data_type(param_names[pi]);\r
- low_hfta_node->param_tbl->add_param(param_names[pi],dt->duplicate(),\r
- param_tbl->handle_access(param_names[pi]));\r
- hi_hfta_node->param_tbl->add_param(param_names[pi],dt->duplicate(),\r
- param_tbl->handle_access(param_names[pi]));\r
- }\r
- low_hfta_node->definitions = definitions;\r
- hi_hfta_node->definitions = definitions;\r
-\r
-\r
- low_hfta_node->table_name->set_machine(table_name->get_machine());\r
- low_hfta_node->table_name->set_interface(table_name->get_interface());\r
- low_hfta_node->table_name->set_ifq(false);\r
-\r
- hi_hfta_node->table_name->set_machine(table_name->get_machine());\r
- hi_hfta_node->table_name->set_interface(table_name->get_interface());\r
- hi_hfta_node->table_name->set_ifq(false);\r
-\r
- ret_vec.push_back(low_hfta_node);\r
- ret_vec.push_back(hi_hfta_node);\r
-\r
-\r
- return(ret_vec);\r
-\r
-\r
- // TODO: add splitting into selection/aggregation\r
-}\r
-\r
-//---------------------------------------------------------------\r
-// Code for propagating Protocol field source information\r
-\r
-\r
-scalarexp_t *resolve_protocol_se(scalarexp_t *se, vector<map<string, scalarexp_t *> *> &src_vec, gb_table *gb_tbl, table_list *Schema){\r
- scalarexp_t *rse, *lse,*p_se, *gb_se;\r
- int tno, schema_type;\r
- map<string, scalarexp_t *> *pse_map;\r
-\r
- switch(se->get_operator_type()){\r
- case SE_LITERAL:\r
- return new scalarexp_t(se->get_literal());\r
- case SE_PARAM:\r
- return scalarexp_t::make_param_reference(se->get_op().c_str());\r
- case SE_COLREF:\r
- if(se->is_gb()){\r
- if(gb_tbl == NULL)\r
- fprintf(stderr,"INTERNAL ERROR, in resolve_protocol_se, se->gb_ref=%d, but gb_tbl is NULL\n",se->get_gb_ref());\r
- gb_se = gb_tbl->get_def(se->get_gb_ref());\r
- return resolve_protocol_se(gb_se,src_vec,gb_tbl,Schema);\r
- }\r
-\r
- schema_type = Schema->get_schema_type(se->get_colref()->get_schema_ref());\r
- if(schema_type == PROTOCOL_SCHEMA)\r
- return dup_se(se,NULL);\r
-\r
- tno = se->get_colref()->get_tablevar_ref();\r
- if(tno >= src_vec.size()){\r
- fprintf(stderr,"INTERNAL ERROR, in resolve_protocol_se, tno=%d, src_vec.size()=%lu\n",tno,src_vec.size());\r
- }\r
- if(src_vec[tno] == NULL)\r
- return NULL;\r
-\r
- pse_map =src_vec[tno];\r
- p_se = (*pse_map)[se->get_colref()->get_field()];\r
- if(p_se == NULL)\r
- return NULL;\r
- return dup_se(p_se,NULL);\r
- case SE_UNARY_OP:\r
- lse = resolve_protocol_se(se->get_left_se(),src_vec,gb_tbl,Schema);\r
- if(lse == NULL)\r
- return NULL;\r
- else\r
- return new scalarexp_t(se->get_op().c_str(),lse);\r
- case SE_BINARY_OP:\r
- lse = resolve_protocol_se(se->get_left_se(),src_vec,gb_tbl,Schema);\r
- if(lse == NULL)\r
- return NULL;\r
- rse = resolve_protocol_se(se->get_right_se(),src_vec,gb_tbl,Schema);\r
- if(rse == NULL)\r
- return NULL;\r
- return new scalarexp_t(se->get_op().c_str(),lse,rse);\r
- case SE_AGGR_STAR:\r
- return( NULL );\r
- case SE_AGGR_SE:\r
- return( NULL );\r
- case SE_FUNC:\r
- return(NULL);\r
- default:\r
- return(NULL);\r
- break;\r
- }\r
-\r
-}\r
-\r
-void spx_qpn::create_protocol_se(vector<qp_node *> q_sources, table_list *Schema){\r
- int i;\r
- vector<map<string, scalarexp_t *> *> src_vec;\r
-\r
- for(i=0;i<q_sources.size();i++){\r
- if(q_sources[i] != NULL)\r
- src_vec.push_back(q_sources[i]->get_protocol_se());\r
- else\r
- src_vec.push_back(NULL);\r
- }\r
-\r
- for(i=0;i<select_list.size();i++){\r
- protocol_map[select_list[i]->name] = resolve_protocol_se(select_list[i]->se,src_vec,NULL,Schema);\r
- }\r
-}\r
-\r
-void join_eq_hash_qpn::create_protocol_se(vector<qp_node *> q_sources, table_list *Schema){\r
- int i;\r
- vector<map<string, scalarexp_t *> *> src_vec;\r
-\r
- for(i=0;i<q_sources.size();i++){\r
- if(q_sources[i] != NULL)\r
- src_vec.push_back(q_sources[i]->get_protocol_se());\r
- else\r
- src_vec.push_back(NULL);\r
- }\r
-\r
- for(i=0;i<select_list.size();i++){\r
- protocol_map[select_list[i]->name] = resolve_protocol_se(select_list[i]->se,src_vec,NULL,Schema);\r
- }\r
-\r
- for(i=0;i<hash_eq.size();i++){\r
- hash_src_l.push_back(resolve_protocol_se(hash_eq[i]->pr->get_left_se(),src_vec,NULL,Schema));\r
- hash_src_r.push_back(resolve_protocol_se(hash_eq[i]->pr->get_right_se(),src_vec,NULL,Schema));\r
- }\r
-}\r
-\r
-void filter_join_qpn::create_protocol_se(vector<qp_node *> q_sources, table_list *Schema){\r
- int i;\r
- vector<map<string, scalarexp_t *> *> src_vec;\r
-\r
- for(i=0;i<q_sources.size();i++){\r
- if(q_sources[i] != NULL)\r
- src_vec.push_back(q_sources[i]->get_protocol_se());\r
- else\r
- src_vec.push_back(NULL);\r
- }\r
-\r
- for(i=0;i<select_list.size();i++){\r
- protocol_map[select_list[i]->name] = resolve_protocol_se(select_list[i]->se,src_vec,NULL,Schema);\r
- }\r
-\r
- for(i=0;i<hash_eq.size();i++){\r
- hash_src_l.push_back(resolve_protocol_se(hash_eq[i]->pr->get_left_se(),src_vec,NULL,Schema));\r
- hash_src_r.push_back(resolve_protocol_se(hash_eq[i]->pr->get_right_se(),src_vec,NULL,Schema));\r
- }\r
-}\r
-\r
-void sgah_qpn::create_protocol_se(vector<qp_node *> q_sources, table_list *Schema){\r
- int i;\r
- vector<map<string, scalarexp_t *> *> src_vec;\r
-\r
- for(i=0;i<q_sources.size();i++){\r
- if(q_sources[i] != NULL)\r
- src_vec.push_back(q_sources[i]->get_protocol_se());\r
- else\r
- src_vec.push_back(NULL);\r
- }\r
-\r
- for(i=0;i<select_list.size();i++){\r
- protocol_map[select_list[i]->name] = resolve_protocol_se(select_list[i]->se,src_vec,&gb_tbl,Schema);\r
- }\r
-\r
- for(i=0;i<gb_tbl.size();i++)\r
- gb_sources.push_back(resolve_protocol_se(gb_tbl.get_def(i),src_vec,&gb_tbl,Schema));\r
-\r
-}\r
-\r
-void rsgah_qpn::create_protocol_se(vector<qp_node *> q_sources, table_list *Schema){\r
- int i;\r
- vector<map<string, scalarexp_t *> *> src_vec;\r
-\r
- for(i=0;i<q_sources.size();i++){\r
- if(q_sources[i] != NULL)\r
- src_vec.push_back(q_sources[i]->get_protocol_se());\r
- else\r
- src_vec.push_back(NULL);\r
- }\r
-\r
- for(i=0;i<select_list.size();i++){\r
- protocol_map[select_list[i]->name] = resolve_protocol_se(select_list[i]->se,src_vec,&gb_tbl,Schema);\r
- }\r
-\r
- for(i=0;i<gb_tbl.size();i++)\r
- gb_sources.push_back(resolve_protocol_se(gb_tbl.get_def(i),src_vec,&gb_tbl,Schema));\r
-}\r
-\r
-void sgahcwcb_qpn::create_protocol_se(vector<qp_node *> q_sources, table_list *Schema){\r
- int i;\r
- vector<map<string, scalarexp_t *> *> src_vec;\r
-\r
- for(i=0;i<q_sources.size();i++){\r
- if(q_sources[i] != NULL)\r
- src_vec.push_back(q_sources[i]->get_protocol_se());\r
- else\r
- src_vec.push_back(NULL);\r
- }\r
-\r
- for(i=0;i<select_list.size();i++){\r
- protocol_map[select_list[i]->name] = resolve_protocol_se(select_list[i]->se,src_vec,&gb_tbl,Schema);\r
- }\r
-\r
- for(i=0;i<gb_tbl.size();i++)\r
- gb_sources.push_back(resolve_protocol_se(gb_tbl.get_def(i),src_vec,&gb_tbl,Schema));\r
-}\r
-\r
-void mrg_qpn::create_protocol_se(vector<qp_node *> q_sources, table_list *Schema){\r
- int f,s,i;\r
- scalarexp_t *first_se;\r
-\r
- vector<map<string, scalarexp_t *> *> src_vec;\r
- map<string, scalarexp_t *> *pse_map;\r
-\r
- for(i=0;i<q_sources.size();i++){\r
- if(q_sources[i] != NULL)\r
- src_vec.push_back(q_sources[i]->get_protocol_se());\r
- else\r
- src_vec.push_back(NULL);\r
- }\r
-\r
- if(q_sources.size() == 0){\r
- fprintf(stderr,"INTERNAL ERROR in mrg_qpn::create_protocol_se, q_sources.size() == 0\n");\r
- exit(1);\r
- }\r
-\r
- vector<field_entry *> tbl_flds = table_layout->get_fields();\r
- for(f=0;f<tbl_flds.size();f++){\r
- bool match = true;\r
- string fld_nm = tbl_flds[f]->get_name();\r
- pse_map = src_vec[0];\r
- first_se = (*pse_map)[fld_nm];\r
- if(first_se == NULL)\r
- match = false;\r
- for(s=1;s<src_vec.size() && match;s++){\r
- pse_map = src_vec[s];\r
- scalarexp_t *match_se = (*pse_map)[fld_nm];\r
- if(match_se == false)\r
- match = false;\r
- else\r
- match = is_equivalent_se_base(first_se, match_se, Schema);\r
- }\r
- if(match)\r
- protocol_map[fld_nm] = first_se;\r
- else\r
- protocol_map[fld_nm] = NULL;\r
- }\r
-}\r
+/* ------------------------------------------------
+Copyright 2014 AT&T Intellectual Property
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ ------------------------------------------- */
+
+// Create, manipulate, and dump query plans.
+
+#include "query_plan.h"
+#include "analyze_fta.h"
+#include "generate_utils.h"
+
+#include<vector>
+
+using namespace std;
+
+extern string hash_nums[NRANDS]; // for fast hashing
+
+
+char tmpstr[1000];
+
+void untaboo(string &s){
+ int c;
+ for(c=0;c<s.size();++c){
+ if(s[c] == '.'){
+ s[c] = '_';
+ }
+ }
+}
+
+// mrg_qpn constructor, define here to avoid
+// circular references in the .h file
+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){
+ param_tbl = spx->param_tbl;
+ int i;
+ node_name = n_name;
+ field_entry_list *fel = new field_entry_list();
+ merge_fieldpos = -1;
+
+ disorder = 1;
+
+ for(i=0;i<spx->select_list.size();++i){
+ data_type *dt = spx->select_list[i]->se->get_data_type()->duplicate();
+ if(dt->is_temporal()){
+ if(merge_fieldpos < 0){
+ merge_fieldpos = i;
+ }else{
+ 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() );
+ dt->reset_temporal();
+ }
+ }
+
+ field_entry *fe = dt->make_field_entry(spx->select_list[i]->name);
+ fel->append_field(fe);
+ delete dt;
+ }
+ if(merge_fieldpos<0){
+ fprintf(stderr,"ERROR, no temporal attribute for merge subquery %s\n",n_name.c_str());
+ exit(1);
+ }
+ table_layout = new table_def( n_name.c_str(), NULL, NULL, fel, STREAM_SCHEMA);
+
+// NEED TO HANDLE USER_SPECIFIED SLACK
+ this->resolve_slack(spx->select_list[merge_fieldpos]->se,
+ spx->select_list[merge_fieldpos]->name, ifaces, ifdb,NULL);
+// if(this->slack == NULL)
+// fprintf(stderr,"Zero slack.\n");
+// else
+// fprintf(stderr,"slack is %s\n",slack->to_string().c_str());
+
+ for(i=0;i<sources.size();i++){
+ std::string rvar = "_m"+int_to_string(i);
+ mvars.push_back(new colref_t(rvar.c_str(), spx->select_list[merge_fieldpos]->name.c_str()));
+ mvars[i]->set_tablevar_ref(i);
+ fm.push_back(new tablevar_t(sources[i].c_str()));
+ fm[i]->set_range_var(rvar);
+ }
+
+ param_tbl = new param_table();
+ std::vector<std::string> param_names = spx->param_tbl->get_param_names();
+ int pi;
+ for(pi=0;pi<param_names.size();pi++){
+ data_type *dt = spx->param_tbl->get_data_type(param_names[pi]);
+ param_tbl->add_param(param_names[pi],dt->duplicate(),
+ spx->param_tbl->handle_access(param_names[pi]));
+ }
+ definitions = spx->definitions;
+
+}
+
+
+mrg_qpn::mrg_qpn(watch_join_qpn *spx, std::string n_name, std::vector<std::string> &sources, std::vector<std::pair<std::string, std::string> > &ifaces, ifq_t *ifdb){
+ param_tbl = spx->param_tbl;
+ int i;
+ node_name = n_name;
+ field_entry_list *fel = new field_entry_list();
+ merge_fieldpos = -1;
+
+ disorder = 1;
+
+ for(i=0;i<spx->select_list.size();++i){
+ data_type *dt = spx->select_list[i]->se->get_data_type()->duplicate();
+ if(dt->is_temporal()){
+ if(merge_fieldpos < 0){
+ merge_fieldpos = i;
+ }else{
+ 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() );
+ dt->reset_temporal();
+ }
+ }
+
+ field_entry *fe = dt->make_field_entry(spx->select_list[i]->name);
+ fel->append_field(fe);
+ delete dt;
+ }
+ if(merge_fieldpos<0){
+ fprintf(stderr,"ERROR, no temporal attribute for merge subquery %s\n",n_name.c_str());
+ exit(1);
+ }
+ table_layout = new table_def( n_name.c_str(), NULL, NULL, fel, STREAM_SCHEMA);
+
+// NEED TO HANDLE USER_SPECIFIED SLACK
+ this->resolve_slack(spx->select_list[merge_fieldpos]->se,
+ spx->select_list[merge_fieldpos]->name, ifaces, ifdb,NULL);
+// if(this->slack == NULL)
+// fprintf(stderr,"Zero slack.\n");
+// else
+// fprintf(stderr,"slack is %s\n",slack->to_string().c_str());
+
+ for(i=0;i<sources.size();i++){
+ std::string rvar = "_m"+int_to_string(i);
+ mvars.push_back(new colref_t(rvar.c_str(), spx->select_list[merge_fieldpos]->name.c_str()));
+ mvars[i]->set_tablevar_ref(i);
+ fm.push_back(new tablevar_t(sources[i].c_str()));
+ fm[i]->set_range_var(rvar);
+ }
+
+ param_tbl = new param_table();
+ std::vector<std::string> param_names = spx->param_tbl->get_param_names();
+ int pi;
+ for(pi=0;pi<param_names.size();pi++){
+ data_type *dt = spx->param_tbl->get_data_type(param_names[pi]);
+ param_tbl->add_param(param_names[pi],dt->duplicate(),
+ spx->param_tbl->handle_access(param_names[pi]));
+ }
+ definitions = spx->definitions;
+
+}
+
+
+
+
+// This function translates an analyzed parse tree
+// into one or more query nodes (qp_node).
+// Currently only one node is created, but some query
+// fragments might create more than one query node,
+// e.g. aggregation over a join, or nested subqueries
+// in the FROM clause (unless this is handled at parse tree
+// analysis time). At this stage, they will be linked
+// by the names in the FROM clause.
+// INVARIANT : if more than one query node is returned,
+// the last one represents the output of the query.
+vector<qp_node *> create_query_nodes(query_summary_class *qs,table_list *Schema){
+
+// Classify the query.
+
+ vector <qp_node *> local_plan;
+ qp_node *plan_root;
+
+// TODO
+// I should probably move a lot of this code
+// into the qp_node constructors,
+// and have this code focus on building the query plan tree.
+
+// Watchlist node
+ if(qs->query_type == WATCHLIST_QUERY){
+ watch_tbl_qpn *watchnode = new watch_tbl_qpn(qs, Schema);
+
+// Done
+ plan_root = watchnode;
+ local_plan.push_back(watchnode);
+ }
+
+
+// MERGE node
+ if(qs->query_type == MERGE_QUERY){
+ mrg_qpn *merge_node = new mrg_qpn(qs,Schema);
+
+// Done
+ plan_root = merge_node;
+ local_plan.push_back(merge_node);
+
+ /*
+ Do not split sources until we are done with optimizations
+ vector<mrg_qpn *> split_merge = merge_node->split_sources();
+ local_plan.insert(local_plan.begin(), split_merge.begin(), split_merge.end());
+ */
+// If children are created, add them to the schema.
+/*
+ int i;
+printf("split_merge size is %d\n",split_merge.size());
+ for(i=1;i<split_merge.size();++i){
+ Schema->add_table(split_merge[i]->get_fields());
+printf("Adding split merge table %d\n",i);
+ }
+*/
+
+/*
+printf("Did split sources on %s:\n",qs->query_name.c_str());
+int ss;
+for(ss=0;ss<local_plan.size();ss++){
+printf("node %d, name=%s, sources=",ss,local_plan[ss]->get_node_name().c_str());
+vector<tablevar_t *> inv = local_plan[ss]->get_input_tbls();
+int nn;
+for(nn=0;nn<inv.size();nn++){
+printf("%s ",inv[nn]->to_string().c_str());
+}
+printf("\n");
+}
+*/
+
+
+ }
+
+ if(qs->query_type == SELECT_QUERY){
+
+// Select / Aggregation / Join
+ if(qs->gb_tbl->size() == 0 && qs->aggr_tbl->size() == 0){
+
+ if(qs->fta_tree->get_from()->size() == 1){
+ spx_qpn *spx_node = new spx_qpn(qs,Schema);
+
+ plan_root = spx_node;
+ local_plan.push_back(spx_node);
+ }else{
+ if(qs->fta_tree->get_from()->get_properties() == FILTER_JOIN_PROPERTY){
+ filter_join_qpn *join_node = new filter_join_qpn(qs,Schema);
+ plan_root = join_node;
+ local_plan.push_back(join_node);
+ }else{
+ if(qs->fta_tree->get_from()->get_properties() == WATCHLIST_JOIN_PROPERTY){
+ watch_join_qpn *join_node = new watch_join_qpn(qs,Schema);
+ plan_root = join_node;
+ local_plan.push_back(join_node);
+ }else{
+ join_eq_hash_qpn *join_node = new join_eq_hash_qpn(qs,Schema);
+ plan_root = join_node;
+ local_plan.push_back(join_node);
+ }
+ }
+ }
+ }else{
+// aggregation
+
+ if(qs->states_refd.size() || qs->sg_tbl.size() || qs->cb_cnf.size()){
+ sgahcwcb_qpn *sgahcwcb_node = new sgahcwcb_qpn(qs,Schema);
+ plan_root = sgahcwcb_node;
+ local_plan.push_back(sgahcwcb_node);
+ }else{
+ if(qs->closew_cnf.size()){
+ rsgah_qpn *rsgah_node = new rsgah_qpn(qs,Schema);
+ plan_root = rsgah_node;
+ local_plan.push_back(rsgah_node);
+ }else{
+ sgah_qpn *sgah_node = new sgah_qpn(qs,Schema);
+ plan_root = sgah_node;
+ local_plan.push_back(sgah_node);
+ }
+ }
+ }
+ }
+
+
+// Get the query name and other definitions.
+ plan_root->set_node_name( qs->query_name);
+ plan_root->set_definitions( qs->definitions) ;
+
+
+// return(plan_root);
+ return(local_plan);
+
+}
+
+
+string se_to_query_string(scalarexp_t *se, aggregate_table *aggr_tbl){
+ string l_str;
+ string r_str;
+ string ret;
+ int p;
+ vector<scalarexp_t *> operand_list;
+ string su_ind = "";
+
+ if(se->is_superaggr())
+ su_ind = "$";
+
+ switch(se->get_operator_type()){
+ case SE_LITERAL:
+ l_str = se->get_literal()->to_query_string();
+ return l_str;
+ case SE_PARAM:
+ l_str = "$" + se->get_op();
+ return l_str;
+ case SE_COLREF:
+ l_str = se->get_colref()->to_query_string() ;
+ return l_str;
+ case SE_UNARY_OP:
+ l_str = se_to_query_string(se->get_left_se(),aggr_tbl);
+
+ return se->get_op()+"( "+l_str+" )";;
+ case SE_BINARY_OP:
+ l_str = se_to_query_string(se->get_left_se(),aggr_tbl);
+ r_str = se_to_query_string(se->get_right_se(),aggr_tbl);
+ return( "("+l_str+")"+se->get_op()+"("+r_str+")" );
+ case SE_AGGR_STAR:
+ return( se->get_op() + su_ind + "(*)");
+ case SE_AGGR_SE:
+ l_str = se_to_query_string(aggr_tbl->get_aggr_se(se->get_aggr_ref()),aggr_tbl);
+ return( se->get_op() + su_ind + "(" + l_str + ")" );
+ case SE_FUNC:
+ if(se->get_aggr_ref() >= 0)
+ operand_list = aggr_tbl->get_operand_list(se->get_aggr_ref());
+ else
+ operand_list = se->get_operands();
+
+ ret = se->get_op() + su_ind + "(";
+ for(p=0;p<operand_list.size();p++){
+ l_str = se_to_query_string(operand_list[p],aggr_tbl);
+ if(p>0) ret += ", ";
+ ret += l_str;
+ }
+ ret += ")";
+ return(ret);
+ break;
+ }
+ return "ERROR SE op type not recognized in se_to_query_string.\n";
+}
+
+
+string pred_to_query_str(predicate_t *pr, aggregate_table *aggr_tbl){
+ string l_str;
+ string r_str;
+ string ret;
+ int o,l;
+ vector<literal_t *> llist;
+ vector<scalarexp_t *> op_list;
+
+ switch(pr->get_operator_type()){
+ case PRED_IN:
+ l_str = se_to_query_string(pr->get_left_se(),aggr_tbl);
+ ret = l_str + " IN [";
+ llist = pr->get_lit_vec();
+ for(l=0;l<llist.size();l++){
+ if(l>0) ret += ", ";
+ ret += llist[l]->to_query_string();
+ }
+ ret += "]";
+
+ return(ret);
+ case PRED_COMPARE:
+ l_str = se_to_query_string(pr->get_left_se(),aggr_tbl);
+ r_str = se_to_query_string(pr->get_right_se(),aggr_tbl);
+ return( l_str + " " + pr->get_op() + " " + r_str );
+ case PRED_UNARY_OP:
+ l_str = pred_to_query_str(pr->get_left_pr(),aggr_tbl);
+ return(pr->get_op() + "( " + l_str + " )");
+ case PRED_BINARY_OP:
+ l_str = pred_to_query_str(pr->get_left_pr(),aggr_tbl);
+ r_str = pred_to_query_str(pr->get_right_pr(),aggr_tbl);
+ return("( " + r_str + " )" + pr->get_op() + "( " + l_str + " )");
+ case PRED_FUNC:
+ ret = pr->get_op()+"[";
+ op_list = pr->get_op_list();
+ for(o=0;o<op_list.size();++o){
+ if(o>0) ret += ", ";
+ ret += se_to_query_string(op_list[o],aggr_tbl);
+ }
+ ret += "]";
+ return(ret);
+ default:
+ fprintf(stderr,"INTERNAL ERROR in pred_to_query_str, line %d, character %d, unknown predicate operator type %d\n",
+ pr->get_lineno(), pr->get_charno(), pr->get_operator_type() );
+ exit(1);
+ }
+
+ return(0);
+}
+
+
+
+// Build a selection list,
+// but avoid adding duplicate SEs.
+
+
+int add_select_list_nodup(vector<select_element *> &lfta_select_list, scalarexp_t *se,
+ bool &new_element){
+ new_element = false;
+ int s;
+ for(s=0;s<lfta_select_list.size();s++){
+ if(is_equivalent_se(lfta_select_list[s]->se, se)){
+ return(s);
+ }
+ }
+ new_element = true;
+ lfta_select_list.push_back(new select_element(se,"NoNameIn:add_select_list_nodup"));
+ return(lfta_select_list.size()-1);
+}
+
+
+
+// TODO: The generated colref should be tied to the tablevar
+// representing the lfta output. For now, always 0.
+
+scalarexp_t *make_fta_se_ref(vector<select_element *> &lfta_select_list, scalarexp_t *se, int h_tvref){
+ bool new_element;
+ int fta_se_nbr = add_select_list_nodup(lfta_select_list, se, new_element);
+ string colname;
+ if(!new_element){
+ colname = lfta_select_list[fta_se_nbr]->name;
+ }else{
+ colname = impute_colname(lfta_select_list, se);
+ lfta_select_list[fta_se_nbr]->name = colname;
+ }
+//
+// TODO: fill in the tablevar and schema of the colref here.
+ colref_t *new_cr = new colref_t(colname.c_str());
+ new_cr->set_tablevar_ref(h_tvref);
+
+
+ scalarexp_t *new_se= new scalarexp_t(new_cr);
+ new_se->use_decorations_of(se);
+
+ return(new_se);
+}
+
+
+// Build a selection list,
+// but avoid adding duplicate SEs.
+
+
+int add_select_list_nodup(vector<select_element *> *lfta_select_list, scalarexp_t *se,
+ bool &new_element){
+ new_element = false;
+ int s;
+ for(s=0;s<lfta_select_list->size();s++){
+ if(is_equivalent_se((*lfta_select_list)[s]->se, se)){
+ return(s);
+ }
+ }
+ new_element = true;
+ lfta_select_list->push_back(new select_element(se,"NoNameIn:add_select_list_nodup"));
+ return(lfta_select_list->size()-1);
+}
+
+
+
+// TODO: The generated colref should be tied to the tablevar
+// representing the lfta output. For now, always 0.
+
+scalarexp_t *make_fta_se_ref(vector<vector<select_element *> *> &lfta_select_list, scalarexp_t *se, int h_tvref){
+ bool new_element;
+ vector<select_element *> *the_sel_list = lfta_select_list[h_tvref];
+ int fta_se_nbr = add_select_list_nodup(the_sel_list, se, new_element);
+ string colname;
+ if(!new_element){
+ colname = (*the_sel_list)[fta_se_nbr]->name;
+ }else{
+ colname = impute_colname(*the_sel_list, se);
+ (*the_sel_list)[fta_se_nbr]->name = colname;
+ }
+//
+// TODO: fill in the tablevar and schema of the colref here.
+ colref_t *new_cr = new colref_t(colname.c_str());
+ new_cr->set_tablevar_ref(h_tvref);
+
+
+ scalarexp_t *new_se= new scalarexp_t(new_cr);
+ new_se->use_decorations_of(se);
+
+ return(new_se);
+}
+
+
+
+
+//
+// Test if a se can be evaluated at the fta.
+// check forbidden types (e.g. float), forbidden operations
+// between types (e.g. divide a long long), forbidden operations
+// (too expensive, not implemented).
+//
+// Return true if not forbidden, false if forbidden
+//
+// TODO: the parameter aggr_tbl is not used, delete it.
+
+bool check_fta_forbidden_se(scalarexp_t *se,
+ aggregate_table *aggr_tbl,
+ ext_fcn_list *Ext_fcns
+ ){
+
+ int p, fcn_id;
+ vector<scalarexp_t *> operand_list;
+ vector<data_type *> dt_signature;
+ data_type *dt = se->get_data_type();
+
+
+
+ switch(se->get_operator_type()){
+ case SE_LITERAL:
+ case SE_PARAM:
+ case SE_COLREF:
+ return( se->get_data_type()->fta_legal_type() );
+ case SE_IFACE_PARAM:
+ return true;
+ case SE_UNARY_OP:
+ if(!check_fta_forbidden_se(se->get_left_se(), aggr_tbl, Ext_fcns))
+ return(false);
+ return(
+ dt->fta_legal_operation(se->get_left_se()->get_data_type(), se->get_op())
+ );
+ case SE_BINARY_OP:
+ if(!check_fta_forbidden_se(se->get_left_se(),aggr_tbl, Ext_fcns))
+ return(false);
+ if(!check_fta_forbidden_se(se->get_right_se(),aggr_tbl, Ext_fcns))
+ return(false);
+ return(dt->fta_legal_operation(se->get_left_se()->get_data_type(),
+ se->get_right_se()->get_data_type(),
+ se->get_op()
+ )
+ );
+
+// return true, aggregate fta-safeness is determined elsewhere.
+ case SE_AGGR_STAR:
+ return(true);
+ case SE_AGGR_SE:
+ return(true);
+
+ case SE_FUNC:
+ if(se->get_aggr_ref() >= 0) return true;
+
+ operand_list = se->get_operands();
+ for(p=0;p<operand_list.size();p++){
+ if(!check_fta_forbidden_se(operand_list[p],aggr_tbl, Ext_fcns))
+ return(false);
+ dt_signature.push_back(operand_list[p]->get_data_type() );
+ }
+ fcn_id = Ext_fcns->lookup_fcn(se->get_op(), dt_signature);
+ if( fcn_id < 0 ){
+ fprintf(stderr,"ERROR, no external function %s(",se->get_op().c_str());
+ int o;
+ for(o=0;o<operand_list.size();o++){
+ if(o>0) fprintf(stderr,", ");
+ fprintf(stderr,"%s",operand_list[o]->get_data_type()->to_string().c_str());
+ }
+ fprintf(stderr,") is defined, line %d, char %d\n", se->get_lineno(), se->get_charno() );
+ if(fcn_id == -2) fprintf(stderr,"(multiple subsuming functions found)\n");
+ return(false);
+ }
+
+ return(Ext_fcns->fta_legal(fcn_id) );
+ default:
+ printf("INTERNAL ERROR in check_fta_forbidden_se: operator type %d\n",se->get_operator_type());
+ exit(1);
+ break;
+ }
+ return(false);
+
+}
+
+
+// test if a pr can be executed at the fta.
+//
+// Return true if not forbidden, false if forbidden
+
+bool check_fta_forbidden_pr(predicate_t *pr,
+ aggregate_table *aggr_tbl,
+ ext_fcn_list *Ext_fcns
+ ){
+
+ vector<literal_t *> llist;
+ data_type *dt;
+ int l,o, fcn_id;
+ vector<scalarexp_t *> op_list;
+ vector<data_type *> dt_signature;
+
+
+
+ switch(pr->get_operator_type()){
+ case PRED_IN:
+ if(! check_fta_forbidden_se(pr->get_left_se(), aggr_tbl, Ext_fcns) )
+ return(false);
+ llist = pr->get_lit_vec();
+ for(l=0;l<llist.size();l++){
+ dt = new data_type(llist[l]->get_type());
+ if(! dt->fta_legal_type()){
+ delete dt;
+ return(false);
+ }
+ delete dt;
+ }
+ return(true);
+ case PRED_COMPARE:
+ if(! check_fta_forbidden_se(pr->get_left_se(), aggr_tbl, Ext_fcns))
+ return(false);
+ if(! check_fta_forbidden_se(pr->get_right_se(), aggr_tbl, Ext_fcns))
+ return(false);
+ return(true);
+ case PRED_UNARY_OP:
+ return( check_fta_forbidden_pr(pr->get_left_pr(), aggr_tbl, Ext_fcns) );
+ case PRED_BINARY_OP:
+ if(! check_fta_forbidden_pr(pr->get_left_pr(), aggr_tbl, Ext_fcns))
+ return(false);
+ if(! check_fta_forbidden_pr(pr->get_right_pr(), aggr_tbl, Ext_fcns))
+ return(false);
+ return(true);
+ case PRED_FUNC:
+ op_list = pr->get_op_list();
+ for(o=0;o<op_list.size();o++){
+ if(!check_fta_forbidden_se(op_list[o],aggr_tbl, Ext_fcns))
+ return(false);
+ dt_signature.push_back(op_list[o]->get_data_type() );
+ }
+ fcn_id = Ext_fcns->lookup_pred(pr->get_op(), dt_signature);
+ if( fcn_id < 0 ){
+ fprintf(stderr,"ERROR, no external predicate %s(",pr->get_op().c_str());
+ int o;
+ for(o=0;o<op_list.size();o++){
+ if(o>0) fprintf(stderr,", ");
+ fprintf(stderr,"%s",op_list[o]->get_data_type()->to_string().c_str());
+ }
+ fprintf(stderr,") is defined, line %d, char %d\n", pr->get_lineno(), pr->get_charno() );
+ if(fcn_id == -2) fprintf(stderr,"(multiple subsuming predicates found)\n");
+ return(false);
+ }
+
+ return(Ext_fcns->fta_legal(fcn_id) );
+ default:
+ fprintf(stderr,"INTERNAL ERROR in check_fta_forbidden_pr, line %d, character %d, unknown predicate operator type %d\n",
+ pr->get_lineno(), pr->get_charno(), pr->get_operator_type() );
+ exit(1);
+ }
+
+ return(0);
+
+}
+
+
+// Split the aggregates in orig_aggr_tbl, into superaggregates and
+// subaggregates.
+// (the value of the HFTA aggregate might be a SE of several LFTA
+// subaggregates, e.g. avg : sum / count )
+// Register the superaggregates in hfta_aggr_tbl, and the
+// subaggregates in lfta_aggr_tbl.
+// Insert references to the subaggregates into lfta_select_list.
+// (and record their names in the currnames list)
+// Create a SE for the superaggregate, put it in hfta_aggr_se,
+// keyed on agr_id.
+
+void split_fta_aggr(aggregate_table *orig_aggr_tbl, int agr_id,
+ aggregate_table *hfta_aggr_tbl,
+ aggregate_table *lfta_aggr_tbl,
+ vector<select_element *> &lfta_select_list,
+ map<int,scalarexp_t *> &hfta_aggr_se,
+ ext_fcn_list *Ext_fcns
+ ){
+ bool new_element;
+ scalarexp_t *subaggr_se;
+ int fta_se_nbr;
+ string colname;
+ int ano;
+ colref_t *new_cr;
+ scalarexp_t *new_se, *l_se;
+ vector<scalarexp_t *> subaggr_ref_se;
+
+// UDAF processing
+ if(! orig_aggr_tbl->is_builtin(agr_id)){
+// Construct the subaggregate
+ int fcn_id = orig_aggr_tbl->get_fcn_id(agr_id);
+ vector<scalarexp_t *> opl = orig_aggr_tbl->get_operand_list(agr_id);
+ vector<scalarexp_t *> subopl;
+ int o;
+ for(o=0;o<opl.size();++o){
+ subopl.push_back(dup_se(opl[o], NULL));
+ }
+ int sub_id = Ext_fcns->get_subaggr_id(fcn_id);
+ subaggr_se = new scalarexp_t(Ext_fcns->get_fcn_name(sub_id).c_str(), subopl);
+ subaggr_se->set_fcn_id(sub_id);
+ subaggr_se->set_data_type(Ext_fcns->get_fcn_dt(sub_id));
+// Add it to the lfta select list.
+ fta_se_nbr = add_select_list_nodup(lfta_select_list, subaggr_se,new_element);
+ if(!new_element){
+ colname = lfta_select_list[fta_se_nbr]->name;
+ }else{
+ colname = impute_colname(lfta_select_list, subaggr_se);
+ lfta_select_list[fta_se_nbr]->name = colname;
+ 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));
+ subaggr_se->set_aggr_id(ano);
+ }
+
+// Construct a reference to the subaggregate
+ new_cr = new colref_t(colname.c_str());
+ new_se = new scalarexp_t(new_cr);
+// I'm not certain what the types should be ....
+// This will need to be filled in by later analysis.
+// NOTE: this might not capture all the meaning of data_type ...
+ new_se->set_data_type(Ext_fcns->get_fcn_dt(sub_id));
+ subaggr_ref_se.push_back(new_se);
+
+// Construct the superaggregate
+ int super_id = Ext_fcns->get_superaggr_id(fcn_id);
+ scalarexp_t *ret_se = new scalarexp_t(Ext_fcns->get_fcn_name(super_id).c_str(), subaggr_ref_se);
+ ret_se->set_fcn_id(super_id);
+ ret_se->set_data_type(Ext_fcns->get_fcn_dt(super_id));
+// Register it in the hfta aggregate table
+ 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);
+ ret_se->set_aggr_id(ano);
+ hfta_aggr_se[agr_id] = ret_se;
+
+ return;
+ }
+
+
+// builtin aggregate processing
+ bool l_forbid;
+
+ vector<bool> use_se;
+ vector<string> subaggr_names = orig_aggr_tbl->get_subaggr_fcns(agr_id, use_se);
+ vector<data_type *> subaggr_dt = orig_aggr_tbl->get_subaggr_dt(agr_id);
+ int sa;
+
+ if(orig_aggr_tbl->is_star_aggr(agr_id)){
+ for(sa=0;sa<subaggr_names.size();sa++){
+ subaggr_se = scalarexp_t::make_star_aggr(subaggr_names[sa].c_str());
+ subaggr_se->set_data_type(subaggr_dt[sa]);
+
+// The following sequence is similar to the code in make_fta_se_ref,
+// but there is special processing for the aggregate tables.
+ int fta_se_nbr = add_select_list_nodup(lfta_select_list, subaggr_se,new_element);
+ if(!new_element){
+ colname = lfta_select_list[fta_se_nbr]->name;
+ }else{
+ colname = impute_colname(lfta_select_list, subaggr_se);
+ lfta_select_list[fta_se_nbr]->name = colname;
+ ano = lfta_aggr_tbl->add_aggr(subaggr_names[sa].c_str(),NULL, false);
+ subaggr_se->set_aggr_id(ano);
+ }
+ new_cr = new colref_t(colname.c_str());
+ new_cr->set_tablevar_ref(0);
+ new_se = new scalarexp_t(new_cr);
+
+// I'm not certain what the types should be ....
+// This will need to be filled in by later analysis.
+// Actually, this is causing a problem.
+// I will assume a UINT data type. / change to INT
+// (consistent with assign_data_types in analyze_fta.cc)
+// TODO: why can't I use subaggr_dt, as I do in the other IF branch?
+ data_type *ndt = new data_type("Int"); // used to be Uint
+ new_se->set_data_type(ndt);
+
+ subaggr_ref_se.push_back(new_se);
+ }
+ }else{
+ for(sa=0;sa<subaggr_names.size();sa++){
+ if(use_se[sa]){
+ scalarexp_t *aggr_operand = orig_aggr_tbl->get_aggr_se(agr_id);
+ l_se = dup_se(aggr_operand, NULL);
+ subaggr_se = scalarexp_t::make_se_aggr(subaggr_names[sa].c_str(),l_se);
+ }else{
+ subaggr_se = scalarexp_t::make_star_aggr(subaggr_names[sa].c_str());
+ }
+ subaggr_se->set_data_type(subaggr_dt[sa]);
+
+// again, similar to make_fta_se_ref.
+ fta_se_nbr = add_select_list_nodup(lfta_select_list, subaggr_se,new_element);
+ if(!new_element){
+ colname = lfta_select_list[fta_se_nbr]->name;
+ }else{
+ colname = impute_colname(lfta_select_list, subaggr_se);
+ lfta_select_list[fta_se_nbr]->name = colname;
+ if(use_se[sa])
+ ano = lfta_aggr_tbl->add_aggr(subaggr_names[sa].c_str(),l_se, false);
+ else
+ ano = lfta_aggr_tbl->add_aggr(subaggr_names[sa].c_str(),NULL,false);
+ subaggr_se->set_aggr_id(ano);
+ }
+ new_cr = new colref_t(colname.c_str());
+ new_se = new scalarexp_t(new_cr);
+// I'm not certain what the types should be ....
+// This will need to be filled in by later analysis.
+// NOTE: this might not capture all the meaning of data_type ...
+ new_se->set_data_type(subaggr_dt[sa]);
+ subaggr_ref_se.push_back(new_se);
+ }
+ }
+ scalarexp_t *ret_se = orig_aggr_tbl->make_superaggr_se(agr_id, subaggr_ref_se);
+ ret_se->set_data_type(orig_aggr_tbl->get_data_type(agr_id));
+
+// ASSUME either the return value is an aggregation,
+// or a binary_op between two aggregations
+ if(ret_se->get_operator_type() == SE_AGGR_SE || ret_se->get_operator_type() == SE_AGGR_SE){
+ ano = hfta_aggr_tbl->add_aggr(ret_se->get_op(), ret_se->get_left_se(), false );
+ ret_se->set_aggr_id(ano);
+ }else{
+// Basically processing for AVG.
+// set the data type of the superagg to that of the subagg.
+ scalarexp_t *left_se = ret_se->get_left_se();
+ left_se->set_data_type(subaggr_dt[0]);
+ ano = hfta_aggr_tbl->add_aggr(left_se->get_op(), left_se->get_left_se(), false );
+ left_se->set_aggr_id(ano);
+
+ scalarexp_t *right_se = ret_se->get_right_se();
+ right_se->set_data_type(subaggr_dt[1]);
+ ano = hfta_aggr_tbl->add_aggr(right_se->get_op(), right_se->get_left_se(), false );
+ right_se->set_aggr_id(ano);
+ }
+
+ hfta_aggr_se[agr_id] = ret_se;
+
+}
+
+
+// Split the aggregates in orig_aggr_tbl, into hfta_superaggregates and
+// hfta_subaggregates.
+// Register the superaggregates in hi_aggr_tbl, and the
+// subaggregates in loq_aggr_tbl.
+// Insert references to the subaggregates into low_select_list.
+// (and record their names in the currnames list)
+// Create a SE for the superaggregate, put it in hfta_aggr_se,
+// keyed on agr_id.
+
+void split_hfta_aggr(aggregate_table *orig_aggr_tbl, int agr_id,
+ aggregate_table *hi_aggr_tbl,
+ aggregate_table *low_aggr_tbl,
+ vector<select_element *> &low_select_list,
+ map<int,scalarexp_t *> &hi_aggr_se,
+ ext_fcn_list *Ext_fcns
+ ){
+ bool new_element;
+ scalarexp_t *subaggr_se;
+ int fta_se_nbr;
+ string colname;
+ int ano;
+ colref_t *new_cr;
+ scalarexp_t *new_se, *l_se;
+ vector<scalarexp_t *> subaggr_ref_se;
+
+// UDAF processing
+ if(! orig_aggr_tbl->is_builtin(agr_id)){
+// Construct the subaggregate
+ int fcn_id = orig_aggr_tbl->get_fcn_id(agr_id);
+ vector<scalarexp_t *> opl = orig_aggr_tbl->get_operand_list(agr_id);
+ vector<scalarexp_t *> subopl;
+ int o;
+ for(o=0;o<opl.size();++o){
+ subopl.push_back(dup_se(opl[o], NULL));
+ }
+ int sub_id = Ext_fcns->get_hfta_subaggr_id(fcn_id);
+ subaggr_se = new scalarexp_t(Ext_fcns->get_fcn_name(sub_id).c_str(), subopl);
+ subaggr_se->set_fcn_id(sub_id);
+ subaggr_se->set_data_type(Ext_fcns->get_fcn_dt(sub_id));
+// Add it to the low select list.
+ fta_se_nbr = add_select_list_nodup(low_select_list, subaggr_se,new_element);
+ if(!new_element){
+ colname = low_select_list[fta_se_nbr]->name;
+ }else{
+ colname = impute_colname(low_select_list, subaggr_se);
+ low_select_list[fta_se_nbr]->name = colname;
+ 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);
+ subaggr_se->set_aggr_id(ano);
+ }
+
+// Construct a reference to the subaggregate
+ new_cr = new colref_t(colname.c_str());
+ new_se = new scalarexp_t(new_cr);
+// I'm not certain what the types should be ....
+// This will need to be filled in by later analysis.
+// NOTE: this might not capture all the meaning of data_type ...
+ new_se->set_data_type(Ext_fcns->get_fcn_dt(sub_id));
+ subaggr_ref_se.push_back(new_se);
+
+// Construct the superaggregate
+ int super_id = Ext_fcns->get_hfta_superaggr_id(fcn_id);
+ scalarexp_t *ret_se = new scalarexp_t(Ext_fcns->get_fcn_name(super_id).c_str(), subaggr_ref_se);
+ ret_se->set_fcn_id(super_id);
+ ret_se->set_data_type(Ext_fcns->get_fcn_dt(super_id));
+// Register it in the high aggregate table
+ 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);
+ ret_se->set_aggr_id(ano);
+ hi_aggr_se[agr_id] = ret_se;
+
+ return;
+ }
+
+
+// builtin aggregate processing
+ bool l_forbid;
+
+ vector<bool> use_se;
+ vector<string> subaggr_names = orig_aggr_tbl->get_subaggr_fcns(agr_id, use_se);
+ vector<data_type *> subaggr_dt = orig_aggr_tbl->get_subaggr_dt(agr_id);
+ int sa;
+
+ if(orig_aggr_tbl->is_star_aggr(agr_id)){
+ for(sa=0;sa<subaggr_names.size();sa++){
+ subaggr_se = scalarexp_t::make_star_aggr(subaggr_names[sa].c_str());
+ subaggr_se->set_data_type(subaggr_dt[sa]);
+
+// The following sequence is similar to the code in make_fta_se_ref,
+// but there is special processing for the aggregate tables.
+ int fta_se_nbr = add_select_list_nodup(low_select_list, subaggr_se,new_element);
+ if(!new_element){
+ colname = low_select_list[fta_se_nbr]->name;
+ }else{
+ colname = impute_colname(low_select_list, subaggr_se);
+ low_select_list[fta_se_nbr]->name = colname;
+ ano = low_aggr_tbl->add_aggr(subaggr_names[sa].c_str(),NULL, false);
+ subaggr_se->set_aggr_id(ano);
+ }
+ new_cr = new colref_t(colname.c_str());
+ new_cr->set_tablevar_ref(0);
+ new_se = new scalarexp_t(new_cr);
+
+// I'm not certain what the types should be ....
+// This will need to be filled in by later analysis.
+// Actually, this is causing a problem.
+// I will assume a UINT data type.
+// (consistent with assign_data_types in analyze_fta.cc)
+// TODO: why can't I use subaggr_dt, as I do in the other IF branch?
+ data_type *ndt = new data_type("Int"); // was Uint
+ new_se->set_data_type(ndt);
+
+ subaggr_ref_se.push_back(new_se);
+ }
+ }else{
+ for(sa=0;sa<subaggr_names.size();sa++){
+ if(use_se[sa]){
+ scalarexp_t *aggr_operand = orig_aggr_tbl->get_aggr_se(agr_id);
+ l_se = dup_se(aggr_operand, NULL);
+ subaggr_se = scalarexp_t::make_se_aggr(subaggr_names[sa].c_str(),l_se);
+ }else{
+ subaggr_se = scalarexp_t::make_star_aggr(subaggr_names[sa].c_str());
+ }
+ subaggr_se->set_data_type(subaggr_dt[sa]);
+
+// again, similar to make_fta_se_ref.
+ fta_se_nbr = add_select_list_nodup(low_select_list, subaggr_se,new_element);
+ if(!new_element){
+ colname = low_select_list[fta_se_nbr]->name;
+ }else{
+ colname = impute_colname(low_select_list, subaggr_se);
+ low_select_list[fta_se_nbr]->name = colname;
+ if(use_se[sa])
+ ano = low_aggr_tbl->add_aggr(subaggr_names[sa].c_str(),l_se, false);
+ else
+ ano = low_aggr_tbl->add_aggr(subaggr_names[sa].c_str(),NULL,false);
+ subaggr_se->set_aggr_id(ano);
+ }
+ new_cr = new colref_t(colname.c_str());
+ new_se = new scalarexp_t(new_cr);
+// I'm not certain what the types should be ....
+// This will need to be filled in by later analysis.
+// NOTE: this might not capture all the meaning of data_type ...
+ new_se->set_data_type(subaggr_dt[sa]);
+ subaggr_ref_se.push_back(new_se);
+ }
+ }
+ scalarexp_t *ret_se = orig_aggr_tbl->make_superaggr_se(agr_id, subaggr_ref_se);
+// ASSUME either the return value is an aggregation,
+// or a binary_op between two aggregations
+ if(ret_se->get_operator_type() == SE_AGGR_SE || ret_se->get_operator_type() == SE_AGGR_SE){
+ ret_se->set_data_type(orig_aggr_tbl->get_data_type(agr_id));
+ ano = hi_aggr_tbl->add_aggr(ret_se->get_op(), ret_se->get_left_se(), false );
+ }else{
+// Basically processing for AVG.
+// set the data type of the superagg to that of the subagg.
+ scalarexp_t *left_se = ret_se->get_left_se();
+ left_se->set_data_type(subaggr_dt[0]);
+ ano = hi_aggr_tbl->add_aggr(left_se->get_op(), left_se->get_left_se(), false );
+ left_se->set_aggr_id(ano);
+
+ scalarexp_t *right_se = ret_se->get_right_se();
+ right_se->set_data_type(subaggr_dt[1]);
+ ano = hi_aggr_tbl->add_aggr(right_se->get_op(), right_se->get_left_se(), false );
+ right_se->set_aggr_id(ano);
+ }
+
+ ret_se->set_aggr_id(ano);
+ hi_aggr_se[agr_id] = ret_se;
+
+}
+
+
+
+
+
+// Split a scalar expression into one part which executes
+// at the stream and another set of parts which execute
+// at the FTA.
+// Because I'm actually modifying the SEs, I will make
+// copies. But I will assume that literals, params, and
+// colrefs are immutable at this point.
+// (if there is ever a need to change one, must make a
+// new value).
+// NOTE : if se is constant (only refrences literals),
+// avoid making the fta compute it.
+//
+// NOTE : This will need to be generalized to
+// handle join expressions, namely to handle a vector
+// of lftas.
+//
+// Return value is the HFTA se.
+// Add lftas select_elements to the fta_select_list.
+// set fta_forbidden if this node or any child cannot
+// execute at the lfta.
+
+/*
+
+scalarexp_t *split_fta_se(scalarexp_t *se,
+ bool &fta_forbidden,
+ vector<select_element *> &lfta_select_list,
+ ext_fcn_list *Ext_fcns
+ ){
+
+ int p, fcn_id;
+ vector<scalarexp_t *> operand_list;
+ vector<data_type *> dt_signature;
+ scalarexp_t *ret_se, *l_se, *r_se;
+ bool l_forbid, r_forbid, this_forbid;
+ colref_t *new_cr;
+ scalarexp_t *new_se;
+ data_type *dt = se->get_data_type();
+
+ switch(se->get_operator_type()){
+ case SE_LITERAL:
+ fta_forbidden = ! se->get_data_type()->fta_legal_type();
+ ret_se = new scalarexp_t(se->get_literal());
+ ret_se->use_decorations_of(se);
+ return(ret_se);
+
+ case SE_PARAM:
+ fta_forbidden = ! se->get_data_type()->fta_legal_type();
+ ret_se = scalarexp_t::make_param_reference(se->get_op().c_str());
+ ret_se->use_decorations_of(se);
+ return(ret_se);
+
+ case SE_COLREF:
+// No colref should be forbidden,
+// the schema is wrong, the fta_legal_type() fcn is wrong,
+// or the source table is actually a stream.
+// Issue a warning, but proceed with processing.
+// Also, should not be a ref to a gbvar.
+// (a gbvar ref only occurs in an aggregation node,
+// and these SEs are rehomed, not split.
+ fta_forbidden = ! se->get_data_type()->fta_legal_type();
+
+ if(fta_forbidden){
+ fprintf(stderr,"WARNING, a colref is a forbidden data type in split_fta_se,"
+ " colref is %s,"
+ " type is %s, line=%d, col=%d\n",
+ se->get_colref()->to_string().c_str(),
+ se->get_data_type()->get_type_str().c_str(),
+ se->lineno, se->charno
+ );
+ }
+
+ if(se->is_gb()){
+ fprintf(stderr,"INTERNAL ERROR, a colref is a gbvar ref in split_fta_se,"
+ " type is %s, line=%d, col=%d\n",
+ se->get_data_type()->get_type_str().c_str(),
+ se->lineno, se->charno
+ );
+ exit(1);
+ }
+
+ ret_se = new scalarexp_t(se->get_colref());
+ ret_se->use_decorations_of(se);
+ return(ret_se);
+
+ case SE_UNARY_OP:
+ l_se = split_fta_se(se->get_left_se(), l_forbid, lfta_select_list, Ext_fcns);
+
+ this_forbid = ! dt->fta_legal_operation(l_se->get_data_type(), se->get_op());
+
+// If this operation is forbidden but the child SE is not,
+// put the child se on the lfta_select_list, create a colref
+// which accesses this se, and make it the child of this op.
+// Exception : the child se is constant (only literal refs).
+ if(this_forbid && !l_forbid){
+ if(!is_literal_or_param_only(l_se)){
+ new_se = make_fta_se_ref(lfta_select_list, l_se,0);
+ ret_se = new scalarexp_t(se->get_op().c_str(), new_se);
+ }
+ }else{
+ ret_se = new scalarexp_t(se->get_op().c_str(), l_se);
+ }
+ ret_se->use_decorations_of(se);
+ fta_forbidden = this_forbid | l_forbid;
+ return(ret_se);
+
+ case SE_BINARY_OP:
+ l_se = split_fta_se(se->get_left_se(), l_forbid, lfta_select_list, Ext_fcns);
+ r_se = split_fta_se(se->get_right_se(), r_forbid, lfta_select_list, Ext_fcns);
+
+ this_forbid = ! dt->fta_legal_operation(l_se->get_data_type(), r_se->get_data_type(), se->get_op());
+
+// Replace the left se if it is not forbidden, but something else is.
+ if((this_forbid || r_forbid) & !l_forbid){
+ if(!is_literal_or_param_only(l_se)){
+ new_se = make_fta_se_ref(lfta_select_list, l_se,0);
+ l_se = new_se;
+ }
+ }
+
+// Replace the right se if it is not forbidden, but something else is.
+ if((this_forbid || l_forbid) & !r_forbid){
+ if(!is_literal_or_param_only(r_se)){
+ new_se = make_fta_se_ref(lfta_select_list, r_se,0);
+ r_se = new_se;
+ }
+ }
+
+ ret_se = new scalarexp_t(se->get_op().c_str(), l_se, r_se);
+ ret_se->use_decorations_of(se);
+ fta_forbidden = this_forbid || r_forbid || l_forbid;
+
+ return(ret_se);
+
+ case SE_AGGR_STAR:
+ case SE_AGGR_SE:
+
+ fprintf(stderr,"INTERNAL ERROR, aggregate ref (%s) in split_fta_se."
+ " line=%d, col=%d\n",
+ se->get_op().c_str(),
+ se->lineno, se->charno
+ );
+ exit(1);
+ break;
+
+ case SE_FUNC:
+ {
+ fta_forbidden = false;
+ operand_list = se->get_operands();
+ vector<scalarexp_t *> new_operands;
+ vector<bool> forbidden_op;
+ for(p=0;p<operand_list.size();p++){
+ l_se = split_fta_se(operand_list[p], l_forbid, lfta_select_list, Ext_fcns);
+
+ fta_forbidden |= l_forbid;
+ new_operands.push_back(l_se);
+ forbidden_op.push_back(l_forbid);
+ dt_signature.push_back(operand_list[p]->get_data_type() );
+ }
+
+ fcn_id = Ext_fcns->lookup_fcn(se->get_op(), dt_signature);
+ if( fcn_id < 0 ){
+ fprintf(stderr,"ERROR, no external function %s(",se->get_op().c_str());
+ int o;
+ for(o=0;o<operand_list.size();o++){
+ if(o>0) fprintf(stderr,", ");
+ fprintf(stderr,"%s",operand_list[o]->get_data_type()->get_type_str().c_str());
+ }
+ fprintf(stderr,") is defined, line %d, char %d\n", se->get_lineno(), se->get_charno() );
+ if(fcn_id == -2) fprintf(stderr,"(multiple subsuming functions found)\n");
+ return(false);
+ }
+
+ fta_forbidden |= (! Ext_fcns->fta_legal(fcn_id));
+
+// Replace the non-forbidden operands.
+// the forbidden ones are already replaced.
+ if(fta_forbidden){
+ for(p=0;p<new_operands.size();p++){
+ if(! forbidden_op[p]){
+// if(new_operands[p]->get_data_type()->get_temporal() != constant_t){
+ if(!is_literal_or_param_only(new_operands[p])){
+ new_se = make_fta_se_ref(lfta_select_list, new_operands[p],0);
+ new_operands[p] = new_se;
+ }
+ }
+ }
+ }
+
+ ret_se = new scalarexp_t(se->get_op().c_str(), new_operands);
+ ret_se->use_decorations_of(se);
+
+ return(ret_se);
+
+ }
+ default:
+ printf("INTERNAL ERROR in check_fta_forbidden_se: operator type %d\n",se->get_operator_type());
+ exit(1);
+ break;
+ }
+ return(false);
+
+}
+
+*/
+
+
+// The predicates have already been
+// broken into conjunctions.
+// If any part of a conjunction is fta-forbidden,
+// it must be executed in the stream operator.
+// Else it is executed in the FTA.
+// A pre-analysis should determine whether this
+// predicate is fta-safe. This procedure will
+// assume that it is fta-forbidden and will
+// prepare it for execution in the stream.
+
+/*
+
+predicate_t *split_fta_pr(predicate_t *pr,
+ vector<select_element *> &lfta_select_list,
+ ext_fcn_list *Ext_fcns
+ ){
+
+ vector<literal_t *> llist;
+ scalarexp_t *se_l, *se_r;
+ bool l_forbid, r_forbid;
+ predicate_t *ret_pr, *pr_l, *pr_r;
+ vector<scalarexp_t *> op_list, new_op_list;
+ int o;
+ vector<data_type *> dt_signature;
+
+
+ switch(pr->get_operator_type()){
+ case PRED_IN:
+ se_l = split_fta_se(pr->get_left_se(), l_forbid, lfta_select_list, Ext_fcns);
+
+ if(!l_forbid){
+ if(!is_literal_or_param_only(se_l)){
+ scalarexp_t *new_se = make_fta_se_ref(lfta_select_list, se_l,0);
+ se_l = new_se;
+ }
+ }
+ ret_pr = new predicate_t(se_l, pr->get_lit_vec());
+
+ return(ret_pr);
+
+ case PRED_COMPARE:
+ se_l = split_fta_se(pr->get_left_se(), l_forbid, lfta_select_list, Ext_fcns);
+ if(!l_forbid){
+ if(!is_literal_or_param_only(se_l)){
+ scalarexp_t *new_se = make_fta_se_ref(lfta_select_list, se_l,0);
+ se_l = new_se;
+ }
+ }
+
+ se_r = split_fta_se(pr->get_right_se(), r_forbid, lfta_select_list, Ext_fcns);
+ if(!r_forbid){
+ if(!is_literal_or_param_only(se_r)){
+ scalarexp_t *new_se = make_fta_se_ref(lfta_select_list, se_r,0);
+ se_r = new_se;
+ }
+ }
+
+ ret_pr = new predicate_t(se_l, pr->get_op().c_str(), se_r);
+ return(ret_pr);
+
+ case PRED_UNARY_OP:
+ pr_l = split_fta_pr(pr->get_left_pr(), lfta_select_list, Ext_fcns);
+ ret_pr = new predicate_t(pr->get_op().c_str(), pr_l);
+ return(ret_pr);
+
+ case PRED_BINARY_OP:
+ pr_l = split_fta_pr(pr->get_left_pr(), lfta_select_list, Ext_fcns);
+ pr_r = split_fta_pr(pr->get_right_pr(), lfta_select_list, Ext_fcns);
+ ret_pr = new predicate_t(pr->get_op().c_str(), pr_l, pr_r);
+ return(ret_pr);
+
+ case PRED_FUNC:
+// I can't push the predicate into the lfta, except by
+// returning a bool value, and that is not worth the trouble,
+ op_list = pr->get_op_list();
+ for(o=0;o<op_list.size();++o){
+ se_l = split_fta_se(op_list[o],l_forbid,lfta_select_list,Ext_fcns);
+ if(!l_forbid){
+ if(!is_literal_or_param_only(se_l)){
+ scalarexp_t *new_se = make_fta_se_ref(lfta_select_list, se_l,0);
+ se_l = new_se;
+ }
+ }
+ new_op_list.push_back(se_l);
+ }
+
+ ret_pr = new predicate_t(pr->get_op().c_str(), new_op_list);
+ ret_pr->set_fcn_id(pr->get_fcn_id());
+ return(ret_pr);
+ default:
+ fprintf(stderr,"INTERNAL ERROR in split_fta_pr, line %d, character %d, unknown predicate operator type %d\n",
+ pr->get_lineno(), pr->get_charno(), pr->get_operator_type() );
+ exit(1);
+ }
+
+ return(0);
+
+}
+
+*/
+
+
+//--------------------------------------------------------------------
+
+
+
+// Split a scalar expression into one part which executes
+// at the stream and another set of parts which execute
+// at the FTA.
+// Because I'm actually modifying the SEs, I will make
+// copies. But I will assume that literals, params, and
+// colrefs are immutable at this point.
+// (if there is ever a need to change one, must make a
+// new value).
+// NOTE : if se is constant (only refrences literals),
+// avoid making the fta compute it.
+//
+// NOTE : This will need to be generalized to
+// handle join expressions, namely to handle a vector
+// of lftas.
+//
+// Return value is the HFTA se.
+// Add lftas select_elements to the fta_select_list.
+// set fta_forbidden if this node or any child cannot
+// execute at the lfta.
+
+#define SPLIT_FTAVEC_NOTBLVAR -1
+#define SPLIT_FTAVEC_MIXED -2
+
+bool is_PROTOCOL_source(int colref_source,
+ vector< vector<select_element *> *> &lfta_select_list){
+ if(colref_source>=0 && lfta_select_list[colref_source]!=NULL) return true;
+ return false;
+}
+
+int combine_colref_source(int s1, int s2){
+ if(s1==s2) return(s1);
+ if(s1==SPLIT_FTAVEC_NOTBLVAR) return s2;
+ if(s2==SPLIT_FTAVEC_NOTBLVAR) return s1;
+ return SPLIT_FTAVEC_MIXED;
+}
+
+scalarexp_t *split_ftavec_se(
+ scalarexp_t *se, // the SE to split
+ bool &fta_forbidden, // return true if some part of se
+ // is fta-unsafe
+ int &colref_source, // the tblvar which sources the
+ // colref, or NOTBLVAR, or MIXED
+ vector< vector<select_element *> *> &lfta_select_list,
+ // NULL if the tblvar is not PROTOCOL,
+ // else build the select list.
+ ext_fcn_list *Ext_fcns // is the fcn lfta-safe?
+ ){
+// Return value is the HFTA SE, unless fta_forbidden is true and
+// colref_source>=0 and the indicated source is PROTOCOL.
+// In that case no split was done, the make_fta_se_ref must
+// be done by the caller.
+
+ int p, fcn_id;
+ vector<scalarexp_t *> operand_list;
+ vector<data_type *> dt_signature;
+ scalarexp_t *ret_se, *l_se, *r_se;
+ bool l_forbid, r_forbid, this_forbid;
+ int l_csource, r_csource, this_csource;
+ colref_t *new_cr;
+ scalarexp_t *new_se;
+ data_type *dt = se->get_data_type();
+
+ switch(se->get_operator_type()){
+ case SE_LITERAL:
+ fta_forbidden = ! se->get_data_type()->fta_legal_type();
+ colref_source = SPLIT_FTAVEC_NOTBLVAR;
+ ret_se = new scalarexp_t(se->get_literal());
+ ret_se->use_decorations_of(se);
+ return(ret_se);
+
+ case SE_PARAM:
+ fta_forbidden = ! se->get_data_type()->fta_legal_type();
+ colref_source = SPLIT_FTAVEC_NOTBLVAR;
+ ret_se = scalarexp_t::make_param_reference(se->get_op().c_str());
+ ret_se->use_decorations_of(se);
+ return(ret_se);
+
+ case SE_IFACE_PARAM:
+ fta_forbidden = false;
+ colref_source = se->get_ifpref()->get_tablevar_ref();
+ ret_se = scalarexp_t::make_iface_param_reference(se->get_ifpref());
+ ret_se->use_decorations_of(se);
+ return(ret_se);
+
+ case SE_COLREF:
+// No colref should be forbidden,
+// the schema is wrong, the fta_legal_type() fcn is wrong,
+// or the source table is actually a stream.
+// Issue a warning, but proceed with processing.
+// Also, should not be a ref to a gbvar.
+// (a gbvar ref only occurs in an aggregation node,
+// and these SEs are rehomed, not split.
+ fta_forbidden = ! se->get_data_type()->fta_legal_type();
+ colref_source = se->get_colref()->get_tablevar_ref();
+
+ if(fta_forbidden && is_PROTOCOL_source(colref_source, lfta_select_list)){
+ fprintf(stderr,"WARNING, a PROTOCOL colref is a forbidden data type in split_ftavec_se,"
+ " colref is %s,"
+ " type is %s, line=%d, col=%d\n",
+ se->get_colref()->to_string().c_str(),
+ se->get_data_type()->to_string().c_str(),
+ se->lineno, se->charno
+ );
+ }
+
+ if(se->is_gb()){
+ fta_forbidden = true; // eval in hfta. ASSUME make copy as below.
+ }
+
+ ret_se = new scalarexp_t(se->get_colref());
+ ret_se->use_decorations_of(se);
+ return(ret_se);
+
+ case SE_UNARY_OP:
+ l_se = split_ftavec_se(se->get_left_se(), l_forbid, colref_source, lfta_select_list, Ext_fcns);
+
+ this_forbid = ! dt->fta_legal_operation(l_se->get_data_type(), se->get_op());
+
+// If this operation is forbidden but the child SE is not,
+// AND the colref source in the se is a single PROTOCOL source
+// put the child se on the lfta_select_list, create a colref
+// which accesses this se, and make it the child of this op.
+// Exception : the child se is constant (only literal refs).
+// TODO: I think the exception is expressed by is_PROTOCOL_source
+ if(this_forbid && !l_forbid && is_PROTOCOL_source(colref_source, lfta_select_list)){
+ if(!is_literal_or_param_only(l_se)){
+ new_se = make_fta_se_ref(lfta_select_list, l_se,colref_source);
+ ret_se = new scalarexp_t(se->get_op().c_str(), new_se);
+ }
+ }else{
+ ret_se = new scalarexp_t(se->get_op().c_str(), l_se);
+ }
+ ret_se->use_decorations_of(se);
+ fta_forbidden = this_forbid | l_forbid;
+ return(ret_se);
+
+ case SE_BINARY_OP:
+ l_se = split_ftavec_se(se->get_left_se(), l_forbid, l_csource, lfta_select_list, Ext_fcns);
+ r_se = split_ftavec_se(se->get_right_se(), r_forbid, r_csource, lfta_select_list, Ext_fcns);
+
+ this_forbid = ! dt->fta_legal_operation(l_se->get_data_type(), r_se->get_data_type(), se->get_op());
+ colref_source=combine_colref_source(l_csource, r_csource);
+
+// Replace the left se if the parent must be hfta but the child can
+// be lfta. This translates to
+// a) result is PROTOCOL and forbidden, but left SE is not forbidden
+// OR b) if result is mixed but the left se is PROTOCOL, not forbidden
+ if( ((this_forbid || r_forbid) && !l_forbid && is_PROTOCOL_source(colref_source, lfta_select_list) ) ||
+ (colref_source==SPLIT_FTAVEC_MIXED && !l_forbid &&
+ is_PROTOCOL_source(l_csource, lfta_select_list)) ){
+ if(!is_literal_or_param_only(l_se)){
+ new_se = make_fta_se_ref(lfta_select_list, l_se,l_csource);
+ l_se = new_se;
+ }
+ }
+
+// same logic as for right se.
+ if( ((this_forbid || l_forbid) && !r_forbid && is_PROTOCOL_source(colref_source, lfta_select_list) ) ||
+ (colref_source==SPLIT_FTAVEC_MIXED && !r_forbid &&
+ is_PROTOCOL_source(r_csource, lfta_select_list)) ){
+ if(!is_literal_or_param_only(r_se)){
+ new_se = make_fta_se_ref(lfta_select_list, r_se,r_csource);
+ r_se = new_se;
+ }
+ }
+
+ ret_se = new scalarexp_t(se->get_op().c_str(), l_se, r_se);
+ ret_se->use_decorations_of(se);
+ fta_forbidden = this_forbid || r_forbid || l_forbid;
+
+ return(ret_se);
+
+ case SE_AGGR_STAR:
+ case SE_AGGR_SE:
+
+ fprintf(stderr,"INTERNAL ERROR, aggregate ref (%s) in split_ftavec_se."
+ " line=%d, col=%d\n",
+ se->get_op().c_str(),
+ se->lineno, se->charno
+ );
+ exit(1);
+ break;
+
+ case SE_FUNC:
+ {
+ operand_list = se->get_operands();
+ vector<scalarexp_t *> new_operands;
+ vector<bool> forbidden_op;
+ vector<int> csource;
+
+ fta_forbidden = false;
+ colref_source = SPLIT_FTAVEC_NOTBLVAR;
+ for(p=0;p<operand_list.size();p++){
+ l_se = split_ftavec_se(operand_list[p], l_forbid, l_csource, lfta_select_list, Ext_fcns);
+
+ fta_forbidden |= l_forbid;
+ colref_source = combine_colref_source(colref_source, l_csource);
+ new_operands.push_back(l_se);
+ forbidden_op.push_back(l_forbid);
+ csource.push_back(l_csource);
+ dt_signature.push_back(operand_list[p]->get_data_type() );
+ }
+
+ fcn_id = Ext_fcns->lookup_fcn(se->get_op(), dt_signature);
+ if( fcn_id < 0 ){
+ fprintf(stderr,"ERROR, no external function %s(",se->get_op().c_str());
+ int o;
+ for(o=0;o<operand_list.size();o++){
+ if(o>0) fprintf(stderr,", ");
+ fprintf(stderr,"%s",operand_list[o]->get_data_type()->to_string().c_str());
+ }
+ fprintf(stderr,") is defined, line %d, char %d\n", se->get_lineno(), se->get_charno() );
+ if(fcn_id == -2) fprintf(stderr,"(multiple subsuming functions found)\n");
+ return NULL;
+ }
+
+ fta_forbidden |= (! Ext_fcns->fta_legal(fcn_id));
+
+// Replace the non-forbidden operands.
+// the forbidden ones are already replaced.
+ if(fta_forbidden || colref_source == SPLIT_FTAVEC_MIXED){
+ for(p=0;p<new_operands.size();p++){
+ if(! forbidden_op[p] && is_PROTOCOL_source(csource[p], lfta_select_list)){
+ if(!is_literal_or_param_only(new_operands[p])){
+ new_se = make_fta_se_ref(lfta_select_list, new_operands[p],csource[p]);
+ new_operands[p] = new_se;
+ }
+ }
+ }
+ }
+
+ ret_se = new scalarexp_t(se->get_op().c_str(), new_operands);
+ ret_se->use_decorations_of(se);
+
+ return(ret_se);
+
+ }
+ default:
+ printf("INTERNAL ERROR in split_ftavec_se: operator type %d\n",se->get_operator_type());
+ exit(1);
+ break;
+ }
+ return(NULL);
+
+}
+
+
+// The predicates have already been
+// broken into conjunctions.
+// If any part of a conjunction is fta-forbidden,
+// it must be executed in the stream operator.
+// Else it is executed in the FTA.
+// A pre-analysis should determine whether this
+// predicate is fta-safe. This procedure will
+// assume that it is fta-forbidden and will
+// prepare it for execution in the stream.
+
+predicate_t *split_ftavec_pr(predicate_t *pr,
+ vector< vector<select_element *> *> &lfta_select_list,
+ ext_fcn_list *Ext_fcns
+ ){
+
+ vector<literal_t *> llist;
+ scalarexp_t *se_l, *se_r;
+ bool l_forbid, r_forbid;
+ int l_csource, r_csource;
+ predicate_t *ret_pr, *pr_l, *pr_r;
+ vector<scalarexp_t *> op_list, new_op_list;
+ int o;
+ vector<data_type *> dt_signature;
+
+
+ switch(pr->get_operator_type()){
+ case PRED_IN:
+ se_l = split_ftavec_se(pr->get_left_se(), l_forbid, l_csource, lfta_select_list, Ext_fcns);
+
+// TODO: checking that the se is a PROTOCOL source should
+// take care of literal_or_param_only.
+ if(!l_forbid && is_PROTOCOL_source(l_csource, lfta_select_list)){
+ if(!is_literal_or_param_only(se_l)){
+ scalarexp_t *new_se = make_fta_se_ref(lfta_select_list, se_l,l_csource);
+ se_l = new_se;
+ }
+ }
+ ret_pr = new predicate_t(se_l, pr->get_lit_vec());
+
+ return(ret_pr);
+
+ case PRED_COMPARE:
+ se_l = split_ftavec_se(pr->get_left_se(), l_forbid, l_csource, lfta_select_list, Ext_fcns);
+ if(!l_forbid && is_PROTOCOL_source(l_csource, lfta_select_list)){
+ if(!is_literal_or_param_only(se_l)){
+ scalarexp_t *new_se = make_fta_se_ref(lfta_select_list, se_l,l_csource);
+ se_l = new_se;
+ }
+ }
+
+ se_r = split_ftavec_se(pr->get_right_se(), r_forbid, r_csource, lfta_select_list, Ext_fcns);
+ if(!r_forbid && is_PROTOCOL_source(r_csource, lfta_select_list)){
+ if(!is_literal_or_param_only(se_r)){
+ scalarexp_t *new_se = make_fta_se_ref(lfta_select_list, se_r,r_csource);
+ se_r = new_se;
+ }
+ }
+
+ ret_pr = new predicate_t(se_l, pr->get_op().c_str(), se_r);
+ return(ret_pr);
+
+ case PRED_UNARY_OP:
+ pr_l = split_ftavec_pr(pr->get_left_pr(), lfta_select_list, Ext_fcns);
+ ret_pr = new predicate_t(pr->get_op().c_str(), pr_l);
+ return(ret_pr);
+
+ case PRED_BINARY_OP:
+ pr_l = split_ftavec_pr(pr->get_left_pr(), lfta_select_list, Ext_fcns);
+ pr_r = split_ftavec_pr(pr->get_right_pr(), lfta_select_list, Ext_fcns);
+ ret_pr = new predicate_t(pr->get_op().c_str(), pr_l, pr_r);
+ return(ret_pr);
+
+ case PRED_FUNC:
+// I can't push the predicate into the lfta, except by
+// returning a bool value, and that is not worth the trouble,
+ op_list = pr->get_op_list();
+ for(o=0;o<op_list.size();++o){
+ se_l = split_ftavec_se(op_list[o],l_forbid,l_csource,lfta_select_list,Ext_fcns);
+ if(!l_forbid && is_PROTOCOL_source(l_csource, lfta_select_list)){
+ if(!is_literal_or_param_only(se_l)){
+ scalarexp_t *new_se = make_fta_se_ref(lfta_select_list, se_l,l_csource);
+ se_l = new_se;
+ }
+ }
+ new_op_list.push_back(se_l);
+ }
+
+ ret_pr = new predicate_t(pr->get_op().c_str(), new_op_list);
+ ret_pr->set_fcn_id(pr->get_fcn_id());
+ return(ret_pr);
+ default:
+ fprintf(stderr,"INTERNAL ERROR in split_fta_pr, line %d, character %d, unknown predicate operator type %d\n",
+ pr->get_lineno(), pr->get_charno(), pr->get_operator_type() );
+ exit(1);
+ }
+
+ return(0);
+
+}
+
+
+
+////////////////////////////////////////////////////////////////////////
+/// rehome_hfta_se rehome_hfta_pr
+/// This is use to split an sgah operator (aggregation),
+/// I just need to make gb, aggr references point to the
+/// new gb, aggr table entries.
+
+
+scalarexp_t *rehome_fta_se(scalarexp_t *se,
+ map< int, scalarexp_t * > *aggr_map
+ ){
+
+ int p, fcn_id;
+ int agr_id;
+ vector<scalarexp_t *> operand_list;
+ scalarexp_t *ret_se, *l_se, *r_se;
+ colref_t *new_cr;
+ scalarexp_t *new_se;
+ data_type *dt = se->get_data_type();
+ vector<scalarexp_t *> new_operands;
+
+ switch(se->get_operator_type()){
+ case SE_LITERAL:
+ ret_se = new scalarexp_t(se->get_literal());
+ ret_se->use_decorations_of(se);
+ return(ret_se);
+
+ case SE_PARAM:
+ ret_se = scalarexp_t::make_param_reference(se->get_op().c_str());
+ ret_se->use_decorations_of(se);
+ return(ret_se);
+
+ case SE_IFACE_PARAM:
+ ret_se = scalarexp_t::make_iface_param_reference(se->get_ifpref());
+ ret_se->use_decorations_of(se);
+ return(ret_se);
+
+
+
+ case SE_COLREF:
+// Must be a GB REF ...
+// I'm assuming that the hfta gbvar table has the
+// same sequence of entries as the input query's gbvar table.
+// Else I'll need some kind of translation table.
+
+ if(! se->is_gb()){
+ fprintf(stderr,"WARNING, a colref is not a gbver ref in rehome_hfta_se"
+ " type is %s, line=%d, col=%d\n",
+ se->get_data_type()->to_string().c_str(),
+ se->lineno, se->charno
+ );
+ }
+
+ ret_se = new scalarexp_t(se->get_colref());
+ ret_se->use_decorations_of(se); // just inherit the gbref
+ return(ret_se);
+
+ case SE_UNARY_OP:
+ l_se = rehome_fta_se(se->get_left_se(), aggr_map);
+
+ ret_se = new scalarexp_t(se->get_op().c_str(), l_se);
+ ret_se->use_decorations_of(se);
+ return(ret_se);
+
+ case SE_BINARY_OP:
+ l_se = rehome_fta_se(se->get_left_se(), aggr_map);
+ r_se = rehome_fta_se(se->get_right_se(), aggr_map);
+
+ ret_se = new scalarexp_t(se->get_op().c_str(), l_se, r_se);
+ ret_se->use_decorations_of(se);
+
+ return(ret_se);
+
+ case SE_AGGR_STAR:
+ case SE_AGGR_SE:
+ agr_id = se->get_aggr_ref();
+ return (*aggr_map)[agr_id];
+ break;
+
+ case SE_FUNC:
+ agr_id = se->get_aggr_ref();
+ if(agr_id >= 0) return (*aggr_map)[agr_id];
+
+ operand_list = se->get_operands();
+ for(p=0;p<operand_list.size();p++){
+ l_se = rehome_fta_se(operand_list[p], aggr_map);
+
+ new_operands.push_back(l_se);
+ }
+
+
+ ret_se = new scalarexp_t(se->get_op().c_str(), new_operands);
+ ret_se->use_decorations_of(se);
+
+ return(ret_se);
+
+ default:
+ printf("INTERNAL ERROR in rehome_fta_se: operator type %d\n",se->get_operator_type());
+ exit(1);
+ break;
+ }
+ return(NULL);
+
+}
+
+
+// The predicates have already been
+// broken into conjunctions.
+// If any part of a conjunction is fta-forbidden,
+// it must be executed in the stream operator.
+// Else it is executed in the FTA.
+// A pre-analysis should determine whether this
+// predicate is fta-safe. This procedure will
+// assume that it is fta-forbidden and will
+// prepare it for execution in the stream.
+
+predicate_t *rehome_fta_pr(predicate_t *pr,
+ map<int, scalarexp_t *> *aggr_map
+ ){
+
+ vector<literal_t *> llist;
+ scalarexp_t *se_l, *se_r;
+ predicate_t *ret_pr, *pr_l, *pr_r;
+ vector<scalarexp_t *> op_list, new_op_list;
+ int o;
+
+ switch(pr->get_operator_type()){
+ case PRED_IN:
+ se_l = rehome_fta_se(pr->get_left_se(), aggr_map);
+ ret_pr = new predicate_t(se_l, pr->get_lit_vec());
+ return(ret_pr);
+
+ case PRED_COMPARE:
+ se_l = rehome_fta_se(pr->get_left_se(), aggr_map);
+ se_r = rehome_fta_se(pr->get_right_se(), aggr_map);
+ ret_pr = new predicate_t(se_l, pr->get_op().c_str(), se_r);
+ return(ret_pr);
+
+ case PRED_UNARY_OP:
+ pr_l = rehome_fta_pr(pr->get_left_pr(), aggr_map);
+ ret_pr = new predicate_t(pr->get_op().c_str(), pr_l);
+ return(ret_pr);
+
+ case PRED_BINARY_OP:
+ pr_l = rehome_fta_pr(pr->get_left_pr(), aggr_map);
+ pr_r = rehome_fta_pr(pr->get_right_pr(), aggr_map);
+ ret_pr = new predicate_t(pr->get_op().c_str(), pr_l, pr_r);
+ return(ret_pr);
+
+ case PRED_FUNC:
+ op_list = pr->get_op_list();
+ for(o=0;o<op_list.size();++o){
+ se_l = rehome_fta_se(op_list[o], aggr_map);
+ new_op_list.push_back(se_l);
+ }
+ ret_pr= new predicate_t(pr->get_op().c_str(), new_op_list);
+ ret_pr->set_fcn_id(pr->get_fcn_id());
+ return(ret_pr);
+
+ default:
+ fprintf(stderr,"INTERNAL ERROR in rehome_fta_pr, line %d, character %d, unknown predicate operator type %d\n",
+ pr->get_lineno(), pr->get_charno(), pr->get_operator_type() );
+ exit(1);
+ }
+
+ return(0);
+
+}
+
+
+////////////////////////////////////////////////////////////////////
+///////////////// Create a STREAM table to represent the FTA output.
+
+table_def *create_attributes(string tname, vector<select_element *> &select_list){
+ int s;
+
+
+// Create a new STREAM schema for the output of the FTA.
+
+ field_entry_list *fel = new field_entry_list();
+ set<string> ufcns;
+ for(s=0;s<select_list.size();s++){
+ scalarexp_t *sel_se = select_list[s]->se;
+ data_type *dt = sel_se->get_data_type();
+
+// Grab the annotations of the field.
+// As of this writing, the only meaningful annotations
+// are whether or not the attribute is temporal.
+// There can be an annotation of constant_t, but
+// I'll ignore this, it feels like an unsafe assumption
+ param_list *plist = new param_list();
+// if(dt->is_temporal()){
+ vector<string> param_strings = dt->get_param_keys();
+ int p;
+ for(p=0;p<param_strings.size();++p){
+ string v = dt->get_param_val(param_strings[p]);
+ if(v != "")
+ plist->append(param_strings[p].c_str(),v.c_str());
+ else
+ plist->append(param_strings[p].c_str());
+ }
+// }
+
+// char access_fcn_name[500];
+ string colname = select_list[s]->name;
+// sprintf(access_fcn_name,"get_field_%s",colname.c_str());
+ string access_fcn_name = "get_field_"+colname;
+ field_entry *fe = new field_entry(
+ dt->get_type_str(), colname, access_fcn_name, plist, ufcns
+ );
+
+ fel->append_field(fe);
+ }
+
+ table_def *fta_tbl = new table_def(
+ tname.c_str(), NULL, NULL, fel, STREAM_SCHEMA
+ );
+
+ return(fta_tbl);
+
+}
+
+//------------------------------------------------------------------
+// Textual representation of the query node.
+
+
+
+string spx_qpn::to_query_string(){
+
+ string ret = "Select ";
+ int s;
+ for(s=0;s<select_list.size();s++){
+ if(s>0) ret+=", ";
+ ret += se_to_query_string(select_list[s]->se, NULL);
+ if(select_list[s]->name != "") ret += " AS "+select_list[s]->name;
+ }
+ ret += "\n";
+
+ ret += "From "+table_name->to_string()+"\n";
+
+ if(where.size() > 0){
+ ret += "Where ";
+ int w;
+ for(w=0;w<where.size();w++){
+ if(w>0) ret += " AND ";
+ ret += "(" + pred_to_query_str(where[w]->pr,NULL) + ")";
+ }
+ ret += "\n";
+ }
+
+ return(ret);
+}
+
+
+
+
+string sgah_qpn::to_query_string(){
+
+ string ret = "Select ";
+ int s;
+ for(s=0;s<select_list.size();s++){
+ if(s>0) ret+=", ";
+ ret += se_to_query_string(select_list[s]->se, &aggr_tbl);
+ if(select_list[s]->name != "") ret += " AS "+select_list[s]->name;
+ }
+ ret += "\n";
+
+ ret += "From "+table_name->to_string()+"\n";
+
+ if(where.size() > 0){
+ ret += "Where ";
+ int w;
+ for(w=0;w<where.size();w++){
+ if(w>0) ret += " AND ";
+ ret += "(" + pred_to_query_str(where[w]->pr,&aggr_tbl) + ")";
+ }
+ ret += "\n";
+ }
+
+ if(gb_tbl.size() > 0){
+ ret += "Group By ";
+ int g;
+ if(gb_tbl.gb_patterns.size() <= 1 || gb_tbl.gb_entry_type.size()==0){
+ for(g=0;g<gb_tbl.size();g++){
+ if(g>0) ret += ", ";
+// if(gb_tbl.get_reftype(g) == GBVAR_SE){
+ ret += se_to_query_string(gb_tbl.get_def(g), &aggr_tbl) + " AS ";
+// }
+ ret += gb_tbl.get_name(g);
+ }
+ }else{
+ int gb_pos = 0;
+ for(g=0;g<gb_tbl.gb_entry_type.size();++g){
+ if(g>0) ret += ", ";
+ if(gb_tbl.gb_entry_type[g] == ""){
+ ret += se_to_query_string(gb_tbl.get_def(gb_pos),&aggr_tbl)+
+ " AS "+ gb_tbl.get_name(gb_pos);
+ gb_pos++;
+ }
+ if(gb_tbl.gb_entry_type[g] == "CUBE" ||
+ gb_tbl.gb_entry_type[g] == "ROLLUP"){
+ ret += gb_tbl.gb_entry_type[g] + "(";
+ int gg = 0;
+ for(gg=0;gg<gb_tbl.gb_entry_count[g];++gg){
+ if(gg>0) ret += ", ";
+ ret += se_to_query_string(gb_tbl.get_def(gb_pos),&aggr_tbl)+ " AS "+ gb_tbl.get_name(gb_pos);
+ gb_pos++;
+ }
+ ret += ")";
+ }
+ if(gb_tbl.gb_entry_type[g] == "GROUPING_SETS"){
+ ret += gb_tbl.gb_entry_type[g] + "(";
+ int g1, g2;
+ vector<vector<bool> > &local_components = gb_tbl.pattern_components[g];
+ for(g1=0;g1<local_components.size();++g1){
+ if(g1>0) ret+=",";
+ bool first_field = true;
+ ret += "\n\t\t(";
+ for(g2=0;g2<=gb_tbl.gb_entry_count[g];g2++){
+ if(local_components[g1][g2]){
+ if(!first_field) ret+=", ";
+ else first_field = false;
+ ret += gb_tbl.get_name(gb_pos+g2);
+ }
+ }
+ ret += ")";
+ }
+ ret += ") ";
+ gb_pos += gb_tbl.gb_entry_count[g];
+ }
+ }
+ }
+ ret += "\n";
+ }
+
+ if(having.size() > 0){
+ ret += "Having ";
+ int h;
+ for(h=0;h<having.size();h++){
+ if(h>0) ret += " AND ";
+ ret += "(" + pred_to_query_str(having[h]->pr,&aggr_tbl) + ")";
+ }
+ ret += "\n";
+ }
+
+ return(ret);
+}
+
+
+string rsgah_qpn::to_query_string(){
+
+ string ret = "Select ";
+ int s;
+ for(s=0;s<select_list.size();s++){
+ if(s>0) ret+=", ";
+ ret += se_to_query_string(select_list[s]->se, &aggr_tbl);
+ if(select_list[s]->name != "") ret += " AS "+select_list[s]->name;
+ }
+ ret += "\n";
+
+ ret += "From "+table_name->to_string()+"\n";
+
+ if(where.size() > 0){
+ ret += "Where ";
+ int w;
+ for(w=0;w<where.size();w++){
+ if(w>0) ret += " AND ";
+ ret += "(" + pred_to_query_str(where[w]->pr,&aggr_tbl) + ")";
+ }
+ ret += "\n";
+ }
+
+ if(gb_tbl.size() > 0){
+ ret += "Group By ";
+ int g;
+ for(g=0;g<gb_tbl.size();g++){
+ if(g>0) ret += ", ";
+// if(gb_tbl.get_reftype(g) == GBVAR_SE){
+ ret += se_to_query_string(gb_tbl.get_def(g), &aggr_tbl)+" AS ";
+// }
+ ret += gb_tbl.get_name(g);
+ }
+ ret += "\n";
+ }
+
+ if(having.size() > 0){
+ ret += "Having ";
+ int h;
+ for(h=0;h<having.size();h++){
+ if(h>0) ret += " AND ";
+ ret += "(" + pred_to_query_str(having[h]->pr,&aggr_tbl) + ")";
+ }
+ ret += "\n";
+ }
+
+ if(closing_when.size() > 0){
+ ret += "Closing_When ";
+ int h;
+ for(h=0;h<closing_when.size();h++){
+ if(h>0) ret += " AND ";
+ ret += "(" + pred_to_query_str(closing_when[h]->pr,&aggr_tbl) + ")";
+ }
+ ret += "\n";
+ }
+
+ return(ret);
+}
+
+
+string sgahcwcb_qpn::to_query_string(){
+
+ string ret = "Select ";
+ int s;
+ for(s=0;s<select_list.size();s++){
+ if(s>0) ret+=", ";
+ ret += se_to_query_string(select_list[s]->se, &aggr_tbl);
+ if(select_list[s]->name != "") ret += " AS "+select_list[s]->name;
+ }
+ ret += "\n";
+
+ ret += "From "+table_name->to_string()+"\n";
+
+ if(where.size() > 0){
+ ret += "Where ";
+ int w;
+ for(w=0;w<where.size();w++){
+ if(w>0) ret += " AND ";
+ ret += "(" + pred_to_query_str(where[w]->pr,&aggr_tbl) + ")";
+ }
+ ret += "\n";
+ }
+
+ if(gb_tbl.size() > 0){
+ ret += "Group By ";
+ int g;
+ for(g=0;g<gb_tbl.size();g++){
+ if(g>0) ret += ", ";
+// if(gb_tbl.get_reftype(g) == GBVAR_SE){
+ ret += se_to_query_string(gb_tbl.get_def(g), &aggr_tbl) + " AS ";
+// }
+ ret += gb_tbl.get_name(g);
+ }
+ ret += "\n";
+ }
+
+ if(sg_tbl.size() > 0){
+ ret += "Supergroup ";
+ int g;
+ bool first_elem = true;
+ for(g=0;g<gb_tbl.size();g++){
+ if(sg_tbl.count(g)){
+ if(first_elem){
+ ret += ", ";
+ first_elem = false;
+ }
+ ret += gb_tbl.get_name(g);
+ }
+ }
+ ret += "\n";
+ }
+
+ if(having.size() > 0){
+ ret += "Having ";
+ int h;
+ for(h=0;h<having.size();h++){
+ if(h>0) ret += " AND ";
+ ret += "(" + pred_to_query_str(having[h]->pr,&aggr_tbl) + ")";
+ }
+ ret += "\n";
+ }
+
+
+ if(cleanwhen.size() > 0){
+ ret += "Cleaning_When ";
+ int h;
+ for(h=0;h<cleanwhen.size();h++){
+ if(h>0) ret += " AND ";
+ ret += "(" + pred_to_query_str(cleanwhen[h]->pr,&aggr_tbl) + ")";
+ }
+ ret += "\n";
+ }
+
+ if(cleanby.size() > 0){
+ ret += "Cleaning_By ";
+ int h;
+ for(h=0;h<cleanby.size();h++){
+ if(h>0) ret += " AND ";
+ ret += "(" + pred_to_query_str(cleanby[h]->pr,&aggr_tbl) + ")";
+ }
+ ret += "\n";
+ }
+
+ return(ret);
+}
+
+string watch_tbl_qpn::to_query_string(){
+ string ret;
+// ret += "DEFINE {\n";
+// ret += "\tfilename='"+filename+";\n";
+// ret += "\trefresh_interval="+to_string(refresh_interval)+";\n}\n";
+ ret += "WATCHLIST FIELDS {\n";
+ std::vector<field_entry *> fields = table_layout->get_fields();
+ for(int f=0;f<fields.size();++f){
+ ret += fields[f]->to_string()+"\n";
+ }
+ ret += "}\n";
+
+ return ret;
+}
+
+string mrg_qpn::to_query_string(){
+
+ string ret="Merge ";
+ ret += mvars[0]->to_query_string() + " : " + mvars[1]->to_query_string();
+ if(slack != NULL){
+ ret += " SLACK "+se_to_query_string(slack, NULL);
+ }
+
+ ret += "\nFrom ";
+ int t;
+ for(t=0;t<fm.size();++t){
+ if(t>0) ret += ", ";
+ ret += fm[t]->to_string();
+ }
+ ret += "\n";
+
+ return(ret);
+}
+
+string join_eq_hash_qpn::to_query_string(){
+
+ string ret = "Select ";
+ int s;
+ for(s=0;s<select_list.size();s++){
+ if(s>0) ret+=", ";
+ ret += se_to_query_string(select_list[s]->se, NULL);
+ if(select_list[s]->name != "") ret += " AS "+select_list[s]->name;
+ }
+ ret += "\n";
+
+// NOTE: assuming binary join.
+ int properties = from[0]->get_property()+2*from[1]->get_property();
+ switch(properties){
+ case 0:
+ ret += "INNER_JOIN ";
+ break;
+ case 1:
+ ret += "LEFT_OUTER_JOIN ";
+ break;
+ case 2:
+ ret += "RIGHT_OUTER_JOIN ";
+ break;
+ case 3:
+ ret += "OUTER_JOIN ";
+ break;
+ }
+
+ ret += "From ";
+ int f;
+ for(f=0;f<from.size();++f){
+ if(f>0) ret+=", ";
+ ret += from[f]->to_string();
+ }
+ ret += "\n";
+
+ if(where.size() > 0){
+ ret += "Where ";
+ int w;
+ for(w=0;w<where.size();w++){
+ if(w>0) ret += " AND ";
+ ret += "(" + pred_to_query_str(where[w]->pr,NULL) + ")";
+ }
+ ret += "\n";
+ }
+
+ return(ret);
+}
+
+string filter_join_qpn::to_query_string(){
+
+ string ret = "Select ";
+ int s;
+ for(s=0;s<select_list.size();s++){
+ if(s>0) ret+=", ";
+ ret += se_to_query_string(select_list[s]->se, NULL);
+ if(select_list[s]->name != "") ret += " AS "+select_list[s]->name;
+ }
+ ret += "\n";
+
+// NOTE: assuming binary join.
+ ret += "FILTER_JOIN("+temporal_var->field+","+int_to_string(temporal_range)+") ";
+
+ ret += "From ";
+ int f;
+ for(f=0;f<from.size();++f){
+ if(f>0) ret+=", ";
+ ret += from[f]->to_string();
+ }
+ ret += "\n";
+
+ if(where.size() > 0){
+ ret += "Where ";
+ int w;
+ for(w=0;w<where.size();w++){
+ if(w>0) ret += " AND ";
+ ret += "(" + pred_to_query_str(where[w]->pr,NULL) + ")";
+ }
+ ret += "\n";
+ }
+
+ return(ret);
+}
+
+string watch_join_qpn::to_query_string(){
+
+ string ret = "Select ";
+ int s;
+ for(s=0;s<select_list.size();s++){
+ if(s>0) ret+=", ";
+ ret += se_to_query_string(select_list[s]->se, NULL);
+ if(select_list[s]->name != "") ret += " AS "+select_list[s]->name;
+ }
+ ret += "\n";
+
+// NOTE: assuming binary join.
+ ret += "WATCHLIST_JOIN ";
+
+ ret += "From ";
+ int f;
+ for(f=0;f<from.size();++f){
+ if(f>0) ret+=", ";
+ ret += from[f]->to_string();
+ }
+ ret += "\n";
+
+ if(where.size() > 0){
+ ret += "Where ";
+ int w;
+ for(w=0;w<where.size();w++){
+ if(w>0) ret += " AND ";
+ ret += "(" + pred_to_query_str(where[w]->pr,NULL) + ")";
+ }
+ ret += "\n";
+ }
+
+ return(ret);
+}
+
+
+
+// -----------------------------------------------------------------
+// Query node subclass specific processing.
+
+
+vector<mrg_qpn *> mrg_qpn::split_sources(){
+ vector<mrg_qpn *> ret;
+ int i;
+
+// sanity check
+ if(fm.size() != mvars.size()){
+ fprintf(stderr,"INTERNAL ERROR in mrg_qpn::split_sources. fm.size() = %lu, mvars.size() = %lu\n",fm.size(),mvars.size());
+ exit(1);
+ }
+ if(fm.size() == 1){
+ fprintf(stderr,"INTERNAL ERROR in mrg_qpn::split_sources, fm size is 1.\n");
+ exit(1);
+ }
+
+/*
+int ff;
+printf("spliting sources merge node, name = %s, %d sources.\n\t",node_name.c_str(), fm.size());
+for(ff=0;ff<fm.size();++ff){
+printf("%s ",fm[ff]->to_string().c_str());
+}
+printf("\n");
+*/
+
+// Handle special cases.
+ if(fm.size() == 2){
+ ret.push_back(this);
+ return ret;
+ }
+
+ if(fm.size() == 3){
+ mrg_qpn *new_mrg = (mrg_qpn *)this->make_copy("_cH1");
+ new_mrg->fm.push_back(this->fm[0]);
+ new_mrg->fm.push_back(this->fm[1]);
+ new_mrg->mvars.push_back(this->mvars[0]);
+ new_mrg->mvars.push_back(this->mvars[1]);
+
+ this->fm.erase(this->fm.begin());
+ this->mvars.erase(this->mvars.begin());
+ string vname = fm[0]->get_var_name();
+ this->fm[0] = new tablevar_t(new_mrg->node_name.c_str());
+ this->fm[0]->set_range_var(vname);
+ this->mvars[0]->set_field(table_layout->get_field_name(merge_fieldpos));
+ this->mvars[0]->set_tablevar_ref(0);
+ this->mvars[1]->set_tablevar_ref(1);
+
+ ret.push_back(new_mrg);
+ ret.push_back(this);
+
+/*
+printf("split sources %s (%s %s)\n",node_name.c_str(),new_mrg->node_name.c_str(),this->node_name.c_str());
+for(i=0;i<new_mrg->fm.size();++i)
+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());
+for(i=0;i<this->fm.size();++i)
+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());
+*/
+
+ return ret;
+ }
+
+// General case.
+// divide up the sources between two children.
+// Then, recurse on the children.
+
+ mrg_qpn *new_mrg1 = (mrg_qpn *)this->make_copy("_cH1");
+ mrg_qpn *new_mrg2 = (mrg_qpn *)this->make_copy("_cH2");
+ for(i=0;i<this->fm.size()/2;++i){
+ new_mrg1->fm.push_back(this->fm[i]);
+ new_mrg1->mvars.push_back(this->mvars[i]);
+//printf("Pushing %d (%s, %s) to new_mrg1\n",i,fm[i]->to_string().c_str(), mvars[i]->to_string().c_str());
+ }
+ for(;i<this->fm.size();++i){
+ new_mrg2->fm.push_back(this->fm[i]);
+ new_mrg2->mvars.push_back(this->mvars[i]);
+//printf("Pushing %d (%s, %s) to new_mrg2\n",i,fm[i]->to_string().c_str(), mvars[i]->to_string().c_str());
+ }
+ for(i=0;i<new_mrg1->mvars.size();++i)
+ new_mrg1->mvars[i]->set_tablevar_ref(i);
+ for(i=0;i<new_mrg2->mvars.size();++i)
+ new_mrg2->mvars[i]->set_tablevar_ref(i);
+
+// Children created, make this merge them.
+ fm.clear();
+ mvars.clear();
+// var 1
+ tablevar_t *tmp_tblvar = new tablevar_t(new_mrg1->node_name.c_str());
+ tmp_tblvar->set_range_var("_mrg_var_1");
+ fm.push_back(tmp_tblvar);
+ colref_t *tmp_cref = new colref_t("_mrg_var_1",table_layout->get_field_name(merge_fieldpos).c_str());
+ tmp_cref->set_tablevar_ref(0);
+ mvars.push_back(tmp_cref);
+// var 2
+ tmp_tblvar = new tablevar_t(new_mrg2->node_name.c_str());
+ tmp_tblvar->set_range_var("_mrg_var_2");
+ fm.push_back(tmp_tblvar);
+ tmp_cref = new colref_t("_mrg_var_2",table_layout->get_field_name(merge_fieldpos).c_str());
+ tmp_cref->set_tablevar_ref(1);
+ mvars.push_back(tmp_cref);
+
+
+/*
+printf("split sources %s (%s %s)\n",node_name.c_str(),new_mrg1->node_name.c_str(),new_mrg2->node_name.c_str());
+for(i=0;i<new_mrg1->fm.size();++i)
+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());
+for(i=0;i<new_mrg2->fm.size();++i)
+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());
+*/
+
+// Recurse and put them together
+ vector<mrg_qpn *> st1 = new_mrg1->split_sources();
+ ret.insert(ret.end(), st1.begin(), st1.end());
+ vector<mrg_qpn *> st2 = new_mrg2->split_sources();
+ ret.insert(ret.end(), st2.begin(), st2.end());
+
+ ret.push_back(this);
+
+ return(ret);
+
+}
+
+
+
+//////// Split helper function : resolve interfaces
+
+vector<pair<string,string> > get_ifaces(tablevar_t *table, ifq_t *ifdb, int n_virtual_ifaces, int hfta_parallelism, int hfta_idx){
+ vector<pair<string,string> > basic_ifaces;
+ int ierr;
+ if(table->get_ifq()){
+ basic_ifaces= ifdb->eval(table->get_interface(),ierr);
+ if(ierr==1){
+ fprintf(stderr,"ERROR, Interface set %s not found.\n",table->get_interface().c_str());
+ }
+ if(ierr==2){
+ fprintf(stderr,"ERROR, interface definition file didn't parse.\n");
+ }
+ }else{
+ basic_ifaces.push_back(make_pair(table->get_machine(), table->get_interface()));
+ }
+
+ if(n_virtual_ifaces == 1)
+ return basic_ifaces;
+
+ int stride = n_virtual_ifaces / hfta_parallelism;
+ int i,s;
+ vector<pair<string,string> > ifaces;
+
+ for(i=0;i<basic_ifaces.size();++i){
+ string mach = basic_ifaces[i].first;
+ string iface = basic_ifaces[i].second;
+ for(s=hfta_idx*stride;s<(hfta_idx+1)*stride;++s){
+ ifaces.push_back(pair<string, string>(mach,iface+"X"+int_to_string(2*s)));
+ }
+ }
+
+ return ifaces;
+}
+
+
+///////// Split helper function : compute slack in a generated
+///////// merge.
+
+void mrg_qpn::resolve_slack(scalarexp_t *t_se, string fname, vector<pair<string, string> > &sources, ifq_t *ifdb, gb_table *gbt){
+ int s,e,v;
+ string es;
+
+// Find slack divisor, if any.
+ string fnm;
+ long long int slack_divisor = find_temporal_divisor(t_se,gbt, fnm);
+ if(slack_divisor <= 0){
+ slack = NULL;
+ return;
+ }
+
+// find max slack in the iface spec
+ long long int max_slacker = 0, this_slacker;
+ string rname = "Slack_"+fnm;
+ for(s=0;s<sources.size();++s){
+ string src_machine = sources[s].first;
+ string src_iface = sources[s].second;
+ vector<string> slack_vec = ifdb->get_iface_vals(src_machine, src_iface,rname,e,es);
+ for(v=0;v<slack_vec.size();++v){
+ if(sscanf(slack_vec[v].c_str(),"%qd",&this_slacker)){
+ if(this_slacker > max_slacker)
+ max_slacker = this_slacker;
+ }
+ }
+ }
+
+ if(max_slacker <= 0){
+ slack = NULL;
+ return;
+ }
+
+// convert to SE
+ long long int the_slack=(long long int)(ceil(((double)max_slacker)/((double)slack_divisor)));
+ char tmps[256];
+ sprintf(tmps,"%lld",the_slack);
+ literal_t *slack_lit = new literal_t(tmps, LITERAL_LONGINT);
+ slack = new scalarexp_t(slack_lit);
+}
+
+
+//------------------------------------------------------------------
+// split a node to extract LFTA components.
+
+vector<qp_node *> watch_tbl_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){
+ // nothing to do, nothing to split, return copy of self.
+
+ hfta_returned = 0;
+
+ vector<qp_node *> ret_vec;
+
+ ret_vec.push_back(this);
+ return(ret_vec);
+
+}
+
+
+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){
+ // nothing to do, nothing to split, return copy of self.
+
+ hfta_returned = 1;
+
+ vector<qp_node *> ret_vec;
+
+ ret_vec.push_back(this);
+ return(ret_vec);
+
+}
+
+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){
+ vector<qp_node *> ret_vec;
+
+// First check if the query can be pushed to the FTA.
+ bool fta_ok = true;
+ int s;
+ for(s=0;s<select_list.size();s++){
+ fta_ok &= check_fta_forbidden_se(select_list[s]->se,NULL, Ext_fcns);
+ }
+ int p;
+ for(p=0;p<where.size();p++){
+ fta_ok &= check_fta_forbidden_pr(where[p]->pr,NULL, Ext_fcns);
+ }
+
+ if(!fta_ok){
+ fprintf(stderr,"ERROR, filter join %s is fta-unsafe.\n",node_name.c_str());
+ exit(1);
+ }
+
+// Can it be done in a single lfta?
+// Get the set of interfaces it accesses.
+ int ierr;
+ int si;
+ vector<string> sel_names;
+ vector<pair<string,string> > ifaces = get_ifaces(from[0], ifdb, n_virtual_ifaces, hfta_parallelism, hfta_idx);
+ if (ifaces.empty()) {
+ fprintf(stderr,"INTERNAL ERROR in filter_join_qpn::split_node_for_fta - empty interface set, node is %s\n", node_name.c_str());
+ exit(1);
+ }
+
+ if(ifaces.size() == 1){
+// Single interface, no need to merge.
+ hfta_returned = 0;
+ ret_vec.push_back(this);
+ int i;
+ for(i=0;i<from.size();i++){
+ from[i]->set_machine(ifaces[0].first);
+ from[i]->set_interface(ifaces[0].second);
+ from[i]->set_ifq(false);
+ }
+ return(ret_vec);
+ }else{
+// Multiple interfaces, generate the interface-specific queries plus
+// the merge.
+ hfta_returned = 1;
+
+ vector<string> sel_names;
+ for(si=0;si<ifaces.size();++si){
+ filter_join_qpn *fta_node = new filter_join_qpn();
+
+// Name the fta
+ if(ifaces.size()==1)
+ fta_node->set_node_name( node_name );
+ else{
+ string new_name = "_"+node_name+"_"+ifaces[si].first+"_"+ifaces[si].second;
+ untaboo(new_name);
+ fta_node->set_node_name(new_name);
+ }
+ sel_names.push_back(fta_node->get_node_name());
+
+// Assign the table
+ int f;
+ for(f=0;f<from.size();f++){
+ fta_node->from.push_back(from[f]->duplicate());
+ fta_node->from[f]->set_machine(ifaces[si].first);
+ fta_node->from[f]->set_interface(ifaces[si].second);
+ fta_node->from[f]->set_ifq(false);
+ }
+ fta_node->temporal_var = temporal_var;
+ fta_node->temporal_range = temporal_range;
+
+ fta_node->use_bloom = use_bloom;
+
+ for(s=0;s<select_list.size();s++){
+ fta_node->select_list.push_back( dup_select(select_list[s], NULL) );
+ }
+
+ for(p=0;p<shared_pred.size();p++){
+ predicate_t *new_pr = dup_pr(shared_pred[p]->pr, NULL);
+ cnf_elem *new_cnf = new cnf_elem(new_pr);
+ analyze_cnf(new_cnf);
+ fta_node->shared_pred.push_back(new_cnf);
+ fta_node->where.push_back(new_cnf);
+ }
+ for(p=0;p<pred_t0.size();p++){
+ predicate_t *new_pr = dup_pr(pred_t0[p]->pr, NULL);
+ cnf_elem *new_cnf = new cnf_elem(new_pr);
+ analyze_cnf(new_cnf);
+ fta_node->pred_t0.push_back(new_cnf);
+ fta_node->where.push_back(new_cnf);
+ }
+ for(p=0;p<pred_t1.size();p++){
+ predicate_t *new_pr = dup_pr(pred_t1[p]->pr, NULL);
+ cnf_elem *new_cnf = new cnf_elem(new_pr);
+ analyze_cnf(new_cnf);
+ fta_node->pred_t1.push_back(new_cnf);
+ fta_node->where.push_back(new_cnf);
+ }
+ for(p=0;p<hash_eq.size();p++){
+ predicate_t *new_pr = dup_pr(hash_eq[p]->pr, NULL);
+ cnf_elem *new_cnf = new cnf_elem(new_pr);
+ analyze_cnf(new_cnf);
+ fta_node->hash_eq.push_back(new_cnf);
+ fta_node->where.push_back(new_cnf);
+ }
+ for(p=0;p<postfilter.size();p++){
+ predicate_t *new_pr = dup_pr(postfilter[p]->pr, NULL);
+ cnf_elem *new_cnf = new cnf_elem(new_pr);
+ analyze_cnf(new_cnf);
+ fta_node->postfilter.push_back(new_cnf);
+ fta_node->where.push_back(new_cnf);
+ }
+
+// Xfer all of the parameters.
+// Use existing handle annotations.
+ vector<string> param_names = param_tbl->get_param_names();
+ int pi;
+ for(pi=0;pi<param_names.size();pi++){
+ data_type *dt = param_tbl->get_data_type(param_names[pi]);
+ fta_node->param_tbl->add_param(param_names[pi],dt->duplicate(),
+ param_tbl->handle_access(param_names[pi]));
+ }
+ fta_node->definitions = definitions;
+ if(fta_node->resolve_if_params(ifdb, this->err_str)){
+ this->error_code = 3;
+ return ret_vec;
+ }
+
+ ret_vec.push_back(fta_node);
+ }
+
+ mrg_qpn *mrg_node = new mrg_qpn((filter_join_qpn *)ret_vec[0],
+ node_name, sel_names,ifaces, ifdb);
+ ret_vec.push_back(mrg_node);
+
+ return(ret_vec);
+ }
+
+}
+
+
+
+
+
+vector<qp_node *> watch_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){
+ vector<qp_node *> ret_vec;
+
+// First check if the query can be pushed to the FTA.
+ bool fta_ok = true;
+ int s;
+ for(s=0;s<select_list.size();s++){
+ fta_ok &= check_fta_forbidden_se(select_list[s]->se,NULL, Ext_fcns);
+ }
+ int p;
+ for(p=0;p<where.size();p++){
+ fta_ok &= check_fta_forbidden_pr(where[p]->pr,NULL, Ext_fcns);
+ }
+
+ if(!fta_ok){
+ fprintf(stderr,"ERROR, watchlist join %s is fta-unsafe.\n",node_name.c_str());
+ exit(1);
+ }
+
+// Can it be done in a single lfta?
+// Get the set of interfaces it accesses.
+ int ierr;
+ int si;
+ vector<string> sel_names;
+ vector<pair<string,string> > ifaces = get_ifaces(from[0], ifdb, n_virtual_ifaces, hfta_parallelism, hfta_idx);
+ if (ifaces.empty()) {
+ fprintf(stderr,"INTERNAL ERROR in filter_join_qpn::split_node_for_fta - empty interface set, node is %s\n", node_name.c_str());
+ exit(1);
+ }
+
+ if(ifaces.size() == 1){
+// Single interface, no need to merge.
+ hfta_returned = 0;
+ ret_vec.push_back(this);
+
+// Treat the range vars a bit differently, the 2nd is reading from a _local_ watchlist.
+ from[0]->set_machine(ifaces[0].first);
+ from[0]->set_interface(ifaces[0].second);
+ from[0]->set_ifq(false);
+
+ from[1]->set_machine(ifaces[0].first);
+ from[1]->set_interface("_local_");
+ from[1]->set_ifq(false);
+
+ return(ret_vec);
+ }else{
+// Multiple interfaces, generate the interface-specific queries plus
+// the merge.
+ hfta_returned = 1;
+
+ vector<string> sel_names;
+ for(si=0;si<ifaces.size();++si){
+ watch_join_qpn *fta_node = new watch_join_qpn();
+
+// Name the fta
+ if(ifaces.size()==1)
+ fta_node->set_node_name( node_name );
+ else{
+ string new_name = "_"+node_name+"_"+ifaces[si].first+"_"+ifaces[si].second;
+ untaboo(new_name);
+ fta_node->set_node_name(new_name);
+ }
+ sel_names.push_back(fta_node->get_node_name());
+
+// Assign the table
+ int f;
+ for(f=0;f<from.size();f++){
+ fta_node->from.push_back(from[f]->duplicate());
+ fta_node->from[f]->set_machine(ifaces[si].first);
+ if(f==0)
+ fta_node->from[f]->set_interface(ifaces[si].second);
+ else
+ fta_node->from[f]->set_interface("_local_");
+ fta_node->from[f]->set_ifq(false);
+ }
+
+ for(s=0;s<select_list.size();s++){
+ fta_node->select_list.push_back( dup_select(select_list[s], NULL) );
+ }
+
+ for(p=0;p<pred_t0.size();p++){
+ predicate_t *new_pr = dup_pr(pred_t0[p]->pr, NULL);
+ cnf_elem *new_cnf = new cnf_elem(new_pr);
+ analyze_cnf(new_cnf);
+ fta_node->pred_t0.push_back(new_cnf);
+ fta_node->where.push_back(new_cnf);
+ }
+ for(p=0;p<pred_t1.size();p++){
+ predicate_t *new_pr = dup_pr(pred_t1[p]->pr, NULL);
+ cnf_elem *new_cnf = new cnf_elem(new_pr);
+ analyze_cnf(new_cnf);
+ fta_node->pred_t1.push_back(new_cnf);
+ fta_node->where.push_back(new_cnf);
+ }
+ for(p=0;p<key_flds.size();p++){ // we've checked that all keys are covered
+ string k = key_flds[p];
+ predicate_t *new_pr = dup_pr(hash_eq[k]->pr, NULL);
+ cnf_elem *new_cnf = new cnf_elem(new_pr);
+ analyze_cnf(new_cnf);
+ fta_node->hash_eq[k] = new_cnf;
+ fta_node->where.push_back(new_cnf);
+ }
+ for(p=0;p<join_filter.size();p++){
+ predicate_t *new_pr = dup_pr(join_filter[p]->pr, NULL);
+ cnf_elem *new_cnf = new cnf_elem(new_pr);
+ analyze_cnf(new_cnf);
+ fta_node->postfilter.push_back(new_cnf);
+ fta_node->where.push_back(new_cnf);
+ }
+ for(p=0;p<postfilter.size();p++){
+ predicate_t *new_pr = dup_pr(postfilter[p]->pr, NULL);
+ cnf_elem *new_cnf = new cnf_elem(new_pr);
+ analyze_cnf(new_cnf);
+ fta_node->postfilter.push_back(new_cnf);
+ fta_node->where.push_back(new_cnf);
+ }
+ fta_node->key_flds = key_flds;
+
+// Xfer all of the parameters.
+// Use existing handle annotations.
+ vector<string> param_names = param_tbl->get_param_names();
+ int pi;
+ for(pi=0;pi<param_names.size();pi++){
+ data_type *dt = param_tbl->get_data_type(param_names[pi]);
+ fta_node->param_tbl->add_param(param_names[pi],dt->duplicate(),
+ param_tbl->handle_access(param_names[pi]));
+ }
+ fta_node->definitions = definitions;
+ if(fta_node->resolve_if_params(ifdb, this->err_str)){
+ this->error_code = 3;
+ return ret_vec;
+ }
+
+ ret_vec.push_back(fta_node);
+ }
+
+ mrg_qpn *mrg_node = new mrg_qpn((watch_join_qpn *)ret_vec[0],
+ node_name, sel_names,ifaces, ifdb);
+ ret_vec.push_back(mrg_node);
+
+ return(ret_vec);
+ }
+
+}
+
+// Use to search for unresolved interface param refs in an hfta.
+
+int spx_qpn::count_ifp_refs(set<string> &ifpnames){
+ int ret = 0;
+ int i;
+ for(i=0;i<select_list.size();++i)
+ ret += count_se_ifp_refs(select_list[i]->se,ifpnames);
+ for(i=0;i<where.size();++i)
+ ret += count_pr_ifp_refs(where[i]->pr,ifpnames);
+ return ret;
+}
+
+int sgah_qpn::count_ifp_refs(set<string> &ifpnames){
+ int ret = 0;
+ int i,j;
+ for(i=0;i<select_list.size();++i)
+ ret += count_se_ifp_refs(select_list[i]->se,ifpnames);
+ for(i=0;i<where.size();++i)
+ ret += count_pr_ifp_refs(where[i]->pr,ifpnames);
+ for(i=0;i<having.size();++i)
+ ret += count_pr_ifp_refs(having[i]->pr,ifpnames);
+ for(i=0;i<aggr_tbl.size();++i){
+ if(aggr_tbl.is_builtin(i) && !aggr_tbl.is_star_aggr(i)){
+ ret += count_se_ifp_refs(aggr_tbl.get_aggr_se(i),ifpnames);
+ }else{
+ vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(i);
+ for(j=0;j<opl.size();++j)
+ ret += count_se_ifp_refs(opl[j],ifpnames);
+ }
+ }
+ for(i=0;i<gb_tbl.size();++i){
+ ret += count_se_ifp_refs(gb_tbl.get_def(i), ifpnames);
+ }
+ return ret;
+}
+
+
+int rsgah_qpn::count_ifp_refs(set<string> &ifpnames){
+ int ret = 0;
+ int i,j;
+ for(i=0;i<select_list.size();++i)
+ ret += count_se_ifp_refs(select_list[i]->se,ifpnames);
+ for(i=0;i<where.size();++i)
+ ret += count_pr_ifp_refs(where[i]->pr,ifpnames);
+ for(i=0;i<having.size();++i)
+ ret += count_pr_ifp_refs(having[i]->pr,ifpnames);
+ for(i=0;i<closing_when.size();++i)
+ ret += count_pr_ifp_refs(closing_when[i]->pr,ifpnames);
+ for(i=0;i<aggr_tbl.size();++i){
+ if(aggr_tbl.is_builtin(i) && !aggr_tbl.is_star_aggr(i)){
+ ret += count_se_ifp_refs(aggr_tbl.get_aggr_se(i),ifpnames);
+ }else{
+ vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(i);
+ for(j=0;j<opl.size();++j)
+ ret += count_se_ifp_refs(opl[j],ifpnames);
+ }
+ }
+ for(i=0;i<gb_tbl.size();++i){
+ ret += count_se_ifp_refs(gb_tbl.get_def(i), ifpnames);
+ }
+ return ret;
+}
+
+int watch_tbl_qpn::count_ifp_refs(set<string> &ifpnames){
+ return 0;
+}
+
+int mrg_qpn::count_ifp_refs(set<string> &ifpnames){
+ return 0;
+}
+
+int join_eq_hash_qpn::count_ifp_refs(set<string> &ifpnames){
+ int ret = 0;
+ int i;
+ for(i=0;i<select_list.size();++i)
+ ret += count_se_ifp_refs(select_list[i]->se,ifpnames);
+ for(i=0;i<prefilter[0].size();++i)
+ ret += count_pr_ifp_refs(prefilter[0][i]->pr,ifpnames);
+ for(i=0;i<prefilter[1].size();++i)
+ ret += count_pr_ifp_refs(prefilter[1][i]->pr,ifpnames);
+ for(i=0;i<temporal_eq.size();++i)
+ ret += count_pr_ifp_refs(temporal_eq[i]->pr,ifpnames);
+ for(i=0;i<hash_eq.size();++i)
+ ret += count_pr_ifp_refs(hash_eq[i]->pr,ifpnames);
+ for(i=0;i<postfilter.size();++i)
+ ret += count_pr_ifp_refs(postfilter[i]->pr,ifpnames);
+ return ret;
+}
+
+int filter_join_qpn::count_ifp_refs(set<string> &ifpnames){
+ int ret = 0;
+ int i;
+ for(i=0;i<select_list.size();++i)
+ ret += count_se_ifp_refs(select_list[i]->se,ifpnames);
+ for(i=0;i<where.size();++i)
+ ret += count_pr_ifp_refs(where[i]->pr,ifpnames);
+ return ret;
+}
+
+int watch_join_qpn::count_ifp_refs(set<string> &ifpnames){
+ int ret = 0;
+ int i;
+ for(i=0;i<select_list.size();++i)
+ ret += count_se_ifp_refs(select_list[i]->se,ifpnames);
+ for(i=0;i<where.size();++i)
+ ret += count_pr_ifp_refs(where[i]->pr,ifpnames);
+ return ret;
+}
+
+
+
+// Resolve interface params to string literals
+int filter_join_qpn::resolve_if_params( ifq_t *ifdb, string &err){
+ int ret = 0;
+ int i;
+ string ifname = from[0]->get_interface();
+ string ifmach = from[0]->get_machine();
+ for(i=0;i<select_list.size();++i)
+ if( resolve_se_ifp_refs(select_list[i]->se,ifmach, ifname, ifdb, err) )
+ ret = 1;
+ for(i=0;i<where.size();++i)
+ if( resolve_pr_ifp_refs(where[i]->pr,ifmach, ifname, ifdb, err))
+ ret = 1;
+ return ret;
+}
+
+int watch_join_qpn::resolve_if_params( ifq_t *ifdb, string &err){
+ int ret = 0;
+ int i;
+ string ifname = from[0]->get_interface();
+ string ifmach = from[0]->get_machine();
+ for(i=0;i<select_list.size();++i)
+ if( resolve_se_ifp_refs(select_list[i]->se,ifmach, ifname, ifdb, err) )
+ ret = 1;
+ for(i=0;i<where.size();++i)
+ if( resolve_pr_ifp_refs(where[i]->pr,ifmach, ifname, ifdb, err))
+ ret = 1;
+ return ret;
+}
+
+
+int spx_qpn::resolve_if_params( ifq_t *ifdb, string &err){
+ int ret = 0;
+ int i;
+ string ifname = table_name->get_interface();
+ string ifmach = table_name->get_machine();
+ for(i=0;i<select_list.size();++i)
+ if( resolve_se_ifp_refs(select_list[i]->se,ifmach, ifname, ifdb, err) )
+ ret = 1;
+ for(i=0;i<where.size();++i)
+ if( resolve_pr_ifp_refs(where[i]->pr,ifmach, ifname, ifdb, err))
+ ret = 1;
+ return ret;
+}
+
+int sgah_qpn::resolve_if_params( ifq_t *ifdb, string &err){
+ int ret = 0;
+ int i,j;
+ string ifname = table_name->get_interface();
+ string ifmach = table_name->get_machine();
+
+//printf("Select list has %d elements\n",select_list.size());
+ for(i=0;i<select_list.size();++i){
+//printf("\tresolving elemet %d\n",i);
+ if( resolve_se_ifp_refs(select_list[i]->se,ifmach, ifname, ifdb, err) ){
+ ret = 1;
+ }
+ }
+ for(i=0;i<where.size();++i){
+ if( resolve_pr_ifp_refs(where[i]->pr,ifmach, ifname, ifdb, err) )
+ ret = 1;
+ }
+ for(i=0;i<having.size();++i){
+ if( resolve_pr_ifp_refs(having[i]->pr,ifmach, ifname, ifdb, err) )
+ ret = 1;
+ }
+//printf("aggr list has %d elements\n",select_list.size());
+ for(i=0;i<aggr_tbl.size();++i){
+//printf("\tresolving elemet %d\n",i);
+ if(aggr_tbl.is_builtin(i) && !aggr_tbl.is_star_aggr(i)){
+//printf("\t\t\tbuiltin\n");
+ if( resolve_se_ifp_refs(aggr_tbl.get_aggr_se(i),ifmach, ifname, ifdb, err) )
+ ret = 1;
+ }else{
+//printf("\t\t\tudaf\n");
+ vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(i);
+ for(j=0;j<opl.size();++j)
+ if( resolve_se_ifp_refs(opl[j],ifmach, ifname, ifdb, err) )
+ ret = 1;
+ }
+ }
+ for(i=0;i<gb_tbl.size();++i){
+ if( resolve_se_ifp_refs(gb_tbl.get_def(i), ifmach, ifname, ifdb, err) )
+ ret = 1;
+ }
+ return ret;
+}
+
+
+
+/*
+ SPLITTING A SELECTION_PROJECTION OPERATOR
+
+ An SPX node may reference:
+ literals, parameters, colrefs, functions, operators
+ An SPX node may not reference:
+ group-by variables, aggregates
+
+ An SPX node contains
+ selection list of SEs
+ where list of CNF predicates
+
+ Algorithm:
+ If each selection SE and each where predicate is fta-safe
+ execute entire operator as an LFTA.
+ Else
+ for each predicate in the where clause
+ if it is fta safe, execute it in the lfta
+ else, split each SE in the predicate, evaluate the
+ top-level SEs in the hfta and eval the predicate on that.
+ For each SE in the se list
+ Split the SE, eval the high level part, push onto hfta
+ selection list
+
+ Splitting an SE:
+ A SE represents a value which must be computed. The LFTA
+ must provide sub-values from which the HFTA can compute the
+ desired value.
+ 1) the SE is fta-safe
+ Create an entry in the selection list of the LFTA which is
+ the SE itself. Reference this LFTA selection list entry in
+ the HFTA (via a field name assigned to the lfta selection
+ list entry).
+ 2) The SE is not fta-safe
+ Determine the boundary between the fta-safe and the fta-unsafe
+ portions of the SE. The result is a rooted tree (which is
+ evaluated at the HFTA) which references sub-SEs (which are
+ evaluated at the LFTA). Each of the sub-SEs is placed on
+ the selection list of the LFTA and assigned field names,
+ the top part is evaluated at the HFTA and references the
+ sub-SEs through their assigned field names.
+ The only SEs on the LFTA selection list are those created by
+ the above mechanism. The collection of assigned field names becomes
+ the schema of the LFTA.
+
+ TODO: insert tablevar names into the colrefs.
+
+*/
+
+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){
+
+ int i;
+ vector<qp_node *> ret_vec;
+
+// If the node reads from a stream, don't split.
+// int t = Schema->get_table_ref(table_name->get_schema_name());
+ int t = table_name->get_schema_ref();
+ if(Schema->get_schema_type(t) != PROTOCOL_SCHEMA){
+ hfta_returned = 1;
+ ret_vec.push_back(this);
+ return(ret_vec);
+ }
+
+
+// Get the set of interfaces it accesses.
+ int ierr;
+ int si;
+ vector<string> sel_names;
+ vector<pair<string,string> > ifaces = get_ifaces(table_name, ifdb, n_virtual_ifaces, hfta_parallelism, hfta_idx);
+ if (ifaces.empty()) {
+ fprintf(stderr,"INTERNAL ERROR in spx_qpn::split_node_for_fta - empty interface set, node is %s\n", node_name.c_str());
+ exit(1);
+ }
+
+
+// The FTA node, it is always returned.
+
+ spx_qpn *fta_node = new spx_qpn();
+ fta_node->table_name = table_name;
+
+// for colname imputation
+// vector<string> fta_flds, stream_flds;
+
+
+// First check if the query can be pushed to the FTA.
+ bool fta_ok = true;
+ int s;
+ for(s=0;s<select_list.size();s++){
+ fta_ok &= check_fta_forbidden_se(select_list[s]->se,NULL, Ext_fcns);
+ }
+ int p;
+ for(p=0;p<where.size();p++){
+ fta_ok &= check_fta_forbidden_pr(where[p]->pr,NULL, Ext_fcns);
+ }
+
+ if(fta_ok){
+////////////////////////////////////////////////////////////
+// The query can be executed entirely in the FTA.
+ hfta_returned = 0;
+
+ for(si=0;si<ifaces.size();++si){
+ fta_node = new spx_qpn();
+
+// Name the fta
+ if(ifaces.size()==1)
+ fta_node->set_node_name( node_name );
+ else{
+ string new_name = "_"+node_name+"_"+ifaces[si].first+"_"+ifaces[si].second;
+ untaboo(new_name);
+ fta_node->set_node_name(new_name);
+ }
+ sel_names.push_back(fta_node->get_node_name());
+
+// Assign the table
+ fta_node->table_name = table_name->duplicate();
+ fta_node->table_name->set_machine(ifaces[si].first);
+ fta_node->table_name->set_interface(ifaces[si].second);
+ fta_node->table_name->set_ifq(false);
+
+ for(s=0;s<select_list.size();s++){
+ fta_node->select_list.push_back( dup_select(select_list[s], NULL) );
+ }
+ for(p=0;p<where.size();p++){
+ predicate_t *new_pr = dup_pr(where[p]->pr, NULL);
+ cnf_elem *new_cnf = new cnf_elem(new_pr);
+ analyze_cnf(new_cnf);
+
+ fta_node->where.push_back(new_cnf);
+ }
+
+// Xfer all of the parameters.
+// Use existing handle annotations.
+ vector<string> param_names = param_tbl->get_param_names();
+ int pi;
+ for(pi=0;pi<param_names.size();pi++){
+ data_type *dt = param_tbl->get_data_type(param_names[pi]);
+ fta_node->param_tbl->add_param(param_names[pi],dt->duplicate(),
+ param_tbl->handle_access(param_names[pi]));
+ }
+ fta_node->definitions = definitions;
+ if(fta_node->resolve_if_params(ifdb, this->err_str)){
+ this->error_code = 3;
+ return ret_vec;
+ }
+
+ ret_vec.push_back(fta_node);
+ }
+
+ if(ifaces.size() > 1){
+ spx_qpn *tmp_spx = (spx_qpn *)(ret_vec[0]);
+ mrg_qpn *mrg_node = new mrg_qpn(tmp_spx,
+ node_name, sel_names,ifaces, ifdb);
+ /*
+ Do not split sources until we are done with optimizations
+ vector<mrg_qpn *> split_merge = mrg_node->split_sources();
+ for(i=0;i<split_merge.size();++i){
+ ret_vec.push_back(split_merge[i]);
+ }
+ hfta_returned = split_merge.size();
+ */
+ ret_vec.push_back(mrg_node);
+ hfta_returned = 1;
+ }
+
+
+// printf("OK as FTA.\n");
+// printf("FTA node is:\n%s\n\n",fta_node->to_query_string().c_str() );
+
+ return(ret_vec);
+ }
+
+////////////////////////////////////////////////////
+// The fta must be split. Create a stream node.
+// NOTE : I am counting on the single
+// table in the from list. (Joins handled in a different operator).
+
+ hfta_returned = 1;
+
+ spx_qpn *stream_node = new spx_qpn();
+ stream_node->set_node_name( node_name );
+// Create the tablevar in the stream's FROM clause.
+// set the schema name to the name of the LFTA,
+// and use the same tablevar name.
+ stream_node->table_name = new tablevar_t(
+ ("_fta_"+node_name).c_str()
+ );
+ stream_node->table_name->set_range_var(table_name->get_var_name());
+
+// Name the fta
+ fta_node->set_node_name( "_fta_"+node_name );
+
+// table var names of fta, stream.
+ string fta_var = fta_node->table_name->get_var_name();
+ string stream_var = stream_node->table_name->get_var_name();
+
+// Set up select list vector
+ vector< vector<select_element *> *> select_vec;
+ select_vec.push_back(&(fta_node->select_list)); // only one child
+
+
+// Split the select list into its FTA and stream parts.
+// If any part of the SE is fta-unsafe, it will return
+// a SE to execute at the stream ref'ing SE's evaluated
+// at the fta (which are put on the FTA's select list as a side effect).
+// If the SE is fta-safe, put it on the fta select list, make
+// a ref to it and put the ref on the stream select list.
+ for(s=0;s<select_list.size();s++){
+ bool fta_forbidden = false;
+ int se_src = SPLIT_FTAVEC_NOTBLVAR;
+// scalarexp_t *root_se = split_fta_se(
+// select_list[s]->se,fta_forbidden, fta_node->select_list, Ext_fcns
+// );
+ scalarexp_t *root_se = split_ftavec_se( select_list[s]->se,
+ fta_forbidden, se_src, select_vec, Ext_fcns
+ );
+// if(fta_forbidden){
+ if(fta_forbidden || se_src == SPLIT_FTAVEC_NOTBLVAR){
+ stream_node->select_list.push_back(
+ new select_element(root_se, select_list[s]->name)
+ );
+ }else{
+ scalarexp_t *new_se=make_fta_se_ref(fta_node->select_list,root_se,0);
+ stream_node->select_list.push_back(
+ new select_element(new_se, select_list[s]->name)
+ );
+ }
+ }
+
+
+// The WHERE clause has already been split into a set of clauses
+// that are ANDED together. For each clause, check if its FTA-safe.
+// If not, split its SE's into fta-safe and stream-executing parts,
+// then put a clause which ref's the SEs into the stream.
+// Else put it into the LFTA.
+ predicate_t *pr_root;
+ bool fta_forbidden;
+ for(p=0;p<where.size();p++){
+ if(! check_fta_forbidden_pr(where[p]->pr, NULL, Ext_fcns) ){
+ pr_root = split_ftavec_pr(where[p]->pr,select_vec,Ext_fcns);
+// pr_root = split_fta_pr( where[p]->pr, fta_node->select_list, Ext_fcns);
+ fta_forbidden = true;
+ }else{
+ pr_root = dup_pr(where[p]->pr, NULL);
+ fta_forbidden = false;
+ }
+ cnf_elem *cnf_root = new cnf_elem(pr_root);
+ analyze_cnf(cnf_root);
+
+ if(fta_forbidden){
+ stream_node->where.push_back(cnf_root);
+ }else{
+ fta_node->where.push_back(cnf_root);
+ }
+ }
+
+
+
+// Divide the parameters among the stream, FTA.
+// Currently : assume that the stream receives all parameters
+// and parameter updates, incorporates them, then passes
+// all of the parameters to the FTA.
+// This will need to change (tables, fta-unsafe types. etc.)
+
+// I will pass on the use_handle_access marking, even
+// though the fcn call that requires handle access might
+// exist in only one of the parts of the query.
+// Parameter manipulation and handle access determination will
+// need to be revisited anyway.
+ vector<string> param_names = param_tbl->get_param_names();
+ int pi;
+ for(pi=0;pi<param_names.size();pi++){
+ data_type *dt = param_tbl->get_data_type(param_names[pi]);
+ fta_node->param_tbl->add_param(param_names[pi],dt->duplicate(),
+ param_tbl->handle_access(param_names[pi]));
+ stream_node->param_tbl->add_param(param_names[pi],dt->duplicate(),
+ param_tbl->handle_access(param_names[pi]));
+ }
+
+ fta_node->definitions = definitions; fta_node->definitions.erase("_referenced_ifaces");
+ stream_node->definitions = definitions;
+
+// Now split by interfaces
+ if(ifaces.size() > 1){
+ for(si=0;si<ifaces.size();++si){
+ spx_qpn *subq_node = new spx_qpn();
+
+// Name the subquery
+ string new_name = "_"+node_name+"_"+ifaces[si].first+"_"+ifaces[si].second;
+ untaboo(new_name);
+ subq_node->set_node_name( new_name) ;
+ sel_names.push_back(subq_node->get_node_name());
+
+// Assign the table
+ subq_node->table_name = fta_node->table_name->duplicate();
+ subq_node->table_name->set_machine(ifaces[si].first);
+ subq_node->table_name->set_interface(ifaces[si].second);
+ subq_node->table_name->set_ifq(false);
+
+ for(s=0;s<fta_node->select_list.size();s++){
+ subq_node->select_list.push_back( dup_select(fta_node->select_list[s], NULL) );
+ }
+ for(p=0;p<fta_node->where.size();p++){
+ predicate_t *new_pr = dup_pr(fta_node->where[p]->pr, NULL);
+ cnf_elem *new_cnf = new cnf_elem(new_pr);
+ analyze_cnf(new_cnf);
+
+ subq_node->where.push_back(new_cnf);
+ }
+// Xfer all of the parameters.
+// Use existing handle annotations.
+ vector<string> param_names = param_tbl->get_param_names();
+ int pi;
+ for(pi=0;pi<param_names.size();pi++){
+ data_type *dt = param_tbl->get_data_type(param_names[pi]);
+ subq_node->param_tbl->add_param(param_names[pi],dt->duplicate(),
+ param_tbl->handle_access(param_names[pi]));
+ }
+ if(subq_node->resolve_if_params(ifdb, this->err_str)){
+ this->error_code = 3;
+ return ret_vec;
+ }
+ subq_node->definitions = definitions; subq_node->definitions.erase("_referenced_ifaces");
+
+ ret_vec.push_back(subq_node);
+ }
+
+ mrg_qpn *mrg_node = new mrg_qpn((spx_qpn *)(ret_vec[0]),
+ fta_node->node_name, sel_names, ifaces, ifdb);
+ /*
+ Do not split sources until we are done with optimizations
+ vector<mrg_qpn *> split_merge = mrg_node->split_sources();
+ for(i=0;i<split_merge.size();++i){
+ ret_vec.push_back(split_merge[i]);
+ }
+ */
+ ret_vec.push_back(mrg_node);
+ ret_vec.push_back(stream_node);
+ hfta_returned = 1/*split_merge.size()*/ + 1;
+
+ }else{
+ fta_node->table_name->set_machine(ifaces[0].first);
+ fta_node->table_name->set_interface(ifaces[0].second);
+ fta_node->table_name->set_ifq(false);
+ if(fta_node->resolve_if_params(ifdb, this->err_str)){
+ this->error_code = 3;
+ return ret_vec;
+ }
+ ret_vec.push_back(fta_node);
+ ret_vec.push_back(stream_node);
+ hfta_returned = 1;
+ }
+
+// printf("FTA node is:\n%s\n\n",fta_node->to_query_string().c_str() );
+// printf("Stream node is:\n%s\n\n",stream_node->to_query_string().c_str() );
+
+
+ return(ret_vec);
+}
+
+
+/*
+ Splitting a aggregation+sampling operator.
+ right now, return an error if any splitting is required.
+*/
+
+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){
+
+ hfta_returned = 1;
+
+ vector<qp_node *> ret_vec;
+ int s, p, g, a, o, i;
+ int si;
+
+ vector<string> fta_flds, stream_flds;
+
+// If the node reads from a stream, don't split.
+// int t = Schema->get_table_ref(table_name->get_schema_name());
+ int t = table_name->get_schema_ref();
+ if(Schema->get_schema_type(t) != PROTOCOL_SCHEMA){
+ ret_vec.push_back(this);
+ return(ret_vec);
+ }
+
+ fprintf(stderr,"ERROR : cannot split a sampling operator (not yet implemented).\n");
+ exit(1);
+
+ return ret_vec;
+
+
+}
+
+
+/*
+ Splitting a running aggregation operator.
+ The code is almost identical to that of the the sgah operator
+ except that
+ - there is no lfta-only option.
+ - the stream node is rsagh_qpn (lfta is sgah or spx)
+ - need to handle the closing when (similar to having)
+*/
+
+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){
+
+ hfta_returned = 1;
+
+ vector<qp_node *> ret_vec;
+ int s, p, g, a, o, i;
+ int si;
+
+ vector<string> fta_flds, stream_flds;
+
+// If the node reads from a stream, don't split.
+// int t = Schema->get_table_ref(table_name->get_schema_name());
+ int t = table_name->get_schema_ref();
+ if(Schema->get_schema_type(t) != PROTOCOL_SCHEMA){
+ ret_vec.push_back(this);
+ return(ret_vec);
+ }
+
+// Get the set of interfaces it accesses.
+ int ierr;
+ vector<string> sel_names;
+ vector<pair<string,string> > ifaces = get_ifaces(table_name, ifdb, n_virtual_ifaces, hfta_parallelism, hfta_idx);
+ if (ifaces.empty()) {
+ fprintf(stderr,"INTERNAL ERROR in rsgah_qpn::split_node_for_fta - empty interface set, node is %s\n", node_name.c_str());
+ exit(1);
+ }
+
+
+
+
+//////////////////////////////////////////////////////////////
+/// Split into lfta, hfta.
+
+// A rsgah node must always be split,
+// if for no other reason than to complete the
+// partial aggregation.
+
+// First, determine if the query can be spit into aggr/aggr,
+// or if it must be selection/aggr.
+// Splitting into selection/aggr is allowed only
+// if select_lfta is set.
+
+
+ bool select_allowed = definitions.count("select_lfta")>0;
+ bool select_rqd = false;
+
+ set<int> unsafe_gbvars; // for processing where clause
+ for(g=0;g<gb_tbl.size();g++){
+ if(! check_fta_forbidden_se(gb_tbl.get_def(g), &aggr_tbl, Ext_fcns)){
+ if(!select_allowed){
+ 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",
+ gb_tbl.get_name(g).c_str(), se_to_query_string(gb_tbl.get_def(g), &aggr_tbl).c_str()
+ );
+ this->error_code = 1;
+ this->err_str = tmpstr;
+ return(ret_vec);
+ }else{
+ select_rqd = true;
+ unsafe_gbvars.insert(g);
+ }
+ }
+ }
+
+// Verify that the SEs in the aggregate definitions are fta-safe
+ for(a=0;a<aggr_tbl.size();++a){
+ scalarexp_t *ase = aggr_tbl.get_aggr_se(a);
+ if(ase != NULL){ // COUNT(*) does not have a SE.
+ if(!select_allowed){
+ if(! check_fta_forbidden_se(aggr_tbl.get_aggr_se(a), &aggr_tbl, Ext_fcns)){
+ 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",
+ aggr_tbl.get_op(a).c_str(), se_to_query_string(aggr_tbl.get_aggr_se(a), &aggr_tbl).c_str()
+ );
+ this->error_code = 1;
+ this->err_str = tmpstr;
+ return(ret_vec);
+ }
+ }else{
+ select_rqd = true;
+ }
+ }
+ }
+
+// Verify that all of the ref'd UDAFs can be split.
+
+ for(a=0;a<aggr_tbl.size();++a){
+ if(! aggr_tbl.is_builtin(a)){
+ int afcn = aggr_tbl.get_fcn_id(a);
+ int super_id = Ext_fcns->get_superaggr_id(afcn);
+ int sub_id = Ext_fcns->get_subaggr_id(afcn);
+ if(super_id < 0 || sub_id < 0){
+ if(!select_allowed){
+ 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";
+ this->error_code = 1;
+ return(ret_vec);
+ }else{
+ select_rqd = true;
+ }
+ }
+ }
+ }
+
+ for(p=0;p<where.size();p++){
+ if(! check_fta_forbidden_pr(where[p]->pr, &aggr_tbl, Ext_fcns) ){
+ if(!select_allowed){
+ 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",
+ pred_to_query_str(where[p]->pr,&aggr_tbl).c_str()
+ );
+ this->error_code = 1;
+ this->err_str = tmpstr;
+ return(ret_vec);
+ }else{
+ select_rqd = true;
+ }
+ }
+ }
+
+
+ if(! select_rqd){
+
+/////////////////////////////////////////////////////
+// Split into aggr/aggr.
+
+
+
+
+
+ sgah_qpn *fta_node = new sgah_qpn();
+ fta_node->table_name = table_name;
+ fta_node->set_node_name( "_fta_"+node_name );
+ fta_node->table_name->set_range_var(table_name->get_var_name());
+
+
+ rsgah_qpn *stream_node = new rsgah_qpn();
+ stream_node->table_name = new tablevar_t( ("_fta_"+node_name).c_str());
+ stream_node->set_node_name( node_name );
+ stream_node->table_name->set_range_var(table_name->get_var_name());
+
+// First, process the group-by variables.
+// The fta must supply the values of all the gbvars.
+// If a gb is computed, the computation must be
+// performed at the FTA, so the SE must be FTA-safe.
+// Nice side effect : the gbvar table contains
+// matching entries for the original query, the lfta query,
+// and the hfta query. So gbrefs in the new queries are set
+// correctly just by inheriting the gbrefs from the old query.
+// If this property changed, I'll need translation tables.
+
+
+ for(g=0;g<gb_tbl.size();g++){
+// Insert the gbvar into the lfta.
+ scalarexp_t *gbvar_def = dup_se(gb_tbl.get_def(g), &aggr_tbl);
+ fta_node->gb_tbl.add_gb_var(
+ gb_tbl.get_name(g), gb_tbl.get_tblvar_ref(g), gbvar_def, gb_tbl.get_reftype(g)
+ );
+
+// Insert a ref to the value of the gbvar into the lfta select list.
+ colref_t *new_cr = new colref_t(gb_tbl.get_name(g).c_str() );
+ scalarexp_t *gbvar_fta = new scalarexp_t(new_cr);
+ gbvar_fta->set_gb_ref(g);
+ gbvar_fta->set_data_type( gb_tbl.get_def(g)->get_data_type() );
+ scalarexp_t *gbvar_stream = make_fta_se_ref(fta_node->select_list, gbvar_fta,0);
+
+// Insert the corresponding gbvar ref (gbvar_stream) into the stream.
+ gbvar_stream->set_gb_ref(-1); // used as GBvar def
+ stream_node->gb_tbl.add_gb_var(
+ gbvar_stream->get_colref()->get_field(), -1, gbvar_stream, gb_tbl.get_reftype(g)
+ );
+
+ }
+
+// SEs in the aggregate definitions.
+// They are all safe, so split them up for later processing.
+ map<int, scalarexp_t *> hfta_aggr_se;
+ for(a=0;a<aggr_tbl.size();++a){
+ split_fta_aggr( &(aggr_tbl), a,
+ &(stream_node->aggr_tbl), &(fta_node->aggr_tbl) ,
+ fta_node->select_list,
+ hfta_aggr_se,
+ Ext_fcns
+ );
+ }
+
+
+// Next, the select list.
+
+ for(s=0;s<select_list.size();s++){
+ bool fta_forbidden = false;
+ scalarexp_t *root_se = rehome_fta_se(select_list[s]->se, &hfta_aggr_se);
+ stream_node->select_list.push_back(
+ new select_element(root_se, select_list[s]->name));
+ }
+
+
+
+// All the predicates in the where clause must execute
+// in the fta.
+
+ for(p=0;p<where.size();p++){
+ predicate_t *new_pr = dup_pr(where[p]->pr, &aggr_tbl);
+ cnf_elem *new_cnf = new cnf_elem(new_pr);
+ analyze_cnf(new_cnf);
+
+ fta_node->where.push_back(new_cnf);
+ }
+
+// All of the predicates in the having clause must
+// execute in the stream node.
+
+ for(p=0;p<having.size();p++){
+ predicate_t *pr_root = rehome_fta_pr( having[p]->pr, &hfta_aggr_se);
+ cnf_elem *cnf_root = new cnf_elem(pr_root);
+ analyze_cnf(cnf_root);
+
+ stream_node->having.push_back(cnf_root);
+ }
+
+// All of the predicates in the closing when clause must
+// execute in the stream node.
+
+ for(p=0;p<closing_when.size();p++){
+ predicate_t *pr_root=rehome_fta_pr(closing_when[p]->pr,&hfta_aggr_se);
+ cnf_elem *cnf_root = new cnf_elem(pr_root);
+ analyze_cnf(cnf_root);
+
+ stream_node->closing_when.push_back(cnf_root);
+ }
+
+
+// Divide the parameters among the stream, FTA.
+// Currently : assume that the stream receives all parameters
+// and parameter updates, incorporates them, then passes
+// all of the parameters to the FTA.
+// This will need to change (tables, fta-unsafe types. etc.)
+
+// I will pass on the use_handle_access marking, even
+// though the fcn call that requires handle access might
+// exist in only one of the parts of the query.
+// Parameter manipulation and handle access determination will
+// need to be revisited anyway.
+ vector<string> param_names = param_tbl->get_param_names();
+ int pi;
+ for(pi=0;pi<param_names.size();pi++){
+ data_type *dt = param_tbl->get_data_type(param_names[pi]);
+ fta_node->param_tbl->add_param(param_names[pi],dt->duplicate(),
+ param_tbl->handle_access(param_names[pi]));
+ stream_node->param_tbl->add_param(param_names[pi],dt->duplicate(),
+ param_tbl->handle_access(param_names[pi]));
+ }
+ fta_node->definitions = definitions; fta_node->definitions.erase("_referenced_ifaces");
+ stream_node->definitions = definitions;
+
+// Now split by interfaces XXXX
+ if(ifaces.size() > 1){
+ for(si=0;si<ifaces.size();++si){
+ sgah_qpn *subq_node = new sgah_qpn();
+
+// Name the subquery
+ string new_name = "_"+node_name+"_"+ifaces[si].first+"_"+ifaces[si].second;
+ untaboo(new_name);
+ subq_node->set_node_name( new_name) ;
+ sel_names.push_back(subq_node->get_node_name());
+
+// Assign the table
+ subq_node->table_name = fta_node->table_name->duplicate();
+ subq_node->table_name->set_machine(ifaces[si].first);
+ subq_node->table_name->set_interface(ifaces[si].second);
+ subq_node->table_name->set_ifq(false);
+
+// the GB vars.
+ for(g=0;g<fta_node->gb_tbl.size();g++){
+// Insert the gbvar into the lfta.
+ scalarexp_t *gbvar_def = dup_se(fta_node->gb_tbl.get_def(g), NULL);
+ subq_node->gb_tbl.add_gb_var(
+ fta_node->gb_tbl.get_name(g), fta_node->gb_tbl.get_tblvar_ref(g), gbvar_def, fta_node->gb_tbl.get_reftype(g)
+ );
+ }
+
+// Insert the aggregates
+ for(a=0;a<fta_node->aggr_tbl.size();++a){
+ subq_node->aggr_tbl.add_aggr(fta_node->aggr_tbl.duplicate(a));
+ }
+
+ for(s=0;s<fta_node->select_list.size();s++){
+ subq_node->select_list.push_back( dup_select(fta_node->select_list[s], NULL) );
+ }
+ for(p=0;p<fta_node->where.size();p++){
+ predicate_t *new_pr = dup_pr(fta_node->where[p]->pr, NULL);
+ cnf_elem *new_cnf = new cnf_elem(new_pr);
+ analyze_cnf(new_cnf);
+
+ subq_node->where.push_back(new_cnf);
+ }
+ for(p=0;p<fta_node->having.size();p++){
+ predicate_t *new_pr = dup_pr(fta_node->having[p]->pr, NULL);
+ cnf_elem *new_cnf = new cnf_elem(new_pr);
+ analyze_cnf(new_cnf);
+
+ subq_node->having.push_back(new_cnf);
+ }
+// Xfer all of the parameters.
+// Use existing handle annotations.
+ vector<string> param_names = param_tbl->get_param_names();
+ int pi;
+ for(pi=0;pi<param_names.size();pi++){
+ data_type *dt = param_tbl->get_data_type(param_names[pi]);
+ subq_node->param_tbl->add_param(param_names[pi],dt->duplicate(),
+ param_tbl->handle_access(param_names[pi]));
+ }
+ subq_node->definitions = definitions; subq_node->definitions.erase("_referenced_ifaces");
+ if(subq_node->resolve_if_params(ifdb, this->err_str)){
+ this->error_code = 3;
+ return ret_vec;
+ }
+
+ ret_vec.push_back(subq_node);
+ }
+
+ mrg_qpn *mrg_node = new mrg_qpn((sgah_qpn *)(ret_vec[0]),
+ fta_node->node_name, sel_names, ifaces, ifdb);
+
+ /*
+ Do not split sources until we are done with optimizations
+ vector<mrg_qpn *> split_merge = mrg_node->split_sources();
+ for(i=0;i<split_merge.size();++i){
+ ret_vec.push_back(split_merge[i]);
+ }
+ */
+ ret_vec.push_back(mrg_node);
+ ret_vec.push_back(stream_node);
+ hfta_returned = 1/*split_merge.size()*/+1;
+
+ }else{
+ fta_node->table_name->set_machine(ifaces[0].first);
+ fta_node->table_name->set_interface(ifaces[0].second);
+ fta_node->table_name->set_ifq(false);
+ if(fta_node->resolve_if_params(ifdb, this->err_str)){
+ this->error_code = 3;
+ return ret_vec;
+ }
+ ret_vec.push_back(fta_node);
+ ret_vec.push_back(stream_node);
+ hfta_returned = 1;
+ }
+
+
+// ret_vec.push_back(fta_node);
+// ret_vec.push_back(stream_node);
+
+
+ return(ret_vec);
+
+ }
+
+/////////////////////////////////////////////////////////////////////
+/// Split into selection LFTA, aggregation HFTA.
+
+ spx_qpn *fta_node = new spx_qpn();
+ fta_node->table_name = table_name;
+ fta_node->set_node_name( "_fta_"+node_name );
+ fta_node->table_name->set_range_var(table_name->get_var_name());
+
+
+ rsgah_qpn *stream_node = new rsgah_qpn();
+ stream_node->table_name = new tablevar_t( ("_fta_"+node_name).c_str());
+ stream_node->set_node_name( node_name );
+ stream_node->table_name->set_range_var(table_name->get_var_name());
+
+
+ vector< vector<select_element *> *> select_vec;
+ select_vec.push_back(&(fta_node->select_list)); // only one child
+
+// Process the gbvars. Split their defining SEs.
+ for(g=0;g<gb_tbl.size();g++){
+ bool fta_forbidden = false;
+ int se_src = SPLIT_FTAVEC_NOTBLVAR;
+
+ scalarexp_t *gbvar_se = split_ftavec_se( gb_tbl.get_def(g),
+ fta_forbidden, se_src, select_vec, Ext_fcns
+ );
+// if(fta_forbidden) (
+ if(fta_forbidden || se_src == SPLIT_FTAVEC_NOTBLVAR){
+ stream_node->gb_tbl.add_gb_var(
+ gb_tbl.get_name(g),gb_tbl.get_tblvar_ref(g),gbvar_se,gb_tbl.get_reftype(g)
+ );
+ }else{
+ scalarexp_t *new_se=make_fta_se_ref(fta_node->select_list,gbvar_se,0);
+ stream_node->gb_tbl.add_gb_var(
+ gb_tbl.get_name(g),gb_tbl.get_tblvar_ref(g),new_se,gb_tbl.get_reftype(g)
+ );
+ }
+ }
+
+// Process the aggregate table.
+// Copy to stream, split the SEs.
+ map<int, scalarexp_t *> hfta_aggr_se; // for rehome
+ for(a=0;a<aggr_tbl.size();++a){
+ scalarexp_t *hse;
+ if(aggr_tbl.is_builtin(a)){
+ if(aggr_tbl.is_star_aggr(a)){
+ stream_node->aggr_tbl.add_aggr(aggr_tbl.get_op(a),NULL, false);
+ hse=scalarexp_t::make_star_aggr(aggr_tbl.get_op(a).c_str());
+ }else{
+ bool fta_forbidden = false;
+ int se_src = SPLIT_FTAVEC_NOTBLVAR;
+
+ scalarexp_t *agg_se = split_ftavec_se( aggr_tbl.get_aggr_se(a),
+ fta_forbidden, se_src, select_vec, Ext_fcns
+ );
+// if(fta_forbidden) (
+ if(fta_forbidden || se_src == SPLIT_FTAVEC_NOTBLVAR){
+ stream_node->aggr_tbl.add_aggr(aggr_tbl.get_op(a), agg_se,false);
+ hse=scalarexp_t::make_se_aggr(aggr_tbl.get_op(a).c_str(),agg_se);
+ }else{
+ scalarexp_t *new_se=make_fta_se_ref(fta_node->select_list,agg_se,0);
+ stream_node->aggr_tbl.add_aggr(aggr_tbl.get_op(a), new_se,false);
+ hse=scalarexp_t::make_se_aggr(aggr_tbl.get_op(a).c_str(),new_se);
+ }
+ }
+ hse->set_data_type(aggr_tbl.get_data_type(a));
+ hse->set_aggr_id(a);
+ hfta_aggr_se[a]=hse;
+ }else{
+ vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(a);
+ vector<scalarexp_t *> new_opl;
+ for(o=0;o<opl.size();++o){
+ bool fta_forbidden = false;
+ int se_src = SPLIT_FTAVEC_NOTBLVAR;
+ scalarexp_t *agg_se = split_ftavec_se( opl[o],
+ fta_forbidden, se_src, select_vec, Ext_fcns
+ );
+// scalarexp_t *agg_se = split_ftavec_se( aggr_tbl.get_aggr_se(a),
+// fta_forbidden, se_src, select_vec, Ext_fcns
+// );
+// if(fta_forbidden) (
+ if(fta_forbidden || se_src == SPLIT_FTAVEC_NOTBLVAR){
+ new_opl.push_back(agg_se);
+ }else{
+ scalarexp_t *new_se=make_fta_se_ref(fta_node->select_list,agg_se,0);
+ new_opl.push_back(new_se);
+ }
+ }
+ 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),aggr_tbl.is_superaggr(a), aggr_tbl.is_running_aggr(a),aggr_tbl.has_bailout(a));
+ hse = new scalarexp_t(aggr_tbl.get_op(a).c_str(),new_opl);
+ hse->set_data_type(Ext_fcns->get_fcn_dt(aggr_tbl.get_fcn_id(a)));
+ hse->set_fcn_id(aggr_tbl.get_fcn_id(a));
+ hse->set_aggr_id(a);
+ hfta_aggr_se[a]=hse;
+ }
+ }
+
+
+// Process the WHERE clause.
+// If it is fta-safe AND it refs only fta-safe gbvars,
+// then expand the gbvars and put it into the lfta.
+// Else, split it into an hfta predicate ref'ing
+// se's computed partially in the lfta.
+
+ predicate_t *pr_root;
+ bool fta_forbidden;
+ for(p=0;p<where.size();p++){
+ if(! check_fta_forbidden_pr(where[p]->pr, NULL, Ext_fcns) || contains_gb_pr(where[p]->pr, unsafe_gbvars) ){
+ pr_root = split_ftavec_pr(where[p]->pr,select_vec,Ext_fcns);
+ fta_forbidden = true;
+ }else{
+ pr_root = dup_pr(where[p]->pr, NULL);
+ expand_gbvars_pr(pr_root, gb_tbl);
+ fta_forbidden = false;
+ }
+ cnf_elem *cnf_root = new cnf_elem(pr_root);
+ analyze_cnf(cnf_root);
+
+ if(fta_forbidden){
+ stream_node->where.push_back(cnf_root);
+ }else{
+ fta_node->where.push_back(cnf_root);
+ }
+ }
+
+
+// Process the Select clause, rehome it on the
+// new defs.
+ for(s=0;s<select_list.size();s++){
+ bool fta_forbidden = false;
+ scalarexp_t *root_se = rehome_fta_se(select_list[s]->se, &hfta_aggr_se);
+ stream_node->select_list.push_back(
+ new select_element(root_se, select_list[s]->name));
+ }
+
+
+// Process the Having clause
+
+// All of the predicates in the having clause must
+// execute in the stream node.
+
+ for(p=0;p<having.size();p++){
+ predicate_t *pr_root = rehome_fta_pr( having[p]->pr, &hfta_aggr_se);
+ cnf_elem *cnf_root = new cnf_elem(pr_root);
+ analyze_cnf(cnf_root);
+
+ stream_node->having.push_back(cnf_root);
+ }
+// Same for closing when
+ for(p=0;p<closing_when.size();p++){
+ predicate_t *pr_root=rehome_fta_pr(closing_when[p]->pr,&hfta_aggr_se);
+ cnf_elem *cnf_root = new cnf_elem(pr_root);
+ analyze_cnf(cnf_root);
+
+ stream_node->closing_when.push_back(cnf_root);
+ }
+
+
+// Handle parameters and a few last details.
+ vector<string> param_names = param_tbl->get_param_names();
+ int pi;
+ for(pi=0;pi<param_names.size();pi++){
+ data_type *dt = param_tbl->get_data_type(param_names[pi]);
+ fta_node->param_tbl->add_param(param_names[pi],dt->duplicate(),
+ param_tbl->handle_access(param_names[pi]));
+ stream_node->param_tbl->add_param(param_names[pi],dt->duplicate(),
+ param_tbl->handle_access(param_names[pi]));
+ }
+
+ fta_node->definitions = definitions; fta_node->definitions.erase("_referenced_ifaces");
+ stream_node->definitions = definitions;
+
+// Now split by interfaces YYYY
+ if(ifaces.size() > 1){
+ for(si=0;si<ifaces.size();++si){
+ spx_qpn *subq_node = new spx_qpn();
+
+// Name the subquery
+ string new_name = "_"+node_name+"_"+ifaces[si].first+"_"+ifaces[si].second;
+ untaboo(new_name);
+ subq_node->set_node_name( new_name) ;
+ sel_names.push_back(subq_node->get_node_name());
+
+// Assign the table
+ subq_node->table_name = fta_node->table_name->duplicate();
+ subq_node->table_name->set_machine(ifaces[si].first);
+ subq_node->table_name->set_interface(ifaces[si].second);
+ subq_node->table_name->set_ifq(false);
+
+ for(s=0;s<fta_node->select_list.size();s++){
+ subq_node->select_list.push_back( dup_select(fta_node->select_list[s], NULL) );
+ }
+ for(p=0;p<fta_node->where.size();p++){
+ predicate_t *new_pr = dup_pr(fta_node->where[p]->pr, NULL);
+ cnf_elem *new_cnf = new cnf_elem(new_pr);
+ analyze_cnf(new_cnf);
+
+ subq_node->where.push_back(new_cnf);
+ }
+// Xfer all of the parameters.
+// Use existing handle annotations.
+ vector<string> param_names = param_tbl->get_param_names();
+ int pi;
+ for(pi=0;pi<param_names.size();pi++){
+ data_type *dt = param_tbl->get_data_type(param_names[pi]);
+ subq_node->param_tbl->add_param(param_names[pi],dt->duplicate(),
+ param_tbl->handle_access(param_names[pi]));
+ }
+ subq_node->definitions = definitions; subq_node->definitions.erase("_referenced_ifaces");
+ if(subq_node->resolve_if_params(ifdb, this->err_str)){
+ this->error_code = 3;
+ return ret_vec;
+ }
+
+ ret_vec.push_back(subq_node);
+ }
+
+ mrg_qpn *mrg_node = new mrg_qpn((spx_qpn *)(ret_vec[0]),
+ fta_node->node_name, sel_names, ifaces, ifdb);
+ /*
+ Do not split sources until we are done with optimizations
+ vector<mrg_qpn *> split_merge = mrg_node->split_sources();
+ for(i=0;i<split_merge.size();++i){
+ ret_vec.push_back(split_merge[i]);
+ }
+ */
+ ret_vec.push_back(mrg_node);
+ ret_vec.push_back(stream_node);
+ hfta_returned = 1/*split_merge.size()*/+1;
+
+ }else{
+ fta_node->table_name->set_machine(ifaces[0].first);
+ fta_node->table_name->set_interface(ifaces[0].second);
+ fta_node->table_name->set_ifq(false);
+ if(fta_node->resolve_if_params(ifdb, this->err_str)){
+ this->error_code = 3;
+ return ret_vec;
+ }
+ ret_vec.push_back(fta_node);
+ ret_vec.push_back(stream_node);
+ hfta_returned = 1;
+ }
+
+ return(ret_vec);
+
+}
+
+
+/*
+ Splitting an aggregation operator
+
+ An aggregation operator can reference
+ literals, parameters, colrefs, group-by vars, aggregates,
+ operators, functions
+
+ an aggregation contains
+ A selection list of SEs
+ A where list of predicates
+ A list group-by variable definition
+ A list of aggregates to be computed
+ A HAVING list of predicates.
+
+ Aggregation involves two phases:
+ 1) given an input tuple, determine if it satisfies all of
+ the WHERE predicates. If so, compute the group.
+ Look up the group, update its aggregates.
+ 2) given a closed group and its aggregates, determine
+ if these values satisfy all of the HAVING predicates.
+ If so, evaluate the SEs on the selection list from the
+ group and its aggregates.
+ The two-phase nature of aggregation places restrictions on
+ what can be referenced by different components of the operator
+ (in addition to functions and operators).
+ - group-by variables : literals, parameters, colrefs
+ - WHERE predicates : group-by vars, literals, params, colrefs
+ - HAVING predicates : group-by vars, literals, params, aggregates
+ - Selection list SEs : group-by vars, literals, params, aggregates
+
+ Splitting an aggregation operator into an LFTA/HFTA part
+ involves performing partial aggregation at the LFTA and
+ completing the aggregation at the HFTA.
+ - given a tuple, the LFTA part evaluates the WHERE clause,
+ and if it is satisfied, computes the group. lookup the group
+ and update the aggregates. output the group and its partial
+ aggregates
+ - Given a partial aggregate from the LFTA, look up the group and
+ update its aggregates. When the group is closed, evalute
+ the HAVING clause and the SEs on the selection list.
+ THEREFORE the selection list of the LFTA must consist of the
+ group-by variables and the set of (bare) subaggregate values
+ necessary to compute the super aggregates.
+ Unlike the case with the SPX operator, the SE splitting point
+ is at the GBvar and the aggregate value level.
+
+ ALGORITHM:
+ For each group-by variable
+ Put the GB variable definition in the LFTA GBVAR list.
+ Put the GBVAR in the LFTA selection list (as an SE).
+ Put a reference to that GBVAR in the HFTA GBVAR list.
+ For each aggregate
+ Split the aggregate into a superaggregate and a subaggregate.
+ The SE of the superaggregate references the subaggregate value.
+ (this will need modifications for MF aggregation)
+ For each SE in the selection list, HAVING predicate
+ Make GBVAR references point to the new GBVAR
+ make the aggregate value references point to the new aggregates.
+
+ SEs are not so much split as their ref's are changed.
+
+ TODO: insert tablevar names into the colrefs.
+*/
+
+
+
+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){
+
+ hfta_returned = 1;
+
+ vector<qp_node *> ret_vec;
+ int s, p, g, a, o, i;
+ int si;
+
+ vector<string> fta_flds, stream_flds;
+
+// If the node reads from a stream, don't split.
+// int t = Schema->get_table_ref(table_name->get_schema_name());
+ int t = table_name->get_schema_ref();
+ if(Schema->get_schema_type(t) != PROTOCOL_SCHEMA){
+ ret_vec.push_back(this);
+ return(ret_vec);
+ }
+
+// Get the set of interfaces it accesses.
+ int ierr;
+ vector<string> sel_names;
+ vector<pair<string,string> > ifaces = get_ifaces(table_name, ifdb, n_virtual_ifaces, hfta_parallelism, hfta_idx);
+ if (ifaces.empty()) {
+ fprintf(stderr,"INTERNAL ERROR in sgah_qpn::split_node_for_fta - empty interface set, node is %s\n", node_name.c_str());
+ exit(1);
+ }
+
+
+
+//////////////////////////////////////////////
+// Is this LFTA-only?
+ if(definitions.count("lfta_aggregation")>0){
+// Yes. Ensure that everything is lfta-safe.
+
+// Check only one interface is accessed.
+ if(ifaces.size()>1){
+ this->err_str = "ERROR, group-by query "+node_name+" is lfta-only, but it accesses more than one interface:\n";
+ for(si=0;si<ifaces.size();++si)
+ this->err_str += "\t"+ifaces[si].first+"."+ifaces[si].second+"\n";
+ this->error_code = 2;
+ return(ret_vec);
+ }
+
+// Check the group-by attributes
+ for(g=0;g<gb_tbl.size();g++){
+ if(! check_fta_forbidden_se(gb_tbl.get_def(g), &aggr_tbl, Ext_fcns)){
+ 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",
+ gb_tbl.get_name(g).c_str(), se_to_query_string(gb_tbl.get_def(g), &aggr_tbl).c_str()
+ );
+ this->error_code = 1;
+ this->err_str = tmpstr;
+ return(ret_vec);
+ }
+ }
+
+// Verify that the SEs in the aggregate definitions are fta-safe
+ for(a=0;a<aggr_tbl.size();++a){
+ scalarexp_t *ase = aggr_tbl.get_aggr_se(a);
+ if(ase != NULL){ // COUNT(*) does not have a SE.
+ if(! check_fta_forbidden_se(aggr_tbl.get_aggr_se(a), &aggr_tbl, Ext_fcns)){
+ 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",
+ aggr_tbl.get_op(a).c_str(), se_to_query_string(aggr_tbl.get_aggr_se(a), &aggr_tbl).c_str()
+ );
+ this->error_code = 1;
+ this->err_str = tmpstr;
+ return(ret_vec);
+ }
+ }
+ if(! aggr_tbl.fta_legal(a,Ext_fcns)){
+ if(! check_fta_forbidden_se(aggr_tbl.get_aggr_se(a), &aggr_tbl, Ext_fcns)){
+ sprintf(tmpstr,"ERROR in sgah_qpn::split_node_for_fta : aggregate (%s) has LFTA-unsafe aggregate and the query is lfta-only (%s).\n",
+ aggr_tbl.get_op(a).c_str(), se_to_query_string(aggr_tbl.get_aggr_se(a), &aggr_tbl).c_str()
+ );
+ this->error_code = 1;
+ this->err_str = tmpstr;
+ return(ret_vec);
+ }
+ }
+ }
+
+// Ensure that all the aggregates are fta-safe ....
+
+// select list
+
+ for(s=0;s<select_list.size();s++){
+ if(! check_fta_forbidden_se(select_list[s]->se,NULL, Ext_fcns)){
+ 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",
+ pred_to_query_str(where[p]->pr,&aggr_tbl).c_str()
+ );
+ this->error_code = 1;
+ this->err_str = tmpstr;
+ return(ret_vec);
+ }
+ }
+
+// where predicate
+
+ for(p=0;p<where.size();p++){
+ if(! check_fta_forbidden_pr(where[p]->pr, &aggr_tbl, Ext_fcns) ){
+ 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",
+ pred_to_query_str(where[p]->pr,&aggr_tbl).c_str()
+ );
+ this->error_code = 1;
+ this->err_str = tmpstr;
+ return(ret_vec);
+ }
+ }
+
+
+// having predicate
+ if(having.size()>0){
+ 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",
+ pred_to_query_str(where[p]->pr,&aggr_tbl).c_str()
+ );
+ this->error_code = 1;
+ this->err_str = tmpstr;
+ return(ret_vec);
+ }
+// The query is lfta safe, return it.
+
+ hfta_returned = 0;
+ ret_vec.push_back(this);
+ return(ret_vec);
+ }
+
+//////////////////////////////////////////////////////////////
+/// Split into lfta, hfta.
+
+// A sgah node must always be split,
+// if for no other reason than to complete the
+// partial aggregation.
+
+// First, determine if the query can be spit into aggr/aggr,
+// or if it must be selection/aggr.
+// Splitting into selection/aggr is allowed only
+// if select_lfta is set.
+
+
+ bool select_allowed = definitions.count("select_lfta")>0;
+ bool select_rqd = false;
+
+ set<int> unsafe_gbvars; // for processing where clause
+ for(g=0;g<gb_tbl.size();g++){
+ if(! check_fta_forbidden_se(gb_tbl.get_def(g), &aggr_tbl, Ext_fcns)){
+ if(!select_allowed){
+ 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",
+ gb_tbl.get_name(g).c_str(), se_to_query_string(gb_tbl.get_def(g), &aggr_tbl).c_str()
+ );
+ this->error_code = 1;
+ this->err_str = tmpstr;
+ return(ret_vec);
+ }else{
+ select_rqd = true;
+ unsafe_gbvars.insert(g);
+ }
+ }
+ }
+
+// Verify that the SEs in the aggregate definitions are fta-safe
+ for(a=0;a<aggr_tbl.size();++a){
+ scalarexp_t *ase = aggr_tbl.get_aggr_se(a);
+ if(ase != NULL){ // COUNT(*) does not have a SE.
+ if(!select_allowed){
+ if(! check_fta_forbidden_se(aggr_tbl.get_aggr_se(a), &aggr_tbl, Ext_fcns)){
+ 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",
+ aggr_tbl.get_op(a).c_str(), se_to_query_string(aggr_tbl.get_aggr_se(a), &aggr_tbl).c_str()
+ );
+ this->error_code = 1;
+ this->err_str = tmpstr;
+ return(ret_vec);
+ }
+ }else{
+ select_rqd = true;
+ }
+ }
+ }
+
+// Verify that all of the ref'd UDAFs can be split.
+
+ for(a=0;a<aggr_tbl.size();++a){
+ if(! aggr_tbl.is_builtin(a)){
+ int afcn = aggr_tbl.get_fcn_id(a);
+ int super_id = Ext_fcns->get_superaggr_id(afcn);
+ int sub_id = Ext_fcns->get_subaggr_id(afcn);
+ if(super_id < 0 || sub_id < 0){
+ if(!select_allowed){
+ 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";
+ this->error_code = 1;
+ return(ret_vec);
+ }else{
+ select_rqd = true;
+ }
+ }
+ }
+ }
+
+ for(p=0;p<where.size();p++){
+ if(! check_fta_forbidden_pr(where[p]->pr, &aggr_tbl, Ext_fcns) ){
+ if(!select_allowed){
+ 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",
+ pred_to_query_str(where[p]->pr,&aggr_tbl).c_str()
+ );
+ this->error_code = 1;
+ this->err_str = tmpstr;
+ return(ret_vec);
+ }else{
+ select_rqd = true;
+ }
+ }
+ }
+
+
+ if(! select_rqd){
+
+/////////////////////////////////////////////////////
+// Split into aggr/aggr.
+
+
+
+
+
+ sgah_qpn *fta_node = new sgah_qpn();
+ fta_node->table_name = table_name;
+ fta_node->set_node_name( "_fta_"+node_name );
+ fta_node->table_name->set_range_var(table_name->get_var_name());
+
+
+ sgah_qpn *stream_node = new sgah_qpn();
+ stream_node->table_name = new tablevar_t( ("_fta_"+node_name).c_str());
+ stream_node->set_node_name( node_name );
+ stream_node->table_name->set_range_var(table_name->get_var_name());
+
+// allowed stream disorder. Default is 1,
+// can override with max_lfta_disorder setting.
+// Also limit the hfta disorder, set to lfta disorder + 1.
+// can override with max_hfta_disorder.
+
+ fta_node->lfta_disorder = 1;
+ if(this->get_val_of_def("max_lfta_disorder") != ""){
+ int d = atoi(this->get_val_of_def("max_lfta_disorder").c_str() );
+ if(d<1){
+ fprintf(stderr,"Warning, max_lfta_disorder in node %s is %d, must be at least 1, ignoring.\n",node_name.c_str(), d);
+ }else{
+ fta_node->lfta_disorder = d;
+printf("node %s setting lfta_disorder = %d\n",node_name.c_str(),fta_node->lfta_disorder);
+ }
+ }
+ if(fta_node->lfta_disorder > 1)
+ stream_node->hfta_disorder = fta_node->lfta_disorder + 1;
+ else
+ stream_node->hfta_disorder = 1;
+
+ if(this->get_val_of_def("max_hfta_disorder") != ""){
+ int d = atoi(this->get_val_of_def("max_hfta_disorder").c_str() );
+ if(d<fta_node->lfta_disorder){
+ 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);
+ }else{
+ fta_node->lfta_disorder = d;
+ }
+ if(fta_node->lfta_disorder < fta_node->hfta_disorder){
+ fta_node->hfta_disorder = fta_node->lfta_disorder + 1;
+ }
+ }
+
+
+// First, process the group-by variables.
+// The fta must supply the values of all the gbvars.
+// If a gb is computed, the computation must be
+// performed at the FTA, so the SE must be FTA-safe.
+// Nice side effect : the gbvar table contains
+// matching entries for the original query, the lfta query,
+// and the hfta query. So gbrefs in the new queries are set
+// correctly just by inheriting the gbrefs from the old query.
+// If this property changed, I'll need translation tables.
+
+
+ for(g=0;g<gb_tbl.size();g++){
+// Insert the gbvar into the lfta.
+ scalarexp_t *gbvar_def = dup_se(gb_tbl.get_def(g), &aggr_tbl);
+ fta_node->gb_tbl.add_gb_var(
+ gb_tbl.get_name(g), gb_tbl.get_tblvar_ref(g), gbvar_def, gb_tbl.get_reftype(g)
+ );
+
+// Insert a ref to the value of the gbvar into the lfta select list.
+ colref_t *new_cr = new colref_t(gb_tbl.get_name(g).c_str() );
+ scalarexp_t *gbvar_fta = new scalarexp_t(new_cr);
+ gbvar_fta->set_gb_ref(g);
+ gbvar_fta->set_data_type( gb_tbl.get_def(g)->get_data_type() );
+ scalarexp_t *gbvar_stream = make_fta_se_ref(fta_node->select_list, gbvar_fta,0);
+
+// Insert the corresponding gbvar ref (gbvar_stream) into the stream.
+ gbvar_stream->set_gb_ref(-1); // used as GBvar def
+ stream_node->gb_tbl.add_gb_var(
+ gbvar_stream->get_colref()->get_field(), -1, gbvar_stream, gb_tbl.get_reftype(g)
+ );
+ }
+// multiple aggregation patterns, if any, go with the hfta
+ stream_node->gb_tbl.set_pattern_info( &gb_tbl);
+
+// SEs in the aggregate definitions.
+// They are all safe, so split them up for later processing.
+ map<int, scalarexp_t *> hfta_aggr_se;
+ for(a=0;a<aggr_tbl.size();++a){
+ split_fta_aggr( &(aggr_tbl), a,
+ &(stream_node->aggr_tbl), &(fta_node->aggr_tbl) ,
+ fta_node->select_list,
+ hfta_aggr_se,
+ Ext_fcns
+ );
+/*
+// OLD TRACING CODE
+
+int ii;
+for(ii=0;ii<fta_flds.size() || ii < fta_node->select_list.size();++ii){
+ if(ii<fta_flds.size())
+ printf("\t%s : ",fta_flds[ii].c_str());
+ else
+ printf("\t. : ");
+ if(ii<fta_node->select_list.size())
+ printf("%s\n",fta_node->select_list[ii]->to_string().c_str());
+ else
+ printf(".\n");
+}
+printf("hfta aggregates are:");
+for(ii=0;ii<stream_node->aggr_tbl.size();++ii){
+ printf(" %s",stream_node->aggr_tbl.get_op(ii).c_str());
+}
+printf("\nlfta aggregates are:");
+for(ii=0;ii<fta_node->aggr_tbl.size();++ii){
+ printf(" %s",fta_node->aggr_tbl.get_op(ii).c_str());
+}
+printf("\n\n");
+*/
+
+ }
+
+
+// Next, the select list.
+
+ for(s=0;s<select_list.size();s++){
+ bool fta_forbidden = false;
+ scalarexp_t *root_se = rehome_fta_se(select_list[s]->se, &hfta_aggr_se);
+ stream_node->select_list.push_back(
+ new select_element(root_se, select_list[s]->name));
+ }
+
+
+
+// All the predicates in the where clause must execute
+// in the fta.
+
+ for(p=0;p<where.size();p++){
+ predicate_t *new_pr = dup_pr(where[p]->pr, &aggr_tbl);
+ cnf_elem *new_cnf = new cnf_elem(new_pr);
+ analyze_cnf(new_cnf);
+
+ fta_node->where.push_back(new_cnf);
+ }
+
+// All of the predicates in the having clause must
+// execute in the stream node.
+
+ for(p=0;p<having.size();p++){
+ predicate_t *pr_root = rehome_fta_pr( having[p]->pr, &hfta_aggr_se);
+ cnf_elem *cnf_root = new cnf_elem(pr_root);
+ analyze_cnf(cnf_root);
+
+ stream_node->having.push_back(cnf_root);
+ }
+
+
+// Divide the parameters among the stream, FTA.
+// Currently : assume that the stream receives all parameters
+// and parameter updates, incorporates them, then passes
+// all of the parameters to the FTA.
+// This will need to change (tables, fta-unsafe types. etc.)
+
+// I will pass on the use_handle_access marking, even
+// though the fcn call that requires handle access might
+// exist in only one of the parts of the query.
+// Parameter manipulation and handle access determination will
+// need to be revisited anyway.
+ vector<string> param_names = param_tbl->get_param_names();
+ int pi;
+ for(pi=0;pi<param_names.size();pi++){
+ data_type *dt = param_tbl->get_data_type(param_names[pi]);
+ fta_node->param_tbl->add_param(param_names[pi],dt->duplicate(),
+ param_tbl->handle_access(param_names[pi]));
+ stream_node->param_tbl->add_param(param_names[pi],dt->duplicate(),
+ param_tbl->handle_access(param_names[pi]));
+ }
+ fta_node->definitions = definitions; fta_node->definitions.erase("_referenced_ifaces");
+ stream_node->definitions = definitions;
+
+// Now split by interfaces XXXX
+ if(ifaces.size() > 1){
+ for(si=0;si<ifaces.size();++si){
+ sgah_qpn *subq_node = new sgah_qpn();
+
+// Name the subquery
+ string new_name = "_"+node_name+"_"+ifaces[si].first+"_"+ifaces[si].second;
+ untaboo(new_name);
+ subq_node->set_node_name( new_name) ;
+ sel_names.push_back(subq_node->get_node_name());
+
+// Assign the table
+ subq_node->table_name = fta_node->table_name->duplicate();
+ subq_node->table_name->set_machine(ifaces[si].first);
+ subq_node->table_name->set_interface(ifaces[si].second);
+ subq_node->table_name->set_ifq(false);
+
+// the GB vars.
+ for(g=0;g<fta_node->gb_tbl.size();g++){
+// Insert the gbvar into the lfta.
+ scalarexp_t *gbvar_def = dup_se(fta_node->gb_tbl.get_def(g), NULL);
+ subq_node->gb_tbl.add_gb_var(
+ fta_node->gb_tbl.get_name(g), fta_node->gb_tbl.get_tblvar_ref(g), gbvar_def, fta_node->gb_tbl.get_reftype(g)
+ );
+ }
+
+// Insert the aggregates
+ for(a=0;a<fta_node->aggr_tbl.size();++a){
+ subq_node->aggr_tbl.add_aggr(fta_node->aggr_tbl.duplicate(a));
+ }
+
+ for(s=0;s<fta_node->select_list.size();s++){
+ subq_node->select_list.push_back( dup_select(fta_node->select_list[s], NULL) );
+ }
+ for(p=0;p<fta_node->where.size();p++){
+ predicate_t *new_pr = dup_pr(fta_node->where[p]->pr, NULL);
+ cnf_elem *new_cnf = new cnf_elem(new_pr);
+ analyze_cnf(new_cnf);
+
+ subq_node->where.push_back(new_cnf);
+ }
+ for(p=0;p<fta_node->having.size();p++){
+ predicate_t *new_pr = dup_pr(fta_node->having[p]->pr, NULL);
+ cnf_elem *new_cnf = new cnf_elem(new_pr);
+ analyze_cnf(new_cnf);
+
+ subq_node->having.push_back(new_cnf);
+ }
+// Xfer all of the parameters.
+// Use existing handle annotations.
+ vector<string> param_names = param_tbl->get_param_names();
+ int pi;
+ for(pi=0;pi<param_names.size();pi++){
+ data_type *dt = param_tbl->get_data_type(param_names[pi]);
+ subq_node->param_tbl->add_param(param_names[pi],dt->duplicate(),
+ param_tbl->handle_access(param_names[pi]));
+ }
+ subq_node->definitions = definitions; subq_node->definitions.erase("_referenced_ifaces");
+ if(subq_node->resolve_if_params(ifdb, this->err_str)){
+ this->error_code = 3;
+ return ret_vec;
+ }
+
+// THe disorder
+ subq_node->lfta_disorder = fta_node->lfta_disorder;
+
+ ret_vec.push_back(subq_node);
+ }
+
+ mrg_qpn *mrg_node = new mrg_qpn((sgah_qpn *)(ret_vec[0]),
+ fta_node->node_name, sel_names, ifaces, ifdb);
+ mrg_node->set_disorder(fta_node->lfta_disorder);
+
+ /*
+ Do not split sources until we are done with optimizations
+ vector<mrg_qpn *> split_merge = mrg_node->split_sources();
+ for(i=0;i<split_merge.size();++i){
+ ret_vec.push_back(split_merge[i]);
+ }
+ */
+ ret_vec.push_back(mrg_node);
+ ret_vec.push_back(stream_node);
+ hfta_returned = 1/*split_merge.size()*/+1;
+
+ }else{
+ fta_node->table_name->set_machine(ifaces[0].first);
+ fta_node->table_name->set_interface(ifaces[0].second);
+ fta_node->table_name->set_ifq(false);
+ if(fta_node->resolve_if_params(ifdb, this->err_str)){
+ this->error_code = 3;
+ return ret_vec;
+ }
+ ret_vec.push_back(fta_node);
+ ret_vec.push_back(stream_node);
+ hfta_returned = 1;
+ }
+
+
+// ret_vec.push_back(fta_node);
+// ret_vec.push_back(stream_node);
+
+
+ return(ret_vec);
+
+ }
+
+/////////////////////////////////////////////////////////////////////
+/// Split into selection LFTA, aggregation HFTA.
+
+ spx_qpn *fta_node = new spx_qpn();
+ fta_node->table_name = table_name;
+ fta_node->set_node_name( "_fta_"+node_name );
+ fta_node->table_name->set_range_var(table_name->get_var_name());
+
+
+ sgah_qpn *stream_node = new sgah_qpn();
+ stream_node->table_name = new tablevar_t( ("_fta_"+node_name).c_str());
+ stream_node->set_node_name( node_name );
+ stream_node->table_name->set_range_var(table_name->get_var_name());
+
+
+ vector< vector<select_element *> *> select_vec;
+ select_vec.push_back(&(fta_node->select_list)); // only one child
+
+// Process the gbvars. Split their defining SEs.
+ for(g=0;g<gb_tbl.size();g++){
+ bool fta_forbidden = false;
+ int se_src = SPLIT_FTAVEC_NOTBLVAR;
+
+ scalarexp_t *gbvar_se = split_ftavec_se( gb_tbl.get_def(g),
+ fta_forbidden, se_src, select_vec, Ext_fcns
+ );
+// if(fta_forbidden) (
+ if(fta_forbidden || se_src == SPLIT_FTAVEC_NOTBLVAR){
+ stream_node->gb_tbl.add_gb_var(
+ gb_tbl.get_name(g),gb_tbl.get_tblvar_ref(g),gbvar_se,gb_tbl.get_reftype(g)
+ );
+ }else{
+ scalarexp_t *new_se=make_fta_se_ref(fta_node->select_list,gbvar_se,0);
+ stream_node->gb_tbl.add_gb_var(
+ gb_tbl.get_name(g),gb_tbl.get_tblvar_ref(g),new_se,gb_tbl.get_reftype(g)
+ );
+ }
+ }
+ stream_node->gb_tbl.set_pattern_info( &gb_tbl);
+
+// Process the aggregate table.
+// Copy to stream, split the SEs.
+ map<int, scalarexp_t *> hfta_aggr_se; // for rehome
+ for(a=0;a<aggr_tbl.size();++a){
+ scalarexp_t *hse;
+ if(aggr_tbl.is_builtin(a)){
+ if(aggr_tbl.is_star_aggr(a)){
+ stream_node->aggr_tbl.add_aggr(aggr_tbl.get_op(a),NULL, false);
+ hse=scalarexp_t::make_star_aggr(aggr_tbl.get_op(a).c_str());
+ }else{
+ bool fta_forbidden = false;
+ int se_src = SPLIT_FTAVEC_NOTBLVAR;
+
+ scalarexp_t *agg_se = split_ftavec_se( aggr_tbl.get_aggr_se(a),
+ fta_forbidden, se_src, select_vec, Ext_fcns
+ );
+// if(fta_forbidden) (
+ if(fta_forbidden || se_src == SPLIT_FTAVEC_NOTBLVAR){
+ stream_node->aggr_tbl.add_aggr(aggr_tbl.get_op(a), agg_se,false);
+ hse=scalarexp_t::make_se_aggr(aggr_tbl.get_op(a).c_str(),agg_se);
+ }else{
+ scalarexp_t *new_se=make_fta_se_ref(fta_node->select_list,agg_se,0);
+ stream_node->aggr_tbl.add_aggr(aggr_tbl.get_op(a), new_se,false);
+ hse=scalarexp_t::make_se_aggr(aggr_tbl.get_op(a).c_str(),new_se);
+ }
+ }
+ hse->set_data_type(aggr_tbl.get_data_type(a));
+ hse->set_aggr_id(a);
+ hfta_aggr_se[a]=hse;
+ }else{
+ vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(a);
+ vector<scalarexp_t *> new_opl;
+ for(o=0;o<opl.size();++o){
+ bool fta_forbidden = false;
+ int se_src = SPLIT_FTAVEC_NOTBLVAR;
+ scalarexp_t *agg_se = split_ftavec_se( opl[o],
+ fta_forbidden, se_src, select_vec, Ext_fcns
+ );
+// scalarexp_t *agg_se = split_ftavec_se( aggr_tbl.get_aggr_se(a),
+// fta_forbidden, se_src, select_vec, Ext_fcns
+// );
+// if(fta_forbidden) (
+ if(fta_forbidden || se_src == SPLIT_FTAVEC_NOTBLVAR){
+ new_opl.push_back(agg_se);
+ }else{
+ scalarexp_t *new_se=make_fta_se_ref(fta_node->select_list,agg_se,0);
+ new_opl.push_back(new_se);
+ }
+ }
+ 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));
+ hse = new scalarexp_t(aggr_tbl.get_op(a).c_str(),new_opl);
+ hse->set_data_type(Ext_fcns->get_fcn_dt(aggr_tbl.get_fcn_id(a)));
+ hse->set_fcn_id(aggr_tbl.get_fcn_id(a));
+ hse->set_aggr_id(a);
+ hfta_aggr_se[a]=hse;
+ }
+ }
+
+
+// Process the WHERE clause.
+// If it is fta-safe AND it refs only fta-safe gbvars,
+// then expand the gbvars and put it into the lfta.
+// Else, split it into an hfta predicate ref'ing
+// se's computed partially in the lfta.
+
+ predicate_t *pr_root;
+ bool fta_forbidden;
+ for(p=0;p<where.size();p++){
+ if(! check_fta_forbidden_pr(where[p]->pr, NULL, Ext_fcns) || contains_gb_pr(where[p]->pr, unsafe_gbvars) ){
+ pr_root = split_ftavec_pr(where[p]->pr,select_vec,Ext_fcns);
+ fta_forbidden = true;
+ }else{
+ pr_root = dup_pr(where[p]->pr, NULL);
+ expand_gbvars_pr(pr_root, gb_tbl);
+ fta_forbidden = false;
+ }
+ cnf_elem *cnf_root = new cnf_elem(pr_root);
+ analyze_cnf(cnf_root);
+
+ if(fta_forbidden){
+ stream_node->where.push_back(cnf_root);
+ }else{
+ fta_node->where.push_back(cnf_root);
+ }
+ }
+
+
+// Process the Select clause, rehome it on the
+// new defs.
+ for(s=0;s<select_list.size();s++){
+ bool fta_forbidden = false;
+ scalarexp_t *root_se = rehome_fta_se(select_list[s]->se, &hfta_aggr_se);
+ stream_node->select_list.push_back(
+ new select_element(root_se, select_list[s]->name));
+ }
+
+
+// Process the Having clause
+
+// All of the predicates in the having clause must
+// execute in the stream node.
+
+ for(p=0;p<having.size();p++){
+ predicate_t *pr_root = rehome_fta_pr( having[p]->pr, &hfta_aggr_se);
+ cnf_elem *cnf_root = new cnf_elem(pr_root);
+ analyze_cnf(cnf_root);
+
+ stream_node->having.push_back(cnf_root);
+ }
+
+// Handle parameters and a few last details.
+ vector<string> param_names = param_tbl->get_param_names();
+ int pi;
+ for(pi=0;pi<param_names.size();pi++){
+ data_type *dt = param_tbl->get_data_type(param_names[pi]);
+ fta_node->param_tbl->add_param(param_names[pi],dt->duplicate(),
+ param_tbl->handle_access(param_names[pi]));
+ stream_node->param_tbl->add_param(param_names[pi],dt->duplicate(),
+ param_tbl->handle_access(param_names[pi]));
+ }
+
+ fta_node->definitions = definitions; fta_node->definitions.erase("_referenced_ifaces");
+ stream_node->definitions = definitions;
+
+// Now split by interfaces YYYY
+ if(ifaces.size() > 1){
+ for(si=0;si<ifaces.size();++si){
+ spx_qpn *subq_node = new spx_qpn();
+
+// Name the subquery
+ string new_name = "_"+node_name+"_"+ifaces[si].first+"_"+ifaces[si].second;
+ untaboo(new_name);
+ subq_node->set_node_name( new_name) ;
+ sel_names.push_back(subq_node->get_node_name());
+
+// Assign the table
+ subq_node->table_name = fta_node->table_name->duplicate();
+ subq_node->table_name->set_machine(ifaces[si].first);
+ subq_node->table_name->set_interface(ifaces[si].second);
+ subq_node->table_name->set_ifq(false);
+
+ for(s=0;s<fta_node->select_list.size();s++){
+ subq_node->select_list.push_back( dup_select(fta_node->select_list[s], NULL) );
+ }
+ for(p=0;p<fta_node->where.size();p++){
+ predicate_t *new_pr = dup_pr(fta_node->where[p]->pr, NULL);
+ cnf_elem *new_cnf = new cnf_elem(new_pr);
+ analyze_cnf(new_cnf);
+
+ subq_node->where.push_back(new_cnf);
+ }
+// Xfer all of the parameters.
+// Use existing handle annotations.
+ vector<string> param_names = param_tbl->get_param_names();
+ int pi;
+ for(pi=0;pi<param_names.size();pi++){
+ data_type *dt = param_tbl->get_data_type(param_names[pi]);
+ subq_node->param_tbl->add_param(param_names[pi],dt->duplicate(),
+ param_tbl->handle_access(param_names[pi]));
+ }
+ subq_node->definitions = definitions; subq_node->definitions.erase("_referenced_ifaces");
+ if(subq_node->resolve_if_params(ifdb, this->err_str)){
+ this->error_code = 3;
+ return ret_vec;
+ }
+
+ ret_vec.push_back(subq_node);
+ }
+
+ mrg_qpn *mrg_node = new mrg_qpn((spx_qpn *)(ret_vec[0]),
+ fta_node->node_name, sel_names, ifaces, ifdb);
+ /*
+ Do not split sources until we are done with optimizations
+ vector<mrg_qpn *> split_merge = mrg_node->split_sources();
+ for(i=0;i<split_merge.size();++i){
+ ret_vec.push_back(split_merge[i]);
+ }
+ */
+ ret_vec.push_back(mrg_node);
+ ret_vec.push_back(stream_node);
+ hfta_returned = 1/*split_merge.size()*/+1;
+
+ }else{
+ fta_node->table_name->set_machine(ifaces[0].first);
+ fta_node->table_name->set_interface(ifaces[0].second);
+ fta_node->table_name->set_ifq(false);
+ if(fta_node->resolve_if_params(ifdb, this->err_str)){
+ this->error_code = 3;
+ return ret_vec;
+ }
+ ret_vec.push_back(fta_node);
+ ret_vec.push_back(stream_node);
+ hfta_returned = 1;
+ }
+
+
+// ret_vec.push_back(fta_node);
+// ret_vec.push_back(stream_node);
+
+
+ return(ret_vec);
+
+}
+
+
+/*
+ SPLITTING A EQ-TEMPORAL, HASH JOIN OPERATOR
+
+ An JOIN_EQ_HASH_QPN node may reference:
+ literals, parameters, colrefs, functions, operators
+ An JOIN_EQ_HASH_QPN node may not reference:
+ group-by variables, aggregates
+
+ An JOIN_EQ_HASH_QPN node contains
+ selection list of SEs
+ where list of CNF predicates, broken into:
+ prefilter[2]
+ temporal_eq
+ hash_eq
+ postfilter
+
+ Algorithm:
+ For each tablevar whose source is a PROTOCOL
+ Create a LFTA for that tablevar
+ Push as many prefilter[..] predicates to that tablevar as is
+ possible.
+ Split the SEs in the select list, and the predicates not
+ pushed to the LFTA.
+
+*/
+
+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){
+
+ vector<qp_node *> ret_vec;
+ int f,p,s;
+
+// If the node reads from streams only, don't split.
+ bool stream_only = true;
+ for(f=0;f<from.size();++f){
+// int t = Schema->get_table_ref(from[f]->get_schema_name());
+ int t = from[f]->get_schema_ref();
+ if(Schema->get_schema_type(t) == PROTOCOL_SCHEMA) stream_only = false;
+ }
+ if(stream_only){
+ hfta_returned = 1;
+ ret_vec.push_back(this);
+ return(ret_vec);
+ }
+
+
+// The HFTA node, it is always returned.
+
+ join_eq_hash_qpn *stream_node = new join_eq_hash_qpn();
+ for(f=0;f<from.size();++f){
+// tablevar_t *tmp_tblvar = new tablevar_t( from[f]->get_interface().c_str(), from[f]->get_schema_name().c_str());
+ tablevar_t *tmp_tblvar = from[f]->duplicate();
+// tmp_tblvar->set_range_var(from[f]->get_var_name());
+
+ stream_node->from.push_back(tmp_tblvar);
+ }
+ stream_node->set_node_name(node_name);
+
+// Create spx (selection) children for each PROTOCOL source.
+ vector<spx_qpn *> child_vec;
+ vector< vector<select_element *> *> select_vec;
+ for(f=0;f<from.size();++f){
+// int t = Schema->get_table_ref(from[f]->get_schema_name());
+ int t = from[f]->get_schema_ref();
+ if(Schema->get_schema_type(t) == PROTOCOL_SCHEMA){
+ spx_qpn *child_qpn = new spx_qpn();
+ sprintf(tmpstr,"_fta_%d_%s",f,node_name.c_str());
+ child_qpn->set_node_name(string(tmpstr));
+ child_qpn->table_name = new tablevar_t(
+ from[f]->get_interface().c_str(), from[f]->get_schema_name().c_str(), from[f]->get_ifq());
+ child_qpn->table_name->set_range_var(from[f]->get_var_name());
+ child_qpn->table_name->set_machine(from[f]->get_machine());
+
+ child_vec.push_back(child_qpn);
+ select_vec.push_back(&(child_qpn->select_list));
+
+// Update the stream's FROM clause to read from this child
+ stream_node->from[f]->set_interface("");
+ stream_node->from[f]->set_schema(tmpstr);
+ }else{
+ child_vec.push_back(NULL);
+ select_vec.push_back(NULL);
+ }
+ }
+
+// Push lfta-safe prefilter to the lfta
+// TODO: I'm not copying the preds, I dont *think* it will be a problem.
+ predicate_t *pr_root;
+
+ for(f=0;f<from.size();++f){
+ vector<cnf_elem *> pred_vec = prefilter[f];
+ if(child_vec[f] != NULL){
+ for(p=0;p<pred_vec.size();++p){
+ if(check_fta_forbidden_pr(pred_vec[p]->pr,NULL, Ext_fcns)){
+ child_vec[f]->where.push_back(pred_vec[p]);
+ }else{
+ pr_root = split_ftavec_pr(pred_vec[p]->pr,select_vec,Ext_fcns);
+ cnf_elem *cnf_root = new cnf_elem(pr_root);
+ analyze_cnf(cnf_root);
+ stream_node->prefilter[f].push_back(cnf_root);
+ }
+ }
+ }else{
+ for(p=0;p<pred_vec.size();++p){
+ stream_node->prefilter[f].push_back(pred_vec[p]);
+ }
+ }
+
+ }
+
+// Process the other predicates
+ for(p=0;p<temporal_eq.size();++p){
+ pr_root = split_ftavec_pr(temporal_eq[p]->pr,select_vec,Ext_fcns);
+ cnf_elem *cnf_root = new cnf_elem(pr_root);
+ analyze_cnf(cnf_root);
+ stream_node->temporal_eq.push_back(cnf_root);
+ }
+ for(p=0;p<hash_eq.size();++p){
+ pr_root = split_ftavec_pr(hash_eq[p]->pr,select_vec,Ext_fcns);
+ cnf_elem *cnf_root = new cnf_elem(pr_root);
+ analyze_cnf(cnf_root);
+ stream_node->hash_eq.push_back(cnf_root);
+ }
+ for(p=0;p<postfilter.size();++p){
+ pr_root = split_ftavec_pr(postfilter[p]->pr,select_vec,Ext_fcns);
+ cnf_elem *cnf_root = new cnf_elem(pr_root);
+ analyze_cnf(cnf_root);
+ stream_node->postfilter.push_back(cnf_root);
+ }
+
+// Process the SEs
+ for(s=0;s<select_list.size();s++){
+ bool fta_forbidden = false;
+ int se_src = SPLIT_FTAVEC_NOTBLVAR;
+ scalarexp_t *root_se = split_ftavec_se( select_list[s]->se,
+ fta_forbidden, se_src, select_vec, Ext_fcns
+ );
+ if(fta_forbidden || !is_PROTOCOL_source(se_src, select_vec)){
+ stream_node->select_list.push_back(
+ new select_element(root_se, select_list[s]->name) );
+ }else{
+ scalarexp_t *new_se=make_fta_se_ref(select_vec,root_se,se_src);
+ stream_node->select_list.push_back(
+ new select_element(new_se, select_list[s]->name)
+ );
+ }
+ }
+
+
+// I need to "rehome" the colrefs -- make the annotations in the colrefs
+// agree with their tablevars.
+ for(f=0;f<child_vec.size();++f){
+ if(child_vec[f]!=NULL){
+ vector<tablevar_t *> fm; fm.push_back(child_vec[f]->table_name);
+
+ for(s=0;s<child_vec[f]->select_list.size();++s)
+ bind_colref_se(child_vec[f]->select_list[s]->se, fm,0,0);
+ for(p=0;p<child_vec[f]->where.size();++p)
+// bind_colref_pr(child_vec[f]->where[p]->pr, fm,f,0);
+ bind_colref_pr(child_vec[f]->where[p]->pr, fm,0,0);
+ }
+ }
+
+// rehome the colrefs in the hfta node.
+ for(f=0;f<stream_node->from.size();++f){
+ stream_node->where.clear();
+ for(s=0;s<stream_node->from.size();++s){
+ for(p=0;p<stream_node->prefilter[s].size();++p){
+ bind_colref_pr((stream_node->prefilter[s])[p]->pr,stream_node->from,f,f);
+ }
+ }
+ for(p=0;p<stream_node->temporal_eq.size();++p){
+ bind_colref_pr(stream_node->temporal_eq[p]->pr,stream_node->from,f,f);
+ }
+ for(p=0;p<stream_node->hash_eq.size();++p){
+ bind_colref_pr(stream_node->hash_eq[p]->pr,stream_node->from,f,f);
+ }
+ for(p=0;p<stream_node->postfilter.size();++p){
+ bind_colref_pr(stream_node->postfilter[p]->pr,stream_node->from,f,f);
+ }
+ for(s=0;s<stream_node->select_list.size();++s){
+ bind_colref_se(stream_node->select_list[s]->se,stream_node->from,f,f);
+ }
+ }
+
+// Rebuild the WHERE clause
+ stream_node->where.clear();
+ for(s=0;s<stream_node->from.size();++s){
+ for(p=0;p<stream_node->prefilter[s].size();++p){
+ stream_node->where.push_back((stream_node->prefilter[s])[p]);
+ }
+ }
+ for(p=0;p<stream_node->temporal_eq.size();++p){
+ stream_node->where.push_back(stream_node->temporal_eq[p]);
+ }
+ for(p=0;p<stream_node->hash_eq.size();++p){
+ stream_node->where.push_back(stream_node->hash_eq[p]);
+ }
+ for(p=0;p<stream_node->postfilter.size();++p){
+ stream_node->where.push_back(stream_node->postfilter[p]);
+ }
+
+
+// Build the return list
+ vector<qp_node *> hfta_nodes;
+ hfta_returned = 1;
+ for(f=0;f<from.size();++f){
+ if(child_vec[f] != NULL){
+ spx_qpn *c_node = child_vec[f];
+ vector<pair<string, string> > ifaces = get_ifaces(c_node->table_name, ifdb, n_virtual_ifaces, hfta_parallelism, hfta_idx);
+ if (ifaces.empty()) {
+ fprintf(stderr,"INTERNAL ERROR in join_eq_hash_qpn::split_node_for_fta - empty interface set, node is %s\n", node_name.c_str());
+ exit(1);
+ }
+
+ if(ifaces.size() == 1){
+ c_node->table_name->set_machine(ifaces[0].first);
+ c_node->table_name->set_interface(ifaces[0].second);
+ c_node->table_name->set_ifq(false);
+ if(c_node->resolve_if_params(ifdb, this->err_str)){
+ this->error_code = 3;
+ return ret_vec;
+ }
+ ret_vec.push_back(c_node);
+ }else{
+ vector<string> sel_names;
+ int si;
+ for(si=0;si<ifaces.size();++si){
+ spx_qpn *subq_node = new spx_qpn();
+
+// Name the subquery
+ string new_name = "_"+c_node->node_name+"_"+ifaces[si].first+"_"+ifaces[si].second;
+ untaboo(new_name);
+ subq_node->set_node_name( new_name) ;
+ sel_names.push_back(subq_node->get_node_name());
+
+// Assign the table
+ subq_node->table_name = c_node->table_name->duplicate();
+ subq_node->table_name->set_machine(ifaces[si].first);
+ subq_node->table_name->set_interface(ifaces[si].second);
+ subq_node->table_name->set_ifq(false);
+
+ for(s=0;s<c_node->select_list.size();s++){
+ subq_node->select_list.push_back(dup_select(c_node->select_list[s], NULL));
+ }
+ for(p=0;p<c_node->where.size();p++){
+ predicate_t *new_pr = dup_pr(c_node->where[p]->pr, NULL);
+ cnf_elem *new_cnf = new cnf_elem(new_pr);
+ analyze_cnf(new_cnf);
+
+printf("table name is %s\n",subq_node->table_name->to_string().c_str());
+ subq_node->where.push_back(new_cnf);
+ }
+// Xfer all of the parameters.
+// Use existing handle annotations.
+// vector<string> param_names = param_tbl->get_param_names();
+// int pi;
+// for(pi=0;pi<param_names.size();pi++){
+// data_type *dt = param_tbl->get_data_type(param_names[pi]);
+// subq_node->param_tbl->add_param(param_names[pi],dt->duplicate(),
+// param_tbl->handle_access(param_names[pi]));
+// }
+// subq_node->definitions = definitions;
+
+ if(subq_node->resolve_if_params(ifdb, this->err_str)){
+ this->error_code = 3;
+ return ret_vec;
+ }
+
+ ret_vec.push_back(subq_node);
+ }
+ int lpos = ret_vec.size()-1 ;
+ mrg_qpn *mrg_node = new mrg_qpn((spx_qpn *)(ret_vec[lpos]),c_node->node_name,sel_names, ifaces, ifdb);
+ /*
+ Do not split sources until we are done with optimizations
+ vector<mrg_qpn *> split_merge = mrg_node->split_sources();
+ int i;
+ for(i=0;i<split_merge.size();++i){
+ hfta_nodes.push_back(split_merge[i]);
+ }
+ */
+ hfta_nodes.push_back(mrg_node);
+ }
+ }
+ }
+ int i;
+ for(i=0;i<hfta_nodes.size();++i) ret_vec.push_back(hfta_nodes[i]);
+ ret_vec.push_back(stream_node);
+ hfta_returned = hfta_nodes.size()+1;
+
+// Currently : assume that the stream receives all parameters
+// and parameter updates, incorporates them, then passes
+// all of the parameters to the FTA.
+// This will need to change (tables, fta-unsafe types. etc.)
+
+// I will pass on the use_handle_access marking, even
+// though the fcn call that requires handle access might
+// exist in only one of the parts of the query.
+// Parameter manipulation and handle access determination will
+// need to be revisited anyway.
+ vector<string> param_names = param_tbl->get_param_names();
+ int pi;
+ for(pi=0;pi<param_names.size();pi++){
+ int ri;
+ data_type *dt = param_tbl->get_data_type(param_names[pi]);
+ for(ri=0;ri<ret_vec.size();++ri){
+ ret_vec[ri]->param_tbl->add_param(param_names[pi],dt->duplicate(),
+ param_tbl->handle_access(param_names[pi]));
+ ret_vec[ri]->definitions = definitions; ret_vec[ri]->definitions.erase("_referenced_ifaces");
+ }
+ }
+
+
+
+ return(ret_vec);
+
+}
+
+
+/////////////////////////////////////////////////////////////
+//// extract_opview
+
+// Common processing
+int process_opview(tablevar_t *fmtbl, int pos, string node_name,
+ table_list *Schema,
+ vector<query_node *> &qnodes,
+ opview_set &opviews,
+ vector<table_exp_t *> &ret, string rootnm, string silo_nm){
+
+ int s,f,q,m;
+
+ int schref = fmtbl->get_schema_ref();
+ if(schref <= 0)
+ return 0;
+
+ if(Schema->get_schema_type(schref) == OPERATOR_VIEW_SCHEMA){
+ opview_entry *opv = new opview_entry();
+ opv->parent_qname = node_name;
+ opv->root_name = rootnm;
+ opv->view_name = fmtbl->get_schema_name();
+ opv->pos = pos;
+ sprintf(tmpstr,"%s_UDOP%d_%s",node_name.c_str(),pos,opv->view_name.c_str());
+ opv->udop_alias = tmpstr;
+ fmtbl->set_udop_alias(opv->udop_alias);
+
+ opv->exec_fl = Schema->get_op_prop(schref, string("file"));
+ opv->liveness_timeout = atoi(Schema->get_op_prop(schref, string("liveness_timeout")).c_str());
+
+ vector<subquery_spec *> subq = Schema->get_subqueryspecs(schref);
+ for(s=0;s<subq.size();++s){
+// Validate that the fields match.
+ subquery_spec *sqs = subq[s];
+ vector<field_entry *> flds = Schema->get_fields(sqs->name+silo_nm);
+ if(flds.size() == 0){
+ fprintf(stderr,"INTERNAL ERROR: subquery %s of view %s not found in Schema.\n",sqs->name.c_str(), opv->view_name.c_str());
+ return(1);
+ }
+ if(flds.size() < sqs->types.size()){
+ 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());
+ return(1);
+ }
+ bool failed = false;
+ for(f=0;f<sqs->types.size();++f){
+ data_type dte(sqs->types[f],sqs->modifiers[f]);
+ data_type dtf(flds[f]->get_type(),flds[f]->get_modifier_list());
+ if(! dte.subsumes_type(&dtf) ){
+ 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());
+ failed = true;
+ }
+/*
+ if(dte.is_temporal() && (dte.get_temporal() != dtf.get_temporal()) ){
+ string pstr = dte.get_temporal_string();
+ 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);
+ failed = true;
+ }
+*/
+ }
+ if(failed)
+ return(1);
+/// Validation done, find the subquery, make a copy of the
+/// parse tree, and add it to the return list.
+ for(q=0;q<qnodes.size();++q)
+ if(qnodes[q]->name == sqs->name)
+ break;
+ if(q==qnodes.size()){
+ 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());
+ return(1);
+ }
+
+ table_exp_t *newq = dup_table_exp(qnodes[q]->parse_tree);
+ sprintf(tmpstr,"%s_OP%d_%s_SUBQ%d",node_name.c_str(),pos,opv->view_name.c_str(),s);
+ string newq_name = tmpstr;
+ newq->nmap["query_name"] = newq_name;
+ ret.push_back(newq);
+ opv->subq_names.push_back(newq_name);
+ }
+ fmtbl->set_opview_idx(opviews.append(opv));
+ }
+
+ return 0;
+}
+
+vector<table_exp_t *> spx_qpn::extract_opview(table_list *Schema, vector<query_node *> &qnodes, opview_set &opviews, string rootnm, string silo_name){
+ vector<table_exp_t *> ret;
+
+ int retval = process_opview(table_name,0,node_name,
+ Schema,qnodes,opviews,ret, rootnm, silo_name);
+ if(retval) exit(1);
+ return(ret);
+}
+
+
+vector<table_exp_t *> sgah_qpn::extract_opview(table_list *Schema, vector<query_node *> &qnodes, opview_set &opviews, string rootnm, string silo_name){
+ vector<table_exp_t *> ret;
+
+ int retval = process_opview(table_name,0,node_name,
+ Schema,qnodes,opviews,ret, rootnm, silo_name);
+ if(retval) exit(1);
+ return(ret);
+}
+
+vector<table_exp_t *> rsgah_qpn::extract_opview(table_list *Schema, vector<query_node *> &qnodes, opview_set &opviews, string rootnm, string silo_name){
+ vector<table_exp_t *> ret;
+
+ int retval = process_opview(table_name,0,node_name,
+ Schema,qnodes,opviews,ret, rootnm, silo_name);
+ if(retval) exit(1);
+ return(ret);
+}
+
+
+vector<table_exp_t *> sgahcwcb_qpn::extract_opview(table_list *Schema, vector<query_node *> &qnodes, opview_set &opviews, string rootnm, string silo_name){
+ vector<table_exp_t *> ret;
+
+ int retval = process_opview(table_name,0,node_name,
+ Schema,qnodes,opviews,ret, rootnm, silo_name);
+ if(retval) exit(1);
+ return(ret);
+}
+
+
+
+vector<table_exp_t *> mrg_qpn::extract_opview(table_list *Schema, vector<query_node *> &qnodes, opview_set &opviews, string rootnm, string silo_name){
+ vector<table_exp_t *> ret;
+ int f;
+ for(f=0;f<fm.size();++f){
+ int retval = process_opview(fm[f],f,node_name,
+ Schema,qnodes,opviews,ret, rootnm, silo_name);
+ if(retval) exit(1);
+ }
+ return(ret);
+}
+
+
+
+
+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){
+ vector<table_exp_t *> ret;
+ int f;
+ for(f=0;f<from.size();++f){
+ int retval = process_opview(from[f],f,node_name,
+ Schema,qnodes,opviews,ret, rootnm, silo_name);
+ if(retval) exit(1);
+ }
+ return(ret);
+}
+
+vector<table_exp_t *> filter_join_qpn::extract_opview(table_list *Schema, vector<query_node *> &qnodes, opview_set &opviews, string rootnm, string silo_name){
+ vector<table_exp_t *> ret;
+ int f;
+ for(f=0;f<from.size();++f){
+ int retval = process_opview(from[f],f,node_name,
+ Schema,qnodes,opviews,ret, rootnm, silo_name);
+ if(retval) exit(1);
+ }
+ return(ret);
+}
+
+vector<table_exp_t *> watch_join_qpn::extract_opview(table_list *Schema, vector<query_node *> &qnodes, opview_set &opviews, string rootnm, string silo_name){
+ vector<table_exp_t *> ret;
+ int retval = process_opview(from[0],0,node_name,
+ Schema,qnodes,opviews,ret, rootnm, silo_name);
+ if(retval) exit(1);
+ return(ret);
+}
+
+
+
+vector<table_exp_t *> watch_tbl_qpn::extract_opview(table_list *Schema, vector<query_node *> &qnodes, opview_set &opviews, string rootnm, string silo_name){
+ vector<table_exp_t *> ret;
+ return ret; // nothing to process
+}
+
+
+
+//////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////
+/////// Additional methods
+
+
+
+//////////////////////////////////////////////////////////////////
+// Get schema of operator output
+
+table_def *mrg_qpn::get_fields(){
+ return(table_layout);
+}
+
+table_def *watch_tbl_qpn::get_fields(){
+ return(table_layout);
+}
+
+
+table_def *spx_qpn::get_fields(){
+ return(create_attributes(node_name, select_list));
+}
+
+table_def *sgah_qpn::get_fields(){
+ return(create_attributes(node_name, select_list));
+}
+
+table_def *rsgah_qpn::get_fields(){
+ return(create_attributes(node_name, select_list));
+}
+
+table_def *sgahcwcb_qpn::get_fields(){
+ return(create_attributes(node_name, select_list));
+}
+
+table_def *filter_join_qpn::get_fields(){
+ return(create_attributes(node_name, select_list));
+}
+
+table_def *watch_join_qpn::get_fields(){
+ return(create_attributes(node_name, select_list));
+}
+
+table_def *join_eq_hash_qpn::get_fields(){
+ int i, h, s, t;
+
+// First, gather temporal colrefs and SEs.
+ map<col_id, temporal_type> temporal_cids;
+ vector<scalarexp_t *> temporal_se;
+ for(h=0;h<temporal_eq.size();++h){
+ scalarexp_t *sel = temporal_eq[h]->pr->get_left_se();
+ scalarexp_t *ser = temporal_eq[h]->pr->get_right_se();
+
+ if(sel->get_operator_type() == SE_COLREF){
+ col_id tcol(sel->get_colref());
+ if(temporal_cids.count(tcol) == 0){
+ temporal_cids[tcol] = sel->get_data_type()->get_temporal();
+ }
+ }else{
+ temporal_se.push_back(sel);
+ }
+
+ if(ser->get_operator_type() == SE_COLREF){
+ col_id tcol(ser->get_colref());
+ if(temporal_cids.count(tcol) == 0){
+ temporal_cids[tcol] = ser->get_data_type()->get_temporal();
+ }
+ }else{
+ temporal_se.push_back(ser);
+ }
+ }
+
+// Mark select elements as nontemporal, then deduce which
+// ones are temporal.
+ for(s=0;s<select_list.size();++s){
+ select_list[s]->se->get_data_type()->set_temporal(
+ compute_se_temporal(select_list[s]->se, temporal_cids)
+ );
+// Second chance if it is an exact match to an SE.
+// for(s=0;s<select_list.size();++s){
+ if(! select_list[s]->se->get_data_type()->is_temporal() ){
+ for(t=0;t<temporal_se.size();++t){
+ if(is_equivalent_se(temporal_se[t], select_list[s]->se)){
+ select_list[s]->se->get_data_type()->set_temporal(
+ temporal_se[t]->get_data_type()->get_temporal()
+ );
+ }
+ }
+ }
+// }
+ }
+
+// If there is an outer join, verify that
+// the temporal attributes are actually temporal.
+// NOTE: this code must be synchronized with the
+// equivalence finding in join_eq_hash_qpn::generate_functor
+// (and also, the join_eq_hash_qpn constructor)
+ if(from[0]->get_property() || from[1]->get_property()){
+ set<string> l_equiv, r_equiv;
+ for(i=0;i<temporal_eq.size();i++){
+ scalarexp_t *lse = temporal_eq[i]->pr->get_left_se();
+ scalarexp_t *rse = temporal_eq[i]->pr->get_right_se();
+ if(lse->get_operator_type()==SE_COLREF){
+ l_equiv.insert(lse->get_colref()->get_field());
+ }
+ if(rse->get_operator_type()==SE_COLREF){
+ r_equiv.insert(rse->get_colref()->get_field());
+ }
+ }
+
+ for(s=0;s<select_list.size();++s){
+ if(select_list[s]->se->get_data_type()->is_temporal()){
+ col_id_set cid_set;
+ col_id_set::iterator ci;
+ bool failed = false;
+ gather_se_col_ids(select_list[s]->se,cid_set, NULL);
+ for(ci=cid_set.begin();ci!=cid_set.end();++ci){
+ if((*ci).tblvar_ref == 0){
+ if(from[0]->get_property()){
+ if(l_equiv.count((*ci).field) == 0){
+ failed = true;
+ }
+ }
+ }else{
+ if(from[1]->get_property()){
+ if(r_equiv.count((*ci).field) == 0){
+ failed = true;
+ }
+ }
+ }
+ }
+ if(failed){
+ select_list[s]->se->get_data_type()->reset_temporal();
+ }
+ }
+ }
+ }
+
+
+ return create_attributes(node_name, select_list);
+}
+
+
+//-----------------------------------------------------------------
+// get output "keys"
+// This is a guess about the set of fields which are a key
+// Use as metadata output, e.g. in qtree.xml
+
+
+
+// refs to GB attribtues are keys, if a SE is not a GB colref
+// but refers to a GB colref (outside of an aggregation)
+// then set partial_keys to true
+vector<string> sgah_qpn::get_tbl_keys(vector<string> &partial_keys){
+ vector<string> keys;
+
+ set<int> gref_set;
+ for(int i=0; i<gb_tbl.size();++i)
+ gref_set.insert(i);
+
+ for(int s=0;s<select_list.size();++s){
+ if(select_list[s]->se->is_gb()){
+ keys.push_back(select_list[s]->name);
+ }else{
+ if(contains_gb_se(select_list[s]->se, gref_set)){
+ partial_keys.push_back(select_list[s]->name);
+ }
+ }
+ }
+ return keys;
+}
+
+vector<string> rsgah_qpn::get_tbl_keys(vector<string> &partial_keys){
+ vector<string> keys;
+
+ set<int> gref_set;
+ for(int i=0; i<gb_tbl.size();++i)
+ gref_set.insert(i);
+
+ for(int s=0;s<select_list.size();++s){
+ if(select_list[s]->se->is_gb()){
+ keys.push_back(select_list[s]->name);
+ }else{
+ if(contains_gb_se(select_list[s]->se, gref_set)){
+ partial_keys.push_back(select_list[s]->name);
+ }
+ }
+ }
+ return keys;
+}
+
+
+
+
+
+//-----------------------------------------------------------------
+// get output tables
+
+
+// Get tablevar_t names of input and output tables
+
+// output_file_qpn::output_file_qpn(){source_op_name = ""; }
+ vector<tablevar_t *> output_file_qpn::get_input_tbls(){
+ return(fm);
+ }
+
+ vector<tablevar_t *> watch_tbl_qpn::get_input_tbls(){
+ vector<tablevar_t *> ret;
+ return(ret);
+ }
+
+ vector<tablevar_t *> mrg_qpn::get_input_tbls(){
+ return(fm);
+ }
+
+ vector<tablevar_t *> spx_qpn::get_input_tbls(){
+ vector<tablevar_t *> retval(1,table_name);
+ return(retval);
+ }
+
+ vector<tablevar_t *> sgah_qpn::get_input_tbls(){
+ vector<tablevar_t *> retval(1,table_name);
+ return(retval);
+ }
+
+ vector<tablevar_t *> rsgah_qpn::get_input_tbls(){
+ vector<tablevar_t *> retval(1,table_name);
+ return(retval);
+ }
+
+ vector<tablevar_t *> sgahcwcb_qpn::get_input_tbls(){
+ vector<tablevar_t *> retval(1,table_name);
+ return(retval);
+ }
+
+ vector<tablevar_t *> join_eq_hash_qpn::get_input_tbls(){
+ return(from);
+ }
+
+ vector<tablevar_t *> filter_join_qpn::get_input_tbls(){
+ return(from);
+ }
+
+ vector<tablevar_t *> watch_join_qpn::get_input_tbls(){
+ return(from);
+ }
+
+//-----------------------------------------------------------------
+// get output tables
+
+
+// This does not make sense, this fcn returns the output table *name*,
+// not its schema, and then there is another fcn to rturn the schema.
+ vector<tablevar_t *> output_file_qpn::get_output_tbls(){
+ vector<tablevar_t *> retval(1,new tablevar_t(node_name.c_str()));
+ return(retval);
+ }
+
+ vector<tablevar_t *> watch_tbl_qpn::get_output_tbls(){
+ vector<tablevar_t *> retval(1,new tablevar_t(node_name.c_str()));
+ return(retval);
+ }
+
+ vector<tablevar_t *> mrg_qpn::get_output_tbls(){
+ vector<tablevar_t *> retval(1,new tablevar_t(node_name.c_str()));
+ return(retval);
+ }
+
+ vector<tablevar_t *> spx_qpn::get_output_tbls(){
+ vector<tablevar_t *> retval(1,new tablevar_t(node_name.c_str()));
+ return(retval);
+ }
+
+ vector<tablevar_t *> sgah_qpn::get_output_tbls(){
+ vector<tablevar_t *> retval(1,new tablevar_t(node_name.c_str()));
+ return(retval);
+ }
+
+ vector<tablevar_t *> rsgah_qpn::get_output_tbls(){
+ vector<tablevar_t *> retval(1,new tablevar_t(node_name.c_str()));
+ return(retval);
+ }
+
+ vector<tablevar_t *> sgahcwcb_qpn::get_output_tbls(){
+ vector<tablevar_t *> retval(1,new tablevar_t(node_name.c_str()));
+ return(retval);
+ }
+
+ vector<tablevar_t *> join_eq_hash_qpn::get_output_tbls(){
+ vector<tablevar_t *> retval(1,new tablevar_t(node_name.c_str()));
+ return(retval);
+ }
+
+ vector<tablevar_t *> filter_join_qpn::get_output_tbls(){
+ vector<tablevar_t *> retval(1,new tablevar_t(node_name.c_str()));
+ return(retval);
+ }
+
+
+ vector<tablevar_t *> watch_join_qpn::get_output_tbls(){
+ vector<tablevar_t *> retval(1,new tablevar_t(node_name.c_str()));
+ return(retval);
+ }
+
+
+
+//-----------------------------------------------------------------
+// Bind to schema
+
+// Associate colrefs with this schema.
+// Also, use this opportunity to create table_layout (the output schema).
+// If the output schema is ever needed before
+void mrg_qpn::bind_to_schema(table_list *Schema){
+ int t;
+ for(t=0;t<fm.size();++t){
+ int tblref = Schema->get_table_ref(fm[t]->get_schema_name());
+ if(tblref>=0)
+ fm[t]->set_schema_ref(tblref );
+ }
+
+// Here I assume that the colrefs have been reorderd
+// during analysis so that mvars line up with fm.
+ mvars[0]->set_schema_ref(fm[0]->get_schema_ref());
+ mvars[1]->set_schema_ref(fm[1]->get_schema_ref());
+
+
+}
+
+
+
+// Associate colrefs in SEs with this schema.
+void spx_qpn::bind_to_schema(table_list *Schema){
+// Bind the tablevars in the From clause to the Schema
+// (it might have changed from analysis time)
+ int t = Schema->get_table_ref(table_name->get_schema_name() );
+ if(t>=0)
+ table_name->set_schema_ref(t );
+
+// Get the "from" clause
+ tablevar_list_t fm(table_name);
+
+// Bind all SEs to this schema
+ int p;
+ for(p=0;p<where.size();++p){
+ bind_to_schema_pr(where[p]->pr, &fm, Schema);
+ }
+ int s;
+ for(s=0;s<select_list.size();++s){
+ bind_to_schema_se(select_list[s]->se, &fm, Schema);
+ }
+
+// Collect set of tuples referenced in this HFTA
+// input, internal, or output.
+
+}
+
+col_id_set spx_qpn::get_colrefs(bool ext_fcns_only,table_list *Schema){
+ col_id_set retval, tmp_cset;
+ int p;
+ for(p=0;p<where.size();++p){
+ gather_pr_col_ids(where[p]->pr, tmp_cset, NULL);
+ }
+ int s;
+ for(s=0;s<select_list.size();++s){
+ gather_se_col_ids(select_list[s]->se, tmp_cset, NULL);
+ }
+ col_id_set::iterator cisi;
+ if(ext_fcns_only){
+ for(cisi=tmp_cset.begin();cisi!=tmp_cset.end();++cisi){
+ field_entry *fe = Schema->get_field((*cisi).schema_ref, (*cisi).field);
+ if(fe->get_unpack_fcns().size()>0)
+ retval.insert((*cisi));
+ }
+ return retval;
+ }
+
+ return tmp_cset;
+}
+
+col_id_set filter_join_qpn::get_colrefs(bool ext_fcns_only,table_list *Schema){
+ col_id_set retval, tmp_cset;
+ int p;
+ for(p=0;p<where.size();++p){
+ gather_pr_col_ids(where[p]->pr, tmp_cset, NULL);
+ }
+ int s;
+ for(s=0;s<select_list.size();++s){
+ gather_se_col_ids(select_list[s]->se, tmp_cset, NULL);
+ }
+ col_id_set::iterator cisi;
+ if(ext_fcns_only){
+ for(cisi=tmp_cset.begin();cisi!=tmp_cset.end();++cisi){
+ field_entry *fe = Schema->get_field((*cisi).schema_ref, (*cisi).field);
+ if(fe->get_unpack_fcns().size()>0)
+ retval.insert((*cisi));
+ }
+ return retval;
+ }
+
+ return tmp_cset;
+}
+
+col_id_set watch_join_qpn::get_colrefs(bool ext_fcns_only,table_list *Schema){
+ col_id_set retval, tmp_cset;
+ int p;
+ for(p=0;p<where.size();++p){
+ gather_pr_col_ids(where[p]->pr, tmp_cset, NULL);
+ }
+ int s;
+ for(s=0;s<select_list.size();++s){
+ gather_se_col_ids(select_list[s]->se, tmp_cset, NULL);
+ }
+ col_id_set::iterator cisi;
+ if(ext_fcns_only){
+ for(cisi=tmp_cset.begin();cisi!=tmp_cset.end();++cisi){
+ field_entry *fe = Schema->get_field((*cisi).schema_ref, (*cisi).field);
+ if(fe->get_unpack_fcns().size()>0)
+ retval.insert((*cisi));
+ }
+ return retval;
+ }
+
+ return tmp_cset;
+}
+
+
+
+
+// Associate colrefs in SEs with this schema.
+void join_eq_hash_qpn::bind_to_schema(table_list *Schema){
+// Bind the tablevars in the From clause to the Schema
+// (it might have changed from analysis time)
+ int f;
+ for(f=0;f<from.size();++f){
+ string snm = from[f]->get_schema_name();
+ int tbl_ref = Schema->get_table_ref(snm);
+ if(tbl_ref >= 0)
+ from[f]->set_schema_ref(tbl_ref);
+ }
+
+// Bind all SEs to this schema
+ tablevar_list_t fm(from);
+
+ int p;
+ for(p=0;p<where.size();++p){
+ bind_to_schema_pr(where[p]->pr, &fm, Schema);
+ }
+ int s;
+ for(s=0;s<select_list.size();++s){
+ bind_to_schema_se(select_list[s]->se, &fm, Schema);
+ }
+
+// Collect set of tuples referenced in this HFTA
+// input, internal, or output.
+
+}
+
+void filter_join_qpn::bind_to_schema(table_list *Schema){
+// Bind the tablevars in the From clause to the Schema
+// (it might have changed from analysis time)
+ int f;
+ for(f=0;f<from.size();++f){
+ string snm = from[f]->get_schema_name();
+ int tbl_ref = Schema->get_table_ref(snm);
+ if(tbl_ref >= 0)
+ from[f]->set_schema_ref(tbl_ref);
+ }
+
+// Bind all SEs to this schema
+ tablevar_list_t fm(from);
+
+ int p;
+ for(p=0;p<where.size();++p){
+ bind_to_schema_pr(where[p]->pr, &fm, Schema);
+ }
+ int s;
+ for(s=0;s<select_list.size();++s){
+ bind_to_schema_se(select_list[s]->se, &fm, Schema);
+ }
+
+// Collect set of tuples referenced in this HFTA
+// input, internal, or output.
+
+}
+
+void watch_join_qpn::bind_to_schema(table_list *Schema){
+// Bind the tablevars in the From clause to the Schema
+// (it might have changed from analysis time)
+ int f;
+ for(f=0;f<from.size();++f){
+ string snm = from[f]->get_schema_name();
+ int tbl_ref = Schema->get_table_ref(snm);
+ if(tbl_ref >= 0)
+ from[f]->set_schema_ref(tbl_ref);
+ }
+
+// Bind all SEs to this schema
+ tablevar_list_t fm(from);
+
+ int p;
+ for(p=0;p<where.size();++p){
+ bind_to_schema_pr(where[p]->pr, &fm, Schema);
+ }
+ int s;
+ for(s=0;s<select_list.size();++s){
+ bind_to_schema_se(select_list[s]->se, &fm, Schema);
+ }
+
+// Collect set of tuples referenced in this HFTA
+// input, internal, or output.
+
+}
+
+
+
+
+
+void sgah_qpn::bind_to_schema(table_list *Schema){
+// Bind the tablevars in the From clause to the Schema
+// (it might have changed from analysis time)
+
+
+ int t = Schema->get_table_ref(table_name->get_schema_name() );
+ if(t>=0)
+ table_name->set_schema_ref(t );
+
+// Get the "from" clause
+ tablevar_list_t fm(table_name);
+
+
+
+// Bind all SEs to this schema
+ int p;
+ for(p=0;p<where.size();++p){
+ bind_to_schema_pr(where[p]->pr, &fm, Schema);
+ }
+ for(p=0;p<having.size();++p){
+ bind_to_schema_pr(having[p]->pr, &fm, Schema);
+ }
+ int s;
+ for(s=0;s<select_list.size();++s){
+ bind_to_schema_se(select_list[s]->se, &fm, Schema);
+ }
+ int g;
+ for(g=0;g<gb_tbl.size();++g){
+ bind_to_schema_se(gb_tbl.get_def(g), &fm, Schema);
+ }
+ int a;
+ for(a=0;a<aggr_tbl.size();++a){
+ if(aggr_tbl.is_builtin(a)){
+ bind_to_schema_se(aggr_tbl.get_aggr_se(a), &fm, Schema);
+ }else{
+ vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(a);
+ int o;
+ for(o=0;o<opl.size();++o){
+ bind_to_schema_se(opl[o],&fm,Schema);
+ }
+ }
+ }
+}
+
+col_id_set sgah_qpn::get_colrefs(bool ext_fcns_only,table_list *Schema){
+ col_id_set retval, tmp_cset;
+ int p;
+ for(p=0;p<where.size();++p){
+ gather_pr_col_ids(where[p]->pr, tmp_cset, &gb_tbl);
+ }
+ int g;
+ for(g=0;g<gb_tbl.size();++g){
+ gather_se_col_ids(gb_tbl.get_def(g), tmp_cset, &gb_tbl);
+ }
+ int a;
+ for(a=0;a<aggr_tbl.size();++a){
+ if(aggr_tbl.is_builtin(a)){
+ gather_se_col_ids(aggr_tbl.get_aggr_se(a), tmp_cset, &gb_tbl);
+ }else{
+ vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(a);
+ int o;
+ for(o=0;o<opl.size();++o){
+ gather_se_col_ids(opl[o], tmp_cset, &gb_tbl);
+ }
+ }
+ }
+
+ col_id_set::iterator cisi;
+ if(ext_fcns_only){
+ for(cisi=tmp_cset.begin();cisi!=tmp_cset.end();++cisi){
+ field_entry *fe = Schema->get_field((*cisi).schema_ref, (*cisi).field);
+ if(fe->get_unpack_fcns().size()>0)
+ retval.insert((*cisi));
+ }
+ return retval;
+ }
+
+ return tmp_cset;
+}
+
+
+void rsgah_qpn::bind_to_schema(table_list *Schema){
+// Bind the tablevars in the From clause to the Schema
+// (it might have changed from analysis time)
+ int t = Schema->get_table_ref(table_name->get_schema_name() );
+ if(t>=0)
+ table_name->set_schema_ref(t );
+
+// Get the "from" clause
+ tablevar_list_t fm(table_name);
+
+// Bind all SEs to this schema
+ int p;
+ for(p=0;p<where.size();++p){
+ bind_to_schema_pr(where[p]->pr, &fm, Schema);
+ }
+ for(p=0;p<having.size();++p){
+ bind_to_schema_pr(having[p]->pr, &fm, Schema);
+ }
+ for(p=0;p<closing_when.size();++p){
+ bind_to_schema_pr(closing_when[p]->pr, &fm, Schema);
+ }
+ int s;
+ for(s=0;s<select_list.size();++s){
+ bind_to_schema_se(select_list[s]->se, &fm, Schema);
+ }
+ int g;
+ for(g=0;g<gb_tbl.size();++g){
+ bind_to_schema_se(gb_tbl.get_def(g), &fm, Schema);
+ }
+ int a;
+ for(a=0;a<aggr_tbl.size();++a){
+ if(aggr_tbl.is_builtin(a)){
+ bind_to_schema_se(aggr_tbl.get_aggr_se(a), &fm, Schema);
+ }else{
+ vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(a);
+ int o;
+ for(o=0;o<opl.size();++o){
+ bind_to_schema_se(opl[o],&fm,Schema);
+ }
+ }
+ }
+}
+
+
+void sgahcwcb_qpn::bind_to_schema(table_list *Schema){
+// Bind the tablevars in the From clause to the Schema
+// (it might have changed from analysis time)
+ int t = Schema->get_table_ref(table_name->get_schema_name() );
+ if(t>=0)
+ table_name->set_schema_ref(t );
+
+// Get the "from" clause
+ tablevar_list_t fm(table_name);
+
+// Bind all SEs to this schema
+ int p;
+ for(p=0;p<where.size();++p){
+ bind_to_schema_pr(where[p]->pr, &fm, Schema);
+ }
+ for(p=0;p<having.size();++p){
+ bind_to_schema_pr(having[p]->pr, &fm, Schema);
+ }
+ for(p=0;p<having.size();++p){
+ bind_to_schema_pr(cleanby[p]->pr, &fm, Schema);
+ }
+ for(p=0;p<having.size();++p){
+ bind_to_schema_pr(cleanwhen[p]->pr, &fm, Schema);
+ }
+ int s;
+ for(s=0;s<select_list.size();++s){
+ bind_to_schema_se(select_list[s]->se, &fm, Schema);
+ }
+ int g;
+ for(g=0;g<gb_tbl.size();++g){
+ bind_to_schema_se(gb_tbl.get_def(g), &fm, Schema);
+ }
+ int a;
+ for(a=0;a<aggr_tbl.size();++a){
+ if(aggr_tbl.is_builtin(a)){
+ bind_to_schema_se(aggr_tbl.get_aggr_se(a), &fm, Schema);
+ }else{
+ vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(a);
+ int o;
+ for(o=0;o<opl.size();++o){
+ bind_to_schema_se(opl[o],&fm,Schema);
+ }
+ }
+ }
+}
+
+
+
+
+
+
+///////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////
+/// Functions for code generation.
+
+
+//-----------------------------------------------------------------
+// get_cplx_lit_tbl
+
+cplx_lit_table *watch_tbl_qpn::get_cplx_lit_tbl(ext_fcn_list *Ext_fcns){
+ return(new cplx_lit_table());
+}
+
+cplx_lit_table *mrg_qpn::get_cplx_lit_tbl(ext_fcn_list *Ext_fcns){
+ return(new cplx_lit_table());
+}
+
+cplx_lit_table *spx_qpn::get_cplx_lit_tbl(ext_fcn_list *Ext_fcns){
+ int i;
+ cplx_lit_table *complex_literals = new cplx_lit_table();
+
+ for(i=0;i<select_list.size();i++){
+ find_complex_literal_se(select_list[i]->se, Ext_fcns, complex_literals);
+ }
+ for(i=0;i<where.size();++i){
+ find_complex_literal_pr(where[i]->pr,Ext_fcns, complex_literals);
+ }
+
+ return(complex_literals);
+}
+
+cplx_lit_table *sgah_qpn::get_cplx_lit_tbl(ext_fcn_list *Ext_fcns){
+ int i,j;
+ cplx_lit_table *complex_literals = new cplx_lit_table();
+
+ for(i=0;i<aggr_tbl.size();++i){
+ if(aggr_tbl.is_builtin(i) && !aggr_tbl.is_star_aggr(i)){
+ find_complex_literal_se(aggr_tbl.get_aggr_se(i), Ext_fcns, complex_literals);
+ }else{
+ vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(i);
+ for(j=0;j<opl.size();++j)
+ find_complex_literal_se(opl[j], Ext_fcns, complex_literals);
+ }
+ }
+
+ for(i=0;i<select_list.size();i++){
+ find_complex_literal_se(select_list[i]->se, Ext_fcns, complex_literals);
+ }
+ for(i=0;i<gb_tbl.size();i++){
+ find_complex_literal_se(gb_tbl.get_def(i), Ext_fcns, complex_literals);
+ }
+ for(i=0;i<where.size();++i){
+ find_complex_literal_pr(where[i]->pr,Ext_fcns, complex_literals);
+ }
+ for(i=0;i<having.size();++i){
+ find_complex_literal_pr(having[i]->pr,Ext_fcns, complex_literals);
+ }
+
+ return(complex_literals);
+}
+
+
+cplx_lit_table *rsgah_qpn::get_cplx_lit_tbl(ext_fcn_list *Ext_fcns){
+ int i,j;
+ cplx_lit_table *complex_literals = new cplx_lit_table();
+
+ for(i=0;i<aggr_tbl.size();++i){
+ if(aggr_tbl.is_builtin(i) && !aggr_tbl.is_star_aggr(i)){
+ find_complex_literal_se(aggr_tbl.get_aggr_se(i), Ext_fcns, complex_literals);
+ }else{
+ vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(i);
+ for(j=0;j<opl.size();++j)
+ find_complex_literal_se(opl[j], Ext_fcns, complex_literals);
+ }
+ }
+
+ for(i=0;i<select_list.size();i++){
+ find_complex_literal_se(select_list[i]->se, Ext_fcns, complex_literals);
+ }
+ for(i=0;i<gb_tbl.size();i++){
+ find_complex_literal_se(gb_tbl.get_def(i), Ext_fcns, complex_literals);
+ }
+ for(i=0;i<where.size();++i){
+ find_complex_literal_pr(where[i]->pr,Ext_fcns, complex_literals);
+ }
+ for(i=0;i<having.size();++i){
+ find_complex_literal_pr(having[i]->pr,Ext_fcns, complex_literals);
+ }
+ for(i=0;i<closing_when.size();++i){
+ find_complex_literal_pr(closing_when[i]->pr,Ext_fcns, complex_literals);
+ }
+
+ return(complex_literals);
+}
+
+
+cplx_lit_table *sgahcwcb_qpn::get_cplx_lit_tbl(ext_fcn_list *Ext_fcns){
+ int i,j;
+ cplx_lit_table *complex_literals = new cplx_lit_table();
+
+ for(i=0;i<aggr_tbl.size();++i){
+ if(aggr_tbl.is_builtin(i) && !aggr_tbl.is_star_aggr(i)){
+ find_complex_literal_se(aggr_tbl.get_aggr_se(i), Ext_fcns, complex_literals);
+ }else{
+ vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(i);
+ for(j=0;j<opl.size();++j)
+ find_complex_literal_se(opl[j], Ext_fcns, complex_literals);
+ }
+ }
+
+ for(i=0;i<select_list.size();i++){
+ find_complex_literal_se(select_list[i]->se, Ext_fcns, complex_literals);
+ }
+ for(i=0;i<gb_tbl.size();i++){
+ find_complex_literal_se(gb_tbl.get_def(i), Ext_fcns, complex_literals);
+ }
+ for(i=0;i<where.size();++i){
+ find_complex_literal_pr(where[i]->pr,Ext_fcns, complex_literals);
+ }
+ for(i=0;i<having.size();++i){
+ find_complex_literal_pr(having[i]->pr,Ext_fcns, complex_literals);
+ }
+ for(i=0;i<cleanwhen.size();++i){
+ find_complex_literal_pr(cleanwhen[i]->pr,Ext_fcns, complex_literals);
+ }
+ for(i=0;i<cleanby.size();++i){
+ find_complex_literal_pr(cleanby[i]->pr,Ext_fcns, complex_literals);
+ }
+
+ return(complex_literals);
+}
+
+cplx_lit_table *join_eq_hash_qpn::get_cplx_lit_tbl(ext_fcn_list *Ext_fcns){
+ int i;
+ cplx_lit_table *complex_literals = new cplx_lit_table();
+
+ for(i=0;i<select_list.size();i++){
+ find_complex_literal_se(select_list[i]->se, Ext_fcns, complex_literals);
+ }
+ for(i=0;i<where.size();++i){
+ find_complex_literal_pr(where[i]->pr,Ext_fcns, complex_literals);
+ }
+
+ return(complex_literals);
+}
+
+cplx_lit_table *filter_join_qpn::get_cplx_lit_tbl(ext_fcn_list *Ext_fcns){
+ int i;
+ cplx_lit_table *complex_literals = new cplx_lit_table();
+
+ for(i=0;i<select_list.size();i++){
+ find_complex_literal_se(select_list[i]->se, Ext_fcns, complex_literals);
+ }
+ for(i=0;i<where.size();++i){
+ find_complex_literal_pr(where[i]->pr,Ext_fcns, complex_literals);
+ }
+
+ return(complex_literals);
+}
+
+cplx_lit_table *watch_join_qpn::get_cplx_lit_tbl(ext_fcn_list *Ext_fcns){
+ int i;
+ cplx_lit_table *complex_literals = new cplx_lit_table();
+
+ for(i=0;i<select_list.size();i++){
+ find_complex_literal_se(select_list[i]->se, Ext_fcns, complex_literals);
+ }
+ for(i=0;i<where.size();++i){
+ find_complex_literal_pr(where[i]->pr,Ext_fcns, complex_literals);
+ }
+
+ return(complex_literals);
+}
+
+
+
+
+
+//-----------------------------------------------------------------
+// get_handle_param_tbl
+
+vector<handle_param_tbl_entry *> watch_tbl_qpn::get_handle_param_tbl(ext_fcn_list *Ext_fcns){
+ vector<handle_param_tbl_entry *> retval;
+ return(retval);
+}
+
+vector<handle_param_tbl_entry *> mrg_qpn::get_handle_param_tbl(ext_fcn_list *Ext_fcns){
+ vector<handle_param_tbl_entry *> retval;
+ return(retval);
+}
+
+
+vector<handle_param_tbl_entry *> spx_qpn::get_handle_param_tbl(ext_fcn_list *Ext_fcns){
+ int i;
+ vector<handle_param_tbl_entry *> retval;
+
+ for(i=0;i<select_list.size();i++){
+ find_param_handles_se(select_list[i]->se, Ext_fcns, retval);
+ }
+ for(i=0;i<where.size();++i){
+ find_param_handles_pr(where[i]->pr,Ext_fcns, retval);
+ }
+
+ return(retval);
+}
+
+
+vector<handle_param_tbl_entry *> sgah_qpn::get_handle_param_tbl(ext_fcn_list *Ext_fcns){
+ int i,j;
+ vector<handle_param_tbl_entry *> retval;
+
+
+ for(i=0;i<aggr_tbl.size();++i){
+ if(aggr_tbl.is_builtin(i) && !aggr_tbl.is_star_aggr(i)){
+ find_param_handles_se(aggr_tbl.get_aggr_se(i), Ext_fcns, retval);
+ }else{
+ vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(i);
+ for(j=0;j<opl.size();++j)
+ find_param_handles_se(opl[j], Ext_fcns, retval);
+ }
+ }
+ for(i=0;i<select_list.size();i++){
+ find_param_handles_se(select_list[i]->se, Ext_fcns, retval);
+ }
+ for(i=0;i<gb_tbl.size();i++){
+ find_param_handles_se(gb_tbl.get_def(i), Ext_fcns, retval);
+ }
+ for(i=0;i<where.size();++i){
+ find_param_handles_pr(where[i]->pr,Ext_fcns, retval);
+ }
+ for(i=0;i<having.size();++i){
+ find_param_handles_pr(having[i]->pr,Ext_fcns, retval);
+ }
+
+ return(retval);
+}
+
+
+vector<handle_param_tbl_entry *> rsgah_qpn::get_handle_param_tbl(ext_fcn_list *Ext_fcns){
+ int i,j;
+ vector<handle_param_tbl_entry *> retval;
+
+
+ for(i=0;i<aggr_tbl.size();++i){
+ if(aggr_tbl.is_builtin(i) && !aggr_tbl.is_star_aggr(i)){
+ find_param_handles_se(aggr_tbl.get_aggr_se(i), Ext_fcns, retval);
+ }else{
+ vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(i);
+ for(j=0;j<opl.size();++j)
+ find_param_handles_se(opl[j], Ext_fcns, retval);
+ }
+ }
+ for(i=0;i<select_list.size();i++){
+ find_param_handles_se(select_list[i]->se, Ext_fcns, retval);
+ }
+ for(i=0;i<gb_tbl.size();i++){
+ find_param_handles_se(gb_tbl.get_def(i), Ext_fcns, retval);
+ }
+ for(i=0;i<where.size();++i){
+ find_param_handles_pr(where[i]->pr,Ext_fcns, retval);
+ }
+ for(i=0;i<having.size();++i){
+ find_param_handles_pr(having[i]->pr,Ext_fcns, retval);
+ }
+ for(i=0;i<closing_when.size();++i){
+ find_param_handles_pr(closing_when[i]->pr,Ext_fcns, retval);
+ }
+
+ return(retval);
+}
+
+
+vector<handle_param_tbl_entry *> sgahcwcb_qpn::get_handle_param_tbl(ext_fcn_list *Ext_fcns){
+ int i,j;
+ vector<handle_param_tbl_entry *> retval;
+
+
+ for(i=0;i<aggr_tbl.size();++i){
+ if(aggr_tbl.is_builtin(i) && !aggr_tbl.is_star_aggr(i)){
+ find_param_handles_se(aggr_tbl.get_aggr_se(i), Ext_fcns, retval);
+ }else{
+ vector<scalarexp_t *> opl = aggr_tbl.get_operand_list(i);
+ for(j=0;j<opl.size();++j)
+ find_param_handles_se(opl[j], Ext_fcns, retval);
+ }
+ }
+ for(i=0;i<select_list.size();i++){
+ find_param_handles_se(select_list[i]->se, Ext_fcns, retval);
+ }
+ for(i=0;i<gb_tbl.size();i++){
+ find_param_handles_se(gb_tbl.get_def(i), Ext_fcns, retval);
+ }
+ for(i=0;i<where.size();++i){
+ find_param_handles_pr(where[i]->pr,Ext_fcns, retval);
+ }
+ for(i=0;i<having.size();++i){
+ find_param_handles_pr(having[i]->pr,Ext_fcns, retval);
+ }
+ for(i=0;i<cleanwhen.size();++i){
+ find_param_handles_pr(cleanwhen[i]->pr,Ext_fcns, retval);
+ }
+ for(i=0;i<cleanby.size();++i){
+ find_param_handles_pr(cleanby[i]->pr,Ext_fcns, retval);
+ }
+
+ return(retval);
+}
+
+vector<handle_param_tbl_entry *> join_eq_hash_qpn::get_handle_param_tbl(ext_fcn_list *Ext_fcns){
+ int i;
+ vector<handle_param_tbl_entry *> retval;
+
+ for(i=0;i<select_list.size();i++){
+ find_param_handles_se(select_list[i]->se, Ext_fcns, retval);
+ }
+ for(i=0;i<where.size();++i){
+ find_param_handles_pr(where[i]->pr,Ext_fcns, retval);
+ }
+
+ return(retval);
+}
+
+
+vector<handle_param_tbl_entry *> filter_join_qpn::get_handle_param_tbl(ext_fcn_list *Ext_fcns){
+ int i;
+ vector<handle_param_tbl_entry *> retval;
+
+ for(i=0;i<select_list.size();i++){
+ find_param_handles_se(select_list[i]->se, Ext_fcns, retval);
+ }
+ for(i=0;i<where.size();++i){
+ find_param_handles_pr(where[i]->pr,Ext_fcns, retval);
+ }
+
+ return(retval);
+}
+
+vector<handle_param_tbl_entry *> watch_join_qpn::get_handle_param_tbl(ext_fcn_list *Ext_fcns){
+ int i;
+ vector<handle_param_tbl_entry *> retval;
+
+ for(i=0;i<select_list.size();i++){
+ find_param_handles_se(select_list[i]->se, Ext_fcns, retval);
+ }
+ for(i=0;i<where.size();++i){
+ find_param_handles_pr(where[i]->pr,Ext_fcns, retval);
+ }
+
+ return(retval);
+}
+
+
+
+///////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////
+/// Functions for operator output rates estimations
+
+
+//-----------------------------------------------------------------
+// get_rate_estimate
+
+double spx_qpn::get_rate_estimate() {
+
+ // dummy method for now
+ return SPX_SELECTIVITY * DEFAULT_INTERFACE_RATE;
+}
+
+double sgah_qpn::get_rate_estimate() {
+
+ // dummy method for now
+ return SGAH_SELECTIVITY * DEFAULT_INTERFACE_RATE;
+}
+
+double rsgah_qpn::get_rate_estimate() {
+
+ // dummy method for now
+ return RSGAH_SELECTIVITY * DEFAULT_INTERFACE_RATE;
+}
+
+double sgahcwcb_qpn::get_rate_estimate() {
+
+ // dummy method for now
+ return SGAHCWCB_SELECTIVITY * DEFAULT_INTERFACE_RATE;
+}
+
+double watch_tbl_qpn::get_rate_estimate() {
+
+ // dummy method for now
+ return DEFAULT_INTERFACE_RATE;
+}
+
+double mrg_qpn::get_rate_estimate() {
+
+ // dummy method for now
+ return MRG_SELECTIVITY * DEFAULT_INTERFACE_RATE;
+}
+
+double join_eq_hash_qpn::get_rate_estimate() {
+
+ // dummy method for now
+ return JOIN_EQ_HASH_SELECTIVITY * DEFAULT_INTERFACE_RATE;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+///// Generate functors
+
+
+
+
+//-------------------------------------------------------------------------
+// Code generation utilities.
+//-------------------------------------------------------------------------
+
+// Globals referenced by generate utilities
+
+static gb_table *segen_gb_tbl; // Table of all group-by attributes.
+
+
+
+// Generate code that makes reference
+// to the tuple, and not to any aggregates.
+// NEW : it might reference a stateful function.
+static string generate_se_code(scalarexp_t *se,table_list *schema){
+ string ret;
+ data_type *ldt, *rdt;
+ int o;
+ vector<scalarexp_t *> operands;
+
+
+ switch(se->get_operator_type()){
+ case SE_LITERAL:
+ if(se->is_handle_ref()){
+ sprintf(tmpstr,"handle_param_%d",se->get_handle_ref() );
+ ret = tmpstr;
+ return(ret);
+ }
+ if(se->get_literal()->is_cpx_lit()){
+ sprintf(tmpstr,"complex_literal_%d",se->get_literal()->get_cpx_lit_ref() );
+ ret = tmpstr;
+ return(ret);
+ }
+ return(se->get_literal()->to_hfta_C_code("")); // not complex no constr.
+ case SE_PARAM:
+ if(se->is_handle_ref()){
+ sprintf(tmpstr,"handle_param_%d",se->get_handle_ref() );
+ ret = tmpstr;
+ return(ret);
+ }
+ ret.append("param_");
+ ret.append(se->get_param_name());
+ return(ret);
+ case SE_UNARY_OP:
+ ldt = se->get_left_se()->get_data_type();
+ if(ldt->complex_operator(se->get_op()) ){
+ ret.append( ldt->get_complex_operator(se->get_op()) );
+ ret.append("(");
+ ret.append(generate_se_code(se->get_left_se(),schema));
+ ret.append(")");
+ }else{
+ ret.append("(");
+ ret.append(se->get_op());
+ ret.append(generate_se_code(se->get_left_se(),schema));
+ ret.append(")");
+ }
+ return(ret);
+ case SE_BINARY_OP:
+ ldt = se->get_left_se()->get_data_type();
+ rdt = se->get_right_se()->get_data_type();
+
+ if(ldt->complex_operator(rdt, se->get_op()) ){
+ ret.append( ldt->get_complex_operator(rdt, se->get_op()) );
+ ret.append("(");
+ ret.append(generate_se_code(se->get_left_se(),schema));
+ ret.append(", ");
+ ret.append(generate_se_code(se->get_right_se(),schema));
+ ret.append(")");
+ }else{
+ ret.append("(");
+ ret.append(generate_se_code(se->get_left_se(),schema));
+ ret.append(se->get_op());
+ ret.append(generate_se_code(se->get_right_se(),schema));
+ ret.append(")");
+ }
+ return(ret);
+ case SE_COLREF:
+ if(se->is_gb()){ // OK to ref gb attrs, but they're not yet unpacked ...
+ // so return the defining code.
+ int gref = se->get_gb_ref();
+ scalarexp_t *gdef_se = segen_gb_tbl->get_def(gref);
+ ret = generate_se_code(gdef_se, schema );
+
+ }else{
+ sprintf(tmpstr,"unpack_var_%s_%d",
+ se->get_colref()->get_field().c_str(), se->get_colref()->get_tablevar_ref() );
+ ret = tmpstr;
+ }
+ return(ret);
+ case SE_FUNC:
+ if(se->is_partial()){
+ sprintf(tmpstr,"partial_fcn_result_%d",se->get_partial_ref());
+ ret = tmpstr;
+ }else{
+ ret += se->op + "(";
+ operands = se->get_operands();
+ bool first_elem = true;
+ if(se->get_storage_state() != ""){
+ ret += "&(stval->state_var_"+se->get_storage_state()+"),cd";
+ first_elem = false;
+ }
+ for(o=0;o<operands.size();o++){
+ if(first_elem) first_elem=false; else ret += ", ";
+ if(operands[o]->get_data_type()->is_buffer_type() &&
+ (! (operands[o]->is_handle_ref()) ) )
+ ret.append("&");
+ ret += generate_se_code(operands[o], schema);
+ }
+ ret += ")";
+ }
+ return(ret);
+ default:
+ fprintf(stderr,"INTERNAL ERROR in generate_se_code (hfta), line %d, character %d: unknown operator type %d\n",
+ se->get_lineno(), se->get_charno(),se->get_operator_type());
+ return("ERROR in generate_se_code");
+ }
+}
+
+// generate code that refers only to aggregate data and constants.
+// NEW : modified to handle superaggregates and stateful fcn refs.
+// Assume that the state is in *stval
+static string generate_se_code_fm_aggr(scalarexp_t *se, string gbvar, string aggvar, table_list *schema){
+
+ string ret;
+ data_type *ldt, *rdt;
+ int o;
+ vector<scalarexp_t *> operands;
+
+
+ switch(se->get_operator_type()){
+ case SE_LITERAL:
+ if(se->is_handle_ref()){
+ sprintf(tmpstr,"handle_param_%d",se->get_handle_ref() );
+ ret = tmpstr;
+ return(ret);
+ }
+ if(se->get_literal()->is_cpx_lit()){
+ sprintf(tmpstr,"complex_literal_%d",se->get_literal()->get_cpx_lit_ref() );
+ ret = tmpstr;
+ return(ret);
+ }
+ return(se->get_literal()->to_hfta_C_code("")); // not complex no constr.
+ case SE_PARAM:
+ if(se->is_handle_ref()){
+ sprintf(tmpstr,"handle_param_%d",se->get_handle_ref() );
+ ret = tmpstr;
+ return(ret);
+ }
+ ret.append("param_");
+ ret.append(se->get_param_name());
+ return(ret);
+ case SE_UNARY_OP:
+ ldt = se->get_left_se()->get_data_type();
+ if(ldt->complex_operator(se->get_op()) ){
+ ret.append( ldt->get_complex_operator(se->get_op()) );
+ ret.append("(");
+ ret.append(generate_se_code_fm_aggr(se->get_left_se(),gbvar,aggvar,schema));
+ ret.append(")");
+ }else{
+ ret.append("(");
+ ret.append(se->get_op());
+ ret.append(generate_se_code_fm_aggr(se->get_left_se(),gbvar,aggvar,schema));
+ ret.append(")");
+ }
+ return(ret);
+ case SE_BINARY_OP:
+ ldt = se->get_left_se()->get_data_type();
+ rdt = se->get_right_se()->get_data_type();
+
+ if(ldt->complex_operator(rdt, se->get_op()) ){
+ ret.append( ldt->get_complex_operator(rdt, se->get_op()) );
+ ret.append("(");
+ ret.append(generate_se_code_fm_aggr(se->get_left_se(),gbvar,aggvar,schema));
+ ret.append(", ");
+ ret.append(generate_se_code_fm_aggr(se->get_right_se(),gbvar,aggvar,schema));
+ ret.append(")");
+ }else{
+ ret.append("(");
+ ret.append(generate_se_code_fm_aggr(se->get_left_se(),gbvar,aggvar,schema));
+ ret.append(se->get_op());
+ ret.append(generate_se_code_fm_aggr(se->get_right_se(),gbvar,aggvar,schema));
+ ret.append(")");
+ }
+ return(ret);
+ case SE_COLREF:
+ if(se->is_gb()){ // OK to ref gb attrs, but they're not yet unpacked ...
+ // so return the defining code.
+ sprintf(tmpstr,"%s%d",gbvar.c_str(),se->get_gb_ref());
+ ret = tmpstr;
+
+ }else{
+ fprintf(stderr,"ERROR reference to non-GB column ref not permitted here,"
+ "error in query_plan.cc:generate_se_code_fm_aggr, line %d, character %d.\n",
+ se->get_lineno(), se->get_charno());
+ ret = tmpstr;
+ }
+ return(ret);
+ case SE_AGGR_STAR:
+ case SE_AGGR_SE:
+ if(se->is_superaggr()){
+ sprintf(tmpstr,"stval->aggr_var%d",se->get_aggr_ref());
+ }else{
+ sprintf(tmpstr,"%saggr_var%d",aggvar.c_str(),se->get_aggr_ref());
+ }
+ ret = tmpstr;
+ return(ret);
+ case SE_FUNC:
+// Is it a UDAF?
+ if(se->get_aggr_ref() >= 0){
+ sprintf(tmpstr,"udaf_ret_%d",se->get_aggr_ref());
+ ret = tmpstr;
+ return(ret);
+ }
+
+ if(se->is_partial()){
+ sprintf(tmpstr,"partial_fcn_result_%d",se->get_partial_ref());
+ ret = tmpstr;
+ }else{
+ ret += se->op + "(";
+ bool first_elem = true;
+ if(se->get_storage_state() != ""){
+ ret += "&(stval->state_var_"+se->get_storage_state()+"),cd";
+ first_elem = false;
+ }
+ operands = se->get_operands();
+ for(o=0;o<operands.size();o++){
+ if(first_elem) first_elem=false; else ret += ", ";
+ if(operands[o]->get_data_type()->is_buffer_type() &&
+ (! (operands[o]->is_handle_ref()) ) )
+ ret.append("&");
+ ret += generate_se_code_fm_aggr(operands[o], gbvar,aggvar, schema);
+ }
+ ret += ")";
+ }
+ return(ret);
+ default:
+ fprintf(stderr,"INTERNAL ERROR in query_plan.cc::generate_se_code_fm_aggr, line %d, character %d: unknown operator type %d\n",
+ se->get_lineno(), se->get_charno(),se->get_operator_type());
+ return("ERROR in generate_se_code_fm_aggr");
+ }
+
+}
+
+
+static string unpack_partial_fcn_fm_aggr(scalarexp_t *se, int pfn_id, string gbvar, string aggvar, table_list *schema){
+ string ret;
+ int o;
+ vector<scalarexp_t *> operands;
+
+
+ if(se->get_operator_type() != SE_FUNC){
+ fprintf(stderr,"INTERNAL ERROR, non-function SE passed to unpack_partial_fcn_fm_aggr. line %d, character %d\n",
+ se->get_lineno(), se->get_charno());
+ return("ERROR in unpack_partial_fcn_fm_aggr");
+ }
+
+ ret = "\tretval = " + se->get_op() + "( ",
+ sprintf(tmpstr, "&partial_fcn_result_%d",pfn_id);
+ ret += tmpstr;
+
+ if(se->get_storage_state() != ""){
+ ret += ",&(stval->state_var_"+se->get_storage_state()+"),cd";
+ }
+
+ operands = se->get_operands();
+ for(o=0;o<operands.size();o++){
+ ret += ", ";
+ if(operands[o]->get_data_type()->is_buffer_type() &&
+ (! (operands[o]->is_handle_ref()) ) )
+ ret.append("&");
+ ret += generate_se_code_fm_aggr(operands[o], gbvar,aggvar, schema);
+ }
+ ret += ");\n";
+
+ return(ret);
+}
+
+
+static string unpack_partial_fcn(scalarexp_t *se, int pfn_id, table_list *schema){
+ string ret;
+ int o;
+ vector<scalarexp_t *> operands;
+
+ if(se->get_operator_type() != SE_FUNC){
+ fprintf(stderr,"INTERNAL ERROR, non-function SE passed to unpack_partial_fcn. line %d, character %d\n",
+ se->get_lineno(), se->get_charno());
+ return("ERROR in unpack_partial_fcn");
+ }
+
+ ret = "\tretval = " + se->get_op() + "( ",
+ sprintf(tmpstr, "&partial_fcn_result_%d",pfn_id);
+ ret += tmpstr;
+
+ if(se->get_storage_state() != ""){
+ ret += ",&(stval->state_var_"+se->get_storage_state()+"),cd";
+ }
+
+ operands = se->get_operands();
+ for(o=0;o<operands.size();o++){
+ ret += ", ";
+ if(operands[o]->get_data_type()->is_buffer_type() &&
+ (! (operands[o]->is_handle_ref()) ) )
+ ret.append("&");
+ ret += generate_se_code(operands[o], schema);
+ }
+ ret += ");\n";
+
+ return(ret);
+}
+
+static string generate_cached_fcn(scalarexp_t *se, int pfn_id, table_list *schema){
+ string ret;
+ int o;
+ vector<scalarexp_t *> operands;
+
+ if(se->get_operator_type() != SE_FUNC){
+ fprintf(stderr,"INTERNAL ERROR, non-function SE passed to generate_cached_fcn. line %d, character %d\n",
+ se->get_lineno(), se->get_charno());
+ return("ERROR in generate_cached_fcn");
+ }
+
+ ret = se->get_op()+"(";
+
+ if(se->get_storage_state() != ""){
+ ret += "&(stval->state_var_"+se->get_storage_state()+"),cd,";
+ }
+
+ operands = se->get_operands();
+ for(o=0;o<operands.size();o++){
+ if(o) ret += ", ";
+ if(operands[o]->get_data_type()->is_buffer_type() &&
+ (! (operands[o]->is_handle_ref()) ) )
+ ret.append("&");
+ ret += generate_se_code(operands[o], schema);
+ }
+ ret += ");\n";
+
+ return(ret);
+}
+
+
+
+
+
+static string generate_C_comparison_op(string op){
+ if(op == "=") return("==");
+ if(op == "<>") return("!=");
+ return(op);
+}
+
+static string generate_C_boolean_op(string op){
+ if( (op == "AND") || (op == "And") || (op == "and") ){
+ return("&&");
+ }
+ if( (op == "OR") || (op == "Or") || (op == "or") ){
+ return("||");
+ }
+ if( (op == "NOT") || (op == "Not") || (op == "not") ){
+ return("!");
+ }
+
+ return("ERROR UNKNOWN BOOLEAN OPERATOR");
+}
+
+
+static string generate_predicate_code(predicate_t *pr,table_list *schema){
+ string ret;
+ vector<literal_t *> litv;
+ int i;
+ data_type *ldt, *rdt;
+ vector<scalarexp_t *> op_list;
+ int o;
+
+ switch(pr->get_operator_type()){
+ case PRED_IN:
+ ldt = pr->get_left_se()->get_data_type();
+
+ ret.append("( ");
+ litv = pr->get_lit_vec();
+ for(i=0;i<litv.size();i++){
+ if(i>0) ret.append(" || ");
+ ret.append("( ");
+
+ if(ldt->complex_comparison(ldt) ){
+ ret.append( ldt->get_hfta_equals_fcn(ldt) );
+ ret.append("( ");
+ if(ldt->is_buffer_type() )
+ ret.append("&");
+ ret.append(generate_se_code(pr->get_left_se(), schema));
+ ret.append(", ");
+ if(ldt->is_buffer_type() )
+ ret.append("&");
+ if(litv[i]->is_cpx_lit()){
+ sprintf(tmpstr,"complex_literal_%d",litv[i]->get_cpx_lit_ref() );
+ ret += tmpstr;
+ }else{
+ ret.append(litv[i]->to_C_code(""));
+ }
+ ret.append(") == 0");
+ }else{
+ ret.append(generate_se_code(pr->get_left_se(), schema));
+ ret.append(" == ");
+ ret.append(litv[i]->to_hfta_C_code(""));
+ }
+
+ ret.append(" )");
+ }
+ ret.append(" )");
+ return(ret);
+
+ case PRED_COMPARE:
+ ldt = pr->get_left_se()->get_data_type();
+ rdt = pr->get_right_se()->get_data_type();
+
+ ret.append("( ");
+ if(ldt->complex_comparison(rdt) ){
+// TODO can use get_hfta_equals_fcn if op is "=" ?
+ ret.append(ldt->get_hfta_comparison_fcn(rdt));
+ ret.append("(");
+ if(ldt->is_buffer_type() )
+ ret.append("&");
+ ret.append(generate_se_code(pr->get_left_se(),schema) );
+ ret.append(", ");
+ if(rdt->is_buffer_type() )
+ ret.append("&");
+ ret.append(generate_se_code(pr->get_right_se(),schema) );
+ ret.append(") ");
+ ret.append( generate_C_comparison_op(pr->get_op()));
+ ret.append("0");
+ }else{
+ ret.append(generate_se_code(pr->get_left_se(),schema) );
+ ret.append( generate_C_comparison_op(pr->get_op()));
+ ret.append(generate_se_code(pr->get_right_se(),schema) );
+ }
+ ret.append(" )");
+ return(ret);
+ case PRED_UNARY_OP:
+ ret.append("( ");
+ ret.append( generate_C_boolean_op(pr->get_op()) );
+ ret.append(generate_predicate_code(pr->get_left_pr(),schema) );
+ ret.append(" )");
+ return(ret);
+ case PRED_BINARY_OP:
+ ret.append("( ");
+ ret.append(generate_predicate_code(pr->get_left_pr(),schema) );
+ ret.append( generate_C_boolean_op(pr->get_op()) );
+ ret.append(generate_predicate_code(pr->get_right_pr(),schema) );
+ ret.append(" )");
+ return(ret);
+ case PRED_FUNC:
+ ret += pr->get_op() + "( ";
+ op_list = pr->get_op_list();
+ for(o=0;o<op_list.size();++o){
+ if(o>0) ret += ", ";
+ if(op_list[o]->get_data_type()->is_buffer_type() && (! (op_list[o]->is_handle_ref()) ) )
+ ret.append("&");
+ ret += generate_se_code(op_list[o], schema);
+ }
+ ret += " )";
+ return(ret);
+ default:
+ fprintf(stderr,"INTERNAL ERROR in generate_predicate_code, line %d, character %d, unknown predicate operator type %d\n",
+ pr->get_lineno(), pr->get_charno(), pr->get_operator_type() );
+ return("ERROR in generate_predicate_code");
+ }
+}
+
+static string generate_predicate_code_fm_aggr(predicate_t *pr, string gbvar, string aggvar,table_list *schema){
+ string ret;
+ vector<literal_t *> litv;
+ int i;
+ data_type *ldt, *rdt;
+ vector<scalarexp_t *> op_list;
+ int o;
+
+ switch(pr->get_operator_type()){
+ case PRED_IN:
+ ldt = pr->get_left_se()->get_data_type();
+
+ ret.append("( ");
+ litv = pr->get_lit_vec();
+ for(i=0;i<litv.size();i++){
+ if(i>0) ret.append(" || ");
+ ret.append("( ");
+
+ if(ldt->complex_comparison(ldt) ){
+ ret.append( ldt->get_hfta_equals_fcn(ldt) );
+ ret.append("( ");
+ if(ldt->is_buffer_type() )
+ ret.append("&");
+ ret.append(generate_se_code_fm_aggr(pr->get_left_se(), gbvar, aggvar, schema));
+ ret.append(", ");
+ if(ldt->is_buffer_type() )
+ ret.append("&");
+ if(litv[i]->is_cpx_lit()){
+ sprintf(tmpstr,"complex_literal_%d",litv[i]->get_cpx_lit_ref() );
+ ret += tmpstr;
+ }else{
+ ret.append(litv[i]->to_C_code(""));
+ }
+ ret.append(") == 0");
+ }else{
+ ret.append(generate_se_code_fm_aggr(pr->get_left_se(), gbvar, aggvar, schema));
+ ret.append(" == ");
+ ret.append(litv[i]->to_hfta_C_code(""));
+ }
+
+ ret.append(" )");
+ }
+ ret.append(" )");
+ return(ret);
+
+ case PRED_COMPARE:
+ ldt = pr->get_left_se()->get_data_type();
+ rdt = pr->get_right_se()->get_data_type();
+
+ ret.append("( ");
+ if(ldt->complex_comparison(rdt) ){
+// TODO can use get_hfta_equals_fcn if op is "=" ?
+ ret.append(ldt->get_hfta_comparison_fcn(rdt));
+ ret.append("(");
+ if(ldt->is_buffer_type() )
+ ret.append("&");
+ ret.append(generate_se_code_fm_aggr(pr->get_left_se(), gbvar, aggvar,schema) );
+ ret.append(", ");
+ if(rdt->is_buffer_type() )
+ ret.append("&");
+ ret.append(generate_se_code_fm_aggr(pr->get_right_se(), gbvar, aggvar,schema) );
+ ret.append(") ");
+ ret.append( generate_C_comparison_op(pr->get_op()));
+ ret.append("0");
+ }else{
+ ret.append(generate_se_code_fm_aggr(pr->get_left_se(), gbvar, aggvar,schema) );
+ ret.append( generate_C_comparison_op(pr->get_op()));
+ ret.append(generate_se_code_fm_aggr(pr->get_right_se(), gbvar, aggvar,schema) );
+ }
+ ret.append(" )");
+ return(ret);
+ case PRED_UNARY_OP:
+ ret.append("( ");
+ ret.append( generate_C_boolean_op(pr->get_op()) );
+ ret.append(generate_predicate_code_fm_aggr(pr->get_left_pr(), gbvar, aggvar,schema) );
+ ret.append(" )");
+ return(ret);
+ case PRED_BINARY_OP:
+ ret.append("( ");
+ ret.append(generate_predicate_code_fm_aggr(pr->get_left_pr(), gbvar, aggvar,schema) );
+ ret.append( generate_C_boolean_op(pr->get_op()) );
+ ret.append(generate_predicate_code_fm_aggr(pr->get_right_pr(), gbvar, aggvar,schema) );
+ ret.append(" )");
+ return(ret);
+ case PRED_FUNC:
+ ret += pr->get_op() + "( ";
+ op_list = pr->get_op_list();
+ for(o=0;o<op_list.size();++o){
+ if(o>0) ret += ", ";
+ if(op_list[o]->get_data_type()->is_buffer_type() && (! (op_list[o]->is_handle_ref()) ) )
+ ret.append("&");
+ ret += generate_se_code_fm_aggr(op_list[o], gbvar, aggvar, schema);
+ }
+ ret += " )";
+ return(ret);
+ default:
+ fprintf(stderr,"INTERNAL ERROR in generate_predicate_code, line %d, character %d, unknown predicate operator type %d\n",
+ pr->get_lineno(), pr->get_charno(), pr->get_operator_type() );
+ return("ERROR in generate_predicate_code");
+ }
+}
+
+
+// Aggregation code
+
+
+static string generate_equality_test(string &lhs_op, string &rhs_op, data_type *dt){
+ string ret;
+
+ if(dt->complex_comparison(dt) ){
+ ret.append(dt->get_hfta_equals_fcn(dt));
+ ret.append("(");
+ if(dt->is_buffer_type() )
+ ret.append("&");
+ ret.append(lhs_op);
+ ret.append(", ");
+ if(dt->is_buffer_type() )
+ ret.append("&");
+ ret.append(rhs_op );
+ ret.append(") == 0");
+ }else{
+ ret.append(lhs_op );
+ ret.append(" == ");
+ ret.append(rhs_op );
+ }
+
+ return(ret);
+}
+
+static string generate_lt_test(string &lhs_op, string &rhs_op, data_type *dt){
+ string ret;
+
+ if(dt->complex_comparison(dt) ){
+ ret.append(dt->get_hfta_comparison_fcn(dt));
+ ret.append("(");
+ if(dt->is_buffer_type() )
+ ret.append("&");
+ ret.append(lhs_op);
+ ret.append(", ");
+ if(dt->is_buffer_type() )
+ ret.append("&");
+ ret.append(rhs_op );
+ ret.append(") == 1");
+ }else{
+ ret.append(lhs_op );
+ ret.append(" < ");
+ ret.append(rhs_op );
+ }
+
+ return(ret);
+}
+
+//static string generate_comparison(string &lhs_op, string &rhs_op, data_type *dt){
+// string ret;
+//
+// if(dt->complex_comparison(dt) ){
+// ret.append(dt->get_hfta_equals_fcn(dt));
+// ret.append("(");
+// if(dt->is_buffer_type() )
+// ret.append("&");
+// ret.append(lhs_op);
+// ret.append(", ");
+// if(dt->is_buffer_type() )
+// ret.append("&");
+// ret.append(rhs_op );
+// ret.append(") == 0");
+// }else{
+// ret.append(lhs_op );
+// ret.append(" == ");
+// ret.append(rhs_op );
+// }
+//
+// return(ret);
+//}
+
+
+// Here I assume that only MIN and MAX aggregates can be computed
+// over BUFFER data types.
+
+static string generate_aggr_update(string var, aggregate_table *atbl,int aidx, table_list *schema){
+ string retval = "\t\t";
+ string op = atbl->get_op(aidx);
+
+// Is it a UDAF
+ if(! atbl->is_builtin(aidx)) {
+ int o;
+ retval += op+"_HFTA_AGGR_UPDATE_(";
+ if(atbl->get_storage_type(aidx)->get_type() != fstring_t) retval+="&";
+ retval+="("+var+")";
+ vector<scalarexp_t *> opl = atbl->get_operand_list(aidx);
+ for(o=0;o<opl.size();++o){{
+ retval += ",";
+ if(opl[o]->get_data_type()->is_buffer_type() && (! (opl[o]->is_handle_ref()) ) )
+ retval.append("&");
+ retval += generate_se_code(opl[o], schema);
+ }
+ }
+ retval += ");\n";
+
+ return retval;
+ }
+
+
+// builtin processing
+ data_type *dt = atbl->get_data_type(aidx);
+
+ if(op == "COUNT"){
+ retval.append(var);
+ retval.append("++;\n");
+ return(retval);
+ }
+ if(op == "SUM"){
+ retval.append(var);
+ retval.append(" += ");
+ retval.append(generate_se_code(atbl->get_aggr_se(aidx), schema) );
+ retval.append(";\n");
+ return(retval);
+ }
+ if(op == "MIN"){
+ sprintf(tmpstr,"aggr_tmp_%d",aidx);
+ retval += dt->make_host_cvar(tmpstr);
+ retval += " = ";
+ retval += generate_se_code(atbl->get_aggr_se(aidx), schema )+";\n";
+ if(dt->complex_comparison(dt)){
+ if(dt->is_buffer_type())
+ sprintf(tmpstr,"\t\tif(%s(&aggr_tmp_%d,&(%s)) < 0)\n",dt->get_hfta_comparison_fcn(dt).c_str(), aidx, var.c_str());
+ else
+ sprintf(tmpstr,"\t\tif(%s(aggr_tmp_%d,%s) < 0)\n",dt->get_hfta_comparison_fcn(dt).c_str(), aidx, var.c_str());
+ }else{
+ sprintf(tmpstr,"\t\tif(aggr_tmp_%d < %s)\n",aidx,var.c_str());
+ }
+ retval.append(tmpstr);
+ if(dt->is_buffer_type()){
+ sprintf(tmpstr,"\t\t\t%s(&(%s),&aggr_tmp_%d);\n",dt->get_hfta_buffer_replace().c_str(),var.c_str(),aidx);
+ }else{
+ sprintf(tmpstr,"\t\t\t%s = aggr_tmp_%d;\n",var.c_str(),aidx);
+ }
+ retval.append(tmpstr);
+
+ return(retval);
+ }
+ if(op == "MAX"){
+ sprintf(tmpstr,"aggr_tmp_%d",aidx);
+ retval+=dt->make_host_cvar(tmpstr);
+ retval+=" = ";
+ retval+=generate_se_code(atbl->get_aggr_se(aidx), schema )+";\n";
+ if(dt->complex_comparison(dt)){
+ if(dt->is_buffer_type())
+ sprintf(tmpstr,"\t\tif(%s(&aggr_tmp_%d,&(%s)) > 0)\n",dt->get_hfta_comparison_fcn(dt).c_str(), aidx, var.c_str());
+ else
+ sprintf(tmpstr,"\t\tif(%s(aggr_tmp_%d,%s) > 0)\n",dt->get_hfta_comparison_fcn(dt).c_str(), aidx, var.c_str());
+ }else{
+ sprintf(tmpstr,"\t\tif(aggr_tmp_%d > %s)\n",aidx,var.c_str());
+ }
+ retval.append(tmpstr);
+ if(dt->is_buffer_type()){
+ sprintf(tmpstr,"\t\t\t%s(&(%s),&aggr_tmp_%d);\n",dt->get_hfta_buffer_replace().c_str(),var.c_str(),aidx);
+ }else{
+ sprintf(tmpstr,"\t\t\t%s = aggr_tmp_%d;\n",var.c_str(),aidx);
+ }
+ retval.append(tmpstr);
+
+ return(retval);
+
+ }
+ if(op == "AND_AGGR"){
+ retval.append(var);
+ retval.append(" &= ");
+ retval.append(generate_se_code(atbl->get_aggr_se(aidx), schema) );
+ retval.append(";\n");
+ return(retval);
+ }
+ if(op == "OR_AGGR"){
+ retval.append(var);
+ retval.append(" |= ");
+ retval.append(generate_se_code(atbl->get_aggr_se(aidx), schema) );
+ retval.append(";\n");
+ return(retval);
+ }
+ if(op == "XOR_AGGR"){
+ retval.append(var);
+ retval.append(" ^= ");
+ retval.append(generate_se_code(atbl->get_aggr_se(aidx), schema) );
+ retval.append(";\n");
+ return(retval);
+ }
+ if(op=="AVG"){
+ retval += var+"_sum += "+generate_se_code(atbl->get_aggr_se(aidx), schema)+";\n";
+ retval += "\t\t"+var+"_cnt += 1;\n";
+ retval += "\t\t"+var+" = "+var+"_sum / "+var+"_cnt;\n";
+ return retval;
+ }
+
+ fprintf(stderr,"INTERNAL ERROR : aggregate %s not recognized in query_plan::generate_aggr_update.\n",op.c_str());
+ exit(1);
+ return(retval);
+
+}
+
+
+// superaggr minus.
+
+static string generate_superaggr_minus(string var, string supervar, aggregate_table *atbl,int aidx, table_list *schema){
+ string retval = "\t\t";
+ string op = atbl->get_op(aidx);
+
+// Is it a UDAF
+ if(! atbl->is_builtin(aidx)) {
+ int o;
+ retval += op+"_HFTA_AGGR_MINUS_(";
+ if(atbl->get_storage_type(aidx)->get_type() != fstring_t) retval+="&";
+ retval+="("+supervar+"),";
+ if(atbl->get_storage_type(aidx)->get_type() != fstring_t) retval+="&";
+ retval+="("+var+");\n";
+
+ return retval;
+ }
+
+
+ if(op == "COUNT" || op == "SUM"){
+ retval += supervar + "-=" +var + ";\n";
+ return(retval);
+ }
+
+ if(op == "XOR_AGGR"){
+ retval += supervar + "^=" +var + ";\n";
+ return(retval);
+ }
+
+ if(op=="MIN" || op == "MAX")
+ return "";
+
+ fprintf(stderr,"INTERNAL ERROR : aggregate %s not recognized in generate_superaggr_minus.\n",op.c_str());
+ exit(1);
+ return(retval);
+
+}
+
+
+
+
+static string generate_aggr_init(string var, aggregate_table *atbl,int aidx, table_list *schema){
+ string retval;
+ string op = atbl->get_op(aidx);
+
+// UDAF processing
+ if(! atbl->is_builtin(aidx)){
+// initialize
+ retval += "\t"+atbl->get_op(aidx)+"_HFTA_AGGR_INIT_(";
+ if(atbl->get_storage_type(aidx)->get_type() != fstring_t) retval+="&";
+ retval+="("+var+"));\n";
+// Add 1st tupl
+ retval += "\t"+atbl->get_op(aidx)+"_HFTA_AGGR_UPDATE_(";
+ if(atbl->get_storage_type(aidx)->get_type() != fstring_t) retval+="&";
+ retval+="("+var+")";
+ vector<scalarexp_t *> opl = atbl->get_operand_list(aidx);
+ int o;
+ for(o=0;o<opl.size();++o){
+ retval += ",";
+ if(opl[o]->get_data_type()->is_buffer_type() && (! (opl[o]->is_handle_ref()) ) )
+ retval.append("&");
+ retval += generate_se_code(opl[o],schema);
+ }
+ retval += ");\n";
+ return(retval);
+ }
+
+// builtin aggregate processing
+ data_type *dt = atbl->get_data_type(aidx);
+
+ if(op == "COUNT"){
+ retval = var;
+ retval.append(" = 1;\n");
+ return(retval);
+ }
+
+ if(op == "SUM" || op == "MIN" || op == "MAX" || op == "AND_AGGR" ||
+ op=="AVG" || op == "OR_AGGR" || op == "XOR_AGGR"){
+ if(dt->is_buffer_type()){
+ sprintf(tmpstr,"\t\taggr_tmp_%d = %s;\n",aidx,generate_se_code(atbl->get_aggr_se(aidx), schema ).c_str() );
+ retval.append(tmpstr);
+ sprintf(tmpstr,"\t\t%s(&(%s),&aggr_tmp_%d);\n",dt->get_hfta_buffer_assign_copy().c_str(),var.c_str(),aidx);
+ retval.append(tmpstr);
+ }else{
+ if(op=="AVG"){
+ retval += var+"_sum = "+generate_se_code(atbl->get_aggr_se(aidx), schema)+";\n";
+ retval += "\t"+var+"_cnt = 1;\n";
+ retval += "\t"+var+" = "+var+"_sum;\n";
+ }else{
+ retval = var;
+ retval += " = ";
+ retval.append(generate_se_code(atbl->get_aggr_se(aidx), schema));
+ retval.append(";\n");
+ }
+ }
+ return(retval);
+ }
+
+ fprintf(stderr,"INTERNAL ERROR : aggregate %s not recognized in query_plan::generate_aggr_init.\n",op.c_str());
+ exit(1);
+ return(retval);
+
+}
+
+
+
+static string generate_aggr_reinitialize(string var, aggregate_table *atbl,int aidx, table_list *schema){
+ string retval;
+ string op = atbl->get_op(aidx);
+
+// UDAF processing
+ if(! atbl->is_builtin(aidx)){
+// initialize
+ retval += "\t"+atbl->get_op(aidx);
+ if(atbl->is_running_aggr(aidx)){
+ retval += "_HFTA_AGGR_REINIT_(";
+ }else{
+ retval += "_HFTA_AGGR_INIT_(";
+ }
+ if(atbl->get_storage_type(aidx)->get_type() != fstring_t) retval+="&";
+ retval+="("+var+"));\n";
+ return(retval);
+ }
+
+// builtin aggregate processing
+ data_type *dt = atbl->get_data_type(aidx);
+
+ if(op == "COUNT"){
+ retval = var;
+ retval.append(" = 0;\n");
+ return(retval);
+ }
+
+ if(op == "SUM" || op == "AND_AGGR" ||
+ op == "OR_AGGR" || op == "XOR_AGGR"){
+ if(dt->is_buffer_type()){
+ return("ERROR, cannot yet handle reinitialization of builtin aggregates over strings.");
+ }else{
+ retval = var;
+ retval += " = ";
+ literal_t l(dt->type_indicator());
+ retval.append(l.to_string());
+ retval.append(";\n");
+ }
+ return(retval);
+ }
+
+ if(op == "MIN"){
+ if(dt->is_buffer_type()){
+ return("ERROR, cannot yet handle reinitialization of builtin aggregates over strings.");
+ }else{
+ retval = var;
+ retval += " = ";
+ retval.append(dt->get_max_literal());
+ retval.append(";\n");
+ }
+ return(retval);
+ }
+
+ if(op == "MAX"){
+ if(dt->is_buffer_type()){
+ return("ERROR, cannot yet handle reinitialization of builtin aggregates over strings.");
+ }else{
+ retval = var;
+ retval += " = ";
+ retval.append(dt->get_min_literal());
+ retval.append(";\n");
+ }
+ return(retval);
+ }
+
+ fprintf(stderr,"INTERNAL ERROR : aggregate %s not recognized in generate_aggr_reinitialize.\n",op.c_str());
+ exit(1);
+ return(retval);
+
+}
+
+
+// Generate parameter holding vars from a param table.
+static string generate_param_vars(param_table *param_tbl){
+ string ret;
+ int p;
+ vector<string> param_vec = param_tbl->get_param_names();
+ for(p=0;p<param_vec.size();p++){
+ data_type *dt = param_tbl->get_data_type(param_vec[p]);
+ sprintf(tmpstr,"param_%s;\n", param_vec[p].c_str());
+ ret += "\t"+dt->make_host_cvar(tmpstr)+";\n";
+ if(param_tbl->handle_access(param_vec[p])){
+ ret += "\tstruct search_handle *param_handle_"+param_vec[p]+";\n";
+ }
+ }
+ return(ret);
+}
+
+// Parameter manipulation routines
+static string generate_load_param_block(string functor_name,
+ param_table *param_tbl,
+ vector<handle_param_tbl_entry *> param_handle_table
+ ){
+ int p;
+ vector<string> param_names = param_tbl->get_param_names();
+
+ string ret = "int load_params_"+functor_name+"(gs_int32_t sz, void *value){\n";
+ ret.append("\tint pos=0;\n");
+ ret.append("\tint data_pos;\n");
+
+ for(p=0;p<param_names.size();p++){
+ data_type *dt = param_tbl->get_data_type(param_names[p]);
+ if(dt->is_buffer_type()){
+ sprintf(tmpstr,"tmp_var_%s;\n", param_names[p].c_str());
+ ret += "\t"+dt->make_host_cvar(tmpstr)+";\n";
+ }
+ }
+
+
+// Verify that the block is of minimum size
+ if(param_names.size() > 0){
+ ret += "//\tVerify that the value block is large enough */\n";
+ ret.append("\n\tdata_pos = ");
+ for(p=0;p<param_names.size();p++){
+ if(p>0) ret.append(" + ");
+ data_type *dt = param_tbl->get_data_type(param_names[p]);
+ ret.append("sizeof( ");
+ ret.append( dt->get_host_cvar_type() );
+ ret.append(" )");
+ }
+ ret.append(";\n");
+ ret.append("\tif(data_pos > sz) return 1;\n\n");
+ }
+
+///////////////////////
+/// Verify that all strings can be unpacked.
+
+ ret += "//\tVerify that the strings can be unpacked */\n";
+ for(p=0;p<param_names.size();p++){
+ data_type *dt = param_tbl->get_data_type(param_names[p]);
+ if(dt->is_buffer_type()){
+ sprintf(tmpstr,"\ttmp_var_%s = *( (%s *)((gs_sp_t )value+pos) );\n",param_names[p].c_str(), dt->get_host_cvar_type().c_str() );
+ ret.append(tmpstr);
+ switch( dt->get_type() ){
+ case v_str_t:
+// ret += "\ttmp_var_"+param_names[p]+".offset = ntohl( tmp_var_"+param_names[p]+".offset );\n"; // ntoh conversion
+// ret += "\ttmp_var_"+param_names[p]+".length = ntohl( tmp_var_"+param_names[p]+".length );\n"; // ntoh conversion
+ 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() );
+ ret.append(tmpstr);
+ 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() );
+ ret.append(tmpstr);
+ break;
+ default:
+ 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() );
+ exit(1);
+ break;
+ }
+ }
+ ret += "\tpos += sizeof( "+dt->get_host_cvar_type()+" );\n";
+ }
+
+
+/////////////////////////
+
+ ret += "/*\tThe block is OK, do the unpacking. */\n";
+ ret += "\tpos = 0;\n";
+
+ for(p=0;p<param_names.size();p++){
+ data_type *dt = param_tbl->get_data_type(param_names[p]);
+ if(dt->is_buffer_type()){
+ sprintf(tmpstr,"\t%s(¶m_%s, &tmp_var_%s);\n", dt->get_hfta_buffer_assign_copy().c_str(),param_names[p].c_str(),param_names[p].c_str() );
+ ret.append(tmpstr);
+ }else{
+// if(dt->needs_hn_translation()){
+// sprintf(tmpstr,"\tparam_%s = %s( *( (%s *)( (gs_sp_t )value+pos) ) );\n",
+// param_names[p].c_str(), dt->ntoh_translation().c_str(), dt->get_host_cvar_type().c_str() );
+// }else{
+ sprintf(tmpstr,"\tparam_%s = *( (%s *)( (gs_sp_t )value+pos) );\n",
+ param_names[p].c_str(), dt->get_host_cvar_type().c_str() );
+// }
+ ret.append(tmpstr);
+ }
+ ret += "\tpos += sizeof( "+dt->get_host_cvar_type()+" );\n";
+ }
+
+// TODO: I think this method of handle registration is obsolete
+// and should be deleted.
+// some examination reveals that handle_access is always false.
+ for(p=0;p<param_names.size();p++){
+ if(param_tbl->handle_access(param_names[p]) ){
+ data_type *pdt = param_tbl->get_data_type(param_names[p]);
+// create the new.
+ ret += "\tt->param_handle_"+param_names[p]+" = " +
+ pdt->handle_registration_name() +
+ "((struct FTA *)t, &(t->param_"+param_names[p]+"));\n";
+ }
+ }
+// Register the pass-by-handle parameters
+
+ ret += "/* register the pass-by-handle parameters */\n";
+
+ int ph;
+ for(ph=0;ph<param_handle_table.size();++ph){
+ data_type pdt(param_handle_table[ph]->type_name);
+ switch(param_handle_table[ph]->val_type){
+ case cplx_lit_e:
+ break;
+ case litval_e:
+ break;
+ case param_e:
+ sprintf(tmpstr,"\thandle_param_%d = %s(",ph,param_handle_table[ph]->lfta_registration_fcn().c_str());
+ ret += tmpstr;
+ if(pdt.is_buffer_type()) ret += "&(";
+ ret += "param_"+param_handle_table[ph]->param_name;
+ if(pdt.is_buffer_type()) ret += ")";
+ ret += ");\n";
+ break;
+ default:
+ fprintf(stderr, "INTERNAL ERROR unknown case found when processing pass-by-handle parameter table.\n");
+ exit(1);
+ }
+ }
+
+
+ ret += "\treturn(0);\n";
+ ret.append("}\n\n");
+
+ return(ret);
+
+}
+
+static string generate_delete_param_block(string functor_name,
+ param_table *param_tbl,
+ vector<handle_param_tbl_entry *> param_handle_table
+ ){
+
+ int p;
+ vector<string> param_names = param_tbl->get_param_names();
+
+ string ret = "void destroy_params_"+functor_name+"(){\n";
+
+ for(p=0;p<param_names.size();p++){
+ data_type *dt = param_tbl->get_data_type(param_names[p]);
+ if(dt->is_buffer_type()){
+ sprintf(tmpstr,"\t\t%s(¶m_%s);\n",dt->get_hfta_buffer_destroy().c_str(),param_names[p].c_str());
+ ret.append(tmpstr);
+ }
+ if(param_tbl->handle_access(param_names[p]) ){
+ ret += "\t\t" + dt->get_handle_destructor() +
+ "(t->param_handle_" + param_names[p] + ");\n";
+ }
+ }
+
+ ret += "//\t\tDeregister handles.\n";
+ int ph;
+ for(ph=0;ph<param_handle_table.size();++ph){
+ if(param_handle_table[ph]->val_type == param_e){
+ sprintf(tmpstr, "\t\t%s(handle_param_%d);\n",
+ param_handle_table[ph]->lfta_deregistration_fcn().c_str(),ph);
+ ret += tmpstr;
+ }
+ }
+
+ ret += "}\n\n";
+ return ret;
+}
+
+// ---------------------------------------------------------------------
+// functions for creating functor variables.
+
+static string generate_access_vars(col_id_set &cid_set, table_list *schema){
+ string ret;
+ col_id_set::iterator csi;
+
+ for(csi=cid_set.begin(); csi!=cid_set.end();++csi){
+ int schref = (*csi).schema_ref;
+ int tblref = (*csi).tblvar_ref;
+ string field = (*csi).field;
+ data_type dt(schema->get_type_name(schref,field));
+ sprintf(tmpstr,"unpack_var_%s_%d", field.c_str(), tblref);
+ ret+="\t"+dt.make_host_cvar(tmpstr)+";\n";
+ sprintf(tmpstr,"\tgs_int32_t unpack_offset_%s_%d;\n", field.c_str(), tblref);
+ ret.append(tmpstr);
+ }
+ return(ret);
+}
+
+static string generate_partial_fcn_vars(vector<scalarexp_t *> &partial_fcns,
+ vector<int> &ref_cnt, vector<bool> &is_partial, bool gen_fcn_cache){
+ string ret;
+ int p;
+
+
+ for(p=0;p<partial_fcns.size();++p){
+ if(!gen_fcn_cache || is_partial[p] || ref_cnt[p]>1){
+ sprintf(tmpstr,"partial_fcn_result_%d", p);
+ ret+="\t"+partial_fcns[p]->get_data_type()->make_host_cvar(tmpstr)+";\n";
+ if(gen_fcn_cache && ref_cnt[p]>1){
+ ret+="\tint fcn_ref_cnt_"+int_to_string(p)+";\n";
+ }
+ }
+ }
+ return(ret);
+}
+
+
+static string generate_complex_lit_vars(cplx_lit_table *complex_literals){
+ string ret;
+ int cl;
+ for(cl=0;cl<complex_literals->size();cl++){
+ literal_t *l = complex_literals->get_literal(cl);
+ data_type *dtl = new data_type( l->get_type() );
+ sprintf(tmpstr,"complex_literal_%d",cl);
+ ret += "\t"+dtl->make_host_cvar(tmpstr)+";\n";
+ if(complex_literals->is_handle_ref(cl)){
+ sprintf(tmpstr,"\tstruct search_handle *lit_handle_%d;\n",cl);
+ ret.append(tmpstr);
+ }
+ }
+ return(ret);
+}
+
+
+static string generate_pass_by_handle_vars(
+ vector<handle_param_tbl_entry *> ¶m_handle_table){
+ string ret;
+ int p;
+
+ for(p=0;p<param_handle_table.size();++p){
+ sprintf(tmpstr,"\tgs_param_handle_t handle_param_%d;\n",p);
+ ret += tmpstr;
+ }
+
+ return(ret);
+}
+
+
+// ------------------------------------------------------------
+// functions for generating initialization code.
+
+static string gen_access_var_init(col_id_set &cid_set){
+ string ret;
+ col_id_set::iterator csi;
+
+ for(csi=cid_set.begin(); csi!=cid_set.end();++csi){
+ int tblref = (*csi).tblvar_ref;
+ string field = (*csi).field;
+ 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());
+ ret.append(tmpstr);
+ }
+ return ret;
+}
+
+
+static string gen_complex_lit_init(cplx_lit_table *complex_literals){
+ string ret;
+
+ int cl;
+ for(cl=0;cl<complex_literals->size();cl++){
+ literal_t *l = complex_literals->get_literal(cl);
+// sprintf(tmpstr,"\tcomplex_literal_%d = ",cl);
+// ret += tmpstr + l->to_hfta_C_code() + ";\n";
+ sprintf(tmpstr,"&(complex_literal_%d)",cl);
+ ret += "\t" + l->to_hfta_C_code(tmpstr) + ";\n";
+// I think that the code below is obsolete
+// TODO: it is obsolete. add_cpx_lit is always
+// called with the handle indicator being false.
+// This entire structure should be cleansed.
+ if(complex_literals->is_handle_ref(cl)){
+ data_type *dt = new data_type( l->get_type() );
+ sprintf(tmpstr,"\tlit_handle_%d = %s(&(f->complex_literal_%d));\n",
+ cl, dt->hfta_handle_registration_name().c_str(), cl);
+ ret += tmpstr;
+ delete dt;
+ }
+ }
+ return(ret);
+}
+
+
+static string gen_partial_fcn_init(vector<scalarexp_t *> &partial_fcns){
+ string ret;
+
+ int p;
+ for(p=0;p<partial_fcns.size();++p){
+ data_type *pdt =partial_fcns[p]->get_data_type();
+ literal_t empty_lit(pdt->type_indicator());
+ if(pdt->is_buffer_type()){
+// sprintf(tmpstr,"\tpartial_fcn_result_%d = %s;\n",
+// p, empty_lit.to_hfta_C_code().c_str());
+ sprintf(tmpstr,"&(partial_fcn_result_%d)",p);
+ ret += "\t"+empty_lit.to_hfta_C_code(tmpstr)+";\n";
+ }
+ }
+ return(ret);
+}
+
+static string gen_pass_by_handle_init(
+ vector<handle_param_tbl_entry *> ¶m_handle_table){
+ string ret;
+
+ int ph;
+ for(ph=0;ph<param_handle_table.size();++ph){
+ data_type pdt(param_handle_table[ph]->type_name);
+ sprintf(tmpstr,"\thandle_param_%d = %s(",ph,param_handle_table[ph]->lfta_registration_fcn().c_str());
+ switch(param_handle_table[ph]->val_type){
+ case cplx_lit_e:
+ ret += tmpstr;
+ if(pdt.is_buffer_type()) ret += "&(";
+ sprintf(tmpstr,"complex_literal_%d",param_handle_table[ph]->complex_literal_idx);
+ ret += tmpstr;
+ if(pdt.is_buffer_type()) ret += ")";
+ ret += ");\n";
+ break;
+ case litval_e:
+ ret += tmpstr;
+ ret += param_handle_table[ph]->litval->to_hfta_C_code("") + ");\n";
+// ret += ");\n";
+ break;
+ case param_e:
+// query parameter handles are regstered/deregistered in the
+// load_params function.
+// ret += "t->param_"+param_handle_table[ph]->param_name;
+ break;
+ default:
+ fprintf(stderr, "INTERNAL ERROR unknown case found when processing pass-by-handle parameter table.\n");
+ exit(1);
+ }
+ }
+ return(ret);
+}
+
+//------------------------------------------------------------
+// functions for destructor and deregistration code
+
+static string gen_complex_lit_dtr(cplx_lit_table *complex_literals){
+ string ret;
+
+ int cl;
+ for(cl=0;cl<complex_literals->size();cl++){
+ literal_t *l = complex_literals->get_literal(cl);
+ data_type ldt( l->get_type() );
+ if(ldt.is_buffer_type()){
+ sprintf(tmpstr,"\t\t%s(&complex_literal_%d);\n",
+ ldt.get_hfta_buffer_destroy().c_str(), cl );
+ ret += tmpstr;
+ }
+ }
+ return(ret);
+}
+
+
+static string gen_pass_by_handle_dtr(
+ vector<handle_param_tbl_entry *> ¶m_handle_table){
+ string ret;
+
+ int ph;
+ for(ph=0;ph<param_handle_table.size();++ph){
+ sprintf(tmpstr, "\t\t%s(handle_param_%d);\n",
+ param_handle_table[ph]->lfta_deregistration_fcn().c_str(),ph);
+ ret += tmpstr;
+ }
+ return(ret);
+}
+
+// Destroy all previous results
+static string gen_partial_fcn_dtr(vector<scalarexp_t *> &partial_fcns){
+ string ret;
+
+ int p;
+ for(p=0;p<partial_fcns.size();++p){
+ data_type *pdt =partial_fcns[p]->get_data_type();
+ if(pdt->is_buffer_type()){
+ sprintf(tmpstr,"\t\t%s(&partial_fcn_result_%d);\n",
+ pdt->get_hfta_buffer_destroy().c_str(), p );
+ ret += tmpstr;
+ }
+ }
+ return(ret);
+}
+
+// Destroy previsou results of fcns in pfcn_set
+static string gen_partial_fcn_dtr(vector<scalarexp_t *> &partial_fcns, set<int> &pfcn_set){
+ string ret;
+ set<int>::iterator si;
+
+ for(si=pfcn_set.begin(); si!=pfcn_set.end(); ++si){
+ data_type *pdt =partial_fcns[(*si)]->get_data_type();
+ if(pdt->is_buffer_type()){
+ sprintf(tmpstr,"\t\t%s(&partial_fcn_result_%d);\n",
+ pdt->get_hfta_buffer_destroy().c_str(), (*si) );
+ ret += tmpstr;
+ }
+ }
+ return(ret);
+}
+
+
+//-------------------------------------------------------------------------
+// Functions related to se generation bookkeeping.
+
+static void get_new_pred_cids(predicate_t *pr, col_id_set &found_cids,
+ col_id_set &new_cids, gb_table *gtbl){
+ col_id_set this_pred_cids;
+ col_id_set::iterator csi;
+
+// get colrefs in predicate not already found.
+ gather_pr_col_ids(pr,this_pred_cids,gtbl);
+ set_difference(this_pred_cids.begin(), this_pred_cids.end(),
+ found_cids.begin(), found_cids.end(),
+ inserter(new_cids,new_cids.begin()) );
+
+// We've found these cids, so update found_cids
+ for(csi=new_cids.begin(); csi!=new_cids.end(); ++csi)
+ found_cids.insert((*csi));
+
+}
+
+// after the call, new_cids will have the colrefs in se but not found_cids.
+// update found_cids with the new cids.
+static void get_new_se_cids(scalarexp_t *se, col_id_set &found_cids,
+ col_id_set &new_cids, gb_table *gtbl){
+ col_id_set this_se_cids;
+ col_id_set::iterator csi;
+
+// get colrefs in se not already found.
+ gather_se_col_ids(se,this_se_cids,gtbl);
+ set_difference(this_se_cids.begin(), this_se_cids.end(),
+ found_cids.begin(), found_cids.end(),
+ inserter(new_cids,new_cids.begin()) );
+
+// We've found these cids, so update found_cids
+ for(csi=new_cids.begin(); csi!=new_cids.end(); ++csi)
+ found_cids.insert((*csi));
+
+}
+
+static string gen_unpack_cids(table_list *schema, col_id_set &new_cids, string on_problem, vector<bool> &needs_xform){
+ string ret;
+ col_id_set::iterator csi;
+
+ for(csi=new_cids.begin(); csi!=new_cids.end(); ++csi){
+ int schref = (*csi).schema_ref;
+ int tblref = (*csi).tblvar_ref;
+ string field = (*csi).field;
+ data_type dt(schema->get_type_name(schref,field));
+ string unpack_fcn;
+ if(needs_xform[tblref]){
+ unpack_fcn = dt.get_hfta_unpack_fcn();
+ }else{
+ unpack_fcn = dt.get_hfta_unpack_fcn_noxf();
+ }
+ if(dt.is_buffer_type()){
+ sprintf(tmpstr,"\tunpack_var_%s_%d = %s(tup%d.data, tup%d.tuple_size, unpack_offset_%s_%d, &problem); // unpack_cid\n",field.c_str(), tblref, unpack_fcn.c_str(), tblref, tblref, field.c_str(), tblref);
+ }else{
+ sprintf(tmpstr,"\tunpack_var_%s_%d = %s_nocheck(tup%d.data, unpack_offset_%s_%d); // unpack_cid\n",field.c_str(), tblref, unpack_fcn.c_str(), tblref, field.c_str(), tblref);
+ }
+ ret += tmpstr;
+ if(dt.is_buffer_type()){
+ ret += "\tif(problem) return "+on_problem+" ;\n";
+ }
+ }
+ return(ret);
+}
+
+// generates the declaration of all the variables related to
+// temp tuples generation
+static string gen_decl_temp_vars(){
+ string ret;
+
+ ret += "\t// variables related to temp tuple generation\n";
+ ret += "\tbool temp_tuple_received;\n";
+
+ return(ret);
+}
+
+// generates initialization code for variables related to temp tuple processing
+static string gen_init_temp_vars(table_list *schema, vector<select_element *>& select_list, gb_table *gtbl){
+ string ret;
+ col_id_set::iterator csi;
+ int s;
+
+// Initialize internal state
+ ret += "\ttemp_tuple_received = false;\n";
+
+ col_id_set temp_cids; // colrefs unpacked thus far.
+
+ for(s=0;s<select_list.size();s++){
+ if (select_list[s]->se->get_data_type()->is_temporal()) {
+// Find the set of attributes accessed in this SE
+ col_id_set new_cids;
+ get_new_se_cids(select_list[s]->se,temp_cids, new_cids, gtbl);
+
+ // init these vars
+ for(csi=new_cids.begin(); csi!=new_cids.end(); ++csi){
+ int schref = (*csi).schema_ref;
+ int tblref = (*csi).tblvar_ref;
+ string field = (*csi).field;
+ data_type dt(schema->get_type_name(schref,field), schema->get_modifier_list(schref,field));
+
+ sprintf(tmpstr,"\t unpack_var_%s_%d = %s;\n", field.c_str(), tblref,
+ dt.is_increasing() ? dt.get_min_literal().c_str() : dt.get_max_literal().c_str());
+ ret += tmpstr;
+ }
+ }
+ }
+ return(ret);
+}
+
+
+
+// generates a check if tuple is temporal
+static string gen_temp_tuple_check(string node_name, int channel) {
+ string ret;
+
+ char tmpstr[256];
+ sprintf(tmpstr, "tup%d", channel);
+ string tup_name = tmpstr;
+ sprintf(tmpstr, "schema_handle%d", channel);
+ string schema_handle_name = tmpstr;
+ string tuple_offset_name = "tuple_metadata_offset"+int_to_string(channel);
+
+// check if it is a temporary status tuple
+ ret += "\t// check if tuple is temp status tuple\n";
+// ret += "\tif (ftaschema_is_temporal_tuple(" + schema_handle_name + ", " + tup_name + ".data)) {\n";
+ ret += "\tif (ftaschema_is_temporal_tuple_offset(" + tuple_offset_name + ", " + tup_name + ".data)) {\n";
+ ret += "\t\ttemp_tuple_received = true;\n";
+ ret += "\t}\n";
+ ret += "\telse\n\t\ttemp_tuple_received = false;\n\n";
+
+ return(ret);
+}
+
+// generates unpacking code for all temporal attributes referenced in select
+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) {
+ string ret;
+ int s;
+
+// Unpack all the temporal attributes references in select list
+// we need it to be able to generate temp status tuples
+ for(s=0;s<select_list.size();s++){
+ if (select_list[s]->se->get_data_type()->is_temporal()) {
+// Find the set of attributes accessed in this SE
+ col_id_set new_cids;
+ get_new_se_cids(select_list[s]->se,found_cids, new_cids, gtbl);
+// Unpack these values.
+ ret += gen_unpack_cids(schema, new_cids, "false", needs_xform);
+ }
+ }
+
+ return(ret);
+}
+
+
+// Generates temporal tuple generation code (except attribute packing)
+static string gen_init_temp_status_tuple(string node_name) {
+ string ret;
+
+ ret += "\t// create temp status tuple\n";
+ ret += "\tresult.tuple_size = sizeof("+generate_tuple_name( node_name)+") + sizeof(gs_uint8_t);\n";
+ ret += "\tresult.data = (gs_sp_t )malloc(result.tuple_size);\n";
+ ret += "\tresult.heap_resident = true;\n";
+ ret += "\t// Mark tuple as temporal\n";
+ ret += "\t*((gs_sp_t )result.data + sizeof("+generate_tuple_name( node_name)+")) = TEMPORAL_TUPLE;\n";
+
+ ret += "\t"+generate_tuple_name( node_name)+" *tuple = ("+
+ generate_tuple_name( node_name) +" *)(result.data);\n";
+
+ return(ret);
+}
+
+
+// Assume that all colrefs unpacked already ...
+static string gen_unpack_partial_fcn(table_list *schema,
+ vector<scalarexp_t *> &partial_fcns,set<int> &pfcn_refs,
+ string on_problem){
+ string ret;
+ set<int>::iterator si;
+
+// Since set<..> is a "Sorted Associative Container",
+// we can walk through it in sorted order by walking from
+// begin() to end(). (and the partial fcns must be
+// evaluated in this order).
+ for(si=pfcn_refs.begin();si!=pfcn_refs.end();++si){
+ ret += unpack_partial_fcn(partial_fcns[(*si)], (*si), schema);
+ ret += "\tif(retval) return "+on_problem+" ;\n";
+ }
+ return(ret);
+}
+
+// Assume that all colrefs unpacked already ...
+// this time with cached functions.
+static string gen_unpack_partial_fcn(table_list *schema,
+ vector<scalarexp_t *> &partial_fcns,set<int> &pfcn_refs,
+ vector<int> &fcn_ref_cnt, vector<bool> &is_partial_fcn,
+ string on_problem){
+ string ret;
+ set<int>::iterator si;
+
+// Since set<..> is a "Sorted Associative Container",
+// we can walk through it in sorted order by walking from
+// begin() to end(). (and the partial fcns must be
+// evaluated in this order).
+ for(si=pfcn_refs.begin();si!=pfcn_refs.end();++si){
+ if(fcn_ref_cnt[(*si)] > 1){
+ ret += "\tif(fcn_ref_cnt_"+int_to_string((*si))+"==0){\n";
+ }
+ if(is_partial_fcn[(*si)]){
+ ret += unpack_partial_fcn(partial_fcns[(*si)], (*si), schema);
+ ret += "\tif(retval) return "+on_problem+" ;\n";
+ }
+ if(fcn_ref_cnt[(*si)] > 1){
+ if(!is_partial_fcn[(*si)]){
+ ret += "\t\tpartial_fcn_result_"+int_to_string((*si))+"="+generate_cached_fcn(partial_fcns[(*si)],(*si),schema)+";\n";
+ }
+ ret += "\t\tfcn_ref_cnt_"+int_to_string((*si))+"=1;\n";
+ ret += "\t}\n";
+ }
+ }
+
+ return(ret);
+}
+
+
+// This version finds and unpacks new colrefs.
+// found_cids gets updated with the newly unpacked cids.
+static string gen_full_unpack_partial_fcn(table_list *schema,
+ vector<scalarexp_t *> &partial_fcns,set<int> &pfcn_refs,
+ col_id_set &found_cids, gb_table *gtbl, string on_problem,
+ vector<bool> &needs_xform){
+ string ret;
+ set<int>::iterator slsi;
+
+ for(slsi=pfcn_refs.begin(); slsi!=pfcn_refs.end(); ++slsi){
+// find all new fields ref'd by this partial fcn.
+ col_id_set new_cids;
+ get_new_se_cids(partial_fcns[(*slsi)], found_cids, new_cids, gtbl);
+// Unpack these values.
+ ret += gen_unpack_cids(schema, new_cids, on_problem, needs_xform);
+
+// Now evaluate the partial fcn.
+ ret += unpack_partial_fcn(partial_fcns[(*slsi)], (*slsi), schema);
+ ret += "\tif(retval) return "+on_problem+" ;\n";
+ }
+ return(ret);
+}
+
+// This version finds and unpacks new colrefs.
+// found_cids gets updated with the newly unpacked cids.
+// BUT : only for the partial functions.
+static string gen_full_unpack_partial_fcn(table_list *schema,
+ vector<scalarexp_t *> &partial_fcns,set<int> &pfcn_refs,
+ vector<int> &fcn_ref_cnt, vector<bool> &is_partial_fcn,
+ col_id_set &found_cids, gb_table *gtbl, string on_problem,
+ vector<bool> &needs_xform){
+ string ret;
+ set<int>::iterator slsi;
+
+ for(slsi=pfcn_refs.begin(); slsi!=pfcn_refs.end(); ++slsi){
+ if(is_partial_fcn[(*slsi)]){
+// find all new fields ref'd by this partial fcn.
+ col_id_set new_cids;
+ get_new_se_cids(partial_fcns[(*slsi)], found_cids, new_cids, gtbl);
+// Unpack these values.
+ ret += gen_unpack_cids(schema, new_cids, on_problem, needs_xform);
+
+// Now evaluate the partial fcn.
+ if(fcn_ref_cnt[(*slsi)] > 1){
+ ret += "\tif(fcn_ref_cnt_"+int_to_string((*slsi))+"==0){\n";
+ }
+ if(is_partial_fcn[(*slsi)]){
+ ret += unpack_partial_fcn(partial_fcns[(*slsi)], (*slsi), schema);
+ ret += "\tif(retval) return "+on_problem+" ;\n";
+ }
+ if(fcn_ref_cnt[(*slsi)] > 1){
+ ret += "\t\tfcn_ref_cnt_"+int_to_string((*slsi))+"=1;\n";
+ ret += "\t}\n";
+ }
+
+ }
+ }
+ return(ret);
+}
+
+static string gen_remaining_cached_fcns(table_list *schema,
+ vector<scalarexp_t *> &partial_fcns,set<int> &pfcn_refs,
+ vector<int> &fcn_ref_cnt, vector<bool> &is_partial_fcn){
+ string ret;
+ set<int>::iterator slsi;
+
+ for(slsi=pfcn_refs.begin(); slsi!=pfcn_refs.end(); ++slsi){
+ if(!is_partial_fcn[(*slsi)] && fcn_ref_cnt[(*slsi)] > 1){
+
+ if(fcn_ref_cnt[(*slsi)] > 1){
+ ret += "\tif(fcn_ref_cnt_"+int_to_string((*slsi))+"==0){\n";
+ ret += "\t\tpartial_fcn_result_"+int_to_string((*slsi))+"="+generate_cached_fcn(partial_fcns[(*slsi)],(*slsi),schema)+";\n";
+ ret += "\t\tfcn_ref_cnt_"+int_to_string((*slsi))+"=1;\n";
+ ret += "\t}\n";
+ }
+ }
+ }
+ return(ret);
+}
+
+
+// unpack the colrefs in cid_set not in found_cids
+static string gen_remaining_colrefs(table_list *schema,
+ col_id_set &cid_set, col_id_set &found_cids, string on_problem,
+ vector<bool> &needs_xform){
+ string ret;
+ col_id_set::iterator csi;
+
+ for(csi=cid_set.begin(); csi!=cid_set.end();csi++){
+ if(found_cids.count( (*csi) ) == 0){
+ int schref = (*csi).schema_ref;
+ int tblref = (*csi).tblvar_ref;
+ string field = (*csi).field;
+ data_type dt(schema->get_type_name(schref,field));
+ string unpack_fcn;
+ if(needs_xform[tblref]){
+ unpack_fcn = dt.get_hfta_unpack_fcn();
+ }else{
+ unpack_fcn = dt.get_hfta_unpack_fcn_noxf();
+ }
+ if(dt.is_buffer_type()){
+ 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);
+ }else{
+ 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);
+ }
+ ret += tmpstr;
+ if(dt.is_buffer_type()){
+ ret.append("\tif(problem) return "+on_problem+" ;\n");
+ }
+ }
+ }
+ return(ret);
+}
+
+static string gen_buffer_selvars(table_list *schema,
+ vector<select_element *> &select_list){
+ string ret;
+ int s;
+
+ for(s=0;s<select_list.size();s++){
+ scalarexp_t *se = select_list[s]->se;
+ data_type *sdt = se->get_data_type();
+ if(sdt->is_buffer_type() &&
+ !( (se->get_operator_type() == SE_COLREF) ||
+ (se->get_operator_type() == SE_FUNC && se->is_partial()) ||
+ (se->get_operator_type() == SE_FUNC && se->get_aggr_ref() >= 0))
+ ){
+ sprintf(tmpstr,"selvar_%d",s);
+ ret+="\t"+sdt->make_host_cvar(tmpstr)+" = ";
+ ret += generate_se_code(se,schema) +";\n";
+ }
+ }
+ return(ret);
+}
+
+static string gen_buffer_selvars_size(vector<select_element *> &select_list,table_list *schema){
+ string ret;
+ int s;
+
+ for(s=0;s<select_list.size();s++){
+ scalarexp_t *se = select_list[s]->se;
+ data_type *sdt = se->get_data_type();
+ if(sdt->is_buffer_type()){
+ if( !( (se->get_operator_type() == SE_COLREF) ||
+ (se->get_operator_type() == SE_FUNC && se->is_partial()) ||
+ (se->get_operator_type() == SE_FUNC && se->get_aggr_ref() >= 0))
+ ){
+ sprintf(tmpstr," + %s(&selvar_%d)", sdt->get_hfta_buffer_size().c_str(),s);
+ ret.append(tmpstr);
+ }else{
+ sprintf(tmpstr," + %s(&%s)", sdt->get_hfta_buffer_size().c_str(),
+ generate_se_code(se,schema).c_str());
+ ret.append(tmpstr);
+ }
+ }
+ }
+ return(ret);
+}
+
+static string gen_buffer_selvars_dtr(vector<select_element *> &select_list){
+ string ret;
+ int s;
+
+ for(s=0;s<select_list.size();s++){
+ scalarexp_t *se = select_list[s]->se;
+ data_type *sdt = se->get_data_type();
+ if(sdt->is_buffer_type() &&
+ !( (se->get_operator_type() == SE_COLREF) ||
+ (se->get_operator_type() == SE_AGGR_STAR) ||
+ (se->get_operator_type() == SE_AGGR_SE) ||
+ (se->get_operator_type() == SE_FUNC && se->is_partial()) ||
+ (se->get_operator_type() == SE_FUNC && se->get_aggr_ref() >= 0))
+ ){
+ sprintf(tmpstr,"\t\t%s(&selvar_%d);\n",
+ sdt->get_hfta_buffer_destroy().c_str(), s );
+ ret += tmpstr;
+ }
+ }
+ return(ret);
+}
+
+
+static string gen_pack_tuple(table_list *schema, vector<select_element *> &select_list, string node_name, bool temporal_only){
+ string ret;
+ int s;
+
+ ret += "\tint tuple_pos = sizeof("+generate_tuple_name(node_name)+") + sizeof(gs_uint8_t);\n";
+ for(s=0;s<select_list.size();s++){
+ scalarexp_t *se = select_list[s]->se;
+ data_type *sdt = se->get_data_type();
+
+ if(!temporal_only && sdt->is_buffer_type()){
+ if( !( (se->get_operator_type() == SE_COLREF) ||
+ (se->get_operator_type() == SE_FUNC && se->is_partial()))
+ ){
+ 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);
+ ret.append(tmpstr);
+ sprintf(tmpstr,"\ttuple_pos += %s(&selvar_%d);\n", sdt->get_hfta_buffer_size().c_str(), s);
+ ret.append(tmpstr);
+ }else{
+ 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());
+ ret.append(tmpstr);
+ sprintf(tmpstr,"\ttuple_pos += %s(&%s);\n", sdt->get_hfta_buffer_size().c_str(), generate_se_code(se,schema).c_str());
+ ret.append(tmpstr);
+ }
+ }else if (!temporal_only || sdt->is_temporal()) {
+ sprintf(tmpstr,"\ttuple->tuple_var%d = ",s);
+ ret.append(tmpstr);
+ ret.append(generate_se_code(se,schema) );
+ ret.append(";\n");
+ }
+ }
+ return(ret);
+}
+
+
+//-------------------------------------------------------------------------
+// functor generation methods
+//-------------------------------------------------------------------------
+
+/////////////////////////////////////////////////////////
+//// File Output Operator
+string output_file_qpn::generate_functor_name(){
+ return("output_file_functor_" + normalize_name(get_node_name()));
+}
+
+
+string output_file_qpn::generate_functor(table_list *schema, ext_fcn_list *Ext_fcns, vector<bool> &needs_xform){
+ string ret = "class " + this->generate_functor_name() + "{\n";
+
+// Find the temporal field
+ int temporal_field_idx;
+ data_type *tdt = NULL;
+ for(temporal_field_idx=0;temporal_field_idx<fields.size();temporal_field_idx++){
+ tdt = new data_type(fields[temporal_field_idx]->get_type(), fields[temporal_field_idx]->get_modifier_list());
+ if(tdt->is_temporal()){
+ break;
+ }else{
+ delete tdt;
+ }
+ }
+
+ if(temporal_field_idx == fields.size()){
+ fprintf(stderr,"ERROR, no temporal field for file output operator %s\n",node_name.c_str());
+ exit(1);
+ }
+
+ ret += "private:\n";
+
+ // var to save the schema handle
+ ret += "\tint schema_handle0;\n";
+// tuple metadata offset
+ ret += "\tint tuple_metadata_offset0;\n";
+ sprintf(tmpstr,"\tgs_int32_t unpack_offset_%s_0;\n", fields[temporal_field_idx]->get_name().c_str());
+ ret.append(tmpstr);
+
+// For unpacking the hashing fields, if any
+ int h;
+ for(h=0;h<hash_flds.size();++h){
+ sprintf(tmpstr,"unpack_var_%s", fields[hash_flds[h]]->get_name().c_str());
+ data_type *hdt = new data_type(fields[hash_flds[h]]->get_type(), fields[hash_flds[h]]->get_modifier_list());
+ ret+="\t"+hdt->make_host_cvar(tmpstr)+";\n";
+ if(hash_flds[h]!=temporal_field_idx){
+ sprintf(tmpstr,"\tgs_int32_t unpack_offset_%s_0;\n", fields[hash_flds[h]]->get_name().c_str());
+ ret.append(tmpstr);
+ }
+ }
+// Specail case for output file hashing
+ if(n_streams>1 && hash_flds.size()==0){
+ ret+="\tgs_uint32_t outfl_cnt;\n";
+ }
+
+ ret += "//\t\tRemember the last posted timestamp.\n";
+ ret+="\t"+tdt->make_host_cvar("timestamp")+";\n";
+ ret+="\t"+tdt->make_host_cvar("last_bucket")+";\n";
+ ret+="\t"+tdt->make_host_cvar("slack")+";\n";
+ ret += "\tbool first_execution;\n";
+ ret += "\tbool temp_tuple_received;\n";
+ ret += "\tbool is_eof;\n";
+
+ ret += "\tgs_int32_t bucketwidth;\n";
+
+ ret += "public:\n";
+//-------------------
+// The functor constructor
+// pass in a schema handle (e.g. for the 1st input stream),
+// use it to determine how to unpack the merge variable.
+// ASSUME that both streams have the same layout,
+// just duplicate it.
+
+// unpack vars
+ ret += "//\t\tFunctor constructor.\n";
+ ret += this->generate_functor_name()+"(int schema_hndl){\n";
+
+ ret += "\tschema_handle0 = schema_hndl;\n";
+// tuple metadata offset
+ ret += "\ttuple_metadata_offset0 = ftaschema_get_tuple_metadata_offset(schema_handle0);\n";
+
+ if(output_spec->bucketwidth == 0)
+ ret += "\tbucketwidth = 60;\n";
+ else
+ ret += "\tbucketwidth = "+int_to_string(output_spec->bucketwidth)+";\n";
+ ret += "//\t\tGet offsets for unpacking fields from input tuple.\n";
+
+ 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());
+ ret.append(tmpstr);
+// Hashing field unpacking, if any
+ for(h=0;h<hash_flds.size();++h){
+ if(hash_flds[h]!=temporal_field_idx){
+ 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());
+ ret.append(tmpstr);
+ }
+ }
+
+ ret+="\tfirst_execution = true;\n";
+
+// Initialize internal state
+ ret += "\ttemp_tuple_received = false;\n";
+
+ // Init last timestamp values to minimum value for their type
+ if (tdt->is_increasing()){
+ ret+="\ttimestamp = " + tdt->get_min_literal() + ";\n";
+ ret+="\tlast_bucket = " + tdt->get_min_literal() + ";\n";
+ }else{
+ ret+="\ttimestamp = " + tdt->get_max_literal() + ";\n";
+ ret+="\tlast_bucket = " + tdt->get_max_literal() + ";\n";
+ }
+
+
+ ret += "};\n\n";
+
+ ret += "//\t\tFunctor destructor.\n";
+ ret += "~"+this->generate_functor_name()+"(){\n";
+ ret+="};\n\n";
+
+
+ ret += "int load_params_"+this->generate_functor_name()+"(gs_int32_t sz, void *value){return 0;}\n";
+ ret += "void destroy_params_"+this->generate_functor_name()+"(){}\n";
+
+// Register new parameter block
+ ret += "int set_param_block(gs_int32_t sz, void* value){\n";
+ ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";
+ ret += "\treturn this->load_params_"+this->generate_functor_name()+
+ "(sz, value);\n";
+ ret += "};\n\n";
+
+ ret+="\nbool temp_status_received(const host_tuple& tup0)/* const*/ {\n";
+ ret+="\tgs_int32_t problem;\n";
+
+ ret += "\tvoid *tup_ptr = (void *)(&tup0);\n";
+ ret += "\tis_eof = ftaschema_is_eof_tuple(schema_handle0,tup_ptr);\n";
+
+ ret += gen_temp_tuple_check(this->node_name, 0);
+
+ 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);
+ ret += tmpstr;
+
+ for(h=0;h<hash_flds.size();++h){
+ data_type *hdt = new data_type(fields[hash_flds[h]]->get_type(), fields[hash_flds[h]]->get_modifier_list());
+ 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);
+ ret += tmpstr;
+ }
+ ret +=
+" return temp_tuple_received;\n"
+"}\n"
+"\n"
+;
+
+ ret +=
+"bool new_epoch(){\n"
+" if(first_execution || (last_bucket + 1) * bucketwidth <= timestamp){\n"
+" last_bucket = timestamp / bucketwidth;\n"
+" first_execution = false;\n"
+" return true;\n"
+" }\n"
+" return false;\n"
+"}\n"
+"\n"
+;
+
+ if(n_streams <= 1){
+ ret+=
+"inline gs_uint32_t output_hash(){return 0;}\n\n";
+ }else{
+ if(hash_flds.size()==0){
+ ret +=
+"gs_uint32_t output_hash(){\n"
+" outfl_cnt++;\n"
+" if(outfl_cnt >= "+int_to_string(n_streams)+")\n"
+" outfl_cnt = 0;\n"
+" return outfl_cnt;\n"
+"}\n"
+"\n"
+;
+ }else{
+ ret +=
+"gs_uint32_t output_hash(){\n"
+" gs_uint32_t ret = "
+;
+ for(h=0;h<hash_flds.size();++h){
+ if(h>0) ret += "^";
+ data_type *hdt = new data_type(fields[hash_flds[h]]->get_type(), fields[hash_flds[h]]->get_modifier_list());
+ if(hdt->use_hashfunc()){
+ sprintf(tmpstr,"%s(&(unpack_var_%s))",hdt->get_hfta_hashfunc().c_str(),fields[hash_flds[h]]->get_name().c_str());
+ }else{
+ sprintf(tmpstr,"unpack_var_%s",fields[hash_flds[h]]->get_name().c_str());
+ }
+ ret += tmpstr;
+ }
+ ret +=
+";\n"
+" return ret % "+int_to_string(hash_flds.size())+";\n"
+"}\n\n"
+;
+ }
+ }
+
+ret +=
+"gs_uint32_t num_file_streams(){\n"
+" return("+int_to_string(n_streams)+");\n"
+"}\n\n"
+;
+
+ ret +=
+"string get_filename_base(){\n"
+" char tmp_fname[500];\n";
+
+ string output_filename_base = hfta_query_name+filestream_id;
+/*
+ if(n_hfta_clones > 1){
+ output_filename_base += "_"+int_to_string(parallel_idx);
+ }
+*/
+
+
+
+ if(output_spec->output_directory == "")
+ ret +=
+" sprintf(tmp_fname,\""+output_filename_base+"_%lld\",(gs_int64_t)(last_bucket*bucketwidth));\n";
+ else ret +=
+" sprintf(tmp_fname,\""+output_spec->output_directory+"/"+output_filename_base+"_%lld\",(gs_int64_t)(last_bucket*bucketwidth));\n";
+ret +=
+" return (string)(tmp_fname);\n"
+"}\n"
+"\n";
+
+
+ret+=
+"bool do_compression(){\n";
+ if(do_gzip)
+ ret += " return true;\n";
+ else
+ ret += " return false;\n";
+ret+=
+"}\n"
+"\n"
+"bool is_eof_tuple(){\n"
+" return is_eof;\n"
+"}\n"
+"\n"
+"bool propagate_tuple(){\n"
+;
+if(eat_input)
+ ret+="\treturn false;\n";
+else
+ ret+="\treturn true;\n";
+ret+="}\n\n";
+// create a temp status tuple
+ ret += "int create_temp_status_tuple(host_tuple& result) {\n\n";
+
+ ret += gen_init_temp_status_tuple(this->hfta_query_name);
+
+ sprintf(tmpstr,"\ttuple->tuple_var%d = timestamp;\n",temporal_field_idx);
+
+
+ ret += tmpstr;
+
+ ret += "\treturn 0;\n";
+ ret += "}\n\n";
+ ret += "};\n\n";
+
+ return ret;
+}
+
+
+string output_file_qpn::generate_operator(int i, string params){
+ string optype = "file_output_operator";
+ switch(compression_type){
+ case regular:
+ optype = "file_output_operator";
+ break;
+ case gzip:
+ optype = "zfile_output_operator";
+ break;
+ case bzip:
+ optype = "bfile_output_operator";
+ break;
+ }
+
+ return(" "+optype+"<" +
+ generate_functor_name() +
+ "> *op"+int_to_string(i)+" = new "+optype+"<"+
+ generate_functor_name() +">("+params+", \"" + hfta_query_name + "\""
+ + "," + hfta_query_name + "_schema_definition);\n");
+}
+
+/////////////////////////////////////////////////////////
+////// SPX functor
+
+
+string spx_qpn::generate_functor_name(){
+ return("spx_functor_" + normalize_name(normalize_name(this->get_node_name())));
+}
+
+string spx_qpn::generate_functor(table_list *schema, ext_fcn_list *Ext_fcns, vector<bool> &needs_xform){
+// Initialize generate utility globals
+ segen_gb_tbl = NULL;
+
+ string ret = "class " + this->generate_functor_name() + "{\n";
+
+// Find variables referenced in this query node.
+
+ col_id_set cid_set;
+ col_id_set::iterator csi;
+
+ int w, s, p;
+ for(w=0;w<where.size();++w)
+ gather_pr_col_ids(where[w]->pr,cid_set,NULL);
+ for(s=0;s<select_list.size();s++){
+ gather_se_col_ids(select_list[s]->se,cid_set,NULL);
+ }
+
+
+// Private variables : store the state of the functor.
+// 1) variables for unpacked attributes
+// 2) offsets of the upacked attributes
+// 3) storage of partial functions
+// 4) storage of complex literals (i.e., require a constructor)
+
+ ret += "private:\n";
+ ret += "\tbool first_execution;\t// internal processing state \n";
+ ret += "\tint schema_handle0;\n";
+
+ // generate the declaration of all the variables related to
+ // temp tuples generation
+ ret += gen_decl_temp_vars();
+
+
+// unpacked attribute storage, offsets
+ ret += "//\t\tstorage and offsets of accessed fields.\n";
+ ret += generate_access_vars(cid_set,schema);
+// tuple metadata management
+ ret += "\tint tuple_metadata_offset0;\n";
+
+// Variables to store results of partial functions.
+// WARNING find_partial_functions modifies the SE
+// (it marks the partial function id).
+ ret += "//\t\tParital function result storage\n";
+ vector<scalarexp_t *> partial_fcns;
+ vector<int> fcn_ref_cnt;
+ vector<bool> is_partial_fcn;
+ for(s=0;s<select_list.size();s++){
+ find_partial_fcns(select_list[s]->se, &partial_fcns,&fcn_ref_cnt,&is_partial_fcn, Ext_fcns);
+ }
+ for(w=0;w<where.size();w++){
+ find_partial_fcns_pr(where[w]->pr, &partial_fcns, &fcn_ref_cnt,&is_partial_fcn,Ext_fcns);
+ }
+// Unmark non-partial expensive functions referenced only once.
+ for(p=0; p<partial_fcns.size();p++){
+ if(!is_partial_fcn[p] && fcn_ref_cnt[p] <= 1){
+ partial_fcns[p]->set_partial_ref(-1);
+ }
+ }
+ if(partial_fcns.size()>0){
+ ret += generate_partial_fcn_vars(partial_fcns,fcn_ref_cnt,is_partial_fcn,true);
+ }
+
+// Complex literals (i.e., they need constructors)
+ ret += "//\t\tComplex literal storage.\n";
+ cplx_lit_table *complex_literals = this->get_cplx_lit_tbl(Ext_fcns);
+ ret += generate_complex_lit_vars(complex_literals);
+
+// Pass-by-handle parameters
+ ret += "//\t\tPass-by-handle storage.\n";
+ vector<handle_param_tbl_entry *> param_handle_table = this->get_handle_param_tbl(Ext_fcns);
+ ret += generate_pass_by_handle_vars(param_handle_table);
+
+// Variables to hold parameters
+ ret += "//\tfor query parameters\n";
+ ret += generate_param_vars(param_tbl);
+
+
+// The publicly exposed functions
+
+ ret += "\npublic:\n";
+
+
+//-------------------
+// The functor constructor
+// pass in the schema handle.
+// 1) make assignments to the unpack offset variables
+// 2) initialize the complex literals
+// 3) Set the initial values of the temporal attributes
+// referenced in select clause (in case we need to emit
+// temporal tuple before receiving first tuple )
+
+ ret += "//\t\tFunctor constructor.\n";
+ ret += this->generate_functor_name()+"(int schema_handle0){\n";
+
+// save schema handle
+ ret += "this->schema_handle0 = schema_handle0;\n";
+
+// unpack vars
+ ret += "//\t\tGet offsets for unpacking fields from input tuple.\n";
+ ret += gen_access_var_init(cid_set);
+// tuple metadata
+ ret += "\ttuple_metadata_offset0 = ftaschema_get_tuple_metadata_offset(schema_handle0);\n";
+
+// complex literals
+ ret += "//\t\tInitialize complex literals.\n";
+ ret += gen_complex_lit_init(complex_literals);
+
+// Initialize partial function results so they can be safely GC'd
+ ret += gen_partial_fcn_init(partial_fcns);
+
+// Initialize non-query-parameter parameter handles
+ ret += gen_pass_by_handle_init(param_handle_table);
+
+// Init temporal attributes referenced in select list
+ ret += gen_init_temp_vars(schema, select_list, NULL);
+
+ ret += "};\n\n";
+
+
+//-------------------
+// Functor destructor
+ ret += "//\t\tFunctor destructor.\n";
+ ret += "~"+this->generate_functor_name()+"(){\n";
+
+// clean up buffer-type complex literals.
+ ret += gen_complex_lit_dtr(complex_literals);
+
+// Deregister the pass-by-handle parameters
+ ret += "/* register and de-register the pass-by-handle parameters */\n";
+ ret += gen_pass_by_handle_dtr(param_handle_table);
+
+// Reclaim buffer space for partial fucntion results
+ ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";
+ ret += gen_partial_fcn_dtr(partial_fcns);
+
+
+// Destroy the parameters, if any need to be destroyed
+ ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";
+
+ ret += "};\n\n";
+
+
+//-------------------
+// Parameter manipulation routines
+ ret += generate_load_param_block(this->generate_functor_name(),
+ this->param_tbl,param_handle_table );
+ ret += generate_delete_param_block(this->generate_functor_name(),
+ this->param_tbl,param_handle_table);
+
+
+//-------------------
+// Register new parameter block
+ ret += "int set_param_block(gs_int32_t sz, void* value){\n";
+ ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";
+ ret += "\treturn this->load_params_"+this->generate_functor_name()+
+ "(sz, value);\n";
+ ret += "};\n\n";
+
+
+//-------------------
+// The selection predicate.
+// Unpack variables for 1 cnf element
+// at a time, return false immediately if the
+// predicate fails.
+// optimization : evaluate the cheap cnf elements
+// first, the expensive ones last.
+
+ ret += "bool predicate(host_tuple &tup0){\n";
+ // Variables for execution of the function.
+ ret += "\tgs_int32_t problem = 0;\n"; // return unpack failure
+// Initialize cached function indicators.
+ for(p=0;p<partial_fcns.size();++p){
+ if(fcn_ref_cnt[p]>1){
+ ret+="\tfcn_ref_cnt_"+int_to_string(p)+"=0;\n";
+ }
+ }
+
+
+ ret += gen_temp_tuple_check(this->node_name, 0);
+
+ if(partial_fcns.size()>0){ // partial fcn access failure
+ ret += "\tgs_retval_t retval = 0;\n";
+ ret += "\n";
+ }
+
+// Reclaim buffer space for partial fucntion results
+ ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";
+ ret += gen_partial_fcn_dtr(partial_fcns);
+
+ col_id_set found_cids; // colrefs unpacked thus far.
+ ret += gen_unpack_temp_vars(schema, found_cids, select_list, NULL, needs_xform);
+
+// For temporal status tuple we don't need to do anything else
+ ret += "\tif (temp_tuple_received) return false;\n\n";
+
+
+ for(w=0;w<where.size();++w){
+ sprintf(tmpstr,"//\t\tPredicate clause %d.\n",w);
+ ret += tmpstr;
+// Find the set of variables accessed in this CNF elem,
+// but in no previous element.
+ col_id_set new_cids;
+ get_new_pred_cids(where[w]->pr,found_cids, new_cids, NULL);
+// Unpack these values.
+ ret += gen_unpack_cids(schema, new_cids, "false", needs_xform);
+// Find partial fcns ref'd in this cnf element
+ set<int> pfcn_refs;
+ collect_partial_fcns_pr(where[w]->pr, pfcn_refs);
+ ret += gen_unpack_partial_fcn(schema,partial_fcns,pfcn_refs,fcn_ref_cnt, is_partial_fcn, "false");
+
+ ret += "\tif( !("+generate_predicate_code(where[w]->pr,schema)+
+ +") ) return(false);\n";
+ }
+
+// The partial functions ref'd in the select list
+// must also be evaluated. If one returns false,
+// then implicitly the predicate is false.
+ set<int> sl_pfcns;
+ for(s=0;s<select_list.size();s++){
+ collect_partial_fcns(select_list[s]->se, sl_pfcns);
+ }
+ if(sl_pfcns.size() > 0)
+ ret += "//\t\tUnpack remaining partial fcns.\n";
+ ret += gen_full_unpack_partial_fcn(schema, partial_fcns, sl_pfcns,
+ fcn_ref_cnt, is_partial_fcn,
+ found_cids, NULL, "false", needs_xform);
+
+// Unpack remaining fields
+ ret += "//\t\tunpack any remaining fields from the input tuple.\n";
+ ret += gen_remaining_colrefs(schema, cid_set, found_cids, "false", needs_xform);
+
+
+ ret += "\treturn(true);\n";
+ ret += "};\n\n";
+
+
+//-------------------
+// The output tuple function.
+// Unpack the remaining attributes into
+// the placeholder variables, unpack the
+// partial fcn refs, then pack up the tuple.
+
+ ret += "host_tuple create_output_tuple() {\n";
+ ret += "\thost_tuple tup;\n";
+ ret += "\tgs_retval_t retval = 0;\n";
+
+// Unpack any remaining cached functions.
+ ret += gen_remaining_cached_fcns(schema, partial_fcns, sl_pfcns,
+ fcn_ref_cnt, is_partial_fcn);
+
+
+// Now, compute the size of the tuple.
+
+// Unpack any BUFFER type selections into temporaries
+// so that I can compute their size and not have
+// to recompute their value during tuple packing.
+// I can use regular assignment here because
+// these temporaries are non-persistent.
+
+ ret += "//\t\tCompute the size of the tuple.\n";
+ ret += "//\t\t\tNote: buffer storage packed at the end of the tuple.\n";
+
+// Unpack all buffer type selections, to be able to compute their size
+ ret += gen_buffer_selvars(schema, select_list);
+
+// The size of the tuple is the size of the tuple struct plus the
+// size of the buffers to be copied in.
+
+
+ ret+="\ttup.tuple_size = sizeof(" + generate_tuple_name( this->get_node_name()) +") + sizeof(gs_uint8_t)";
+ ret += gen_buffer_selvars_size(select_list,schema);
+ ret.append(";\n");
+
+// Allocate tuple data block.
+ ret += "//\t\tCreate the tuple block.\n";
+ ret += "\ttup.data = malloc(tup.tuple_size);\n";
+ ret += "\ttup.heap_resident = true;\n";
+// Mark tuple as regular
+ ret += "\t*((gs_sp_t )tup.data + sizeof(" + generate_tuple_name( this->get_node_name()) +")) = REGULAR_TUPLE;\n";
+
+// ret += "\ttup.channel = 0;\n";
+ ret += "\t"+generate_tuple_name( this->get_node_name())+" *tuple = ("+
+ generate_tuple_name( this->get_node_name())+" *)(tup.data);\n";
+
+// Start packing.
+// (Here, offsets are hard-wired. is this a problem?)
+
+ ret += "//\t\tPack the fields into the tuple.\n";
+ ret += gen_pack_tuple(schema,select_list,this->get_node_name(), false );
+
+// Delete string temporaries
+ ret += gen_buffer_selvars_dtr(select_list);
+
+ ret += "\treturn tup;\n";
+ ret += "};\n";
+
+//-------------------------------------------------------------------
+// Temporal update functions
+
+ ret += "bool temp_status_received(){return temp_tuple_received;};\n\n";
+
+
+// create a temp status tuple
+ ret += "int create_temp_status_tuple(host_tuple& result) {\n\n";
+
+ ret += gen_init_temp_status_tuple(this->get_node_name());
+
+// Start packing.
+// (Here, offsets are hard-wired. is this a problem?)
+
+ ret += "//\t\tPack the fields into the tuple.\n";
+ ret += gen_pack_tuple(schema,select_list,this->get_node_name(), true );
+
+ ret += "\treturn 0;\n";
+ ret += "};};\n\n";
+
+ return(ret);
+}
+
+
+string spx_qpn::generate_operator(int i, string params){
+
+ return(" select_project_operator<" +
+ generate_functor_name() +
+ "> *op"+int_to_string(i)+" = new select_project_operator<"+
+ generate_functor_name() +">("+params+", \"" + get_node_name() + "\");\n");
+}
+
+
+////////////////////////////////////////////////////////////////
+//// SGAH functor
+
+
+
+string sgah_qpn::generate_functor_name(){
+ return("sgah_functor_" + normalize_name(this->get_node_name()));
+}
+
+
+string sgah_qpn::generate_functor(table_list *schema, ext_fcn_list *Ext_fcns, vector<bool> &needs_xform){
+ int a,g,w,s;
+
+// Regular or slow flush?
+ hfta_slow_flush = 0;
+ if(this->get_val_of_def("hfta_slow_flush") != ""){
+ int d = atoi(this->get_val_of_def("hfta_slow_flush").c_str() );
+ if(d<0){
+ fprintf(stderr,"Warning, hfta_slow_flush in node %s is %d, must be at least 0, setting to 0.\n",node_name.c_str(), d);
+ hfta_slow_flush = 0;
+ }else{
+ hfta_slow_flush = d;
+ }
+ }
+
+
+// Initialize generate utility globals
+ segen_gb_tbl = &(gb_tbl);
+
+// Might need to generate empty values for cube processing.
+ map<int, string> structured_types;
+ for(g=0;g<gb_tbl.size();++g){
+ if(gb_tbl.get_data_type(g)->is_structured_type()){
+ structured_types[gb_tbl.get_data_type(g)->type_indicator()] = gb_tbl.get_data_type(g)->get_type_str();
+ }
+ }
+
+//--------------------------------
+// group definition class
+ string ret = "class " + generate_functor_name() + "_groupdef{\n";
+ ret += "public:\n";
+ for(g=0;g<this->gb_tbl.size();g++){
+ sprintf(tmpstr,"gb_var%d",g);
+ ret+="\t"+this->gb_tbl.get_data_type(g)->make_host_cvar(tmpstr)+";\n";
+ }
+// empty strucutred literals
+// map<int, string>::iterator sii;
+// for(sii=structured_types.begin();sii!=structured_types.end();++sii){
+// data_type dt(sii->second);
+// literal_t empty_lit(sii->first);
+// ret += "\t"+dt.make_host_cvar(empty_lit.hfta_empty_literal_name())+";\n";
+// }
+// Constructors
+ if(structured_types.size()==0){
+ ret += "\t"+generate_functor_name() + "_groupdef(){};\n";
+ }else{
+ ret += "\t"+generate_functor_name() + "_groupdef(){\n";
+ for(g=0;g<gb_tbl.size();g++){
+ data_type *gdt = gb_tbl.get_data_type(g);
+ if(gdt->is_buffer_type()){
+ sprintf(tmpstr,"\t\t%s(&gb_var%d);\n",
+ gdt->get_hfta_buffer_init().c_str(), g );
+ ret += tmpstr;
+ }
+ }
+ ret += "\t};\n";
+ }
+
+
+ ret += "\t// shallow copy constructors\n";
+ ret += "\t"+generate_functor_name() + "_groupdef("+
+ "const " + this->generate_functor_name() + "_groupdef &gd){\n";
+ for(g=0;g<gb_tbl.size();g++){
+ data_type *gdt = gb_tbl.get_data_type(g);
+ sprintf(tmpstr,"\t\tgb_var%d = gd.gb_var%d;\n",g,g);
+ ret += tmpstr;
+// TODO : do strings perisist after the call? its a shllow copy
+// if(gdt->is_buffer_type()){
+// sprintf(tmpstr,"\t\t%s(&gb_var%d, &(gd->gb_var%d));\n",
+// gdt->get_hfta_buffer_assign_copy().c_str(),g,g );
+// ret += tmpstr;
+// }else{
+// sprintf(tmpstr,"\t\tgb_var%d = gd->gb_var%d;\n",g,g);
+// ret += tmpstr;
+// }
+ }
+ ret += "\t}\n";
+ ret += "\t"+generate_functor_name() + "_groupdef("+
+ "const " + this->generate_functor_name() + "_groupdef &gd, bool *pattern){\n";
+// -- For patterns, need empty strucutred literals
+ map<int, string>::iterator sii;
+ for(sii=structured_types.begin();sii!=structured_types.end();++sii){
+ data_type dt(sii->second);
+ literal_t empty_lit(sii->first);
+ ret += "\t"+dt.make_host_cvar(empty_lit.hfta_empty_literal_name())+";\n";
+ }
+
+ for(sii=structured_types.begin();sii!=structured_types.end();++sii){
+ literal_t empty_lit(sii->first);
+ ret += "\t\t"+empty_lit.to_hfta_C_code("&"+empty_lit.hfta_empty_literal_name())+";\n";
+ }
+ for(g=0;g<gb_tbl.size();g++){
+ data_type *gdt = gb_tbl.get_data_type(g);
+ ret += "\t\tif(pattern["+int_to_string(g)+"]){\n";
+ sprintf(tmpstr,"\t\t\tgb_var%d = gd.gb_var%d;\n",g,g);
+ ret += tmpstr;
+// TODO Do strings persist long enough? its a shllow copy constructor?
+// if(gdt->is_buffer_type()){
+// sprintf(tmpstr,"\t\t\t%s(&gb_var%d, &(gd->gb_var%d));\n",
+// gdt->get_hfta_buffer_assign_copy().c_str(),g,g );
+// ret += tmpstr;
+// }else{
+// sprintf(tmpstr,"\t\t\tgb_var%d = gd->gb_var%d;\n",g,g);
+// ret += tmpstr;
+// }
+ ret += "\t\t}else{\n";
+ literal_t empty_lit(gdt->type_indicator());
+ if(empty_lit.is_cpx_lit()){
+ ret +="\t\t\tgb_var"+int_to_string(g)+"= "+empty_lit.hfta_empty_literal_name()+";\n";
+ }else{
+ ret +="\t\t\tgb_var"+int_to_string(g)+"="+empty_lit.to_hfta_C_code("")+";\n";
+ }
+ ret += "\t\t}\n";
+ }
+ ret += "\t};\n";
+
+ ret += "\t// deep assignment operator\n";
+ ret += "\t"+generate_functor_name() + "_groupdef& operator=(const "+
+ this->generate_functor_name() + "_groupdef &gd){\n";
+ for(g=0;g<gb_tbl.size();g++){
+ data_type *gdt = gb_tbl.get_data_type(g);
+ if(gdt->is_buffer_type()){
+ sprintf(tmpstr,"\t\t%s(&gb_var%d, &(gd.gb_var%d));\n",
+ gdt->get_hfta_buffer_assign_copy().c_str(),g,g );
+ ret += tmpstr;
+ }else{
+ sprintf(tmpstr,"\t\tgb_var%d = gd.gb_var%d;\n",g,g);
+ ret += tmpstr;
+ }
+ }
+ ret += "\t}\n";
+
+// destructor
+ ret += "\t~"+ generate_functor_name() + "_groupdef(){\n";
+ for(g=0;g<gb_tbl.size();g++){
+ data_type *gdt = gb_tbl.get_data_type(g);
+ if(gdt->is_buffer_type()){
+ sprintf(tmpstr,"\t\t%s(&gb_var%d);\n",
+ gdt->get_hfta_buffer_destroy().c_str(), g );
+ ret += tmpstr;
+ }
+ }
+ ret += "\t};\n";
+
+ data_type *tgdt;
+ for(g=0;g<gb_tbl.size();g++){
+ data_type *gdt = gb_tbl.get_data_type(g);
+ if(gdt->is_temporal()){
+ tgdt = gdt;
+ break;
+ }
+ }
+ ret += tgdt->get_host_cvar_type()+" get_curr_gb(){\n";
+ ret+="\treturn gb_var"+int_to_string(g)+";\n";
+ ret+="}\n";
+
+ ret +="};\n\n";
+
+//--------------------------------
+// aggr definition class
+ ret += "class " + this->generate_functor_name() + "_aggrdef{\n";
+ ret += "public:\n";
+ for(a=0;a<aggr_tbl.size();a++){
+ aggr_table_entry *ate = aggr_tbl.agr_tbl[a];
+ sprintf(tmpstr,"aggr_var%d",a);
+ if(aggr_tbl.is_builtin(a)){
+ ret+="\t"+ aggr_tbl.get_data_type(a)->make_host_cvar(tmpstr)+";\n";
+ if(aggr_tbl.get_op(a) == "AVG"){ // HACK!
+ data_type cnt_type = data_type("ullong");
+ ret+="\t"+cnt_type.make_host_cvar(string(tmpstr)+"_cnt")+";\n";
+ ret+="\t"+ aggr_tbl.get_data_type(a)->make_host_cvar(string(tmpstr)+"_sum")+";\n";
+ }
+ }else{
+ ret+="\t"+ aggr_tbl.get_storage_type(a)->make_host_cvar(tmpstr)+";\n";
+ }
+ }
+// Constructors
+ ret += "\t"+this->generate_functor_name() + "_aggrdef(){};\n";
+// destructor
+ ret += "\t~"+this->generate_functor_name() + "_aggrdef(){\n";
+ for(a=0;a<aggr_tbl.size();a++){
+ if(aggr_tbl.is_builtin(a)){
+ data_type *adt = aggr_tbl.get_data_type(a);
+ if(adt->is_buffer_type()){
+ sprintf(tmpstr,"\t\t%s(&aggr_var%d);\n",
+ adt->get_hfta_buffer_destroy().c_str(), a );
+ ret += tmpstr;
+ }
+ }else{
+ ret+="\t\t"+aggr_tbl.get_op(a)+"_HFTA_AGGR_DESTROY_(";
+ if(aggr_tbl.get_storage_type(a)->get_type() != fstring_t) ret+="&";
+ ret+="(aggr_var"+int_to_string(a)+"));\n";
+ }
+ }
+ ret += "\t};\n";
+ ret +="};\n\n";
+
+//-------------------------------------------
+// group-by patterns for the functor,
+// initialization within the class is cumbersome.
+ int n_patterns = gb_tbl.gb_patterns.size();
+ int i,j;
+ ret += "bool "+this->generate_functor_name()+"_gb_patterns["+int_to_string(n_patterns)+
+ "]["+int_to_string(gb_tbl.size())+"] = {\n";
+ if(n_patterns == 0){
+ for(i=0;i<gb_tbl.size();++i){
+ if(i>0) ret += ",";
+ ret += "true";
+ }
+ }else{
+ for(i=0;i<n_patterns;++i){
+ if(i>0) ret += ",\n";
+ ret += "\t{";
+ for(j=0;j<gb_tbl.size();j++){
+ if(j>0) ret += ", ";
+ if(gb_tbl.gb_patterns[i][j]){
+ ret += "true";
+ }else{
+ ret += "false";
+ }
+ }
+ ret += "}";
+ }
+ ret += "\n";
+ }
+ ret += "};\n";
+
+
+//--------------------------------
+// gb functor class
+ ret += "class " + this->generate_functor_name() + "{\n";
+
+// Find variables referenced in this query node.
+
+ col_id_set cid_set;
+ col_id_set::iterator csi;
+
+ for(w=0;w<where.size();++w)
+ gather_pr_col_ids(where[w]->pr,cid_set,segen_gb_tbl);
+ for(w=0;w<having.size();++w)
+ gather_pr_col_ids(having[w]->pr,cid_set,segen_gb_tbl);
+ for(g=0;g<gb_tbl.size();g++)
+ gather_se_col_ids(gb_tbl.get_def(g),cid_set,segen_gb_tbl);
+
+ for(s=0;s<select_list.size();s++){
+ gather_se_col_ids(select_list[s]->se,cid_set,segen_gb_tbl); // descends into aggregates
+ }
+
+
+// Private variables : store the state of the functor.
+// 1) variables for unpacked attributes
+// 2) offsets of the upacked attributes
+// 3) storage of partial functions
+// 4) storage of complex literals (i.e., require a constructor)
+
+ ret += "private:\n";
+
+ // var to save the schema handle
+ ret += "\tint schema_handle0;\n";
+ // metadata from schema handle
+ ret += "\tint tuple_metadata_offset0;\n";
+
+ // generate the declaration of all the variables related to
+ // temp tuples generation
+ ret += gen_decl_temp_vars();
+
+// unpacked attribute storage, offsets
+ ret += "//\t\tstorage and offsets of accessed fields.\n";
+ ret += generate_access_vars(cid_set, schema);
+
+// Variables to store results of partial functions.
+// WARNING find_partial_functions modifies the SE
+// (it marks the partial function id).
+ ret += "//\t\tParital function result storage\n";
+ vector<scalarexp_t *> partial_fcns;
+ vector<int> fcn_ref_cnt;
+ vector<bool> is_partial_fcn;
+ for(s=0;s<select_list.size();s++){
+ find_partial_fcns(select_list[s]->se, &partial_fcns,NULL,NULL, Ext_fcns);
+ }
+ for(w=0;w<where.size();w++){
+ find_partial_fcns_pr(where[w]->pr, &partial_fcns,NULL,NULL, Ext_fcns);
+ }
+ for(w=0;w<having.size();w++){
+ find_partial_fcns_pr(having[w]->pr, &partial_fcns,NULL,NULL, Ext_fcns);
+ }
+ for(g=0;g<gb_tbl.size();g++){
+ find_partial_fcns(gb_tbl.get_def(g), &partial_fcns,NULL,NULL, Ext_fcns);
+ }
+ for(a=0;a<aggr_tbl.size();a++){
+ find_partial_fcns(aggr_tbl.get_aggr_se(a), &partial_fcns,NULL,NULL, Ext_fcns);
+ }
+ if(partial_fcns.size()>0){
+ ret += "/*\t\tVariables for storing results of partial functions. \t*/\n";
+ ret += generate_partial_fcn_vars(partial_fcns,fcn_ref_cnt,is_partial_fcn,false);
+ }
+
+// Complex literals (i.e., they need constructors)
+ ret += "//\t\tComplex literal storage.\n";
+ cplx_lit_table *complex_literals = this->get_cplx_lit_tbl(Ext_fcns);
+ ret += generate_complex_lit_vars(complex_literals);
+
+// Pass-by-handle parameters
+ ret += "//\t\tPass-by-handle storage.\n";
+ vector<handle_param_tbl_entry *> param_handle_table = this->get_handle_param_tbl(Ext_fcns);
+ ret += generate_pass_by_handle_vars(param_handle_table);
+
+
+// variables to hold parameters.
+ ret += "//\tfor query parameters\n";
+ ret += generate_param_vars(param_tbl);
+
+// Is there a temporal flush? If so create flush temporaries,
+// create flush indicator.
+ bool uses_temporal_flush = false;
+ for(g=0;g<gb_tbl.size();g++){
+ data_type *gdt = gb_tbl.get_data_type(g);
+ if(gdt->is_temporal())
+ uses_temporal_flush = true;
+ }
+
+ if(uses_temporal_flush){
+ ret += "//\t\tFor temporal flush\n";
+ for(g=0;g<gb_tbl.size();g++){
+ data_type *gdt = gb_tbl.get_data_type(g);
+ if(gdt->is_temporal()){
+ sprintf(tmpstr,"last_gb%d",g);
+ ret+="\t"+gb_tbl.get_data_type(g)->make_host_cvar(tmpstr)+";\n";
+ sprintf(tmpstr,"last_flushed_gb%d",g);
+ ret+="\t"+gb_tbl.get_data_type(g)->make_host_cvar(tmpstr)+";\n";
+ }
+ }
+ ret += "\tbool needs_temporal_flush;\n";
+ ret += "\tbool disordered_arrival;\n";
+ }
+
+
+// The publicly exposed functions
+
+ ret += "\npublic:\n";
+
+
+//-------------------
+// The functor constructor
+// pass in the schema handle.
+// 1) make assignments to the unpack offset variables
+// 2) initialize the complex literals
+
+ ret += "//\t\tFunctor constructor.\n";
+ ret += this->generate_functor_name()+"(int schema_handle0){\n";
+
+ // save the schema handle
+ ret += "\t\tthis->schema_handle0 = schema_handle0;\n";
+
+// unpack vars
+ ret += "//\t\tGet offsets for unpacking fields from input tuple.\n";
+ ret += gen_access_var_init(cid_set);
+// tuple metadata
+ ret += "tuple_metadata_offset0 = ftaschema_get_tuple_metadata_offset(schema_handle0);\n";
+
+// complex literals
+ ret += "//\t\tInitialize complex literals.\n";
+ ret += gen_complex_lit_init(complex_literals);
+
+// Initialize partial function results so they can be safely GC'd
+ ret += gen_partial_fcn_init(partial_fcns);
+
+// Initialize non-query-parameter parameter handles
+ ret += gen_pass_by_handle_init(param_handle_table);
+
+// temporal flush variables
+// ASSUME that structured values won't be temporal.
+ if(uses_temporal_flush){
+ ret += "//\t\tInitialize temporal flush variables.\n";
+ for(g=0;g<gb_tbl.size();g++){
+ data_type *gdt = gb_tbl.get_data_type(g);
+ if(gdt->is_temporal()){
+ literal_t gl(gdt->type_indicator());
+ sprintf(tmpstr,"\tlast_gb%d = %s;\n",g, gl.to_hfta_C_code("").c_str());
+ ret.append(tmpstr);
+ sprintf(tmpstr,"\tlast_flushed_gb%d = %s;\n",g, gl.to_hfta_C_code("").c_str());
+ ret.append(tmpstr);
+ }
+ }
+ ret += "\tneeds_temporal_flush = false;\n";
+ }
+
+ // Init temporal attributes referenced in select list
+ ret += gen_init_temp_vars(schema, select_list, segen_gb_tbl);
+
+ ret += "}\n\n";
+
+//-------------------
+// Functor destructor
+ ret += "//\t\tFunctor destructor.\n";
+ ret += "~"+this->generate_functor_name()+"(){\n";
+
+// clean up buffer type complex literals
+ ret += gen_complex_lit_dtr(complex_literals);
+
+// Deregister the pass-by-handle parameters
+ ret += "/* register and de-register the pass-by-handle parameters */\n";
+ ret += gen_pass_by_handle_dtr(param_handle_table);
+
+// clean up partial function results.
+ ret += "/* clean up partial function storage */\n";
+ ret += gen_partial_fcn_dtr(partial_fcns);
+
+// Destroy the parameters, if any need to be destroyed
+ ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";
+
+ ret += "};\n\n";
+
+
+//-------------------
+// Parameter manipulation routines
+ ret += generate_load_param_block(this->generate_functor_name(),
+ this->param_tbl,param_handle_table);
+ ret += generate_delete_param_block(this->generate_functor_name(),
+ this->param_tbl,param_handle_table);
+
+//-------------------
+// Register new parameter block
+
+ ret += "int set_param_block(gs_int32_t sz, void* value){\n";
+ ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";
+ ret += "\treturn this->load_params_"+this->generate_functor_name()+
+ "(sz, value);\n";
+ ret += "};\n\n";
+
+// -----------------------------------
+// group-by pattern support
+
+ ret +=
+"int n_groupby_patterns(){\n"
+" return "+int_to_string(gb_tbl.gb_patterns.size())+";\n"
+"}\n"
+"bool *get_pattern(int p){\n"
+" return "+this->generate_functor_name()+"_gb_patterns[p];\n"
+"}\n\n"
+;
+
+//---------------------------------------
+// Parameterized number of tuples output per slow flush
+ ret +=
+"int gb_flush_per_tuple(){\n"
+" return "+int_to_string(hfta_slow_flush)+";\n"
+"}\n\n";
+
+
+
+
+
+//-------------------
+// the create_group method.
+// This method creates a group in a buffer passed in
+// (to allow for creation on the stack).
+// There are also a couple of side effects:
+// 1) evaluate the WHERE clause (and therefore, unpack all partial fcns)
+// 2) determine if a temporal flush is required.
+
+ ret += this->generate_functor_name()+"_groupdef *create_group(host_tuple &tup0, gs_sp_t buffer){\n";
+ // Variables for execution of the function.
+ ret += "\tgs_int32_t problem = 0;\n"; // return unpack failure
+
+ if(partial_fcns.size()>0){ // partial fcn access failure
+ ret += "\tgs_retval_t retval = 0;\n";
+ ret += "\n";
+ }
+// return value
+ ret += "\t"+generate_functor_name()+"_groupdef *gbval = ("+generate_functor_name()+
+ "_groupdef *) buffer;\n";
+
+// Start by cleaning up partial function results
+ ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";
+ set<int> w_pfcns; // partial fcns in where clause
+ for(w=0;w<where.size();++w)
+ collect_partial_fcns_pr(where[w]->pr, w_pfcns);
+
+ set<int> ag_gb_pfcns; // partial fcns in gbdefs, aggr se's
+ for(g=0;g<gb_tbl.size();g++){
+ collect_partial_fcns(gb_tbl.get_def(g), ag_gb_pfcns);
+ }
+ for(a=0;a<aggr_tbl.size();a++){
+ collect_partial_fcns(aggr_tbl.get_aggr_se(a), ag_gb_pfcns);
+ }
+ ret += gen_partial_fcn_dtr(partial_fcns,w_pfcns);
+ ret += gen_partial_fcn_dtr(partial_fcns,ag_gb_pfcns);
+// ret += gen_partial_fcn_dtr(partial_fcns);
+
+
+ ret += gen_temp_tuple_check(this->node_name, 0);
+ col_id_set found_cids; // colrefs unpacked thus far.
+ ret += gen_unpack_temp_vars(schema, found_cids, select_list, segen_gb_tbl, needs_xform);
+
+
+// Save temporal group-by variables
+
+
+ ret.append("\n\t//\t\tCompute temporal groupby attributes\n\n");
+
+ for(g=0;g<gb_tbl.size();g++){
+
+ data_type *gdt = gb_tbl.get_data_type(g);
+
+ if(gdt->is_temporal()){
+ sprintf(tmpstr,"\tgbval->gb_var%d = %s;\n",
+ g, generate_se_code(gb_tbl.get_def(g),schema).c_str() );
+ ret.append(tmpstr);
+ }
+ }
+ ret.append("\n");
+
+
+
+// Compare the temporal GB vars with the stored ones,
+// set flush indicator and update stored GB vars if there is any change.
+
+ret += "// hfta_disorder = "+int_to_string(hfta_disorder)+"\n";
+ if(hfta_disorder < 2){
+ if(uses_temporal_flush){
+ ret+= "\tif( ( (";
+ bool first_one = true;
+ string disorder_test;
+ for(g=0;g<gb_tbl.size();g++){
+ data_type *gdt = gb_tbl.get_data_type(g);
+
+ if(gdt->is_temporal()){
+ sprintf(tmpstr,"last_gb%d",g); string lhs_op = tmpstr;
+ sprintf(tmpstr,"gbval->gb_var%d",g); string rhs_op = tmpstr;
+ if(first_one){first_one = false;} else {ret += ") && (";}
+ ret += generate_lt_test(lhs_op, rhs_op, gdt);
+ disorder_test += generate_lt_test(rhs_op, lhs_op, gdt);
+ }
+ }
+ ret += ") ) ){\n";
+ for(g=0;g<gb_tbl.size();g++){
+ data_type *gdt = gb_tbl.get_data_type(g);
+ if(gdt->is_temporal()){
+ if(gdt->is_buffer_type()){
+ sprintf(tmpstr,"\t\t%s(&(gbval->gb_var%d),&last_gb%d);\n",gdt->get_hfta_buffer_replace().c_str(),g,g);
+ }else{
+ sprintf(tmpstr,"\t\tlast_flushed_gb%d = last_gb%d;\n",g,g);
+ ret += tmpstr;
+ sprintf(tmpstr,"\t\tlast_gb%d = gbval->gb_var%d;\n",g,g);
+ }
+ ret += tmpstr;
+ }
+ }
+ ret += "\t\tneeds_temporal_flush=true;\n";
+ ret += "\t}else{\n"
+ "\t\tneeds_temporal_flush=false;\n"
+ "\t}\n";
+
+ ret += "\tdisordered_arrival = "+disorder_test+";\n";
+// ret += "\tif( ( ("+disorder_test+") ) ){\n";
+// ret += "\t\tdisordered_arrival=true;\n";
+// ret += "\t}else{\n";
+// ret += "\t\tdisordered_arrival=false;\n";
+// ret += "\t}\n";
+
+ }
+ }else{
+ ret+= "\tif(temp_tuple_received && !( (";
+ bool first_one = true;
+ for(g=0;g<gb_tbl.size();g++){
+ data_type *gdt = gb_tbl.get_data_type(g);
+
+ if(gdt->is_temporal()){
+ sprintf(tmpstr,"last_gb%d",g); string lhs_op = tmpstr;
+ sprintf(tmpstr,"gbval->gb_var%d",g); string rhs_op = tmpstr;
+ if(first_one){first_one = false;} else {ret += ") && (";}
+ ret += generate_equality_test(lhs_op, rhs_op, gdt);
+ break;
+ }
+ }
+ ret += ") ) ){\n";
+ int temporal_g = 0;
+ for(g=0;g<gb_tbl.size();g++){
+ data_type *gdt = gb_tbl.get_data_type(g);
+ if(gdt->is_temporal()){
+ temporal_g = g;
+ if(gdt->is_buffer_type()){
+ sprintf(tmpstr,"\t\t%s(&(gbval->gb_var%d),&last_gb%d);\n",gdt->get_hfta_buffer_replace().c_str(),g,g);
+ }else{
+ sprintf(tmpstr,"\t\tlast_flushed_gb%d = last_gb%d;\n",g,g);
+ ret += tmpstr;
+ sprintf(tmpstr,"\t\tlast_gb%d = gbval->gb_var%d;\n",g,g);
+ }
+ ret += tmpstr;
+ break;
+ }
+ }
+ data_type *tgdt = gb_tbl.get_data_type(temporal_g);
+ literal_t gl(tgdt->type_indicator());
+ ret += "\t\tif(last_flushed_gb"+int_to_string(temporal_g)+">"+gl.to_hfta_C_code("")+")\n";
+ ret += "\t\t\tneeds_temporal_flush=true;\n";
+ ret += "\t\t}else{\n"
+ "\t\t\tneeds_temporal_flush=false;\n"
+ "\t\t}\n";
+ }
+
+
+// For temporal status tuple we don't need to do anything else
+ ret += "\tif (temp_tuple_received){\n";
+ ret += "\t\tdisordered_arrival = false;\n";
+ ret += "\t\treturn NULL;\n\n";
+ ret += "\t}\n";
+
+ for(w=0;w<where.size();++w){
+ sprintf(tmpstr,"//\t\tPredicate clause %d.\n",w);
+ ret += tmpstr;
+// Find the set of variables accessed in this CNF elem,
+// but in no previous element.
+ col_id_set new_cids;
+ get_new_pred_cids(where[w]->pr, found_cids, new_cids, segen_gb_tbl);
+
+// Unpack these values.
+ ret += gen_unpack_cids(schema, new_cids, "NULL", needs_xform);
+// Find partial fcns ref'd in this cnf element
+ set<int> pfcn_refs;
+ collect_partial_fcns_pr(where[w]->pr, pfcn_refs);
+ ret += gen_unpack_partial_fcn(schema, partial_fcns, pfcn_refs,"NULL");
+
+ ret += "\tif( !("+generate_predicate_code(where[w]->pr,schema)+
+ +") ) return(NULL);\n";
+ }
+
+// The partial functions ref'd in the group-by var and aggregate
+// definitions must also be evaluated. If one returns false,
+// then implicitly the predicate is false.
+ set<int>::iterator pfsi;
+
+ if(ag_gb_pfcns.size() > 0)
+ ret += "//\t\tUnpack remaining partial fcns.\n";
+ ret += gen_full_unpack_partial_fcn(schema, partial_fcns, ag_gb_pfcns,
+ found_cids, segen_gb_tbl, "NULL", needs_xform);
+
+// Unpack the group-by variables
+
+ for(g=0;g<gb_tbl.size();g++){
+ data_type *gdt = gb_tbl.get_data_type(g);
+
+ if(!gdt->is_temporal()){
+// Find the new fields ref'd by this GBvar def.
+ col_id_set new_cids;
+ get_new_se_cids(gb_tbl.get_def(g), found_cids, new_cids, segen_gb_tbl);
+// Unpack these values.
+ ret += gen_unpack_cids(schema, new_cids, "NULL", needs_xform);
+
+ sprintf(tmpstr,"\tgbval->gb_var%d = %s;\n",
+ g, generate_se_code(gb_tbl.get_def(g),schema).c_str() );
+/*
+// There seems to be no difference between the two
+// branches of the IF statement.
+ data_type *gdt = gb_tbl.get_data_type(g);
+ if(gdt->is_buffer_type()){
+// Create temporary copy.
+ sprintf(tmpstr,"\tgbval->gb_var%d = %s;\n",
+ g, generate_se_code(gb_tbl.get_def(g),schema).c_str() );
+ }else{
+ scalarexp_t *gse = gb_tbl.get_def(g);
+ sprintf(tmpstr,"\tgbval->gb_var%d = %s;\n",
+ g,generate_se_code(gse,schema).c_str());
+ }
+*/
+
+ ret.append(tmpstr);
+ }
+ }
+ ret.append("\n");
+
+ ret+= "\treturn gbval;\n";
+ ret += "};\n\n\n";
+
+//--------------------------------------------------------
+// Create and initialize an aggregate object
+
+ ret += this->generate_functor_name()+"_aggrdef *create_aggregate(host_tuple &tup0, gs_sp_t buffer){\n";
+ // Variables for execution of the function.
+ ret += "\tgs_int32_t problem = 0;\n"; // return unpack failure
+
+// return value
+ ret += "\t"+generate_functor_name()+"_aggrdef *aggval = ("+generate_functor_name()+
+ "_aggrdef *)buffer;\n";
+
+ for(a=0;a<aggr_tbl.size();a++){
+ if(aggr_tbl.is_builtin(a)){
+// Create temporaries for buffer return values
+ data_type *adt = aggr_tbl.get_data_type(a);
+ if(adt->is_buffer_type()){
+ sprintf(tmpstr,"aggr_tmp_%d", a);
+ ret+=adt->make_host_cvar(tmpstr)+";\n";
+ }
+ }
+ }
+
+// Unpack all remaining attributes
+ ret += gen_remaining_colrefs(schema, cid_set, found_cids, "NULL", needs_xform);
+ for(a=0;a<aggr_tbl.size();a++){
+ sprintf(tmpstr,"aggval->aggr_var%d",a);
+ string assignto_var = tmpstr;
+ ret += "\t"+generate_aggr_init(assignto_var,&aggr_tbl,a, schema);
+ }
+
+ ret += "\treturn aggval;\n";
+ ret += "};\n\n";
+
+//--------------------------------------------------------
+// update an aggregate object
+
+ ret += "void update_aggregate(host_tuple &tup0, "
+ +generate_functor_name()+"_groupdef &gbval, "+
+ generate_functor_name()+"_aggrdef &aggval){\n";
+ // Variables for execution of the function.
+ ret += "\tgs_int32_t problem = 0;\n"; // return unpack failure
+
+// use of temporaries depends on the aggregate,
+// generate them in generate_aggr_update
+
+
+// Unpack all remaining attributes
+ ret += gen_remaining_colrefs(schema, cid_set, found_cids, "", needs_xform);
+ for(a=0;a<aggr_tbl.size();a++){
+ sprintf(tmpstr,"aggval.aggr_var%d",a);
+ string varname = tmpstr;
+ ret.append(generate_aggr_update(varname,&aggr_tbl,a, schema));
+ }
+
+ ret += "\treturn;\n";
+ ret += "};\n";
+
+//---------------------------------------------------
+// Flush test
+
+ ret += "\tbool flush_needed(){\n";
+ if(uses_temporal_flush){
+ ret += "\t\treturn needs_temporal_flush;\n";
+ }else{
+ ret += "\t\treturn false;\n";
+ }
+ ret += "\t};\n";
+
+ ret += "bool disordered(){return disordered_arrival;}\n";
+
+//---------------------------------------------------
+// create output tuple
+// Unpack the partial functions ref'd in the where clause,
+// select clause. Evaluate the where clause.
+// Finally, pack the tuple.
+
+// I need to use special code generation here,
+// so I'll leave it in longhand.
+
+ ret += "host_tuple create_output_tuple("
+ +generate_functor_name()+"_groupdef &gbval, "+
+ generate_functor_name()+"_aggrdef &aggval, bool &failed){\n";
+
+ ret += "\thost_tuple tup;\n";
+ ret += "\tfailed = false;\n";
+ ret += "\tgs_retval_t retval = 0;\n";
+
+ string gbvar = "gbval.gb_var";
+ string aggvar = "aggval.";
+
+// Create cached temporaries for UDAF return values.
+ for(a=0;a<aggr_tbl.size();a++){
+ if(! aggr_tbl.is_builtin(a)){
+ int afcn_id = aggr_tbl.get_fcn_id(a);
+ data_type *adt = Ext_fcns->get_fcn_dt(afcn_id);
+ sprintf(tmpstr,"udaf_ret_%d", a);
+ ret+="\t"+adt->make_host_cvar(tmpstr)+";\n";
+ }
+ }
+
+
+// First, get the return values from the UDAFS
+ for(a=0;a<aggr_tbl.size();a++){
+ if(! aggr_tbl.is_builtin(a)){
+ ret += "\t"+aggr_tbl.get_op(a)+"_HFTA_AGGR_OUTPUT_(&(udaf_ret_"+int_to_string(a)+"),";
+ if(aggr_tbl.get_storage_type(a)->get_type() != fstring_t) ret+="&";
+ ret+="("+aggvar+"aggr_var"+int_to_string(a)+"));\n";
+ }
+ }
+
+ set<int> hv_sl_pfcns;
+ for(w=0;w<having.size();w++){
+ collect_partial_fcns_pr(having[w]->pr, hv_sl_pfcns);
+ }
+ for(s=0;s<select_list.size();s++){
+ collect_partial_fcns(select_list[s]->se, hv_sl_pfcns);
+ }
+
+// clean up the partial fcn results from any previous execution
+ ret += gen_partial_fcn_dtr(partial_fcns,hv_sl_pfcns);
+
+// Unpack them now
+ for(pfsi=hv_sl_pfcns.begin();pfsi!=hv_sl_pfcns.end();++pfsi){
+ ret += unpack_partial_fcn_fm_aggr(partial_fcns[(*pfsi)], (*pfsi), gbvar, aggvar, schema);
+ ret += "\tif(retval){ failed = true; return(tup);}\n";
+ }
+
+// Evalaute the HAVING clause
+// TODO: this seems to have a ++ operator rather than a + operator.
+ for(w=0;w<having.size();++w){
+ ret += "\tif( !("+generate_predicate_code_fm_aggr(having[w]->pr,gbvar, aggvar, schema) +") ) { failed = true; return(tup);}\n";
+ }
+
+// Now, compute the size of the tuple.
+
+// Unpack any BUFFER type selections into temporaries
+// so that I can compute their size and not have
+// to recompute their value during tuple packing.
+// I can use regular assignment here because
+// these temporaries are non-persistent.
+// TODO: should I be using the selvar generation routine?
+
+ ret += "//\t\tCompute the size of the tuple.\n";
+ ret += "//\t\t\tNote: buffer storage packed at the end of the tuple.\n";
+ for(s=0;s<select_list.size();s++){
+ scalarexp_t *se = select_list[s]->se;
+ data_type *sdt = se->get_data_type();
+ if(sdt->is_buffer_type() &&
+ !( (se->get_operator_type() == SE_COLREF) ||
+ (se->get_operator_type() == SE_AGGR_STAR) ||
+ (se->get_operator_type() == SE_AGGR_SE) ||
+ (se->get_operator_type() == SE_FUNC && se->is_partial()) ||
+ (se->get_operator_type() == SE_FUNC && se->get_aggr_ref() >= 0))
+ ){
+ sprintf(tmpstr,"selvar_%d",s);
+ ret+="\t"+sdt->make_host_cvar(tmpstr)+" = ";
+ ret += generate_se_code_fm_aggr(se,gbvar, aggvar, schema) +";\n";
+ }
+ }
+
+// The size of the tuple is the size of the tuple struct plus the
+// size of the buffers to be copied in.
+
+ ret+="\ttup.tuple_size = sizeof(" + generate_tuple_name( this->get_node_name()) +") + sizeof(gs_uint8_t)";
+ for(s=0;s<select_list.size();s++){
+// if(s>0) ret += "+";
+ scalarexp_t *se = select_list[s]->se;
+ data_type *sdt = select_list[s]->se->get_data_type();
+ if(sdt->is_buffer_type()){
+ if(!( (se->get_operator_type() == SE_COLREF) ||
+ (se->get_operator_type() == SE_AGGR_STAR) ||
+ (se->get_operator_type() == SE_AGGR_SE) ||
+ (se->get_operator_type() == SE_FUNC && se->is_partial()) ||
+ (se->get_operator_type() == SE_FUNC && se->get_aggr_ref() >= 0))
+ ){
+ sprintf(tmpstr," + %s(&selvar_%d)", sdt->get_hfta_buffer_size().c_str(),s);
+ ret.append(tmpstr);
+ }else{
+ sprintf(tmpstr," + %s(&%s)", sdt->get_hfta_buffer_size().c_str(),generate_se_code_fm_aggr(se,gbvar, aggvar, schema).c_str());
+ ret.append(tmpstr);
+ }
+ }
+ }
+ ret.append(";\n");
+
+// Allocate tuple data block.
+ ret += "//\t\tCreate the tuple block.\n";
+ ret += "\ttup.data = malloc(tup.tuple_size);\n";
+ ret += "\ttup.heap_resident = true;\n";
+
+// Mark tuple as regular
+ ret += "\t*((gs_sp_t )tup.data + sizeof(" + generate_tuple_name( this->get_node_name()) +")) = REGULAR_TUPLE;\n";
+
+// ret += "\ttup.channel = 0;\n";
+ ret += "\t"+generate_tuple_name( this->get_node_name())+" *tuple = ("+
+ generate_tuple_name( this->get_node_name())+" *)(tup.data);\n";
+
+// Start packing.
+// (Here, offsets are hard-wired. is this a problem?)
+
+ ret += "//\t\tPack the fields into the tuple.\n";
+ ret += "\tint tuple_pos = sizeof("+generate_tuple_name( this->get_node_name()) +") + sizeof(gs_uint8_t);\n";
+ for(s=0;s<select_list.size();s++){
+ scalarexp_t *se = select_list[s]->se;
+ data_type *sdt = se->get_data_type();
+ if(sdt->is_buffer_type()){
+ if(!( (se->get_operator_type() == SE_COLREF) ||
+ (se->get_operator_type() == SE_AGGR_STAR) ||
+ (se->get_operator_type() == SE_AGGR_SE) ||
+ (se->get_operator_type() == SE_FUNC && se->is_partial()) ||
+ (se->get_operator_type() == SE_FUNC && se->get_aggr_ref() >= 0))
+ ){
+ 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);
+ ret.append(tmpstr);
+ sprintf(tmpstr,"\ttuple_pos += %s(&selvar_%d);\n", sdt->get_hfta_buffer_size().c_str(), s);
+ ret.append(tmpstr);
+ }else{
+ 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());
+ ret.append(tmpstr);
+ 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());
+ ret.append(tmpstr);
+ }
+ }else{
+ sprintf(tmpstr,"\ttuple->tuple_var%d = ",s);
+ ret.append(tmpstr);
+ ret.append(generate_se_code_fm_aggr(se,gbvar, aggvar, schema) );
+ ret.append(";\n");
+ }
+ }
+
+// Destroy string temporaries
+ ret += gen_buffer_selvars_dtr(select_list);
+// Destroy string return vals of UDAFs
+ for(a=0;a<aggr_tbl.size();a++){
+ if(! aggr_tbl.is_builtin(a)){
+ int afcn_id = aggr_tbl.get_fcn_id(a);
+ data_type *adt = Ext_fcns->get_fcn_dt(afcn_id);
+ if(adt->is_buffer_type()){
+ sprintf(tmpstr,"\t%s(&udaf_ret_%d);\n",
+ adt->get_hfta_buffer_destroy().c_str(), a );
+ ret += tmpstr;
+ }
+ }
+ }
+
+
+ ret += "\treturn tup;\n";
+ ret += "};\n";
+
+
+//-------------------------------------------------------------------
+// Temporal update functions
+
+ ret+="bool temp_status_received(){return temp_tuple_received;};\n\n";
+
+ for(g=0;g<gb_tbl.size();g++){
+ data_type *gdt = gb_tbl.get_data_type(g);
+ if(gdt->is_temporal()){
+ tgdt = gdt;
+ break;
+ }
+ }
+ ret += tgdt->get_host_cvar_type()+" get_last_flushed_gb(){\n";
+ ret+="\treturn last_flushed_gb"+int_to_string(g)+";\n";
+ ret+="}\n";
+ ret += tgdt->get_host_cvar_type()+" get_last_gb(){\n";
+ ret+="\treturn last_gb"+int_to_string(g)+";\n";
+ ret+="}\n";
+
+
+
+
+// create a temp status tuple
+ ret += "int create_temp_status_tuple(host_tuple& result, bool flush_finished) {\n\n";
+
+ ret += gen_init_temp_status_tuple(this->get_node_name());
+
+// Start packing.
+// (Here, offsets are hard-wired. is this a problem?)
+
+ ret += "//\t\tPack the fields into the tuple.\n";
+ for(s=0;s<select_list.size();s++){
+ data_type *sdt = select_list[s]->se->get_data_type();
+ if(sdt->is_temporal()){
+ sprintf(tmpstr,"\ttuple->tuple_var%d = ",s);
+ ret += tmpstr;
+
+ 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());
+ ret += tmpstr;
+ ret += ";\n";
+ }
+ }
+
+
+ ret += "\treturn 0;\n";
+ ret += "};};\n\n\n";
+
+
+//----------------------------------------------------------
+// The hash function
+
+ ret += "struct "+generate_functor_name()+"_hash_func{\n";
+ ret += "\tgs_uint32_t operator()(const "+generate_functor_name()+
+ "_groupdef &grp) const{\n";
+ ret += "\t\treturn( (";
+ for(g=0;g<gb_tbl.size();g++){
+ if(g>0) ret += "^";
+ data_type *gdt = gb_tbl.get_data_type(g);
+ if(gdt->use_hashfunc()){
+ if(gdt->is_buffer_type())
+ sprintf(tmpstr,"(%s*%s(&(grp.gb_var%d)))",hash_nums[g%NRANDS].c_str(),gdt->get_hfta_hashfunc().c_str(),g);
+ else
+ sprintf(tmpstr,"(%s*%s(grp.gb_var%d))",hash_nums[g%NRANDS].c_str(),gdt->get_hfta_hashfunc().c_str(),g);
+ }else{
+ sprintf(tmpstr,"(%s*grp.gb_var%d)",hash_nums[g%NRANDS].c_str(),g);
+ }
+ ret += tmpstr;
+ }
+ ret += ") >> 32);\n";
+ ret += "\t}\n";
+ ret += "};\n\n";
+
+//----------------------------------------------------------
+// The comparison function
+
+ ret += "struct "+generate_functor_name()+"_equal_func{\n";
+ ret += "\tbool operator()(const "+generate_functor_name()+"_groupdef &grp1, "+
+ "const "+generate_functor_name()+"_groupdef &grp2) const{\n";
+ ret += "\t\treturn( (";
+
+ for(g=0;g<gb_tbl.size();g++){
+ if(g>0) ret += ") && (";
+ data_type *gdt = gb_tbl.get_data_type(g);
+ if(gdt->complex_comparison(gdt)){
+ if(gdt->is_buffer_type())
+ sprintf(tmpstr,"(%s(&(grp1.gb_var%d), &(grp2.gb_var%d))==0)",
+ gdt->get_hfta_equals_fcn(gdt).c_str(),g,g);
+ else
+ sprintf(tmpstr,"(%s((grp1.gb_var%d), (grp2.gb_var%d))==0)",
+ gdt->get_hfta_equals_fcn(gdt).c_str(),g,g);
+ }else{
+ sprintf(tmpstr,"grp1.gb_var%d == grp2.gb_var%d",g,g);
+ }
+ ret += tmpstr;
+ }
+ ret += ") );\n";
+ ret += "\t}\n";
+ ret += "};\n\n";
+
+
+ return(ret);
+}
+
+string sgah_qpn::generate_operator(int i, string params){
+
+ if(hfta_disorder < 2){
+ string op_name = "groupby_operator";
+ if(hfta_slow_flush>0)
+ op_name = "groupby_slowflush_operator";
+ return(
+ " "+op_name+"<" +
+ generate_functor_name()+","+
+ generate_functor_name() + "_groupdef, " +
+ generate_functor_name() + "_aggrdef, " +
+ generate_functor_name()+"_hash_func, "+
+ generate_functor_name()+"_equal_func "
+ "> *op"+int_to_string(i)+" = new "+op_name+"<"+
+ generate_functor_name()+","+
+ generate_functor_name() + "_groupdef, " +
+ generate_functor_name() + "_aggrdef, " +
+ generate_functor_name()+"_hash_func, "+
+ generate_functor_name()+"_equal_func "
+ ">("+params+", \"" + get_node_name() +
+"\");\n"
+ );
+ }
+ data_type *tgdt;
+ for(int g=0;g<gb_tbl.size();g++){
+ data_type *gdt = gb_tbl.get_data_type(g);
+ if(gdt->is_temporal()){
+ tgdt = gdt;
+ break;
+ }
+ }
+
+ return(
+ " groupby_operator_oop<" +
+ generate_functor_name()+","+
+ generate_functor_name() + "_groupdef, " +
+ generate_functor_name() + "_aggrdef, " +
+ generate_functor_name()+"_hash_func, "+
+ generate_functor_name()+"_equal_func, " +
+ tgdt->get_host_cvar_type() +
+ "> *op"+int_to_string(i)+" = new groupby_operator_oop<"+
+ generate_functor_name()+","+
+ generate_functor_name() + "_groupdef, " +
+ generate_functor_name() + "_aggrdef, " +
+ generate_functor_name()+"_hash_func, "+
+ generate_functor_name()+"_equal_func, " +
+ tgdt->get_host_cvar_type() +
+ ">("+params+", \"" + get_node_name() +
+"\");\n"
+ );
+}
+
+
+////////////////////////////////////////////////
+/// MERGE operator
+/// MRG functor
+////////////////////////////////////////////
+
+string mrg_qpn::generate_functor_name(){
+ return("mrg_functor_" + normalize_name(this->get_node_name()));
+}
+
+string mrg_qpn::generate_functor(table_list *schema, ext_fcn_list *Ext_fcns, vector<bool> &needs_xform){
+ int tblref;
+
+
+// Sanity check
+ if(fm.size() != mvars.size()){
+ fprintf(stderr,"INTERNAL ERROR in mrg_qpn::generate_functor fm.size=%lu, mvars.size=%lu\n",fm.size(),mvars.size());
+ exit(1);
+ }
+ if(fm.size() != 2){
+ fprintf(stderr,"INTERNAL ERROR in mrg_qpn::generate_functor fm.size=mvars.size=%lu\n",fm.size());
+ exit(1);
+ }
+
+
+// Initialize generate utility globals
+ segen_gb_tbl = NULL;
+
+ string ret = "class " + this->generate_functor_name() + "{\n";
+
+// Private variable:
+// 1) Vars for unpacked attrs.
+// 2) offsets ofthe unpakced attrs
+// 3) last_posted_timestamp
+
+ data_type dta(
+ schema->get_type_name(mvars[0]->get_schema_ref(), mvars[0]->get_field()),
+ schema->get_modifier_list(mvars[0]->get_schema_ref(), mvars[0]->get_field())
+ );
+ data_type dtb(
+ schema->get_type_name(mvars[1]->get_schema_ref(), mvars[1]->get_field()),
+ schema->get_modifier_list(mvars[1]->get_schema_ref(), mvars[1]->get_field())
+ );
+
+ ret += "private:\n";
+
+ // var to save the schema handle
+ ret += "\tint schema_handle0;\n";
+
+ // generate the declaration of all the variables related to
+ // temp tuples generation
+ ret += gen_decl_temp_vars();
+
+// unpacked attribute storage, offsets
+ ret += "//\t\tstorage and offsets of accessed fields.\n";
+ ret += "\tint tuple_metadata_offset0, tuple_metadata_offset1;\n";
+ tblref = 0;
+ sprintf(tmpstr,"unpack_var_%s_%d", mvars[0]->get_field().c_str(), tblref);
+ ret+="\t"+dta.make_host_cvar(tmpstr)+";\n";
+ sprintf(tmpstr,"\tgs_int32_t unpack_offset_%s_%d;\n", mvars[0]->get_field().c_str(), tblref);
+ ret.append(tmpstr);
+ tblref = 1;
+ sprintf(tmpstr,"unpack_var_%s_%d", mvars[1]->get_field().c_str(), tblref);
+ ret+="\t"+dtb.make_host_cvar(tmpstr)+";\n";
+ sprintf(tmpstr,"\tgs_int32_t unpack_offset_%s_%d;\n", mvars[1]->get_field().c_str(), tblref);
+ ret.append(tmpstr);
+
+ ret += "//\t\tRemember the last posted timestamp.\n";
+ ret+="\t"+dta.make_host_cvar("last_posted_timestamp_0")+";\n";
+ ret+="\t"+dta.make_host_cvar("last_posted_timestamp_1")+";\n";
+ ret+="\t"+dta.make_host_cvar("timestamp")+";\n";
+ ret+="\t"+dta.make_host_cvar("slack")+";\n";
+// ret += "\t bool first_execution_0, first_execution_1;\n";
+
+// variables to hold parameters.
+ ret += "//\tfor query parameters\n";
+ ret += generate_param_vars(param_tbl);
+
+ ret += "public:\n";
+//-------------------
+// The functor constructor
+// pass in a schema handle (e.g. for the 1st input stream),
+// use it to determine how to unpack the merge variable.
+// ASSUME that both streams have the same layout,
+// just duplicate it.
+
+// unpack vars
+ ret += "//\t\tFunctor constructor.\n";
+ ret += this->generate_functor_name()+"(int schema_handle0){\n";
+
+ // var to save the schema handle
+ ret += "\tthis->schema_handle0 = schema_handle0;\n";
+ ret += "\ttuple_metadata_offset0=ftaschema_get_tuple_metadata_offset(schema_handle0);\n";
+ ret += "\ttuple_metadata_offset1=ftaschema_get_tuple_metadata_offset(schema_handle0);\n";
+
+ ret += "//\t\tGet offsets for unpacking fields from input tuple.\n";
+
+ 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());
+ ret.append(tmpstr);
+ 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);
+ ret.append(tmpstr);
+// ret+="\tfirst_execution_0 = first_execution_1 = true;\n";
+ if(slack)
+ ret+="\tslack = "+generate_se_code(slack,schema)+";\n";
+ else
+ ret+="\tslack = 0;\n";
+
+// Initialize internal state
+ ret += "\ttemp_tuple_received = false;\n";
+
+ // Init last timestamp values to minimum value for their type
+ if (dta.is_increasing())
+ ret+="\tlast_posted_timestamp_0 = last_posted_timestamp_1 = " + dta.get_min_literal() + ";\n";
+ else
+ ret+="\tlast_posted_timestamp_0 = last_posted_timestamp_1 = " + dta.get_max_literal() + ";\n";
+
+
+ ret += "};\n\n";
+
+ ret += "//\t\tFunctor destructor.\n";
+ ret += "~"+this->generate_functor_name()+"(){\n";
+
+// Destroy the parameters, if any need to be destroyed
+ ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";
+
+ ret+="};\n\n";
+
+
+// no pass-by-handle params.
+ vector<handle_param_tbl_entry *> param_handle_table;
+
+// Parameter manipulation routines
+ ret += generate_load_param_block(this->generate_functor_name(),
+ this->param_tbl,param_handle_table);
+ ret += generate_delete_param_block(this->generate_functor_name(),
+ this->param_tbl,param_handle_table);
+
+// Register new parameter block
+
+ ret += "int set_param_block(gs_int32_t sz, void* value){\n";
+ ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";
+ ret += "\treturn this->load_params_"+this->generate_functor_name()+
+ "(sz, value);\n";
+ ret += "};\n\n";
+
+
+// -----------------------------------
+// Compare method
+
+ string unpack_fcna;
+ if(needs_xform[0]) unpack_fcna = dta.get_hfta_unpack_fcn();
+ else unpack_fcna = dta.get_hfta_unpack_fcn_noxf();
+ string unpack_fcnb;
+ if(needs_xform[1]) unpack_fcnb = dtb.get_hfta_unpack_fcn();
+ else unpack_fcnb = dtb.get_hfta_unpack_fcn_noxf();
+
+/*
+ ret+="\tint compare(const host_tuple& tup1, const host_tuple& tup2) const{ \n";
+ ret+="\t"+dta.make_host_cvar("timestamp1")+";\n";
+ ret+="\t"+dta.make_host_cvar("timestamp2")+";\n";
+ ret+="\tgs_int32_t problem;\n";
+ ret+="\tif (tup1.channel == 0) {\n";
+ 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);
+ ret += tmpstr;
+ 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);
+ ret += tmpstr;
+ ret+="\t}else{\n";
+ 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);
+ ret += tmpstr;
+ 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);
+ ret += tmpstr;
+ ret+="\t}\n";
+ ret+=
+" if (timestamp1 > timestamp2+slack)\n"
+" return 1;\n"
+" else if (timestamp1 < timestamp2)\n"
+" return -1;\n"
+" else\n"
+" return 0;\n"
+"\n"
+" }\n\n";
+*/
+
+ret +=
+" void get_timestamp(const host_tuple& tup0){\n"
+" gs_int32_t problem;\n"
+;
+ sprintf(tmpstr,"\t\ttimestamp = %s_nocheck(tup0.data, unpack_offset_%s_%d);\n", unpack_fcna.c_str(), mvars[0]->get_field().c_str(), 0);
+ ret += tmpstr;
+ret +=
+" }\n"
+"\n"
+;
+
+
+
+// Compare to temp status.
+ ret+=
+" int compare_with_temp_status(int channel) {\n"
+" // check if tuple is temp status tuple\n"
+"\n"
+" if (channel == 0) {\n"
+//" if(first_execution_0) return 1;\n"
+" if (timestamp == last_posted_timestamp_0)\n"
+" return 0;\n"
+" else if (timestamp < last_posted_timestamp_0)\n"
+" return -1;\n"
+" else\n"
+" return 1;\n"
+" }\n"
+//" if(first_execution_1) return 1;\n"
+" if (timestamp == last_posted_timestamp_1)\n"
+" return 0;\n"
+" else if (timestamp < last_posted_timestamp_1)\n"
+" return -1;\n"
+" else\n"
+" return 1;\n"
+"\n"
+" }\n"
+;
+
+ ret +=
+" int compare_stored_with_temp_status(const host_tuple& tup0, int channel)/* const*/ {\n"
+;
+ ret+="\t"+dta.make_host_cvar("l_timestamp")+";\n";
+ ret+="\tgs_int32_t problem;\n";
+
+ 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);
+ ret += tmpstr;
+ ret+="\tif (channel == 0) {\n";
+// ret+="\tif(first_execution_0) return 1;\n";
+ ret+=
+" if (l_timestamp == last_posted_timestamp_0)\n"
+" return 0;\n"
+" else if (l_timestamp < last_posted_timestamp_0)\n"
+" return -1;\n"
+" else\n"
+" return 1;\n"
+" }\n";
+// ret+="\tif(first_execution_1) return 1;\n";
+ ret+=
+" if (l_timestamp == last_posted_timestamp_1)\n"
+" return 0;\n"
+" else if (l_timestamp < last_posted_timestamp_1)\n"
+" return -1;\n"
+" else\n"
+" return 1;\n"
+"\n"
+" }\n\n";
+
+
+// update temp status.
+ ret+=
+" int update_temp_status(const host_tuple& tup) {\n"
+" if (tup.channel == 0) {\n"
+" last_posted_timestamp_0=timestamp;\n"
+//" first_execution_0 = false;\n"
+" }else{\n"
+" last_posted_timestamp_1=timestamp;\n"
+//" first_execution_1 = false;\n"
+" }\n"
+" return 0;\n"
+" }\n"
+;
+ ret+=
+" int update_stored_temp_status(const host_tuple& tup, int channel) {\n"
+;
+ ret+="\t"+dta.make_host_cvar("l_timestamp")+";\n";
+ ret+="\tgs_int32_t problem;\n";
+ 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);
+ ret += tmpstr;
+ret+=
+" if (tup.channel == 0) {\n"
+" last_posted_timestamp_0=l_timestamp;\n"
+//" first_execution_0 = false;\n"
+" }else{\n"
+" last_posted_timestamp_1=l_timestamp;\n"
+//" first_execution_1 = false;\n"
+" }\n"
+" return 0;\n"
+" }\n"
+;
+/*
+ ret+="\t"+dta.make_host_cvar("timestamp")+";\n";
+ ret+="\tgs_int32_t problem;\n";
+ ret+="\tif (tup.channel == 0) {\n";
+ 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);
+ ret += tmpstr;
+ ret+="\t}else{\n";
+ 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);
+ ret += tmpstr;
+ ret+="\t}\n";
+ ret+="\tif (tup.channel == 0) {\n";
+ ret+="\tlast_posted_timestamp_0=timestamp;\n";
+ ret +="\tfirst_execution_0 = false;\n";
+ ret+="\t}else{\n";
+ ret+="\tlast_posted_timestamp_1=timestamp;\n";
+ ret +="\tfirst_execution_1 = false;\n";
+ ret+="\t}\n";
+ ret+=
+" }\n\n";
+*/
+
+
+// update temp status modulo slack.
+ ret+="\tint update_temp_status_by_slack(const host_tuple& tup, int channel) {\n";
+ if(slack){
+ ret+="\t"+dta.make_host_cvar("timestamp")+";\n";
+ ret+="\tgs_int32_t problem;\n";
+ ret+="\tif (tup.channel == 0) {\n";
+ sprintf(tmpstr,"\t\ttimestamp = %s_nocheck(tup.data, unpack_offset_%s_%d);\n", unpack_fcna.c_str(), mvars[0]->get_field().c_str(), 0);
+ ret += tmpstr;
+ ret+="\t}else{\n";
+ sprintf(tmpstr,"\t\ttimestamp = %s_nocheck(tup.data, unpack_offset_%s_%d);\n", unpack_fcnb.c_str(), mvars[1]->get_field().c_str(), 1);
+ ret += tmpstr;
+ ret+="\t}\n";
+ret +=
+" if (channel == 0) {\n"
+" if(first_execution_0){\n"
+" last_posted_timestamp_0=timestamp - slack;\n"
+" first_execution_0 = false;\n"
+" }else{\n"
+" if(last_posted_timestamp_0 < timestamp-slack)\n"
+" last_posted_timestamp_0 = timestamp-slack;\n"
+" }\n"
+" }else{\n"
+" if(first_execution_1){\n"
+" last_posted_timestamp_1=timestamp - slack;\n"
+" first_execution_1 = false;\n"
+" }else{\n"
+" if(last_posted_timestamp_1 < timestamp-slack)\n"
+" last_posted_timestamp_1 = timestamp-slack;\n"
+" }\n"
+" }\n"
+" return 0;\n"
+" }\n\n";
+ }else{
+ ret +=
+" return 0;\n"
+" }\n\n";
+ }
+
+
+//
+ ret+=
+"bool temp_status_received(const host_tuple& tup0){\n"
+" return ftaschema_is_temporal_tuple_offset(tuple_metadata_offset0, tup0.data);\n"
+"};\n"
+;
+//"bool temp_status_received(){return temp_tuple_received;};\n\n";
+
+
+// create a temp status tuple
+ ret += "int create_temp_status_tuple(host_tuple& result) {\n\n";
+
+ ret += gen_init_temp_status_tuple(this->get_node_name());
+
+// Start packing.
+ ret += "//\t\tPack the fields into the tuple.\n";
+
+ string fld_name = mvars[0]->get_field();
+ int idx = table_layout->get_field_idx(fld_name);
+ field_entry* fld = table_layout->get_field(idx);
+ data_type dt(fld->get_type());
+
+// if (needs_xform[0] && needs_xform[1] && dt.needs_hn_translation())
+// 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());
+// else
+ sprintf(tmpstr,"\ttuple->tuple_var%d = (last_posted_timestamp_0 < last_posted_timestamp_1 ? last_posted_timestamp_0 : last_posted_timestamp_1);\n",idx);
+
+ ret += tmpstr;
+
+ ret += "\treturn 0;\n";
+ ret += "}\n\n";
+
+// Transform tuple (before output)
+
+
+ ret += "void xform_tuple(host_tuple &tup){\n";
+ if((needs_xform[0] && !needs_xform[1]) || (needs_xform[1] && !needs_xform[0])){
+ ret += "\tstruct "+generate_tuple_name(this->get_node_name())+" *tuple = ("+
+ generate_tuple_name(this->get_node_name())+" *)(tup.data);\n";
+
+ vector<field_entry *> flds = table_layout->get_fields();
+
+ ret+="\tif(tup.channel == 0){\n";
+ if(needs_xform[0] && !needs_xform[1]){
+ int f;
+ for(f=0;f<flds.size();f++){
+ ret.append("\t");
+ data_type dt(flds[f]->get_type());
+ if(dt.get_type() == v_str_t){
+// sprintf(tmpstr,"\ttuple->tuple_var%d.offset = htonl(tuple->tuple_var%d.offset);\n",f,f);
+// ret += tmpstr;
+// sprintf(tmpstr,"\ttuple->tuple_var%d.length = htonl(tuple->tuple_var%d.length);\n",f,f);
+// ret += tmpstr;
+// sprintf(tmpstr,"\ttuple->tuple_var%d.reserved = htonl(tuple->tuple_var%d.reserved);\n",f,f);
+// ret += tmpstr;
+ }else{
+ if(dt.needs_hn_translation()){
+// sprintf(tmpstr,"\ttuple->tuple_var%d = %s(tuple->tuple_var%d);\n",
+// f, dt.hton_translation().c_str(), f);
+// ret += tmpstr;
+ }
+ }
+ }
+ }else{
+ ret += "\t\treturn;\n";
+ }
+ ret.append("\t}\n");
+
+
+ ret+="\tif(tup.channel == 1){\n";
+ if(needs_xform[1] && !needs_xform[0]){
+ int f;
+ for(f=0;f<flds.size();f++){
+ ret.append("\t");
+ data_type dt(flds[f]->get_type());
+ if(dt.get_type() == v_str_t){
+// sprintf(tmpstr,"\ttuple->tuple_var%d.offset = htonl(tuple->tuple_var%d.offset);\n",f,f);
+// ret += tmpstr;
+// sprintf(tmpstr,"\ttuple->tuple_var%d.length = htonl(tuple->tuple_var%d.length);\n",f,f);
+// ret += tmpstr;
+// sprintf(tmpstr,"\ttuple->tuple_var%d.reserved = htonl(tuple->tuple_var%d.reserved);\n",f,f);
+// ret += tmpstr;
+ }else{
+ if(dt.needs_hn_translation()){
+// sprintf(tmpstr,"\ttuple->tuple_var%d = %s(tuple->tuple_var%d);\n",
+// f, dt.hton_translation().c_str(), f);
+// ret += tmpstr;
+ }
+ }
+ }
+ }else{
+ ret += "\t\treturn;\n";
+ }
+ ret.append("\t}\n");
+ }
+
+ ret.append("};\n\n");
+
+// print_warnings() : tell the functor if the user wants to print warnings.
+ ret += "bool print_warnings(){\n";
+ if(definitions.count("print_warnings") && (
+ definitions["print_warnings"] == "yes" ||
+ definitions["print_warnings"] == "Yes" ||
+ definitions["print_warnings"] == "YES" )) {
+ ret += "return true;\n";
+ }else{
+ ret += "return false;\n";
+ }
+ ret.append("};\n\n");
+
+
+// Done with methods.
+ ret+="\n};\n\n";
+
+
+ return(ret);
+}
+
+string mrg_qpn::generate_operator(int i, string params){
+
+ if(disorder < 2){
+ return(
+ " merge_operator<" +
+ generate_functor_name()+
+ "> *op"+int_to_string(i)+" = new merge_operator<"+
+ generate_functor_name()+
+ ">("+params+",10000,\"" + get_node_name() + "\");\n"
+ );
+ }
+ return(
+ " merge_operator_oop<" +
+ generate_functor_name()+
+ "> *op"+int_to_string(i)+" = new merge_operator_oop<"+
+ generate_functor_name()+
+ ">("+params+",10000,\"" + get_node_name() + "\");\n"
+ );
+}
+
+////////////////////////////////////////////////
+/// WATCHLIST_TBL operator
+/// WATCHLIST_TBL functor
+////////////////////////////////////////////
+
+string watch_tbl_qpn::generate_functor_name(){
+ return("watch_tbl_functor_" + normalize_name(this->get_node_name()));
+}
+
+string watch_tbl_qpn::generate_functor(table_list *schema, ext_fcn_list *Ext_fcns, vector<bool> &needs_xform){
+
+ return("ERROR_WATCH_TBL_FUNCTOR_NOT_YET_IMPLEMENTED");
+}
+
+string watch_tbl_qpn::generate_operator(int i, string params){
+ return("ERROR_WATCH_TBL_FUNCTOR_NOT_YET_IMPLEMENTED");
+}
+
+/////////////////////////////////////////////////////////
+////// JOIN_EQ_HASH functor
+
+
+string join_eq_hash_qpn::generate_functor_name(){
+ return("join_eq_hash_functor_" + normalize_name(this->get_node_name()));
+}
+
+string join_eq_hash_qpn::generate_functor(table_list *schema, ext_fcn_list *Ext_fcns, vector<bool> &needs_xform){
+ int p,s;
+ vector<data_type *> hashkey_dt; // data types in the hash key
+ vector<data_type *> temporal_dt; // data types in the temporal key
+ map<string,scalarexp_t *> l_equiv, r_equiv; // field equivalences
+ set<int> pfcn_refs;
+ col_id_set new_cids, local_cids;
+
+//--------------------------------
+// Global init
+
+ string plus_op = "+";
+
+//--------------------------------
+// key definition class
+ string ret = "class " + generate_functor_name() + "_keydef{\n";
+ ret += "public:\n";
+// Collect attributes from hash join predicates.
+// ASSUME equality predicate.
+// Use the upwardly compatible data type
+// (infer from '+' operator if possible, else use left type)
+ for(p=0;p<this->hash_eq.size();++p){
+ scalarexp_t *lse = hash_eq[p]->pr->get_left_se();
+ scalarexp_t *rse = hash_eq[p]->pr->get_right_se();
+ data_type *hdt = new data_type(
+ lse->get_data_type(), rse->get_data_type(), plus_op );
+ if(hdt->get_type() == undefined_t){
+ hashkey_dt.push_back(lse->get_data_type()->duplicate());
+ delete hdt;
+ }else{
+ hashkey_dt.push_back(hdt);
+ }
+ sprintf(tmpstr,"hashkey_var%d",p);
+ ret+="\t"+hashkey_dt[p]->make_host_cvar(tmpstr)+";\n";
+
+// find equivalences
+// NOTE: this code needs to be synched with the temporality
+// checking done at join_eq_hash_qpn::get_fields
+ if(lse->get_operator_type()==SE_COLREF){
+ l_equiv[lse->get_colref()->get_field()] = rse;
+ }
+ if(rse->get_operator_type()==SE_COLREF){
+ r_equiv[rse->get_colref()->get_field()] = lse;
+ }
+ }
+ ret += "\tbool touched;\n";
+
+// Constructors
+ ret += "\t"+generate_functor_name() + "_keydef(){touched=false;};\n";
+// destructor
+ ret += "\t~"+ generate_functor_name() + "_keydef(){\n";
+ for(p=0;p<hashkey_dt.size();p++){
+ if(hashkey_dt[p]->is_buffer_type()){
+ sprintf(tmpstr,"\t\t%s(&hashkey_var%d);\n",
+ hashkey_dt[p]->get_hfta_buffer_destroy().c_str(), p );
+ ret += tmpstr;
+ }
+ }
+ ret += "\t};\n";
+ ret+="\tvoid touch(){touched = true;};\n";
+ ret+="\tbool is_touched(){return touched;};\n";
+ ret +="};\n\n";
+
+
+//--------------------------------
+// temporal equality definition class
+ ret += "class " + generate_functor_name() + "_tempeqdef{\n";
+ ret += "public:\n";
+// Collect attributes from hash join predicates.
+// ASSUME equality predicate.
+// Use the upwardly compatible date type
+// (infer from '+' operator if possible, else use left type)
+ for(p=0;p<this->temporal_eq.size();++p){
+ scalarexp_t *lse = temporal_eq[p]->pr->get_left_se();
+ scalarexp_t *rse = temporal_eq[p]->pr->get_right_se();
+ data_type *hdt = new data_type(
+ lse->get_data_type(), rse->get_data_type(), plus_op );
+ if(hdt->get_type() == undefined_t){
+ temporal_dt.push_back(hash_eq[p]->pr->get_left_se()->get_data_type()->duplicate());
+ delete hdt;
+ }else{
+ temporal_dt.push_back(hdt);
+ }
+ sprintf(tmpstr,"tempeq_var%d",p);
+ ret+="\t"+temporal_dt[p]->make_host_cvar(tmpstr)+";\n";
+// find equivalences
+ if(lse->get_operator_type()==SE_COLREF){
+ l_equiv[lse->get_colref()->get_field()] = rse;
+ }
+ if(rse->get_operator_type()==SE_COLREF){
+ r_equiv[rse->get_colref()->get_field()] = lse;
+ }
+ }
+
+// Constructors
+ ret += "\t"+generate_functor_name() + "_tempeqdef(){};\n";
+// destructor
+ ret += "\t~"+ generate_functor_name() + "_tempeqdef(){\n";
+ for(p=0;p<temporal_dt.size();p++){
+ if(temporal_dt[p]->is_buffer_type()){
+ sprintf(tmpstr,"\t\t%s(&tempeq_var%d);\n",
+ temporal_dt[p]->get_hfta_buffer_destroy().c_str(), p );
+ ret += tmpstr;
+ }
+ }
+ ret += "\t};\n";
+ ret +="};\n\n";
+
+
+//--------------------------------
+// temporal eq, hash join functor class
+ ret += "class " + this->generate_functor_name() + "{\n";
+
+// Find variables referenced in this query node.
+
+ col_id_set cid_set;
+ col_id_set::iterator csi;
+
+ for(p=0;p<where.size();++p)
+ gather_pr_col_ids(where[p]->pr,cid_set,NULL);
+ for(s=0;s<select_list.size();s++)
+ gather_se_col_ids(select_list[s]->se,cid_set,NULL);
+
+// Private variables : store the state of the functor.
+// 1) variables for unpacked attributes
+// 2) offsets of the upacked attributes
+// 3) storage of partial functions
+// 4) storage of complex literals (i.e., require a constructor)
+
+ ret += "private:\n";
+
+ // var to save the schema handles
+ ret += "\tint schema_handle0;\n";
+ ret += "\tint schema_handle1;\n";
+
+ // generate the declaration of all the variables related to
+ // temp tuples generation
+ ret += gen_decl_temp_vars();
+ // tuple metadata offsets
+ ret += "\tint tuple_metadata_offset0, tuple_metadata_offset1;\n";
+
+// unpacked attribute storage, offsets
+ ret += "//\t\tstorage and offsets of accessed fields.\n";
+ ret += generate_access_vars(cid_set, schema);
+
+
+// Variables to store results of partial functions.
+// WARNING find_partial_functions modifies the SE
+// (it marks the partial function id).
+ ret += "//\t\tParital function result storage\n";
+ vector<scalarexp_t *> partial_fcns;
+ vector<int> fcn_ref_cnt;
+ vector<bool> is_partial_fcn;
+ for(s=0;s<select_list.size();s++){
+ find_partial_fcns(select_list[s]->se, &partial_fcns,NULL,NULL, Ext_fcns);
+ }
+ for(p=0;p<where.size();p++){
+ find_partial_fcns_pr(where[p]->pr, &partial_fcns,NULL,NULL, Ext_fcns);
+ }
+ if(partial_fcns.size()>0){
+ ret += "/*\t\tVariables for storing results of partial functions. \t*/\n";
+ ret += generate_partial_fcn_vars(partial_fcns,fcn_ref_cnt,is_partial_fcn,false);
+ }
+
+// Complex literals (i.e., they need constructors)
+ ret += "//\t\tComplex literal storage.\n";
+ cplx_lit_table *complex_literals = this->get_cplx_lit_tbl(Ext_fcns);
+ ret += generate_complex_lit_vars(complex_literals);
+// We need the following to handle strings in outer joins.
+// NEED AN EMPTY LITERAL FOR EAcH STRUCTURED LITERAL
+ ret += "\tstruct vstring EmptyString;\n";
+ ret += "\tstruct hfta_ipv6_str EmptyIp6;\n";
+
+// Pass-by-handle parameters
+ ret += "//\t\tPass-by-handle storage.\n";
+ vector<handle_param_tbl_entry *> param_handle_table = this->get_handle_param_tbl(Ext_fcns);
+ ret += generate_pass_by_handle_vars(param_handle_table);
+
+
+// variables to hold parameters.
+ ret += "//\tfor query parameters\n";
+ ret += generate_param_vars(param_tbl);
+
+
+ ret += "\npublic:\n";
+//-------------------
+// The functor constructor
+// pass in the schema handle.
+// 1) make assignments to the unpack offset variables
+// 2) initialize the complex literals
+
+ ret += "//\t\tFunctor constructor.\n";
+ ret += this->generate_functor_name()+"(int schema_handle0, int schema_handle1){\n";
+
+ ret += "\t\tthis->schema_handle0 = schema_handle0;\n";
+ ret += "\t\tthis->schema_handle1 = schema_handle1;\n";
+// metadata offsets
+ ret += "\ttuple_metadata_offset0 = ftaschema_get_tuple_metadata_offset(schema_handle0);\n";
+ ret += "\ttuple_metadata_offset1 = ftaschema_get_tuple_metadata_offset(schema_handle1);\n";
+
+// unpack vars
+ ret += "//\t\tGet offsets for unpacking fields from input tuple.\n";
+ ret += gen_access_var_init(cid_set);
+
+// complex literals
+ ret += "//\t\tInitialize complex literals.\n";
+ ret += gen_complex_lit_init(complex_literals);
+// Initialize EmptyString to the ... empty string
+// NEED AN EMPTY LITERAL FOR EAcH STRUCTURED LITERAL
+ literal_t mtstr_lit("");
+ ret += "\t" + mtstr_lit.to_hfta_C_code("&EmptyString")+";\n";
+ literal_t mip6_lit("0:0:0:0:0:0:0:0",LITERAL_IPV6);
+ ret += "\t" + mip6_lit.to_hfta_C_code("&EmptyIp6")+";\n";
+
+// Initialize partial function results so they can be safely GC'd
+ ret += gen_partial_fcn_init(partial_fcns);
+
+// Initialize non-query-parameter parameter handles
+ ret += gen_pass_by_handle_init(param_handle_table);
+
+// Init temporal attributes referenced in select list
+ ret += gen_init_temp_vars(schema, select_list, NULL);
+
+
+ ret += "};\n";
+
+
+
+//-------------------
+// Functor destructor
+ ret += "//\t\tFunctor destructor.\n";
+ ret += "~"+this->generate_functor_name()+"(){\n";
+
+// clean up buffer type complex literals
+ ret += gen_complex_lit_dtr(complex_literals);
+
+// Deregister the pass-by-handle parameters
+ ret += "/* register and de-register the pass-by-handle parameters */\n";
+ ret += gen_pass_by_handle_dtr(param_handle_table);
+
+// clean up partial function results.
+ ret += "/* clean up partial function storage */\n";
+ ret += gen_partial_fcn_dtr(partial_fcns);
+
+// Destroy the parameters, if any need to be destroyed
+ ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";
+
+ ret += "};\n\n";
+
+
+//-------------------
+// Parameter manipulation routines
+ ret += generate_load_param_block(this->generate_functor_name(),
+ this->param_tbl,param_handle_table);
+ ret += generate_delete_param_block(this->generate_functor_name(),
+ this->param_tbl,param_handle_table);
+
+//-------------------
+// Register new parameter block
+
+ ret += "int set_param_block(gs_int32_t sz, void* value){\n";
+ ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";
+ ret += "\treturn this->load_params_"+this->generate_functor_name()+
+ "(sz, value);\n";
+ ret += "};\n\n";
+
+
+//-------------------
+// The create_key method.
+// Perform heap allocation.
+// ASSUME : the LHS of the preds reference channel 0 attributes
+// NOTE : it may fail if a partial function fails.
+
+ ret += this->generate_functor_name()+"_keydef *create_key(host_tuple &tup, bool &failed){\n";
+// Variables for execution of the function.
+ ret+="\t"+this->generate_functor_name()+"_keydef *retval = NULL;\n";
+ ret+="\tgs_int32_t problem = 0;\n";
+
+// Assume unsuccessful completion
+ ret+= "\tfailed = true;\n";
+
+// Switch the processing based on the channel
+ ret+="\tif(tup.channel == 0){\n";
+ ret+="// ------------ processing for channel 0\n";
+ ret+="\t\thost_tuple &tup0 = tup;\n";
+// Gather partial fcns and colids ref'd by this branch
+ pfcn_refs.clear();
+ new_cids.clear(); local_cids.clear();
+ for(p=0;p<hash_eq.size();p++){
+ collect_partial_fcns(hash_eq[p]->pr->get_left_se(), pfcn_refs);
+ gather_se_col_ids(hash_eq[p]->pr->get_left_se(),local_cids,NULL);
+ }
+
+// Start by cleaning up partial function results
+ ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";
+ ret += gen_partial_fcn_dtr(partial_fcns,pfcn_refs);
+
+// Evaluate the partial functions
+ ret += gen_full_unpack_partial_fcn(schema, partial_fcns, pfcn_refs,
+ new_cids, NULL, "NULL", needs_xform);
+// test passed -- unpack remaining cids.
+ ret += gen_remaining_colrefs(schema, local_cids, new_cids, "NULL", needs_xform);
+
+// Alloc and load a key object
+ ret += "\t\tretval = new "+this->generate_functor_name()+"_keydef();\n";
+ for(p=0;p<hash_eq.size();p++){
+ data_type *hdt = hash_eq[p]->pr->get_left_se()->get_data_type();
+ if(hdt->is_buffer_type()){
+ string vname = "tmp_keyvar"+int_to_string(p);
+ ret += "\t\t"+hdt->make_host_cvar(vname)+" = "+generate_se_code(hash_eq[p]->pr->get_left_se(),schema)+";\n";
+ ret += "\t\t"+hdt->get_hfta_buffer_assign_copy()+"(&(retval->hashkey_var"+int_to_string(p)+"),&"+vname+");\n";
+ }else{
+ sprintf(tmpstr,"\t\tretval->hashkey_var%d = %s;\n",
+ p,generate_se_code(hash_eq[p]->pr->get_left_se(),schema).c_str() );
+ ret += tmpstr;
+ }
+ }
+ ret += "\t}else{\n";
+
+ ret+="// ------------ processing for channel 1\n";
+ ret+="\t\thost_tuple &tup1 = tup;\n";
+// Gather partial fcns and colids ref'd by this branch
+ pfcn_refs.clear();
+ new_cids.clear(); local_cids.clear();
+ for(p=0;p<hash_eq.size();p++){
+ collect_partial_fcns(hash_eq[p]->pr->get_right_se(), pfcn_refs);
+ gather_se_col_ids(hash_eq[p]->pr->get_right_se(),local_cids,NULL);
+ }
+
+// Start by cleaning up partial function results
+ ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";
+ ret += gen_partial_fcn_dtr(partial_fcns,pfcn_refs);
+
+// Evaluate the partial functions
+ ret += gen_full_unpack_partial_fcn(schema, partial_fcns, pfcn_refs,
+ new_cids, NULL, "NULL", needs_xform);
+
+// test passed -- unpack remaining cids.
+ ret += gen_remaining_colrefs(schema, local_cids, new_cids, "NULL", needs_xform);
+
+// Alloc and load a key object
+ ret += "\t\tretval = new "+this->generate_functor_name()+"_keydef();\n";
+ for(p=0;p<hash_eq.size();p++){
+ data_type *hdt = hash_eq[p]->pr->get_right_se()->get_data_type();
+ if(hdt->is_buffer_type()){
+ string vname = "tmp_keyvar"+int_to_string(p);
+ ret += "\t\t"+hdt->make_host_cvar(vname)+" = "+generate_se_code(hash_eq[p]->pr->get_right_se(),schema)+";\n";
+ ret += "\t\t"+hdt->get_hfta_buffer_assign_copy()+"(&(retval->hashkey_var"+int_to_string(p)+"),&"+vname+");\n";
+ }else{
+ sprintf(tmpstr,"\t\tretval->hashkey_var%d = %s;\n",
+ p,generate_se_code(hash_eq[p]->pr->get_right_se(),schema).c_str() );
+ ret += tmpstr;
+ }
+ }
+ ret += "\t}\n";
+
+ ret += "\tfailed = false;\n";
+ ret += "\t return retval;\n";
+ ret += "}\n";
+
+
+//-------------------
+// The load_ts method.
+// load into an allocated buffer.
+// ASSUME : the LHS of the preds reference channel 0 attributes
+// NOTE : it may fail if a partial function fails.
+// NOTE : cann't handle buffer attributes
+
+ ret += "bool load_ts_from_tup("+this->generate_functor_name()+"_tempeqdef *ts, host_tuple &tup){\n";
+// Variables for execution of the function.
+ ret+="\tgs_int32_t problem = 0;\n";
+
+// Switch the processing based on the channel
+ ret+="\tif(tup.channel == 0){\n";
+ ret+="// ------------ processing for channel 0\n";
+ ret+="\t\thost_tuple &tup0 = tup;\n";
+
+// Gather partial fcns and colids ref'd by this branch
+ pfcn_refs.clear();
+ new_cids.clear(); local_cids.clear();
+ for(p=0;p<temporal_eq.size();p++){
+ collect_partial_fcns(temporal_eq[p]->pr->get_left_se(), pfcn_refs);
+ gather_se_col_ids(temporal_eq[p]->pr->get_left_se(),local_cids,NULL);
+ }
+
+// Start by cleaning up partial function results
+ ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";
+ ret += gen_partial_fcn_dtr(partial_fcns,pfcn_refs);
+
+// Evaluate the partial functions
+ ret += gen_full_unpack_partial_fcn(schema, partial_fcns, pfcn_refs,
+ new_cids, NULL, "false", needs_xform);
+
+// test passed -- unpack remaining cids.
+ ret += gen_remaining_colrefs(schema, local_cids, new_cids, "false", needs_xform);
+
+// load the temporal key object
+ for(p=0;p<temporal_eq.size();p++){
+ sprintf(tmpstr,"\t\tts->tempeq_var%d = %s;\n",
+ p,generate_se_code(temporal_eq[p]->pr->get_left_se(),schema).c_str() );
+ ret += tmpstr;
+ }
+
+ ret += "\t}else{\n";
+
+ ret+="// ------------ processing for channel 1\n";
+ ret+="\t\thost_tuple &tup1 = tup;\n";
+
+// Gather partial fcns and colids ref'd by this branch
+ pfcn_refs.clear();
+ new_cids.clear(); local_cids.clear();
+ for(p=0;p<temporal_eq.size();p++){
+ collect_partial_fcns(temporal_eq[p]->pr->get_right_se(), pfcn_refs);
+ gather_se_col_ids(temporal_eq[p]->pr->get_right_se(),local_cids,NULL);
+ }
+
+// Start by cleaning up partial function results
+ ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";
+ ret += gen_partial_fcn_dtr(partial_fcns,pfcn_refs);
+
+// Evaluate the partial functions
+ ret += gen_full_unpack_partial_fcn(schema, partial_fcns, pfcn_refs,
+ new_cids, NULL, "false", needs_xform);
+
+// test passed -- unpack remaining cids.
+ ret += gen_remaining_colrefs(schema, local_cids, new_cids, "false", needs_xform);
+
+// load the key object
+ for(p=0;p<temporal_eq.size();p++){
+ sprintf(tmpstr,"\t\tts->tempeq_var%d = %s;\n",
+ p,generate_se_code(temporal_eq[p]->pr->get_right_se(),schema).c_str() );
+ ret += tmpstr;
+ }
+
+ ret += "\t}\n";
+
+ ret += "\t return true;\n";
+ ret += "}\n";
+
+
+// ------------------------------
+// Load ts from ts
+// (i.e make a copy)
+
+ ret += "bool load_ts_from_ts("+this->generate_functor_name()+"_tempeqdef *lts,"+this->generate_functor_name()+"_tempeqdef *rts){\n";
+ for(p=0;p<temporal_eq.size();p++){
+ sprintf(tmpstr,"\tlts->tempeq_var%d = rts->tempeq_var%d;\n",p,p);
+ ret += tmpstr;
+ }
+ ret += "}\n";
+
+// -------------------------------------
+// compare_ts_to_ts
+// There should be only one variable to compare.
+// If there is more, assume an arbitrary lexicographic order.
+
+ ret += "int compare_ts_with_ts("+this->generate_functor_name()+"_tempeqdef *lts,"+this->generate_functor_name()+"_tempeqdef *rts){\n";
+ for(p=0;p<temporal_eq.size();p++){
+ sprintf(tmpstr,"\tif(lts->tempeq_var%d < rts->tempeq_var%d) return(-1);\n",p,p);
+ ret += tmpstr;
+ sprintf(tmpstr,"\tif(lts->tempeq_var%d > rts->tempeq_var%d) return(1);\n",p,p);
+ ret += tmpstr;
+ }
+ ret += "\treturn(0);\n";
+ ret += "}\n";
+
+// ------------------------------------------
+// apply_prefilter
+// apply the prefilter
+
+ ret += "bool apply_prefilter(host_tuple &tup){\n";
+
+// Variables for this procedure
+ ret+="\tgs_int32_t problem = 0;\n";
+ ret+="\tgs_retval_t retval;\n";
+
+// Switch the processing based on the channel
+ ret+="\tif(tup.channel == 0){\n";
+ ret+="// ------------ processing for channel 0\n";
+ ret+="\t\thost_tuple &tup0 = tup;\n";
+// Gather partial fcns and colids ref'd by this branch
+ pfcn_refs.clear();
+ new_cids.clear(); local_cids.clear();
+ for(p=0;p<prefilter[0].size();p++){
+ collect_partial_fcns_pr((prefilter[0])[p]->pr, pfcn_refs);
+ }
+
+// Start by cleaning up partial function results
+ ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";
+ ret += gen_partial_fcn_dtr(partial_fcns,pfcn_refs);
+
+ for(p=0;p<(prefilter[0]).size();++p){
+ sprintf(tmpstr,"//\t\tPredicate clause %d.\n",p);
+ ret += tmpstr;
+// Find the set of variables accessed in this CNF elem,
+// but in no previous element.
+ col_id_set new_pr_cids;
+ get_new_pred_cids((prefilter[0])[p]->pr,local_cids,new_pr_cids, NULL);
+// Unpack these values.
+ ret += gen_unpack_cids(schema, new_pr_cids, "false", needs_xform);
+// Find partial fcns ref'd in this cnf element
+ set<int> pr_pfcn_refs;
+ collect_partial_fcns_pr((prefilter[0])[p]->pr, pr_pfcn_refs);
+ ret += gen_unpack_partial_fcn(schema,partial_fcns,pr_pfcn_refs,"false");
+
+ ret += "\t\tif( !("+generate_predicate_code((prefilter[0])[p]->pr,schema)+") ) return(false);\n";
+ }
+ ret += "\t}else{\n";
+ ret+="// ------------ processing for channel 1\n";
+ ret+="\t\thost_tuple &tup1 = tup;\n";
+// Gather partial fcns and colids ref'd by this branch
+ pfcn_refs.clear();
+ new_cids.clear(); local_cids.clear();
+ for(p=0;p<prefilter[1].size();p++){
+ collect_partial_fcns_pr((prefilter[1])[p]->pr, pfcn_refs);
+ }
+
+// Start by cleaning up partial function results
+ ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";
+ ret += gen_partial_fcn_dtr(partial_fcns,pfcn_refs);
+
+ for(p=0;p<(prefilter[1]).size();++p){
+ sprintf(tmpstr,"//\t\tPredicate clause %d.\n",p);
+ ret += tmpstr;
+// Find the set of variables accessed in this CNF elem,
+// but in no previous element.
+ col_id_set pr_new_cids;
+ get_new_pred_cids((prefilter[1])[p]->pr,local_cids, pr_new_cids, NULL);
+// Unpack these values.
+ ret += gen_unpack_cids(schema, pr_new_cids, "false", needs_xform);
+// Find partial fcns ref'd in this cnf element
+ set<int> pr_pfcn_refs;
+ collect_partial_fcns_pr((prefilter[1])[p]->pr, pr_pfcn_refs);
+ ret += gen_unpack_partial_fcn(schema,partial_fcns,pr_pfcn_refs,"false");
+
+ ret += "\t\tif( !("+generate_predicate_code((prefilter[1])[p]->pr,schema)+ ") ) return(false);\n";
+ }
+
+ ret += "\t}\n";
+ ret+="\treturn true;\n";
+ ret += "}\n";
+
+
+// -------------------------------------
+// create_output_tuple
+// If the postfilter on the pair of tuples passes,
+// create an output tuple from the combined information.
+// (Plus, outer join processing)
+
+ ret += "host_tuple create_output_tuple(const host_tuple &tup0, const host_tuple &tup1, bool &failed){\n";
+
+ ret += "\thost_tuple tup;\n";
+ ret += "\tfailed = true;\n";
+ ret += "\tgs_retval_t retval = 0;\n";
+ ret += "\tgs_int32_t problem = 0;\n";
+
+// Start by cleaning up partial function results
+ ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";
+ pfcn_refs.clear();
+ new_cids.clear(); local_cids.clear();
+ for(p=0;p<postfilter.size();p++){
+ collect_partial_fcns_pr(postfilter[p]->pr, pfcn_refs);
+ }
+ for(s=0;s<select_list.size();s++){
+ collect_partial_fcns(select_list[s]->se, pfcn_refs);
+ }
+ ret += gen_partial_fcn_dtr(partial_fcns,pfcn_refs);
+
+
+ ret+="\tif(tup0.data && tup1.data){\n";
+// Evaluate the postfilter
+ new_cids.clear(); local_cids.clear();
+ for(p=0;p<postfilter.size();p++){
+ sprintf(tmpstr,"//\t\tPredicate clause %d.\n",p);
+ ret += tmpstr;
+// Find the set of variables accessed in this CNF elem,
+// but in no previous element.
+ col_id_set pr_new_cids;
+ get_new_pred_cids(postfilter[p]->pr,local_cids, pr_new_cids, NULL);
+// Unpack these values.
+ ret += gen_unpack_cids(schema, pr_new_cids, "tup", needs_xform);
+// Find partial fcns ref'd in this cnf element
+ set<int> pr_pfcn_refs;
+ collect_partial_fcns_pr(postfilter[p]->pr, pr_pfcn_refs);
+ ret += gen_unpack_partial_fcn(schema,partial_fcns,pr_pfcn_refs,"tup");
+
+ ret += "\t\tif( !("+generate_predicate_code(postfilter[p]->pr,schema)+ ") ) return(tup);\n";
+ }
+
+
+// postfilter passed, evaluate partial functions for select list
+
+ set<int> sl_pfcns;
+ col_id_set se_cids;
+ for(s=0;s<select_list.size();s++){
+ collect_partial_fcns(select_list[s]->se, sl_pfcns);
+ }
+
+ if(sl_pfcns.size() > 0)
+ ret += "//\t\tUnpack remaining partial fcns.\n";
+ ret += gen_full_unpack_partial_fcn(schema, partial_fcns, sl_pfcns,
+ local_cids, NULL, "tup", needs_xform);
+
+// Unpack remaining fields
+ ret += "//\t\tunpack any remaining fields from the input tuples.\n";
+ for(s=0;s<select_list.size();s++)
+ get_new_se_cids(select_list[s]->se, local_cids,se_cids,NULL);
+ ret += gen_unpack_cids(schema, se_cids,"tup", needs_xform);
+
+
+// Deal with outer join stuff
+ col_id_set l_cids, r_cids;
+ col_id_set l_base_cids, r_base_cids; // l_cids and r_cids get modified
+ // to account for extra_f fields to
+ // unpack for value imputation
+ col_id_set::iterator ocsi;
+ for(ocsi=local_cids.begin();ocsi!=local_cids.end();++ocsi){
+ if((*ocsi).tblvar_ref == 0){
+ l_cids.insert((*ocsi)); l_base_cids.insert((*ocsi));
+ }else{
+ r_cids.insert((*ocsi)); r_base_cids.insert((*ocsi));
+ }
+ }
+ for(ocsi=se_cids.begin();ocsi!=se_cids.end();++ocsi){
+ if((*ocsi).tblvar_ref == 0){
+ l_cids.insert((*ocsi)); l_base_cids.insert((*ocsi));
+ }else{
+ r_cids.insert((*ocsi)); r_base_cids.insert((*ocsi));
+ }
+ }
+
+ ret += "\t}else if(tup0.data){\n";
+ string unpack_null = ""; col_id_set extra_cids;
+ for(ocsi=r_base_cids.begin();ocsi!=r_base_cids.end();++ocsi){
+ string field = (*ocsi).field;
+ if(r_equiv.count(field)){
+ unpack_null+="\t\tunpack_var_"+field+"_1="+generate_se_code(r_equiv[field],schema)+"; // r_equiv\n";
+ get_new_se_cids(r_equiv[field],l_cids,new_cids,NULL);
+ }else{
+ int schref = (*ocsi).schema_ref;
+ data_type dt(schema->get_type_name(schref,field));
+ literal_t empty_lit(dt.type_indicator());
+ if(empty_lit.is_cpx_lit()){
+// sprintf(tmpstr,"&(unpack_var_%s_1)",field.c_str());
+// unpack_null += "\t"+empty_lit.to_hfta_C_code(tmpstr)+";\n";
+// NB : works for string type only
+// NNB: installed fix for ipv6, more of this should be pushed
+// into the literal_t code.
+ unpack_null+="\t\tunpack_var_"+field+"_1= "+empty_lit.hfta_empty_literal_name()+"; // empty\n";
+ }else{
+ unpack_null+="\t\tunpack_var_"+field+"_1="+empty_lit.to_hfta_C_code("")+"; // empty\n";
+ }
+ }
+ }
+ ret += "// l_cids\n";
+ ret += gen_unpack_cids(schema, l_cids, "tup", needs_xform);
+ ret += "// extra_cids\n";
+ ret += gen_unpack_cids(schema, extra_cids, "tup", needs_xform);
+ ret += unpack_null;
+ ret += gen_unpack_partial_fcn(schema, partial_fcns, sl_pfcns, "tup");
+
+ ret+="\t}else{\n";
+ unpack_null = ""; extra_cids.clear(); new_cids.clear();
+ for(ocsi=l_base_cids.begin();ocsi!=l_base_cids.end();++ocsi){
+ string field = (*ocsi).field;
+ if(l_equiv.count(field)){
+ unpack_null+="\t\tunpack_var_"+field+"_0="+generate_se_code(l_equiv[field],schema)+"; // l_equiv\n";
+ get_new_se_cids(l_equiv[field],r_cids,new_cids,NULL);
+ }else{
+ int schref = (*ocsi).schema_ref;
+ data_type dt(schema->get_type_name(schref,field));
+ literal_t empty_lit(dt.type_indicator());
+ if(empty_lit.is_cpx_lit()){
+// sprintf(tmpstr,"&(unpack_var_%s_0)",field.c_str());
+// unpack_null += "\t"+empty_lit.to_hfta_C_code(tmpstr)+";\n";
+// NB : works for string type only
+// NNB: installed fix for ipv6, more of this should be pushed
+// into the literal_t code.
+ unpack_null+="\t\tunpack_var_"+field+"_0= "+empty_lit.hfta_empty_literal_name()+"; // empty\n";
+ }else{
+ unpack_null+="\t\tunpack_var_"+field+"_0="+empty_lit.to_hfta_C_code("")+"; // empty\n";
+ }
+ }
+ }
+ ret += "// r_cids\n";
+ ret += gen_unpack_cids(schema, r_cids, "tup", needs_xform);
+ ret += "// extra_cids\n";
+ ret += gen_unpack_cids(schema, extra_cids, "tup", needs_xform);
+ ret += unpack_null;
+ ret += gen_unpack_partial_fcn(schema, partial_fcns, sl_pfcns, "tup");
+ ret+="\t}\n";
+
+
+
+// Unpack any BUFFER type selections into temporaries
+// so that I can compute their size and not have
+// to recompute their value during tuple packing.
+// I can use regular assignment here because
+// these temporaries are non-persistent.
+
+ ret += "//\t\tCompute the size of the tuple.\n";
+ ret += "//\t\t\tNote: buffer storage packed at the end of the tuple.\n";
+
+// Unpack all buffer type selections, to be able to compute their size
+ ret += gen_buffer_selvars(schema, select_list);
+
+// The size of the tuple is the size of the tuple struct plus the
+// size of the buffers to be copied in.
+
+ ret+="\ttup.tuple_size = sizeof(" + generate_tuple_name( this->get_node_name()) +") + sizeof(gs_uint8_t)";
+ ret += gen_buffer_selvars_size(select_list,schema);
+ ret.append(";\n");
+
+// Allocate tuple data block.
+ ret += "//\t\tCreate the tuple block.\n";
+ ret += "\ttup.data = malloc(tup.tuple_size);\n";
+ ret += "\ttup.heap_resident = true;\n";
+// ret += "\ttup.channel = 0;\n";
+
+// Mark tuple as regular
+ ret += "\t*((gs_sp_t )tup.data + sizeof(" + generate_tuple_name( this->get_node_name()) +")) = REGULAR_TUPLE;\n";
+
+
+ ret += "\t"+generate_tuple_name( this->get_node_name())+" *tuple = ("+
+ generate_tuple_name( this->get_node_name())+" *)(tup.data);\n";
+
+// Start packing.
+// (Here, offsets are hard-wired. is this a problem?)
+
+ ret += "//\t\tPack the fields into the tuple.\n";
+ ret += gen_pack_tuple(schema,select_list,this->get_node_name(), false );
+
+// Delete string temporaries
+ ret += gen_buffer_selvars_dtr(select_list);
+
+ ret += "\tfailed = false;\n";
+ ret += "\treturn tup;\n";
+ ret += "};\n";
+
+
+
+//-----------------------------
+// Method for checking whether tuple is temporal
+
+ ret += "bool temp_status_received(host_tuple &tup){\n";
+
+// Switch the processing based on the channel
+ ret+="\tif(tup.channel == 0){\n";
+ ret+="\t\thost_tuple &tup0 = tup;\n";
+ ret += gen_temp_tuple_check(this->node_name, 0);
+ ret += "\t}else{\n";
+ ret+="\t\thost_tuple &tup1 = tup;\n";
+ ret += gen_temp_tuple_check(this->node_name, 1);
+ ret += "\t}\n";
+ ret += "\treturn temp_tuple_received;\n};\n\n";
+
+
+//-------------------------------------------------------------------
+// Temporal update functions
+
+
+// create a temp status tuple
+ ret += "int create_temp_status_tuple("+this->generate_functor_name()+"_tempeqdef *lts,"+this->generate_functor_name()+"_tempeqdef *rts, host_tuple& result) {\n\n";
+
+ ret += "\tgs_retval_t retval = 0;\n";
+ ret += "\tgs_int32_t problem = 0;\n";
+
+ for(p=0;p<temporal_dt.size();p++){
+ sprintf(tmpstr,"lhs_var");
+ ret+="\t"+temporal_dt[p]->make_host_cvar(tmpstr)+";\n";
+ sprintf(tmpstr,"rhs_var");
+ ret+="\t"+temporal_dt[p]->make_host_cvar(tmpstr)+";\n";
+ }
+
+ ret += "\tif(lts!=NULL){\n";
+ for(p=0;p<temporal_dt.size();p++){
+ ret += "\t\tlhs_var = lts->tempeq_var"+to_string(p)+";\n";
+ }
+ ret += "\t}else{\n";
+ for(p=0;p<temporal_dt.size();p++){
+ ret += "\t\tlhs_var = 0;\n";
+ }
+ ret += "\t}\n";
+
+ ret += "\tif(rts!=NULL){\n";
+ for(p=0;p<temporal_dt.size();p++){
+ ret += "\t\trhs_var = rts->tempeq_var"+to_string(p)+";\n";
+ }
+ ret += "\t}else{\n";
+ for(p=0;p<temporal_dt.size();p++){
+ ret += "\t\trhs_var = 0;\n";
+ }
+ ret += "\t}\n";
+
+ ret += gen_init_temp_status_tuple(this->get_node_name());
+
+// Start packing.
+
+
+// This is checked in the query analyzer so I think its safe,
+// But a lot of older code has complex code to propagate multiple
+// timestamps
+ for(s=0;s<select_list.size();s++){
+ scalarexp_t *se = select_list[s]->se;
+ data_type *sdt = se->get_data_type();
+ if(sdt->is_temporal()){
+ string target = "\ttuple->tuple_var"+to_string(s)+" = ";
+ if(from[0]->get_property()==0 && from[1]->get_property()==0){ // INNER
+ ret += target+"(lhs_var>rhs_var ? lhs_var : rhs_var); // INNER\n";
+ }
+ if(from[0]->get_property()!=0 && from[1]->get_property()==0){ // LEFT
+ ret += target+"lhs_var; // LEFT\n";
+// ret += target+"rhs_var; // LEFT\n";
+ }
+ if(from[0]->get_property()==0 && from[1]->get_property()!=0){ // RIGHT
+ ret += target+"rhs_var; // RIGHT\n";
+// ret += target+"lhs_var; // RIGHT\n";
+ }
+ if(from[0]->get_property()!=0 && from[1]->get_property()!=0){ // OUTER
+ ret += target+"(lhs_var<rhs_var ? lhs_var : rhs_var); // OUTER\n";
+ }
+ }
+ }
+
+
+ ret += "\treturn 0;\n";
+ ret += "};\n\n";
+
+
+ ret += "};\n\n\n";
+
+//----------------------------------------------------------
+// The hash function
+
+ ret += "struct "+generate_functor_name()+"_hash_func{\n";
+ ret += "\tgs_uint32_t operator()(const "+generate_functor_name()+
+ "_keydef *key) const{\n";
+ ret += "\t\treturn( (";
+ if(hashkey_dt.size() > 0){
+ for(p=0;p<hashkey_dt.size();p++){
+ if(p>0) ret += "^";
+ if(hashkey_dt[p]->use_hashfunc()){
+// sprintf(tmpstr,"%s(&(key->hashkey_var%d))",hashkey_dt[p]->get_hfta_hashfunc().c_str(),p);
+ if(hashkey_dt[p]->is_buffer_type())
+ sprintf(tmpstr,"(%s*%s(&(key->hashkey_var%d)))",hash_nums[p%NRANDS].c_str(),hashkey_dt[p]->get_hfta_hashfunc().c_str(),p);
+ else
+ sprintf(tmpstr,"(%s*%s(key->hashkey_var%d))",hash_nums[p%NRANDS].c_str(),hashkey_dt[p]->get_hfta_hashfunc().c_str(),p);
+ }else{
+ sprintf(tmpstr,"(%s*key->hashkey_var%d)",hash_nums[p%NRANDS].c_str(),p);
+ }
+ ret += tmpstr;
+ }
+ }else{
+ ret += "0";
+ }
+ ret += ") >> 32);\n";
+ ret += "\t}\n";
+ ret += "};\n\n";
+
+//----------------------------------------------------------
+// The comparison function
+
+ ret += "struct "+generate_functor_name()+"_equal_func{\n";
+ ret += "\tbool operator()(const "+generate_functor_name()+"_keydef *key1, "+
+ generate_functor_name()+"_keydef *key2) const{\n";
+ ret += "\t\treturn( (";
+ if(hashkey_dt.size() > 0){
+ for(p=0;p<hashkey_dt.size();p++){
+ if(p>0) ret += ") && (";
+ if(hashkey_dt[p]->complex_comparison(hashkey_dt[p])){
+ if(hashkey_dt[p]->is_buffer_type())
+ sprintf(tmpstr,"(%s(&(key1->hashkey_var%d), &(key2->hashkey_var%d))==0)",
+ hashkey_dt[p]->get_hfta_equals_fcn(hashkey_dt[p]).c_str(),p,p);
+ else
+ sprintf(tmpstr,"(%s((key1->hashkey_var%d), (key2->hashkey_var%d))==0)",
+ hashkey_dt[p]->get_hfta_equals_fcn(hashkey_dt[p]).c_str(),p,p);
+ }else{
+ sprintf(tmpstr,"key1->hashkey_var%d == key2->hashkey_var%d",p,p);
+ }
+ ret += tmpstr;
+ }
+ }else{
+ ret += "1";
+ }
+ ret += ") );\n";
+ ret += "\t}\n";
+ ret += "};\n\n";
+
+
+ return(ret);
+}
+
+
+
+string join_eq_hash_qpn::generate_operator(int i, string params){
+
+ return(
+ " join_eq_hash_operator<" +
+ generate_functor_name()+ ","+
+ generate_functor_name() + "_tempeqdef,"+
+ generate_functor_name() + "_keydef,"+
+ generate_functor_name()+"_hash_func,"+
+ generate_functor_name()+"_equal_func"
+ "> *op"+int_to_string(i)+" = new join_eq_hash_operator<"+
+ generate_functor_name()+","+
+ generate_functor_name() + "_tempeqdef,"+
+ generate_functor_name() + "_keydef,"+
+ generate_functor_name()+"_hash_func,"+
+ generate_functor_name()+"_equal_func"
+ ">("+params+", "+
+ int_to_string(from[0]->get_property()+2*from[1]->get_property())+", \"" + get_node_name() +
+"\");\n"
+ );
+}
+
+
+
+////////////////////////////////////////////////////////////////
+//// SGAHCWCB functor
+
+
+
+string sgahcwcb_qpn::generate_functor_name(){
+ return("sgahcwcb_functor_" + normalize_name(this->get_node_name()));
+}
+
+
+string sgahcwcb_qpn::generate_functor(table_list *schema, ext_fcn_list *Ext_fcns, vector<bool> &needs_xform){
+ int a,g,w,s;
+
+
+// Initialize generate utility globals
+ segen_gb_tbl = &(gb_tbl);
+
+
+//--------------------------------
+// group definition class
+ string ret = "class " + generate_functor_name() + "_groupdef{\n";
+ ret += "public:\n";
+ ret += "\tbool valid;\n";
+ for(g=0;g<this->gb_tbl.size();g++){
+ sprintf(tmpstr,"gb_var%d",g);
+ ret+="\t"+this->gb_tbl.get_data_type(g)->make_host_cvar(tmpstr)+";\n";
+ }
+// Constructors
+ ret += "\t"+generate_functor_name() + "_groupdef(){valid=true;};\n";
+ ret += "\t"+generate_functor_name() + "_groupdef("+
+ this->generate_functor_name() + "_groupdef *gd){\n";
+ for(g=0;g<gb_tbl.size();g++){
+ data_type *gdt = gb_tbl.get_data_type(g);
+ if(gdt->is_buffer_type()){
+ sprintf(tmpstr,"\t\t%s(&gb_var%d, &(gd->gb_var%d));\n",
+ gdt->get_hfta_buffer_assign_copy().c_str(),g,g );
+ ret += tmpstr;
+ }else{
+ sprintf(tmpstr,"\t\tgb_var%d = gd->gb_var%d;\n",g,g);
+ ret += tmpstr;
+ }
+ }
+ ret += "\tvalid=true;\n";
+ ret += "\t};\n";
+// destructor
+ ret += "\t~"+ generate_functor_name() + "_groupdef(){\n";
+ for(g=0;g<gb_tbl.size();g++){
+ data_type *gdt = gb_tbl.get_data_type(g);
+ if(gdt->is_buffer_type()){
+ sprintf(tmpstr,"\t\t%s(&gb_var%d);\n",
+ gdt->get_hfta_buffer_destroy().c_str(), g );
+ ret += tmpstr;
+ }
+ }
+ ret += "\t};\n";
+ ret +="};\n\n";
+
+//--------------------------------
+// aggr definition class
+ ret += "class " + this->generate_functor_name() + "_aggrdef{\n";
+ ret += "public:\n";
+ for(a=0;a<aggr_tbl.size();a++){
+aggr_table_entry *ate = aggr_tbl.agr_tbl[a];
+ sprintf(tmpstr,"aggr_var%d",a);
+ if(aggr_tbl.is_builtin(a))
+ ret+="\t"+ aggr_tbl.get_data_type(a)->make_host_cvar(tmpstr)+";\n";
+ else
+ ret+="\t"+ aggr_tbl.get_storage_type(a)->make_host_cvar(tmpstr)+";\n";
+ }
+// Constructors
+ ret += "\t"+this->generate_functor_name() + "_aggrdef(){};\n";
+// destructor
+ ret += "\t~"+this->generate_functor_name() + "_aggrdef(){\n";
+ for(a=0;a<aggr_tbl.size();a++){
+aggr_table_entry *ate = aggr_tbl.agr_tbl[a];
+ if(aggr_tbl.is_builtin(a)){
+ data_type *adt = aggr_tbl.get_data_type(a);
+ if(adt->is_buffer_type()){
+ sprintf(tmpstr,"\t\t%s(&aggr_var%d);\n",
+ adt->get_hfta_buffer_destroy().c_str(), a );
+ ret += tmpstr;
+ }
+ }else{
+ ret+="\t\t"+aggr_tbl.get_op(a)+"_HFTA_AGGR_DESTROY_(";
+ if(aggr_tbl.get_storage_type(a)->get_type() != fstring_t) ret+="&";
+ ret+="(aggr_var"+int_to_string(a)+"));\n";
+ }
+ }
+ ret += "\t};\n";
+ ret +="};\n\n";
+
+//--------------------------------
+// superaggr definition class
+ ret += "class " + this->generate_functor_name() + "_statedef{\n";
+ ret += "public:\n";
+ for(a=0;a<aggr_tbl.size();a++){
+aggr_table_entry *ate = aggr_tbl.agr_tbl[a];
+ if(ate->is_superaggr()){
+ sprintf(tmpstr,"aggr_var%d",a);
+ if(aggr_tbl.is_builtin(a))
+ ret+="\t"+ aggr_tbl.get_data_type(a)->make_host_cvar(tmpstr)+";\n";
+ else
+ ret+="\t"+ aggr_tbl.get_storage_type(a)->make_host_cvar(tmpstr)+";\n";
+ }
+ }
+ set<string>::iterator ssi;
+ for(ssi=states_refd.begin(); ssi!=states_refd.end(); ++ssi){
+ string state_nm = (*ssi);
+ int state_id = Ext_fcns->lookup_state(state_nm);
+ data_type *dt = Ext_fcns->get_storage_dt(state_id);
+ string state_var = "state_var_"+state_nm;
+ ret += "\t"+dt->make_host_cvar(state_var)+";\n";
+ }
+// Constructors
+ ret += "\t"+this->generate_functor_name() + "_statedef(){};\n";
+// destructor
+ ret += "\t~"+this->generate_functor_name() + "_statedef(){\n";
+ for(a=0;a<aggr_tbl.size();a++){
+aggr_table_entry *ate = aggr_tbl.agr_tbl[a];
+ if(ate->is_superaggr()){
+ if(aggr_tbl.is_builtin(a)){
+ data_type *adt = aggr_tbl.get_data_type(a);
+ if(adt->is_buffer_type()){
+ sprintf(tmpstr,"\t\t%s(&aggr_var%d);\n",
+ adt->get_hfta_buffer_destroy().c_str(), a );
+ ret += tmpstr;
+ }
+ }else{
+ ret+="\t\t"+aggr_tbl.get_op(a)+"_HFTA_AGGR_DESTROY_(";
+ if(aggr_tbl.get_storage_type(a)->get_type() != fstring_t) ret+="&";
+ ret+="(aggr_var"+int_to_string(a)+"));\n";
+ }
+ }
+ }
+ for(ssi=states_refd.begin(); ssi!=states_refd.end(); ++ssi){
+ string state_nm = (*ssi);
+ int state_id = Ext_fcns->lookup_state(state_nm);
+ string state_var = "state_var_"+state_nm;
+ ret += "\t_sfun_state_destroy_"+state_nm+"(&"+state_var+");\n";
+ }
+
+ ret += "\t};\n";
+ ret +="};\n\n";
+
+
+//--------------------------------
+// gb functor class
+ ret += "class " + this->generate_functor_name() + "{\n";
+
+// Find variables referenced in this query node.
+
+ col_id_set cid_set;
+ col_id_set::iterator csi;
+
+ for(w=0;w<where.size();++w)
+ gather_pr_col_ids(where[w]->pr,cid_set,segen_gb_tbl);
+ for(w=0;w<having.size();++w)
+ gather_pr_col_ids(having[w]->pr,cid_set,segen_gb_tbl);
+ for(w=0;w<cleanby.size();++w)
+ gather_pr_col_ids(cleanby[w]->pr,cid_set,segen_gb_tbl);
+ for(w=0;w<cleanwhen.size();++w)
+ gather_pr_col_ids(cleanwhen[w]->pr,cid_set,segen_gb_tbl);
+ for(g=0;g<gb_tbl.size();g++)
+ gather_se_col_ids(gb_tbl.get_def(g),cid_set,segen_gb_tbl);
+
+ for(s=0;s<select_list.size();s++){
+ gather_se_col_ids(select_list[s]->se,cid_set,segen_gb_tbl); // descends into aggregates
+ }
+
+
+// Private variables : store the state of the functor.
+// 1) variables for unpacked attributes
+// 2) offsets of the upacked attributes
+// 3) storage of partial functions
+// 4) storage of complex literals (i.e., require a constructor)
+
+ ret += "private:\n";
+
+ // var to save the schema handle
+ ret += "\tint schema_handle0;\n";
+
+ // generate the declaration of all the variables related to
+ // temp tuples generation
+ ret += gen_decl_temp_vars();
+
+// unpacked attribute storage, offsets
+ ret += "//\t\tstorage and offsets of accessed fields.\n";
+ ret += generate_access_vars(cid_set, schema);
+// tuple metadata offset
+ ret += "\ttuple_metadata_offset0;\n";
+
+// Variables to store results of partial functions.
+// WARNING find_partial_functions modifies the SE
+// (it marks the partial function id).
+ ret += "//\t\tParital function result storage\n";
+ vector<scalarexp_t *> partial_fcns;
+ vector<int> fcn_ref_cnt;
+ vector<bool> is_partial_fcn;
+ for(s=0;s<select_list.size();s++){
+ find_partial_fcns(select_list[s]->se, &partial_fcns, NULL,NULL, Ext_fcns);
+ }
+ for(w=0;w<where.size();w++){
+ find_partial_fcns_pr(where[w]->pr, &partial_fcns, NULL,NULL, Ext_fcns);
+ }
+ for(w=0;w<having.size();w++){
+ find_partial_fcns_pr(having[w]->pr, &partial_fcns, NULL,NULL, Ext_fcns);
+ }
+ for(w=0;w<cleanby.size();w++){
+ find_partial_fcns_pr(cleanby[w]->pr, &partial_fcns, NULL,NULL, Ext_fcns);
+ }
+ for(w=0;w<cleanwhen.size();w++){
+ find_partial_fcns_pr(cleanwhen[w]->pr, &partial_fcns, NULL,NULL, Ext_fcns);
+ }
+ for(g=0;g<gb_tbl.size();g++){
+ find_partial_fcns(gb_tbl.get_def(g), &partial_fcns, NULL,NULL, Ext_fcns);
+ }
+ for(a=0;a<aggr_tbl.size();a++){
+ find_partial_fcns(aggr_tbl.get_aggr_se(a), &partial_fcns, NULL,NULL, Ext_fcns);
+ }
+ if(partial_fcns.size()>0){
+ ret += "/*\t\tVariables for storing results of partial functions. \t*/\n";
+ ret += generate_partial_fcn_vars(partial_fcns,fcn_ref_cnt,is_partial_fcn,false);
+ }
+
+// Complex literals (i.e., they need constructors)
+ ret += "//\t\tComplex literal storage.\n";
+ cplx_lit_table *complex_literals = this->get_cplx_lit_tbl(Ext_fcns);
+ ret += generate_complex_lit_vars(complex_literals);
+
+// Pass-by-handle parameters
+ ret += "//\t\tPass-by-handle storage.\n";
+ vector<handle_param_tbl_entry *> param_handle_table = this->get_handle_param_tbl(Ext_fcns);
+ ret += generate_pass_by_handle_vars(param_handle_table);
+
+// Create cached temporaries for UDAF return values.
+ ret += "//\t\tTemporaries for UDAF return values.\n";
+ for(a=0;a<aggr_tbl.size();a++){
+ if(! aggr_tbl.is_builtin(a)){
+ int afcn_id = aggr_tbl.get_fcn_id(a);
+ data_type *adt = Ext_fcns->get_fcn_dt(afcn_id);
+ sprintf(tmpstr,"udaf_ret_%d", a);
+ ret+="\t"+adt->make_host_cvar(tmpstr)+";\n";
+ }
+ }
+
+
+
+// variables to hold parameters.
+ ret += "//\tfor query parameters\n";
+ ret += generate_param_vars(param_tbl);
+
+// Is there a temporal flush? If so create flush temporaries,
+// create flush indicator.
+ bool uses_temporal_flush = false;
+ for(g=0;g<gb_tbl.size();g++){
+ data_type *gdt = gb_tbl.get_data_type(g);
+ if(gdt->is_temporal())
+ uses_temporal_flush = true;
+ }
+
+ if(uses_temporal_flush){
+ ret += "//\t\tFor temporal flush\n";
+ for(g=0;g<gb_tbl.size();g++){
+ data_type *gdt = gb_tbl.get_data_type(g);
+ if(gdt->is_temporal()){
+ sprintf(tmpstr,"last_gb%d",g);
+ ret+="\t"+gb_tbl.get_data_type(g)->make_host_cvar(tmpstr)+";\n";
+ sprintf(tmpstr,"last_flushed_gb%d",g);
+ ret+="\t"+gb_tbl.get_data_type(g)->make_host_cvar(tmpstr)+";\n";
+ }
+ }
+ ret += "\tbool needs_temporal_flush;\n";
+ }
+
+// The publicly exposed functions
+
+ ret += "\npublic:\n";
+
+
+//-------------------
+// The functor constructor
+// pass in the schema handle.
+// 1) make assignments to the unpack offset variables
+// 2) initialize the complex literals
+
+ ret += "//\t\tFunctor constructor.\n";
+ ret += this->generate_functor_name()+"(int schema_handle0){\n";
+
+ // save the schema handle
+ ret += "\t\tthis->schema_handle0 = schema_handle0;\n";
+// tuple metadata offset
+ ret += "\ttuple_metadata_offset0 = ftaschema_get_tuple_metadata_offset(schema_handle0);\n";
+
+// unpack vars
+ ret += "//\t\tGet offsets for unpacking fields from input tuple.\n";
+ ret += gen_access_var_init(cid_set);
+
+// aggregate return vals : refd in both final_sample
+// and create_output_tuple
+// Create cached temporaries for UDAF return values.
+ for(a=0;a<aggr_tbl.size();a++){
+ if(! aggr_tbl.is_builtin(a)){
+ int afcn_id = aggr_tbl.get_fcn_id(a);
+ data_type *adt = Ext_fcns->get_fcn_dt(afcn_id);
+ sprintf(tmpstr,"udaf_ret_%d", a);
+ ret+="\t"+adt->make_host_cvar(tmpstr)+";\n";
+ }
+ }
+
+// complex literals
+ ret += "//\t\tInitialize complex literals.\n";
+ ret += gen_complex_lit_init(complex_literals);
+
+// Initialize partial function results so they can be safely GC'd
+ ret += gen_partial_fcn_init(partial_fcns);
+
+// Initialize non-query-parameter parameter handles
+ ret += gen_pass_by_handle_init(param_handle_table);
+
+// temporal flush variables
+// ASSUME that structured values won't be temporal.
+ if(uses_temporal_flush){
+ ret += "//\t\tInitialize temporal flush variables.\n";
+ for(g=0;g<gb_tbl.size();g++){
+ data_type *gdt = gb_tbl.get_data_type(g);
+ if(gdt->is_temporal()){
+ literal_t gl(gdt->type_indicator());
+ sprintf(tmpstr,"\tlast_gb%d = %s;\n",g, gl.to_hfta_C_code("").c_str());
+ ret.append(tmpstr);
+ }
+ }
+ ret += "\tneeds_temporal_flush = false;\n";
+ }
+
+ // Init temporal attributes referenced in select list
+ ret += gen_init_temp_vars(schema, select_list, segen_gb_tbl);
+
+ ret += "};\n";
+
+
+//-------------------
+// Functor destructor
+ ret += "//\t\tFunctor destructor.\n";
+ ret += "~"+this->generate_functor_name()+"(){\n";
+
+// clean up buffer type complex literals
+ ret += gen_complex_lit_dtr(complex_literals);
+
+// Deregister the pass-by-handle parameters
+ ret += "/* register and de-register the pass-by-handle parameters */\n";
+ ret += gen_pass_by_handle_dtr(param_handle_table);
+
+// clean up partial function results.
+ ret += "/* clean up partial function storage */\n";
+ ret += gen_partial_fcn_dtr(partial_fcns);
+
+// Destroy the parameters, if any need to be destroyed
+ ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";
+
+ ret += "};\n\n";
+
+
+//-------------------
+// Parameter manipulation routines
+ ret += generate_load_param_block(this->generate_functor_name(),
+ this->param_tbl,param_handle_table);
+ ret += generate_delete_param_block(this->generate_functor_name(),
+ this->param_tbl,param_handle_table);
+
+//-------------------
+// Register new parameter block
+
+ ret += "int set_param_block(gs_int32_t sz, void* value){\n";
+ ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";
+ ret += "\treturn this->load_params_"+this->generate_functor_name()+
+ "(sz, value);\n";
+ ret += "};\n\n";
+
+//-------------------
+// the create_group method.
+// This method creates a group in a buffer passed in
+// (to allow for creation on the stack).
+// There are also a couple of side effects:
+// 1) evaluate the WHERE clause (and therefore, unpack all partial fcns)
+// 2) determine if a temporal flush is required.
+
+ ret += this->generate_functor_name()+"_groupdef *create_group(host_tuple &tup0, gs_sp_t buffer){\n";
+ // Variables for execution of the function.
+ ret += "\tgs_int32_t problem = 0;\n"; // return unpack failure
+
+ if(partial_fcns.size()>0){ // partial fcn access failure
+ ret += "\tgs_retval_t retval = 0;\n";
+ ret += "\n";
+ }
+// return value
+ ret += "\t"+generate_functor_name()+"_groupdef *gbval = ("+generate_functor_name()+
+ "_groupdef *) buffer;\n";
+
+// Start by cleaning up partial function results
+ ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";
+
+ set<int> gb_pfcns; // partial fcns in gbdefs, aggr se's
+ for(g=0;g<gb_tbl.size();g++){
+ collect_partial_fcns(gb_tbl.get_def(g), gb_pfcns);
+ }
+ ret += gen_partial_fcn_dtr(partial_fcns,gb_pfcns);
+// ret += gen_partial_fcn_dtr(partial_fcns);
+
+
+ ret += gen_temp_tuple_check(this->node_name, 0);
+ col_id_set found_cids; // colrefs unpacked thus far.
+ ret += gen_unpack_temp_vars(schema, found_cids, select_list, segen_gb_tbl, needs_xform);
+
+
+
+// Save temporal group-by variables
+
+
+ ret.append("\n\t//\t\tCompute temporal groupby attributes\n\n");
+
+ for(g=0;g<gb_tbl.size();g++){
+
+ data_type *gdt = gb_tbl.get_data_type(g);
+
+ if(gdt->is_temporal()){
+ sprintf(tmpstr,"\tgbval->gb_var%d = %s;\n",
+ g, generate_se_code(gb_tbl.get_def(g),schema).c_str() );
+ ret.append(tmpstr);
+ }
+ }
+ ret.append("\n");
+
+
+
+// Compare the temporal GB vars with the stored ones,
+// set flush indicator and update stored GB vars if there is any change.
+
+ if(uses_temporal_flush){
+ ret+= "\tif( !( (";
+ bool first_one = true;
+ for(g=0;g<gb_tbl.size();g++){
+ data_type *gdt = gb_tbl.get_data_type(g);
+
+ if(gdt->is_temporal()){
+ sprintf(tmpstr,"last_gb%d",g); string lhs_op = tmpstr;
+ sprintf(tmpstr,"gbval->gb_var%d",g); string rhs_op = tmpstr;
+ if(first_one){first_one = false;} else {ret += ") && (";}
+ ret += generate_equality_test(lhs_op, rhs_op, gdt);
+ }
+ }
+ ret += ") ) ){\n";
+ for(g=0;g<gb_tbl.size();g++){
+ data_type *gdt = gb_tbl.get_data_type(g);
+ if(gdt->is_temporal()){
+ if(gdt->is_buffer_type()){
+ sprintf(tmpstr,"\t\t%s(&(gbval->gb_var%d),&last_gb%d);\n",gdt->get_hfta_buffer_replace().c_str(),g,g);
+ }else{
+ sprintf(tmpstr,"\t\tlast_flushed_gb%d = last_gb%d;\n",g,g);
+ ret += tmpstr;
+ sprintf(tmpstr,"\t\tlast_gb%d = gbval->gb_var%d;\n",g,g);
+ }
+ ret += tmpstr;
+ }
+ }
+/*
+ if(uses_temporal_flush){
+ for(g=0;g<gb_tbl.size();g++){
+ data_type *gdt = gb_tbl.get_data_type(g);
+ if(gdt->is_temporal()){
+ ret+="if(last_flushed_gb"+int_to_string(g)+">0)\n";
+ break;
+ }
+ }
+ }
+*/
+ ret += "\t\tneeds_temporal_flush=true;\n";
+ ret += "\t\t}else{\n"
+ "\t\t\tneeds_temporal_flush=false;\n"
+ "\t\t}\n";
+ }
+
+
+// For temporal status tuple we don't need to do anything else
+ ret += "\tif (temp_tuple_received) return NULL;\n\n";
+
+
+// The partial functions ref'd in the group-by var
+// definitions must be evaluated. If one returns false,
+// then implicitly the predicate is false.
+ set<int>::iterator pfsi;
+
+ if(gb_pfcns.size() > 0)
+ ret += "//\t\tUnpack partial fcns.\n";
+ ret += gen_full_unpack_partial_fcn(schema, partial_fcns, gb_pfcns,
+ found_cids, segen_gb_tbl, "NULL", needs_xform);
+
+// Unpack the group-by variables
+
+ for(g=0;g<gb_tbl.size();g++){
+// Find the new fields ref'd by this GBvar def.
+ col_id_set new_cids;
+ get_new_se_cids(gb_tbl.get_def(g), found_cids, new_cids, segen_gb_tbl);
+// Unpack these values.
+ ret += gen_unpack_cids(schema, new_cids, "NULL", needs_xform);
+
+ sprintf(tmpstr,"\tgbval->gb_var%d = %s;\n",
+ g, generate_se_code(gb_tbl.get_def(g),schema).c_str() );
+/*
+// There seems to be no difference between the two
+// branches of the IF statement.
+ data_type *gdt = gb_tbl.get_data_type(g);
+ if(gdt->is_buffer_type()){
+// Create temporary copy.
+ sprintf(tmpstr,"\tgbval->gb_var%d = %s;\n",
+ g, generate_se_code(gb_tbl.get_def(g),schema).c_str() );
+ }else{
+ scalarexp_t *gse = gb_tbl.get_def(g);
+ sprintf(tmpstr,"\tgbval->gb_var%d = %s;\n",
+ g,generate_se_code(gse,schema).c_str());
+ }
+*/
+ ret.append(tmpstr);
+ }
+ ret.append("\n");
+
+
+ ret+= "\treturn gbval;\n";
+ ret += "};\n\n\n";
+
+
+
+//-------------------
+// the create_group method.
+// This method creates a group in a buffer passed in
+// (to allow for creation on the stack).
+// There are also a couple of side effects:
+// 1) evaluate the WHERE clause (and therefore, unpack all partial fcns)
+// 2) determine if a temporal flush is required.
+
+ ret += "bool evaluate_predicate(host_tuple &tup0, "+generate_functor_name()+"_groupdef *gbval, "+generate_functor_name()+"_statedef *stval, int cd){\n";
+ // Variables for execution of the function.
+ ret += "\tgs_int32_t problem = 0;\n"; // return unpack failure
+
+ if(partial_fcns.size()>0){ // partial fcn access failure
+ ret += "\tgs_retval_t retval = 0;\n";
+ ret += "\n";
+ }
+
+// Start by cleaning up partial function results
+ ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";
+ set<int> w_pfcns; // partial fcns in where clause
+ for(w=0;w<where.size();++w)
+ collect_partial_fcns_pr(where[w]->pr, w_pfcns);
+
+ set<int> ag_pfcns; // partial fcns in gbdefs, aggr se's
+ for(a=0;a<aggr_tbl.size();a++){
+ collect_partial_fcns(aggr_tbl.get_aggr_se(a), ag_pfcns);
+ }
+ ret += gen_partial_fcn_dtr(partial_fcns,w_pfcns);
+ ret += gen_partial_fcn_dtr(partial_fcns,ag_pfcns);
+
+ ret+="//\t\tEvaluate clauses which don't reference stateful fcns first \n";
+ for(w=0;w<where.size();++w){
+ if(! pred_refs_sfun(where[w]->pr)){
+ sprintf(tmpstr,"//\t\tPredicate clause %d.\n",w);
+ ret += tmpstr;
+// Find the set of variables accessed in this CNF elem,
+// but in no previous element.
+ col_id_set new_cids;
+ get_new_pred_cids(where[w]->pr, found_cids, new_cids, segen_gb_tbl);
+
+// Unpack these values.
+ ret += gen_unpack_cids(schema, new_cids, "false", needs_xform);
+// Find partial fcns ref'd in this cnf element
+ set<int> pfcn_refs;
+ collect_partial_fcns_pr(where[w]->pr, pfcn_refs);
+ ret += gen_unpack_partial_fcn(schema, partial_fcns, pfcn_refs,"false");
+
+ ret += "\tif( !("+generate_predicate_code(where[w]->pr,schema)+
+ +") ) return(false);\n";
+ }
+ }
+
+
+// The partial functions ref'd in the and aggregate
+// definitions must also be evaluated. If one returns false,
+// then implicitly the predicate is false.
+// ASSUME that aggregates cannot reference stateful fcns.
+
+ if(ag_pfcns.size() > 0)
+ ret += "//\t\tUnpack remaining partial fcns.\n";
+ ret += gen_full_unpack_partial_fcn(schema, partial_fcns, ag_pfcns,
+ found_cids, segen_gb_tbl, "false", needs_xform);
+
+ ret+="//\t\tEvaluate all remaining where clauses.\n";
+ ret+="\tbool retval = true;\n";
+ for(w=0;w<where.size();++w){
+ if( pred_refs_sfun(where[w]->pr)){
+ sprintf(tmpstr,"//\t\tPredicate clause %d.\n",w);
+ ret += tmpstr;
+// Find the set of variables accessed in this CNF elem,
+// but in no previous element.
+ col_id_set new_cids;
+ get_new_pred_cids(where[w]->pr, found_cids, new_cids, segen_gb_tbl);
+
+// Unpack these values.
+ ret += gen_unpack_cids(schema, new_cids, "false", needs_xform);
+// Find partial fcns ref'd in this cnf element
+ set<int> pfcn_refs;
+ collect_partial_fcns_pr(where[w]->pr, pfcn_refs);
+ ret += gen_unpack_partial_fcn(schema, partial_fcns, pfcn_refs,"false");
+
+ ret += "\tif( !("+generate_predicate_code(where[w]->pr,schema)+
+ +") ) retval = false;\n";
+ }
+ }
+
+ ret+="// Unpack all remaining attributes\n";
+ ret += gen_remaining_colrefs(schema, cid_set, found_cids, "false", needs_xform);
+
+ ret += "\n\treturn retval;\n";
+ ret += "};\n\n\n";
+
+//--------------------------------------------------------
+// Create and initialize an aggregate object
+
+ 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";
+ // Variables for execution of the function.
+ ret += "\tgs_int32_t problem = 0;\n"; // return unpack failure
+
+// return value
+ ret += "\t"+generate_functor_name()+"_aggrdef *aggval = ("+generate_functor_name()+ "_aggrdef *)a;\n";
+
+ for(a=0;a<aggr_tbl.size();a++){
+ if(aggr_tbl.is_builtin(a)){
+// Create temporaries for buffer return values
+ data_type *adt = aggr_tbl.get_data_type(a);
+ if(adt->is_buffer_type()){
+ sprintf(tmpstr,"aggr_tmp_%d", a);
+ ret+=adt->make_host_cvar(tmpstr)+";\n";
+ }
+ }
+ }
+
+ for(a=0;a<aggr_tbl.size();a++){
+ sprintf(tmpstr,"aggval->aggr_var%d",a);
+ string assignto_var = tmpstr;
+ ret += "\t"+generate_aggr_init(assignto_var,&aggr_tbl,a, schema);
+ }
+
+ ret += "\treturn aggval;\n";
+ ret += "};\n\n";
+
+
+//--------------------------------------------------------
+// initialize an aggregate object inplace
+
+ ret += "void create_aggregate(host_tuple &tup0, "+this->generate_functor_name()+"_aggrdef *aggval,"+generate_functor_name()+"_statedef *stval, int cd){\n";
+ // Variables for execution of the function.
+ ret += "\tgs_int32_t problem = 0;\n"; // return unpack failure
+
+// return value
+
+ for(a=0;a<aggr_tbl.size();a++){
+ if(aggr_tbl.is_builtin(a)){
+// Create temporaries for buffer return values
+ data_type *adt = aggr_tbl.get_data_type(a);
+ if(adt->is_buffer_type()){
+ sprintf(tmpstr,"aggr_tmp_%d", a);
+ ret+=adt->make_host_cvar(tmpstr)+";\n";
+ }
+ }
+ }
+
+ for(a=0;a<aggr_tbl.size();a++){
+ sprintf(tmpstr,"aggval->aggr_var%d",a);
+ string assignto_var = tmpstr;
+ ret += "\t"+generate_aggr_init(assignto_var,&aggr_tbl,a, schema);
+ }
+
+ ret += "};\n\n";
+
+
+//--------------------------------------------------------
+// Create and clean-initialize an state object
+
+ ret += "void initialize_state(host_tuple &tup0, "+generate_functor_name()+"_groupdef *gbval, "+generate_functor_name()+"_statedef *stval){\n";
+ // Variables for execution of the function.
+ ret += "\tgs_int32_t problem = 0;\n"; // return unpack failure
+
+// return value
+// ret += "\t"+generate_functor_name()+"_statedef *stval = ("+generate_functor_name()+ "_statedef *)s;\n";
+
+ for(a=0;a<aggr_tbl.size();a++){
+ if( aggr_tbl.is_superaggr(a)){
+ if(aggr_tbl.is_builtin(a)){
+// Create temporaries for buffer return values
+ data_type *adt = aggr_tbl.get_data_type(a);
+ if(adt->is_buffer_type()){
+ sprintf(tmpstr,"aggr_tmp_%d", a);
+ ret+=adt->make_host_cvar(tmpstr)+";\n";
+ }
+ }
+ }
+ }
+
+ for(a=0;a<aggr_tbl.size();a++){
+ if( aggr_tbl.is_superaggr(a)){
+ sprintf(tmpstr,"stval->aggr_var%d",a);
+ string assignto_var = tmpstr;
+ ret += "\t"+generate_aggr_init(assignto_var,&aggr_tbl,a, schema);
+ }
+ }
+
+ for(ssi=states_refd.begin(); ssi!=states_refd.end();++ssi){
+ string state_nm = (*ssi);
+ ret += "_sfun_state_clean_init_"+state_nm+"(&(stval->state_var_"+state_nm+"));\n";
+ }
+
+ ret += "};\n\n";
+
+
+//--------------------------------------------------------
+// Create and dirty-initialize an state object
+
+ 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";
+ // Variables for execution of the function.
+ ret += "\tgs_int32_t problem = 0;\n"; // return unpack failure
+
+// return value
+// ret += "\t"+generate_functor_name()+"_statedef *stval = ("+generate_functor_name()+ "_statedef *)s;\n";
+
+ for(a=0;a<aggr_tbl.size();a++){
+ if( aggr_tbl.is_superaggr(a)){
+ if(aggr_tbl.is_builtin(a)){
+// Create temporaries for buffer return values
+ data_type *adt = aggr_tbl.get_data_type(a);
+ if(adt->is_buffer_type()){
+ sprintf(tmpstr,"aggr_tmp_%d", a);
+ ret+=adt->make_host_cvar(tmpstr)+";\n";
+ }
+ }
+ }
+ }
+
+// initialize superaggregates
+ for(a=0;a<aggr_tbl.size();a++){
+ if( aggr_tbl.is_superaggr(a)){
+ sprintf(tmpstr,"stval->aggr_var%d",a);
+ string assignto_var = tmpstr;
+ ret += "\t"+generate_aggr_init(assignto_var,&aggr_tbl,a, schema);
+ }
+ }
+
+ for(ssi=states_refd.begin(); ssi!=states_refd.end();++ssi){
+ string state_nm = (*ssi);
+ ret += "_sfun_state_dirty_init_"+state_nm+"(&(stval->state_var_"+state_nm+"),&(old_stval->state_var_"+state_nm+"), cd );\n";
+ }
+
+ ret += "};\n\n";
+
+//--------------------------------------------------------
+// Finalize_state : call the finalize fcn on all states
+
+
+ ret += "void finalize_state( "+generate_functor_name()+"_statedef *stval, int cd){\n";
+
+ for(ssi=states_refd.begin(); ssi!=states_refd.end();++ssi){
+ string state_nm = (*ssi);
+ ret += "_sfun_state_final_init_"+state_nm+"(&(stval->state_var_"+state_nm+"), cd);\n";
+ }
+
+ ret += "};\n\n";
+
+
+
+
+//--------------------------------------------------------
+// update (plus) a superaggregate object
+
+ ret += "void update_plus_superaggr(host_tuple &tup0, " +
+ generate_functor_name()+"_groupdef *gbval, "+
+ generate_functor_name()+"_statedef *stval){\n";
+ // Variables for execution of the function.
+ ret += "\tgs_int32_t problem = 0;\n"; // return unpack failure
+
+// use of temporaries depends on the aggregate,
+// generate them in generate_aggr_update
+
+
+ for(a=0;a<aggr_tbl.size();a++){
+ if(aggr_tbl.is_superaggr(a)){
+ sprintf(tmpstr,"stval->aggr_var%d",a);
+ string varname = tmpstr;
+ ret.append(generate_aggr_update(varname,&aggr_tbl,a, schema));
+ }
+ }
+
+ ret += "\treturn;\n";
+ ret += "};\n";
+
+
+
+//--------------------------------------------------------
+// update (minus) a superaggregate object
+
+ ret += "void update_minus_superaggr( "+
+ generate_functor_name()+"_groupdef *gbval, "+
+ generate_functor_name()+"_aggrdef *aggval,"+
+ generate_functor_name()+"_statedef *stval"+
+ "){\n";
+ // Variables for execution of the function.
+ ret += "\tgs_int32_t problem = 0;\n"; // return unpack failure
+
+// use of temporaries depends on the aggregate,
+// generate them in generate_aggr_update
+
+
+ for(a=0;a<aggr_tbl.size();a++){
+ if(aggr_tbl.is_superaggr(a)){
+ sprintf(tmpstr,"stval->aggr_var%d",a);
+ string super_varname = tmpstr;
+ sprintf(tmpstr,"aggval->aggr_var%d",a);
+ string sub_varname = tmpstr;
+ ret.append(generate_superaggr_minus(sub_varname, super_varname,&aggr_tbl,a, schema));
+ }
+ }
+
+ ret += "\treturn;\n";
+ ret += "};\n";
+
+
+//--------------------------------------------------------
+// update an aggregate object
+
+ ret += "void update_aggregate(host_tuple &tup0, "
+ +generate_functor_name()+"_groupdef *gbval, "+
+ generate_functor_name()+"_aggrdef *aggval,"+generate_functor_name()+"_statedef *stval, int cd){\n";
+ // Variables for execution of the function.
+ ret += "\tgs_int32_t problem = 0;\n"; // return unpack failure
+
+// use of temporaries depends on the aggregate,
+// generate them in generate_aggr_update
+
+
+ for(a=0;a<aggr_tbl.size();a++){
+ sprintf(tmpstr,"aggval->aggr_var%d",a);
+ string varname = tmpstr;
+ ret.append(generate_aggr_update(varname,&aggr_tbl,a, schema));
+ }
+
+ ret += "\treturn;\n";
+ ret += "};\n";
+
+//---------------------------------------------------
+// Flush test
+
+ ret += "\tbool flush_needed(){\n";
+ if(uses_temporal_flush){
+ ret += "\t\treturn needs_temporal_flush;\n";
+ }else{
+ ret += "\t\treturn false;\n";
+ }
+ ret += "\t};\n";
+
+
+//------------------------------------------------------
+// THe cleaning_when predicate
+
+ string gbvar = "gbval->gb_var";
+ string aggvar = "aggval->";
+
+ ret += "bool need_to_clean( "
+ +generate_functor_name()+"_groupdef *gbval, "+
+ generate_functor_name()+"_statedef *stval, int cd"+
+ "){\n";
+
+ if(cleanwhen.size()>0)
+ ret += "\tbool predval = true;\n";
+ else
+ ret += "\tbool predval = false;\n";
+
+// Find the udafs ref'd in the having clause
+ set<int> cw_aggs;
+ for(w=0;w<cleanwhen.size();++w)
+ collect_aggr_refs_pr(cleanwhen[w]->pr, cw_aggs);
+
+
+// get the return values from the UDAFS
+ for(a=0;a<aggr_tbl.size();a++){
+ if(! aggr_tbl.is_builtin(a) && cw_aggs.count(a)){
+ ret += "\t"+aggr_tbl.get_op(a)+"_HFTA_AGGR_OUTPUT_(&(udaf_ret_"+int_to_string(a)+"),";
+ if(aggr_tbl.get_storage_type(a)->get_type() != fstring_t) ret+="&";
+ ret+="("+aggvar+"aggr_var"+int_to_string(a)+"));\n";
+ }
+ }
+
+
+// Start by cleaning up partial function results
+ ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";
+ set<int> cw_pfcns; // partial fcns in where clause
+ for(w=0;w<cleanwhen.size();++w)
+ collect_partial_fcns_pr(cleanwhen[w]->pr, cw_pfcns);
+
+ ret += gen_partial_fcn_dtr(partial_fcns,cw_pfcns);
+
+
+ for(w=0;w<cleanwhen.size();++w){
+ sprintf(tmpstr,"//\t\tPredicate clause %d.\n",w);
+ ret += tmpstr;
+// Find partial fcns ref'd in this cnf element
+ set<int> pfcn_refs;
+ collect_partial_fcns_pr(cleanwhen[w]->pr, pfcn_refs);
+ for(pfsi=pfcn_refs.begin();pfsi!=pfcn_refs.end();++pfsi){
+ ret += unpack_partial_fcn_fm_aggr(partial_fcns[(*pfsi)], (*pfsi), gbvar, aggvar, schema);
+ ret += "\tif(retval){ return false;}\n";
+ }
+// ret += unpack_partial_fcn_fm_aggr(schema, partial_fcns, pfcn_refs,"false");
+
+ ret += "\tif( !("+generate_predicate_code_fm_aggr(cleanwhen[w]->pr,gbvar, aggvar, schema)+
+ ") ) predval = false;\n";
+ }
+
+ ret += "\treturn predval;\n";
+ ret += "\t};\n";
+
+//------------------------------------------------------
+// THe cleaning_by predicate
+
+ ret += "bool sample_group("
+ +generate_functor_name()+"_groupdef *gbval, "+
+ generate_functor_name()+"_aggrdef *aggval,"+
+ generate_functor_name()+"_statedef *stval, int cd"+
+ "){\n";
+
+ if(cleanby.size()>0)
+ ret += "\tbool retval = true;\n";
+ else
+ ret += "\tbool retval = false;\n";
+
+// Find the udafs ref'd in the having clause
+ set<int> cb_aggs;
+ for(w=0;w<cleanby.size();++w)
+ collect_aggr_refs_pr(cleanby[w]->pr, cb_aggs);
+
+
+// get the return values from the UDAFS
+ for(a=0;a<aggr_tbl.size();a++){
+ if(! aggr_tbl.is_builtin(a) && cb_aggs.count(a)){
+ ret += "\t"+aggr_tbl.get_op(a)+"_HFTA_AGGR_OUTPUT_(&(udaf_ret_"+int_to_string(a)+"),";
+ if(aggr_tbl.get_storage_type(a)->get_type() != fstring_t) ret+="&";
+ ret+="("+aggvar+"aggr_var"+int_to_string(a)+"));\n";
+ }
+ }
+
+
+// Start by cleaning up partial function results
+ ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";
+ set<int> cb_pfcns; // partial fcns in where clause
+ for(w=0;w<cleanby.size();++w)
+ collect_partial_fcns_pr(cleanby[w]->pr, cb_pfcns);
+
+ ret += gen_partial_fcn_dtr(partial_fcns,cb_pfcns);
+
+
+ for(w=0;w<cleanwhen.size();++w){
+ sprintf(tmpstr,"//\t\tPredicate clause %d.\n",w);
+ ret += tmpstr;
+
+/*
+// Find the set of variables accessed in this CNF elem,
+// but in no previous element.
+ col_id_set new_cids;
+ get_new_pred_cids(cleanby[w]->pr, found_cids, new_cids, segen_gb_tbl);
+
+// Unpack these values.
+ ret += gen_unpack_cids(schema, new_cids, "false", needs_xform);
+*/
+
+// Find partial fcns ref'd in this cnf element
+ set<int> pfcn_refs;
+ collect_partial_fcns_pr(cleanby[w]->pr, pfcn_refs);
+ for(pfsi=pfcn_refs.begin();pfsi!=pfcn_refs.end();++pfsi){
+ ret += unpack_partial_fcn_fm_aggr(partial_fcns[(*pfsi)], (*pfsi), gbvar, aggvar, schema);
+ ret += "\tif(retval){ return false;}\n";
+ }
+// ret += gen_unpack_partial_fcn(schema, partial_fcns, pfcn_refs,"false");
+
+ ret += "\tif( !("+generate_predicate_code_fm_aggr(cleanby[w]->pr,gbvar, aggvar, schema)+
+ +") ) retval = false;\n";
+ }
+
+ ret += "\treturn retval;\n";
+ ret += "\t};\n";
+
+
+//-----------------------------------------------------
+//
+ ret += "bool final_sample_group("
+ +generate_functor_name()+"_groupdef *gbval, "+
+ generate_functor_name()+"_aggrdef *aggval,"+
+ generate_functor_name()+"_statedef *stval,"+
+ "int cd){\n";
+
+ ret += "\tgs_retval_t retval = 0;\n";
+
+// Find the udafs ref'd in the having clause
+ set<int> hv_aggs;
+ for(w=0;w<having.size();++w)
+ collect_aggr_refs_pr(having[w]->pr, hv_aggs);
+
+
+// get the return values from the UDAFS
+ for(a=0;a<aggr_tbl.size();a++){
+ if(! aggr_tbl.is_builtin(a) && hv_aggs.count(a)){
+ ret += "\t"+aggr_tbl.get_op(a)+"_HFTA_AGGR_OUTPUT_(&(udaf_ret_"+int_to_string(a)+"),";
+ if(aggr_tbl.get_storage_type(a)->get_type() != fstring_t) ret+="&";
+ ret+="("+aggvar+"aggr_var"+int_to_string(a)+"));\n";
+ }
+ }
+
+
+ set<int> hv_sl_pfcns;
+ for(w=0;w<having.size();w++){
+ collect_partial_fcns_pr(having[w]->pr, hv_sl_pfcns);
+ }
+
+// clean up the partial fcn results from any previous execution
+ ret += gen_partial_fcn_dtr(partial_fcns,hv_sl_pfcns);
+
+// Unpack them now
+ for(pfsi=hv_sl_pfcns.begin();pfsi!=hv_sl_pfcns.end();++pfsi){
+ ret += unpack_partial_fcn_fm_aggr(partial_fcns[(*pfsi)], (*pfsi), gbvar, aggvar, schema);
+ ret += "\tif(retval){ return false;}\n";
+ }
+
+// Evalaute the HAVING clause
+// TODO: this seems to have a ++ operator rather than a + operator.
+ for(w=0;w<having.size();++w){
+ ret += "\tif( !("+generate_predicate_code_fm_aggr(having[w]->pr,gbvar, aggvar, schema) +") ) { return false;}\n";
+ }
+
+ ret += "\treturn true;\n";
+ ret+="}\n\n";
+
+//---------------------------------------------------
+// create output tuple
+// Unpack the partial functions ref'd in the where clause,
+// select clause. Evaluate the where clause.
+// Finally, pack the tuple.
+
+// I need to use special code generation here,
+// so I'll leave it in longhand.
+
+ ret += "host_tuple create_output_tuple("
+ +generate_functor_name()+"_groupdef *gbval, "+
+ generate_functor_name()+"_aggrdef *aggval,"+
+ generate_functor_name()+"_statedef *stval,"+
+ "int cd, bool &failed){\n";
+
+ ret += "\thost_tuple tup;\n";
+ ret += "\tfailed = false;\n";
+ ret += "\tgs_retval_t retval = 0;\n";
+
+
+// Find the udafs ref'd in the select clause
+ set<int> sl_aggs;
+ for(s=0;s<select_list.size();s++)
+ collect_agg_refs(select_list[s]->se, sl_aggs);
+
+
+// get the return values from the UDAFS
+ for(a=0;a<aggr_tbl.size();a++){
+ if(! aggr_tbl.is_builtin(a) && sl_aggs.count(a)){
+ ret += "\t"+aggr_tbl.get_op(a)+"_HFTA_AGGR_OUTPUT_(&(udaf_ret_"+int_to_string(a)+"),";
+ if(aggr_tbl.get_storage_type(a)->get_type() != fstring_t) ret+="&";
+ ret+="("+aggvar+"aggr_var"+int_to_string(a)+"));\n";
+ }
+ }
+
+
+// I can't cache partial fcn results from the having
+// clause because evaluation is separated.
+ set<int> sl_pfcns;
+ for(s=0;s<select_list.size();s++){
+ collect_partial_fcns(select_list[s]->se, sl_pfcns);
+ }
+// Unpack them now
+ for(pfsi=sl_pfcns.begin();pfsi!=sl_pfcns.end();++pfsi){
+ ret += unpack_partial_fcn_fm_aggr(partial_fcns[(*pfsi)], (*pfsi), gbvar, aggvar, schema);
+ ret += "\tif(retval){ failed=true; return tup;}\n";
+ }
+
+
+// Now, compute the size of the tuple.
+
+// Unpack any BUFFER type selections into temporaries
+// so that I can compute their size and not have
+// to recompute their value during tuple packing.
+// I can use regular assignment here because
+// these temporaries are non-persistent.
+// TODO: should I be using the selvar generation routine?
+
+ ret += "//\t\tCompute the size of the tuple.\n";
+ ret += "//\t\t\tNote: buffer storage packed at the end of the tuple.\n";
+ for(s=0;s<select_list.size();s++){
+ scalarexp_t *se = select_list[s]->se;
+ data_type *sdt = se->get_data_type();
+ if(sdt->is_buffer_type() &&
+ !( (se->get_operator_type() == SE_COLREF) ||
+ (se->get_operator_type() == SE_AGGR_STAR) ||
+ (se->get_operator_type() == SE_AGGR_SE) ||
+ (se->get_operator_type() == SE_FUNC && se->is_partial()) ||
+ (se->get_operator_type() == SE_FUNC && se->get_aggr_ref() >= 0))
+ ){
+ sprintf(tmpstr,"selvar_%d",s);
+ ret+="\t"+sdt->make_host_cvar(tmpstr)+" = ";
+ ret += generate_se_code_fm_aggr(se,gbvar, aggvar, schema) +";\n";
+ }
+ }
+
+// The size of the tuple is the size of the tuple struct plus the
+// size of the buffers to be copied in.
+
+ ret+="\ttup.tuple_size = sizeof(" + generate_tuple_name( this->get_node_name()) +") + sizeof(gs_uint8_t)";
+ for(s=0;s<select_list.size();s++){
+// if(s>0) ret += "+";
+ scalarexp_t *se = select_list[s]->se;
+ data_type *sdt = select_list[s]->se->get_data_type();
+ if(sdt->is_buffer_type()){
+ if(!( (se->get_operator_type() == SE_COLREF) ||
+ (se->get_operator_type() == SE_AGGR_STAR) ||
+ (se->get_operator_type() == SE_AGGR_SE) ||
+ (se->get_operator_type() == SE_FUNC && se->is_partial()) ||
+ (se->get_operator_type() == SE_FUNC && se->get_aggr_ref() >= 0))
+ ){
+ sprintf(tmpstr," + %s(&selvar_%d)", sdt->get_hfta_buffer_size().c_str(),s);
+ ret.append(tmpstr);
+ }else{
+ sprintf(tmpstr," + %s(&%s)", sdt->get_hfta_buffer_size().c_str(),generate_se_code_fm_aggr(se,gbvar, aggvar, schema).c_str());
+ ret.append(tmpstr);
+ }
+ }
+ }
+ ret.append(";\n");
+
+// Allocate tuple data block.
+ ret += "//\t\tCreate the tuple block.\n";
+ ret += "\ttup.data = malloc(tup.tuple_size);\n";
+ ret += "\ttup.heap_resident = true;\n";
+
+// Mark tuple as regular
+ ret += "\t*((gs_sp_t )tup.data + sizeof(" + generate_tuple_name( this->get_node_name()) +")) = REGULAR_TUPLE;\n";
+
+// ret += "\ttup.channel = 0;\n";
+ ret += "\t"+generate_tuple_name( this->get_node_name())+" *tuple = ("+
+ generate_tuple_name( this->get_node_name())+" *)(tup.data);\n";
+
+// Start packing.
+// (Here, offsets are hard-wired. is this a problem?)
+
+ ret += "//\t\tPack the fields into the tuple.\n";
+ ret += "\tint tuple_pos = sizeof("+generate_tuple_name( this->get_node_name()) +") + sizeof(gs_uint8_t);\n";
+ for(s=0;s<select_list.size();s++){
+ scalarexp_t *se = select_list[s]->se;
+ data_type *sdt = se->get_data_type();
+ if(sdt->is_buffer_type()){
+ if(!( (se->get_operator_type() == SE_COLREF) ||
+ (se->get_operator_type() == SE_AGGR_STAR) ||
+ (se->get_operator_type() == SE_AGGR_SE) ||
+ (se->get_operator_type() == SE_FUNC && se->is_partial()) ||
+ (se->get_operator_type() == SE_FUNC && se->get_aggr_ref() >= 0))
+ ){
+ 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);
+ ret.append(tmpstr);
+ sprintf(tmpstr,"\ttuple_pos += %s(&selvar_%d);\n", sdt->get_hfta_buffer_size().c_str(), s);
+ ret.append(tmpstr);
+ }else{
+ 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());
+ ret.append(tmpstr);
+ 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());
+ ret.append(tmpstr);
+ }
+ }else{
+ sprintf(tmpstr,"\ttuple->tuple_var%d = ",s);
+ ret.append(tmpstr);
+ ret.append(generate_se_code_fm_aggr(se,gbvar, aggvar, schema) );
+ ret.append(";\n");
+ }
+ }
+
+// Destroy string temporaries
+ ret += gen_buffer_selvars_dtr(select_list);
+// Destroy string return vals of UDAFs
+ for(a=0;a<aggr_tbl.size();a++){
+ if(! aggr_tbl.is_builtin(a)){
+ int afcn_id = aggr_tbl.get_fcn_id(a);
+ data_type *adt = Ext_fcns->get_fcn_dt(afcn_id);
+ if(adt->is_buffer_type()){
+ sprintf(tmpstr,"\t%s(&udaf_ret_%d);\n",
+ adt->get_hfta_buffer_destroy().c_str(), a );
+ ret += tmpstr;
+ }
+ }
+ }
+
+
+ ret += "\treturn tup;\n";
+ ret += "};\n";
+
+
+//-------------------------------------------------------------------
+// Temporal update functions
+
+ ret+="bool temp_status_received(){return temp_tuple_received;};\n\n";
+
+// create a temp status tuple
+ ret += "int create_temp_status_tuple(host_tuple& result, bool flush_finished) {\n\n";
+
+ ret += gen_init_temp_status_tuple(this->get_node_name());
+
+// Start packing.
+// (Here, offsets are hard-wired. is this a problem?)
+
+ ret += "//\t\tPack the fields into the tuple.\n";
+ for(s=0;s<select_list.size();s++){
+ data_type *sdt = select_list[s]->se->get_data_type();
+ if(sdt->is_temporal()){
+ sprintf(tmpstr,"\ttuple->tuple_var%d = ",s);
+ ret += tmpstr;
+ 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());
+ ret += tmpstr;
+ ret += ";\n";
+ }
+ }
+
+ ret += "\treturn 0;\n";
+ ret += "};};\n\n\n";
+
+
+//----------------------------------------------------------
+// The hash function
+
+ ret += "struct "+generate_functor_name()+"_hash_func{\n";
+ ret += "\tgs_uint32_t operator()(const "+generate_functor_name()+
+ "_groupdef *grp) const{\n";
+ ret += "\t\treturn(";
+ for(g=0;g<gb_tbl.size();g++){
+ if(g>0) ret += "^";
+ data_type *gdt = gb_tbl.get_data_type(g);
+ if(gdt->use_hashfunc()){
+ if(gdt->is_buffer_type())
+ sprintf(tmpstr,"(%s*%s(&)grp->gb_var%d)))",hash_nums[g%NRANDS].c_str(),gdt->get_hfta_hashfunc().c_str(),g);
+ else
+ sprintf(tmpstr,"(%s*%s(grp->gb_var%d))",hash_nums[g%NRANDS].c_str(),gdt->get_hfta_hashfunc().c_str(),g);
+ }else{
+ sprintf(tmpstr,"(%s*grp->gb_var%d)",hash_nums[g%NRANDS].c_str(),g);
+ }
+ ret += tmpstr;
+ }
+ ret += ") >> 32);\n";
+ ret += "\t}\n";
+ ret += "};\n\n";
+
+//----------------------------------------------------------
+// The superhash function
+
+ ret += "struct "+generate_functor_name()+"_superhash_func{\n";
+ ret += "\tgs_uint32_t operator()(const "+generate_functor_name()+
+ "_groupdef *grp) const{\n";
+ ret += "\t\treturn(0";
+
+ for(g=0;g<gb_tbl.size();g++){
+ if(sg_tbl.count(g)>0){
+ ret += "^";
+ data_type *gdt = gb_tbl.get_data_type(g);
+ if(gdt->use_hashfunc()){
+ sprintf(tmpstr,"(%s*%s(&(grp->gb_var%d)))",hash_nums[g%NRANDS].c_str(),gdt->get_hfta_hashfunc().c_str(),g);
+ }else{
+ sprintf(tmpstr,"(%s*grp->gb_var%d)",hash_nums[g%NRANDS].c_str(),g);
+ }
+ ret += tmpstr;
+ }
+ }
+ ret += ") >> 32);\n";
+
+ ret += "\t}\n";
+ ret += "};\n\n";
+
+//----------------------------------------------------------
+// The comparison function
+
+ ret += "struct "+generate_functor_name()+"_equal_func{\n";
+ ret += "\tbool operator()(const "+generate_functor_name()+"_groupdef *grp1, "+
+ generate_functor_name()+"_groupdef *grp2) const{\n";
+ ret += "\t\treturn( (";
+ for(g=0;g<gb_tbl.size();g++){
+ if(g>0) ret += ") && (";
+ data_type *gdt = gb_tbl.get_data_type(g);
+ if(gdt->complex_comparison(gdt)){
+ if(gdt->is_buffer_type())
+ sprintf(tmpstr,"(%s(&(grp1->gb_var%d), &(grp2->gb_var%d))==0)",
+ gdt->get_hfta_equals_fcn(gdt).c_str(),g,g);
+ else
+ sprintf(tmpstr,"(%s((grp1->gb_var%d), (grp2->gb_var%d))==0)",
+ gdt->get_hfta_equals_fcn(gdt).c_str(),g,g);
+ }else{
+ sprintf(tmpstr,"grp1->gb_var%d == grp2->gb_var%d",g,g);
+ }
+ ret += tmpstr;
+ }
+ ret += ") );\n";
+ ret += "\t}\n";
+ ret += "};\n\n";
+
+
+//----------------------------------------------------------
+// The superhashcomparison function
+
+ ret += "struct "+generate_functor_name()+"_superequal_func{\n";
+ ret += "\tbool operator()(const "+generate_functor_name()+"_groupdef *grp1, "+
+ generate_functor_name()+"_groupdef *grp2) const{\n";
+ ret += "\t\treturn( (";
+ if(sg_tbl.size()){
+ bool first_elem = true;
+ for(g=0;g<gb_tbl.size();g++){
+ if(sg_tbl.count(g)){
+ if(first_elem) first_elem=false; else ret += ") && (";
+ data_type *gdt = gb_tbl.get_data_type(g);
+ if(gdt->complex_comparison(gdt)){
+ if(gdt->is_buffer_type())
+ sprintf(tmpstr,"(%s(&(grp1->gb_var%d), &(grp2->gb_var%d))==0)",
+ gdt->get_hfta_equals_fcn(gdt).c_str(),g,g);
+ else
+ sprintf(tmpstr,"(%s((grp1->gb_var%d), (grp2->gb_var%d))==0)",
+ gdt->get_hfta_equals_fcn(gdt).c_str(),g,g);
+ }else{
+ sprintf(tmpstr,"grp1->gb_var%d == grp2->gb_var%d",g,g);
+ }
+ ret += tmpstr;
+ }
+ }
+ }else{
+ ret += "true";
+ }
+
+ ret += ") );\n";
+ ret += "\t}\n";
+
+
+ ret += "};\n\n";
+ return(ret);
+}
+
+string sgahcwcb_qpn::generate_operator(int i, string params){
+
+ return(
+ " clean_operator<" +
+ generate_functor_name()+",\n\t"+
+ generate_functor_name() + "_groupdef, \n\t" +
+ generate_functor_name() + "_aggrdef, \n\t" +
+ generate_functor_name() + "_statedef, \n\t" +
+ generate_functor_name()+"_hash_func, \n\t"+
+ generate_functor_name()+"_equal_func ,\n\t"+
+ generate_functor_name()+"_superhash_func,\n\t "+
+ generate_functor_name()+"_superequal_func \n\t"+
+ "> *op"+int_to_string(i)+" = new clean_operator<"+
+ generate_functor_name()+",\n\t"+
+ generate_functor_name() + "_groupdef,\n\t " +
+ generate_functor_name() + "_aggrdef, \n\t" +
+ generate_functor_name() + "_statedef, \n\t" +
+ generate_functor_name()+"_hash_func, \n\t"+
+ generate_functor_name()+"_equal_func, \n\t"+
+ generate_functor_name()+"_superhash_func, \n\t"+
+ generate_functor_name()+"_superequal_func\n\t "
+ ">("+params+", \"" + get_node_name() + "\");\n"
+ );
+}
+
+////////////////////////////////////////////////////////////////
+//// RSGAH functor
+
+
+
+string rsgah_qpn::generate_functor_name(){
+ return("rsgah_functor_" + normalize_name(this->get_node_name()));
+}
+
+
+string rsgah_qpn::generate_functor(table_list *schema, ext_fcn_list *Ext_fcns, vector<bool> &needs_xform){
+ int a,g,w,s;
+
+
+// Initialize generate utility globals
+ segen_gb_tbl = &(gb_tbl);
+
+
+//--------------------------------
+// group definition class
+ string ret = "class " + generate_functor_name() + "_groupdef{\n";
+ ret += "public:\n";
+ for(g=0;g<this->gb_tbl.size();g++){
+ sprintf(tmpstr,"gb_var%d",g);
+ ret+="\t"+this->gb_tbl.get_data_type(g)->make_host_cvar(tmpstr)+";\n";
+ }
+// Constructors
+
+ ret += "\t"+generate_functor_name() + "_groupdef(){\n";
+ for(g=0;g<gb_tbl.size();g++){
+ data_type *gdt = gb_tbl.get_data_type(g);
+ if(gdt->is_buffer_type()){
+ sprintf(tmpstr,"\t\t%s(&gb_var%d);\n",
+ gdt->get_hfta_buffer_init().c_str(), g );
+ ret += tmpstr;
+ }
+ }
+ ret += "\t};\n";
+
+ ret += "\t// shallow copy constructor\n";
+ ret += "\t"+generate_functor_name() + "_groupdef("+
+ this->generate_functor_name() + "_groupdef &gd){\n";
+ for(g=0;g<gb_tbl.size();g++){
+ data_type *gdt = gb_tbl.get_data_type(g);
+ sprintf(tmpstr,"\t\tgb_var%d = gd.gb_var%d;\n",g,g);
+ ret += tmpstr;
+ }
+ ret += "\t};\n";
+
+ ret += "\t// deep assignment operator\n";
+ ret += "\t"+generate_functor_name() + "_groupdef& operator=(const "+
+ this->generate_functor_name() + "_groupdef &gd){\n";
+ for(g=0;g<gb_tbl.size();g++){
+ data_type *gdt = gb_tbl.get_data_type(g);
+ if(gdt->is_buffer_type()){
+ sprintf(tmpstr,"\t\t%s(&gb_var%d, &(gd.gb_var%d));\n",
+ gdt->get_hfta_buffer_assign_copy().c_str(),g,g );
+ ret += tmpstr;
+ }else{
+ sprintf(tmpstr,"\t\tgb_var%d = gd.gb_var%d;\n",g,g);
+ ret += tmpstr;
+ }
+ }
+ ret += "\t}\n";
+
+// destructor
+ ret += "\t~"+ generate_functor_name() + "_groupdef(){\n";
+ for(g=0;g<gb_tbl.size();g++){
+ data_type *gdt = gb_tbl.get_data_type(g);
+ if(gdt->is_buffer_type()){
+ sprintf(tmpstr,"\t\t%s(&gb_var%d);\n",
+ gdt->get_hfta_buffer_destroy().c_str(), g );
+ ret += tmpstr;
+ }
+ }
+ ret += "\t};\n";
+ ret +="};\n\n";
+
+//--------------------------------
+// aggr definition class
+ ret += "class " + this->generate_functor_name() + "_aggrdef{\n";
+ ret += "public:\n";
+ for(a=0;a<aggr_tbl.size();a++){
+aggr_table_entry *ate = aggr_tbl.agr_tbl[a];
+ sprintf(tmpstr,"aggr_var%d",a);
+ if(aggr_tbl.is_builtin(a))
+ ret+="\t"+ aggr_tbl.get_data_type(a)->make_host_cvar(tmpstr)+";\n";
+ else
+ ret+="\t"+ aggr_tbl.get_storage_type(a)->make_host_cvar(tmpstr)+";\n";
+ }
+// Constructors
+ ret += "\t"+this->generate_functor_name() + "_aggrdef(){};\n";
+// destructor
+ ret += "\t~"+this->generate_functor_name() + "_aggrdef(){\n";
+ for(a=0;a<aggr_tbl.size();a++){
+ if(aggr_tbl.is_builtin(a)){
+ data_type *adt = aggr_tbl.get_data_type(a);
+ if(adt->is_buffer_type()){
+ sprintf(tmpstr,"\t\t%s(&aggr_var%d);\n",
+ adt->get_hfta_buffer_destroy().c_str(), a );
+ ret += tmpstr;
+ }
+ }else{
+ ret+="\t\t"+aggr_tbl.get_op(a)+"_HFTA_AGGR_DESTROY_(";
+ if(aggr_tbl.get_storage_type(a)->get_type() != fstring_t) ret+="&";
+ ret+="(aggr_var"+int_to_string(a)+"));\n";
+ }
+ }
+ ret += "\t};\n";
+ ret +="};\n\n";
+
+//--------------------------------
+// gb functor class
+ ret += "class " + this->generate_functor_name() + "{\n";
+
+// Find variables referenced in this query node.
+
+ col_id_set cid_set;
+ col_id_set::iterator csi;
+
+ for(w=0;w<where.size();++w)
+ gather_pr_col_ids(where[w]->pr,cid_set,segen_gb_tbl);
+ for(w=0;w<having.size();++w)
+ gather_pr_col_ids(having[w]->pr,cid_set,segen_gb_tbl);
+ for(w=0;w<closing_when.size();++w)
+ gather_pr_col_ids(closing_when[w]->pr,cid_set,segen_gb_tbl);
+ for(g=0;g<gb_tbl.size();g++)
+ gather_se_col_ids(gb_tbl.get_def(g),cid_set,segen_gb_tbl);
+
+ for(s=0;s<select_list.size();s++){
+ gather_se_col_ids(select_list[s]->se,cid_set,segen_gb_tbl); // descends into aggregates
+ }
+
+
+// Private variables : store the state of the functor.
+// 1) variables for unpacked attributes
+// 2) offsets of the upacked attributes
+// 3) storage of partial functions
+// 4) storage of complex literals (i.e., require a constructor)
+
+ ret += "private:\n";
+
+ // var to save the schema handle
+ ret += "\tint schema_handle0;\n";
+
+ // generate the declaration of all the variables related to
+ // temp tuples generation
+ ret += gen_decl_temp_vars();
+
+// unpacked attribute storage, offsets
+ ret += "//\t\tstorage and offsets of accessed fields.\n";
+ ret += generate_access_vars(cid_set, schema);
+// tuple metadata offset
+ ret += "\tint tuple_metadata_offset0;\n";
+
+// Variables to store results of partial functions.
+// WARNING find_partial_functions modifies the SE
+// (it marks the partial function id).
+ ret += "//\t\tParital function result storage\n";
+ vector<scalarexp_t *> partial_fcns;
+ vector<int> fcn_ref_cnt;
+ vector<bool> is_partial_fcn;
+ for(s=0;s<select_list.size();s++){
+ find_partial_fcns(select_list[s]->se, &partial_fcns, NULL,NULL, Ext_fcns);
+ }
+ for(w=0;w<where.size();w++){
+ find_partial_fcns_pr(where[w]->pr, &partial_fcns, NULL,NULL, Ext_fcns);
+ }
+ for(w=0;w<having.size();w++){
+ find_partial_fcns_pr(having[w]->pr, &partial_fcns, NULL,NULL, Ext_fcns);
+ }
+ for(w=0;w<closing_when.size();w++){
+ find_partial_fcns_pr(closing_when[w]->pr, &partial_fcns, NULL,NULL, Ext_fcns);
+ }
+ for(g=0;g<gb_tbl.size();g++){
+ find_partial_fcns(gb_tbl.get_def(g), &partial_fcns, NULL,NULL, Ext_fcns);
+ }
+ for(a=0;a<aggr_tbl.size();a++){
+ find_partial_fcns(aggr_tbl.get_aggr_se(a), &partial_fcns, NULL,NULL, Ext_fcns);
+ }
+ if(partial_fcns.size()>0){
+ ret += "/*\t\tVariables for storing results of partial functions. \t*/\n";
+ ret += generate_partial_fcn_vars(partial_fcns,fcn_ref_cnt,is_partial_fcn,false);
+ }
+
+// Create cached temporaries for UDAF return values.
+ for(a=0;a<aggr_tbl.size();a++){
+ if(! aggr_tbl.is_builtin(a)){
+ int afcn_id = aggr_tbl.get_fcn_id(a);
+ data_type *adt = Ext_fcns->get_fcn_dt(afcn_id);
+ sprintf(tmpstr,"udaf_ret_%d", a);
+ ret+="\t"+adt->make_host_cvar(tmpstr)+";\n";
+ }
+ }
+
+
+// Complex literals (i.e., they need constructors)
+ ret += "//\t\tComplex literal storage.\n";
+ cplx_lit_table *complex_literals = this->get_cplx_lit_tbl(Ext_fcns);
+ ret += generate_complex_lit_vars(complex_literals);
+
+// Pass-by-handle parameters
+ ret += "//\t\tPass-by-handle storage.\n";
+ vector<handle_param_tbl_entry *> param_handle_table = this->get_handle_param_tbl(Ext_fcns);
+ ret += generate_pass_by_handle_vars(param_handle_table);
+
+
+// variables to hold parameters.
+ ret += "//\tfor query parameters\n";
+ ret += generate_param_vars(param_tbl);
+
+// Is there a temporal flush? If so create flush temporaries,
+// create flush indicator.
+ bool uses_temporal_flush = false;
+ for(g=0;g<gb_tbl.size();g++){
+ data_type *gdt = gb_tbl.get_data_type(g);
+ if(gdt->is_temporal())
+ uses_temporal_flush = true;
+ }
+
+ if(uses_temporal_flush){
+ ret += "//\t\tFor temporal flush\n";
+ for(g=0;g<gb_tbl.size();g++){
+ data_type *gdt = gb_tbl.get_data_type(g);
+ if(gdt->is_temporal()){
+ sprintf(tmpstr,"curr_gb%d",g);
+ ret+="\t"+gb_tbl.get_data_type(g)->make_host_cvar(tmpstr)+";\n";
+ sprintf(tmpstr,"last_gb%d",g);
+ ret+="\t"+gb_tbl.get_data_type(g)->make_host_cvar(tmpstr)+";\n";
+ }
+ }
+ ret += "\tgs_int32_t needs_temporal_flush;\n";
+ ret += "\tbool disordered_arrival;\n";
+ }
+
+// The publicly exposed functions
+
+ ret += "\npublic:\n";
+
+
+//-------------------
+// The functor constructor
+// pass in the schema handle.
+// 1) make assignments to the unpack offset variables
+// 2) initialize the complex literals
+
+ ret += "//\t\tFunctor constructor.\n";
+ ret += this->generate_functor_name()+"(int schema_handle0){\n";
+
+ // save the schema handle
+ ret += "\t\tthis->schema_handle0 = schema_handle0;\n";
+// metadata offset
+ ret += "\ttuple_metadata_offset0 = ftaschema_get_tuple_metadata_offset(schema_handle0);\n";
+
+// unpack vars
+ ret += "//\t\tGet offsets for unpacking fields from input tuple.\n";
+ ret += gen_access_var_init(cid_set);
+
+// complex literals
+ ret += "//\t\tInitialize complex literals.\n";
+ ret += gen_complex_lit_init(complex_literals);
+
+// Initialize partial function results so they can be safely GC'd
+ ret += gen_partial_fcn_init(partial_fcns);
+
+// Initialize non-query-parameter parameter handles
+ ret += gen_pass_by_handle_init(param_handle_table);
+
+// temporal flush variables
+// ASSUME that structured values won't be temporal.
+ if(uses_temporal_flush){
+ ret += "//\t\tInitialize temporal flush variables.\n";
+ for(g=0;g<gb_tbl.size();g++){
+ data_type *gdt = gb_tbl.get_data_type(g);
+ if(gdt->is_temporal()){
+ literal_t gl(gdt->type_indicator());
+ sprintf(tmpstr,"\tcurr_gb%d = %s;\n",g, gl.to_hfta_C_code("").c_str());
+ ret.append(tmpstr);
+ sprintf(tmpstr,"\tlast_gb%d = %s;\n",g, gl.to_hfta_C_code("").c_str());
+ ret.append(tmpstr);
+ }
+ }
+ ret += "\tneeds_temporal_flush = 0;\n";
+ }
+
+ // Init temporal attributes referenced in select list
+ ret += gen_init_temp_vars(schema, select_list, segen_gb_tbl);
+
+ ret += "};\n";
+
+
+//-------------------
+// Functor destructor
+ ret += "//\t\tFunctor destructor.\n";
+ ret += "~"+this->generate_functor_name()+"(){\n";
+
+// clean up buffer type complex literals
+ ret += gen_complex_lit_dtr(complex_literals);
+
+// Deregister the pass-by-handle parameters
+ ret += "/* register and de-register the pass-by-handle parameters */\n";
+ ret += gen_pass_by_handle_dtr(param_handle_table);
+
+// clean up partial function results.
+ ret += "/* clean up partial function storage */\n";
+ ret += gen_partial_fcn_dtr(partial_fcns);
+
+// Destroy the parameters, if any need to be destroyed
+ ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";
+
+ ret += "};\n\n";
+
+
+//-------------------
+// Parameter manipulation routines
+ ret += generate_load_param_block(this->generate_functor_name(),
+ this->param_tbl,param_handle_table);
+ ret += generate_delete_param_block(this->generate_functor_name(),
+ this->param_tbl,param_handle_table);
+
+//-------------------
+// Register new parameter block
+
+ ret += "int set_param_block(gs_int32_t sz, void* value){\n";
+ ret += "\tthis->destroy_params_"+this->generate_functor_name()+"();\n";
+ ret += "\treturn this->load_params_"+this->generate_functor_name()+
+ "(sz, value);\n";
+ ret += "};\n\n";
+
+
+//-------------------
+// the create_group method.
+// This method creates a group in a buffer passed in
+// (to allow for creation on the stack).
+// There are also a couple of side effects:
+// 1) evaluate the WHERE clause (and therefore, unpack all partial fcns)
+// 2) determine if a temporal flush is required.
+
+ ret += this->generate_functor_name()+"_groupdef *create_group(host_tuple &tup0, gs_sp_t buffer){\n";
+ // Variables for execution of the function.
+ ret += "\tgs_int32_t problem = 0;\n"; // return unpack failure
+
+ if(partial_fcns.size()>0){ // partial fcn access failure
+ ret += "\tgs_retval_t retval = 0;\n";
+ ret += "\n";
+ }
+// return value
+ ret += "\t"+generate_functor_name()+"_groupdef *gbval = ("+generate_functor_name()+
+ "_groupdef *) buffer;\n";
+
+// Start by cleaning up partial function results
+ ret += "//\t\tcall destructors for partial fcn storage vars of buffer type\n";
+ set<int> w_pfcns; // partial fcns in where clause
+ for(w=0;w<where.size();++w)
+ collect_partial_fcns_pr(where[w]->pr, w_pfcns);
+
+ set<int> ag_gb_pfcns; // partial fcns in gbdefs, aggr se's
+ for(g=0;g<gb_tbl.size();g++){
+ collect_partial_fcns(gb_tbl.get_def(g), ag_gb_pfcns);
+ }
+ for(a=0;a<aggr_tbl.size();a++){
+ collect_partial_fcns(aggr_tbl.get_aggr_se(a), ag_gb_pfcns);
+ }
+ ret += gen_partial_fcn_dtr(partial_fcns,w_pfcns);
+ ret += gen_partial_fcn_dtr(partial_fcns,ag_gb_pfcns);
+// ret += gen_partial_fcn_dtr(partial_fcns);
+
+
+ ret += gen_temp_tuple_check(this->node_name, 0);
+ col_id_set found_cids; // colrefs unpacked thus far.
+ ret += gen_unpack_temp_vars(schema, found_cids, select_list, segen_gb_tbl, needs_xform);
+
+
+// Save temporal group-by variables
+
+
+ ret.append("\n\t//\t\tCompute temporal groupby attributes\n\n");
+
+ for(g=0;g<gb_tbl.size();g++){
+
+ data_type *gdt = gb_tbl.get_data_type(g);
+
+ if(gdt->is_temporal()){
+ sprintf(tmpstr,"\tgbval->gb_var%d = %s;\n",
+ g, generate_se_code(gb_tbl.get_def(g),schema).c_str() );
+ ret.append(tmpstr);
+ }
+ }
+ ret.append("\n");
+
+
+
+// Compare the temporal GB vars with the stored ones,
+// set flush indicator and update stored GB vars if there is any change.
+
+ if(uses_temporal_flush){
+ ret+= "\tif( ( (";
+ bool first_one = true;
+ string disorder_test;
+ for(g=0;g<gb_tbl.size();g++){
+ data_type *gdt = gb_tbl.get_data_type(g);
+
+ if(gdt->is_temporal()){
+ sprintf(tmpstr,"curr_gb%d",g); string lhs_op = tmpstr;
+ sprintf(tmpstr,"gbval->gb_var%d",g); string rhs_op = tmpstr;
+ if(first_one){first_one = false;} else {ret += ") && (";}
+ ret += generate_lt_test(lhs_op, rhs_op, gdt);
+ disorder_test += generate_lt_test(rhs_op, lhs_op, gdt);
+ }
+ }
+ ret += ") ) ){\n";
+ int temporal_gb=-1;
+ for(g=0;g<gb_tbl.size();g++){
+ data_type *gdt = gb_tbl.get_data_type(g);
+ if(gdt->is_temporal()){
+ if(gdt->is_buffer_type()){
+ sprintf(tmpstr,"\t\t%s(&(gbval->gb_var%d),&curr_gb%d);\n",gdt->get_hfta_buffer_replace().c_str(),g,g);
+ }else{
+// sprintf(tmpstr,"\t\tlast_gb%d = curr_gb%d;\n",g,g);
+// ret += tmpstr;
+// sprintf(tmpstr,"\t\tcurr_gb%d = gbval->gb_var%d;\n",g,g);
+
+ ret += "\t\tif(curr_gb"+to_string(g)+"==0){\n";
+ ret += "\t\t\tlast_gb"+to_string(g)+" = gbval->gb_var"+to_string(g)+";\n";
+ ret += "\t\t}else{\n";
+ ret += "\t\t\tlast_gb"+to_string(g)+" = curr_gb"+to_string(g)+";\n";
+ ret += "\t\t}\n";
+ sprintf(tmpstr,"\t\tcurr_gb%d = gbval->gb_var%d;\n",g,g);
+ temporal_gb=g;
+ }
+ ret += tmpstr;
+ }
+ }
+ ret += "\t\tneeds_temporal_flush = curr_gb"+to_string (temporal_gb)+" - last_gb"+to_string(temporal_gb)+";\n";
+ ret += "\t}else{\n"
+ "\t\tneeds_temporal_flush=0;\n"
+ "\t}\n";
+
+ ret += "\tdisordered_arrival = "+disorder_test+";\n";
+// ret += "\tif( ( ("+disorder_test+") ) ){\n";
+// ret += "\t\tdisordered_arrival=true;\n";
+// ret += "\t}else{\n";
+// ret += "\t\tdisordered_arrival=false;\n";
+// ret += "\t}\n";
+ }
+
+
+// For temporal status tuple we don't need to do anything else
+ ret += "\tif (temp_tuple_received) return NULL;\n\n";
+
+ for(w=0;w<where.size();++w){
+ sprintf(tmpstr,"//\t\tPredicate clause %d.\n",w);
+ ret += tmpstr;
+// Find the set of variables accessed in this CNF elem,
+// but in no previous element.
+ col_id_set new_cids;
+ get_new_pred_cids(where[w]->pr, found_cids, new_cids, segen_gb_tbl);
+
+// Unpack these values.
+ ret += gen_unpack_cids(schema, new_cids, "NULL", needs_xform);
+// Find partial fcns ref'd in this cnf element
+ set<int> pfcn_refs;
+ collect_partial_fcns_pr(where[w]->pr, pfcn_refs);
+ ret += gen_unpack_partial_fcn(schema, partial_fcns, pfcn_refs,"NULL");
+
+ ret += "\tif( !("+generate_predicate_code(where[w]->pr,schema)+
+ +") ) return(NULL);\n";
+ }
+
+// The partial functions ref'd in the group-by var and aggregate
+// definitions must also be evaluated. If one returns false,
+// then implicitly the predicate is false.
+ set<int>::iterator pfsi;
+
+ if(ag_gb_pfcns.size() > 0)
+ ret += "//\t\tUnpack remaining partial fcns.\n";
+ ret += gen_full_unpack_partial_fcn(schema, partial_fcns, ag_gb_pfcns,
+ found_cids, segen_gb_tbl, "NULL", needs_xform);
+
+// Unpack the group-by variables
+
+ for(g=0;g<gb_tbl.size();g++){
+ data_type *gdt = gb_tbl.get_data_type(g);
+ if(!gdt->is_temporal()){ // temproal gbs already computed
+// Find the new fields ref'd by this GBvar def.
+ col_id_set new_cids;
+ get_new_se_cids(gb_tbl.get_def(g), found_cids, new_cids, segen_gb_tbl);
+// Unpack these values.
+ ret += gen_unpack_cids(schema, new_cids, "NULL", needs_xform);
+
+ sprintf(tmpstr,"\tgbval->gb_var%d = %s;\n",
+ g, generate_se_code(gb_tbl.get_def(g),schema).c_str() );
+/*
+// There seems to be no difference between the two
+// branches of the IF statement.
+ data_type *gdt = gb_tbl.get_data_type(g);
+ if(gdt->is_buffer_type()){
+// Create temporary copy.
+ sprintf(tmpstr,"\tgbval->gb_var%d = %s;\n",
+ g, generate_se_code(gb_tbl.get_def(g),schema).c_str() );
+ }else{
+ scalarexp_t *gse = gb_tbl.get_def(g);
+ sprintf(tmpstr,"\tgbval->gb_var%d = %s;\n",
+ g,generate_se_code(gse,schema).c_str());
+ }
+*/
+ ret.append(tmpstr);
+ }
+ }
+ ret.append("\n");
+
+
+ ret+= "\treturn gbval;\n";
+ ret += "};\n\n\n";
+
+//--------------------------------------------------------
+// Create and initialize an aggregate object
+
+ ret += this->generate_functor_name()+"_aggrdef *create_aggregate(host_tuple &tup0, gs_sp_t buffer){\n";
+ // Variables for execution of the function.
+ ret += "\tgs_int32_t problem = 0;\n"; // return unpack failure
+
+// return value
+ ret += "\t"+generate_functor_name()+"_aggrdef *aggval = ("+generate_functor_name()+
+ "_aggrdef *)buffer;\n";
+
+ for(a=0;a<aggr_tbl.size();a++){
+ if(aggr_tbl.is_builtin(a)){
+// Create temporaries for buffer return values
+ data_type *adt = aggr_tbl.get_data_type(a);
+ if(adt->is_buffer_type()){
+ sprintf(tmpstr,"aggr_tmp_%d", a);
+ ret+=adt->make_host_cvar(tmpstr)+";\n";
+ }
+ }
+ }
+
+// Unpack all remaining attributes
+ ret += gen_remaining_colrefs(schema, cid_set, found_cids, "NULL", needs_xform);
+ for(a=0;a<aggr_tbl.size();a++){
+ sprintf(tmpstr,"aggval->aggr_var%d",a);
+ string assignto_var = tmpstr;
+ ret += "\t"+generate_aggr_init(assignto_var,&aggr_tbl,a, schema);
+ }
+
+ ret += "\treturn aggval;\n";
+ ret += "};\n\n";
+
+//--------------------------------------------------------
+// update an aggregate object
+
+ ret += "void update_aggregate(host_tuple &tup0, "
+ +generate_functor_name()+"_groupdef &gbval, "+
+ generate_functor_name()+"_aggrdef &aggval){\n";
+ // Variables for execution of the function.
+ ret += "\tgs_int32_t problem = 0;\n"; // return unpack failure
+
+// use of temporaries depends on the aggregate,
+// generate them in generate_aggr_update
+
+
+// Unpack all remaining attributes
+ ret += gen_remaining_colrefs(schema, cid_set, found_cids, "", needs_xform);
+ for(a=0;a<aggr_tbl.size();a++){
+ sprintf(tmpstr,"aggval.aggr_var%d",a);
+ string varname = tmpstr;
+ ret.append(generate_aggr_update(varname,&aggr_tbl,a, schema));
+ }
+
+ ret += "\treturn;\n";
+ ret += "};\n";
+
+//--------------------------------------------------------
+// reinitialize an aggregate object
+
+ ret += "void reinit_aggregates( "+
+ generate_functor_name()+"_groupdef &gbval, "+
+ generate_functor_name()+"_aggrdef &aggval){\n";
+ // Variables for execution of the function.
+ ret += "\tgs_int32_t problem = 0;\n"; // return unpack failure
+
+// use of temporaries depends on the aggregate,
+// generate them in generate_aggr_update
+
+ int temporal_gb; // track the # of the temporal gb
+ for(g=0;g<gb_tbl.size();g++){
+ data_type *gdt = gb_tbl.get_data_type(g);
+ if(gdt->is_temporal()){
+ if(gdt->is_buffer_type()){
+ sprintf(tmpstr,"\t\t%s(&(gbval.gb_var%d),&last_gb%d);\n",gdt->get_hfta_buffer_replace().c_str(),g,g);
+ }else{
+ sprintf(tmpstr,"\t\t gbval.gb_var%d =last_gb%d;\n",g,g);
+ }
+ ret += tmpstr;
+ temporal_gb = g;
+ }
+ }
+
+// Unpack all remaining attributes
+ for(a=0;a<aggr_tbl.size();a++){
+ sprintf(tmpstr,"aggval.aggr_var%d",a);
+ string varname = tmpstr;
+ ret.append(generate_aggr_reinitialize(varname,&aggr_tbl,a, schema));
+ }
+
+ ret += "\treturn;\n";
+ ret += "};\n";
+
+
+
+
+
+//---------------------------------------------------
+// Flush test
+
+ ret += "gs_int32_t flush_needed(){\n";
+ if(uses_temporal_flush){
+ ret += "\treturn needs_temporal_flush;\n";
+ }else{
+ ret += "\treturn false;\n";
+ }
+ ret += "};\n";
+
+ ret += "bool disordered(){return disordered_arrival;}\n";
+
+//------------------------------------------------
+// time bucket management
+ ret += "void advance_last_tb(){\n";
+ ret += "\tlast_gb"+to_string(temporal_gb)+"++;\n";
+ ret += "}\n\n";
+ ret += "void reset_last_tb(){\n";
+ ret += "\tlast_gb"+to_string(temporal_gb)+" = curr_gb"+to_string(temporal_gb)+";\n";
+ ret += "}\n\n";
+
+//---------------------------------------------------
+// create output tuple
+// Unpack the partial functions ref'd in the where clause,
+// select clause. Evaluate the where clause.
+// Finally, pack the tuple.
+
+// I need to use special code generation here,
+// so I'll leave it in longhand.
+
+ ret += "host_tuple create_output_tuple("
+ +generate_functor_name()+"_groupdef &gbval, "+
+ generate_functor_name()+"_aggrdef &aggval, bool &failed){\n";
+
+ ret += "\thost_tuple tup;\n";
+ ret += "\tfailed = false;\n";
+ ret += "\tgs_retval_t retval = 0;\n";
+
+ string gbvar = "gbval.gb_var";
+ string aggvar = "aggval.";
+
+
+// First, get the return values from the UDAFS
+ for(a=0;a<aggr_tbl.size();a++){
+ if(! aggr_tbl.is_builtin(a)){
+ ret += "\t"+aggr_tbl.get_op(a)+"_HFTA_AGGR_OUTPUT_(&(udaf_ret_"+int_to_string(a)+"),";
+ if(aggr_tbl.get_storage_type(a)->get_type() != fstring_t) ret+="&";
+ ret+="("+aggvar+"aggr_var"+int_to_string(a)+"));\n";
+ }
+ }
+
+ set<int> hv_sl_pfcns;
+ for(w=0;w<having.size();w++){
+ collect_partial_fcns_pr(having[w]->pr, hv_sl_pfcns);
+ }
+ for(s=0;s<select_list.size();s++){
+ collect_partial_fcns(select_list[s]->se, hv_sl_pfcns);
+ }
+
+// clean up the partial fcn results from any previous execution
+ ret += gen_partial_fcn_dtr(partial_fcns,hv_sl_pfcns);
+
+// Unpack them now
+ for(pfsi=hv_sl_pfcns.begin();pfsi!=hv_sl_pfcns.end();++pfsi){
+ ret += unpack_partial_fcn_fm_aggr(partial_fcns[(*pfsi)], (*pfsi), gbvar, aggvar, schema);
+ ret += "\tif(retval){ failed = true; return(tup);}\n";
+ }
+
+// Evalaute the HAVING clause
+// TODO: this seems to have a ++ operator rather than a + operator.
+ for(w=0;w<having.size();++w){
+ ret += "\tif( !("+generate_predicate_code_fm_aggr(having[w]->pr,gbvar, aggvar, schema) +") ) { failed = true; return(tup);}\n";
+ }
+
+// Now, compute the size of the tuple.
+
+// Unpack any BUFFER type selections into temporaries
+// so that I can compute their size and not have
+// to recompute their value during tuple packing.
+// I can use regular assignment here because
+// these temporaries are non-persistent.
+// TODO: should I be using the selvar generation routine?
+
+ ret += "//\t\tCompute the size of the tuple.\n";
+ ret += "//\t\t\tNote: buffer storage packed at the end of the tuple.\n";
+ for(s=0;s<select_list.size();s++){
+ scalarexp_t *se = select_list[s]->se;
+ data_type *sdt = se->get_data_type();
+ if(sdt->is_buffer_type() &&
+ !( (se->get_operator_type() == SE_COLREF) ||
+ (se->get_operator_type() == SE_AGGR_STAR) ||
+ (se->get_operator_type() == SE_AGGR_SE) ||
+ (se->get_operator_type() == SE_FUNC && se->is_partial()) ||
+ (se->get_operator_type() == SE_FUNC && se->get_aggr_ref() >= 0))
+ ){
+ sprintf(tmpstr,"selvar_%d",s);
+ ret+="\t"+sdt->make_host_cvar(tmpstr)+" = ";
+ ret += generate_se_code_fm_aggr(se,gbvar, aggvar, schema) +";\n";
+ }
+ }
+
+// The size of the tuple is the size of the tuple struct plus the
+// size of the buffers to be copied in.
+
+ ret+="\ttup.tuple_size = sizeof(" + generate_tuple_name( this->get_node_name()) +") + sizeof(gs_uint8_t)";
+ for(s=0;s<select_list.size();s++){
+// if(s>0) ret += "+";
+ scalarexp_t *se = select_list[s]->se;
+ data_type *sdt = select_list[s]->se->get_data_type();
+ if(sdt->is_buffer_type()){
+ if(!( (se->get_operator_type() == SE_COLREF) ||
+ (se->get_operator_type() == SE_AGGR_STAR) ||
+ (se->get_operator_type() == SE_AGGR_SE) ||
+ (se->get_operator_type() == SE_FUNC && se->is_partial()) ||
+ (se->get_operator_type() == SE_FUNC && se->get_aggr_ref() >= 0))
+ ){
+ sprintf(tmpstr," + %s(&selvar_%d)", sdt->get_hfta_buffer_size().c_str(),s);
+ ret.append(tmpstr);
+ }else{
+ sprintf(tmpstr," + %s(&%s)", sdt->get_hfta_buffer_size().c_str(),generate_se_code_fm_aggr(se,gbvar, aggvar, schema).c_str());
+ ret.append(tmpstr);
+ }
+ }
+ }
+ ret.append(";\n");
+
+// Allocate tuple data block.
+ ret += "//\t\tCreate the tuple block.\n";
+ ret += "\ttup.data = malloc(tup.tuple_size);\n";
+ ret += "\ttup.heap_resident = true;\n";
+
+// Mark tuple as regular
+ ret += "\t*((gs_sp_t )tup.data + sizeof(" + generate_tuple_name( this->get_node_name()) +")) = REGULAR_TUPLE;\n";
+
+// ret += "\ttup.channel = 0;\n";
+ ret += "\t"+generate_tuple_name( this->get_node_name())+" *tuple = ("+
+ generate_tuple_name( this->get_node_name())+" *)(tup.data);\n";
+
+// Start packing.
+// (Here, offsets are hard-wired. is this a problem?)
+
+ ret += "//\t\tPack the fields into the tuple.\n";
+ ret += "\tint tuple_pos = sizeof("+generate_tuple_name( this->get_node_name()) +") + sizeof(gs_uint8_t);\n";
+ for(s=0;s<select_list.size();s++){
+ scalarexp_t *se = select_list[s]->se;
+ data_type *sdt = se->get_data_type();
+ if(sdt->is_buffer_type()){
+ if(!( (se->get_operator_type() == SE_COLREF) ||
+ (se->get_operator_type() == SE_AGGR_STAR) ||
+ (se->get_operator_type() == SE_AGGR_SE) ||
+ (se->get_operator_type() == SE_FUNC && se->is_partial()) ||
+ (se->get_operator_type() == SE_FUNC && se->get_aggr_ref() >= 0))
+ ){
+ 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);
+ ret.append(tmpstr);
+ sprintf(tmpstr,"\ttuple_pos += %s(&selvar_%d);\n", sdt->get_hfta_buffer_size().c_str(), s);
+ ret.append(tmpstr);
+ }else{
+ 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());
+ ret.append(tmpstr);
+ 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());
+ ret.append(tmpstr);
+ }
+ }else{
+ sprintf(tmpstr,"\ttuple->tuple_var%d = ",s);
+ ret.append(tmpstr);
+ ret.append(generate_se_code_fm_aggr(se,gbvar, aggvar, schema) );
+ ret.append(";\n");
+ }
+ }
+
+// Destroy string temporaries
+ ret += gen_buffer_selvars_dtr(select_list);
+
+ ret += "\treturn tup;\n";
+ ret += "};\n";
+
+//------------------------------------------------------------------
+// Cleaning_when : evaluate the cleaning_when clause.
+// ASSUME that the udaf return values have already
+// been unpacked. delete the string udaf return values at the end.
+
+ ret += "bool cleaning_when("
+ +generate_functor_name()+"_groupdef &gbval, "+
+ generate_functor_name()+"_aggrdef &aggval){\n";
+
+ ret += "\tbool retval = true;\n";
+
+
+ gbvar = "gbval.gb_var";
+ aggvar = "aggval.";
+
+
+ set<int> clw_pfcns;
+ for(w=0;w<closing_when.size();w++){
+ collect_partial_fcns_pr(closing_when[w]->pr, clw_pfcns);
+ }
+
+// clean up the partial fcn results from any previous execution
+ ret += gen_partial_fcn_dtr(partial_fcns,clw_pfcns);
+
+// Unpack them now
+ for(pfsi=clw_pfcns.begin();pfsi!=clw_pfcns.end();++pfsi){
+ ret += unpack_partial_fcn_fm_aggr(partial_fcns[(*pfsi)], (*pfsi), gbvar, aggvar, schema);
+ ret += "\tif(retval){ return false;}\n";
+ }
+
+// Evalaute the Closing When clause
+// TODO: this seems to have a ++ operator rather than a + operator.
+ for(w=0;w<closing_when.size();++w){
+ ret += "\tif( !("+generate_predicate_code_fm_aggr(closing_when[w]->pr,gbvar, aggvar, schema) +") ) { return false;}\n";
+ }
+
+
+// Destroy string return vals of UDAFs
+ for(a=0;a<aggr_tbl.size();a++){
+ if(! aggr_tbl.is_builtin(a)){
+ int afcn_id = aggr_tbl.get_fcn_id(a);
+ data_type *adt = Ext_fcns->get_fcn_dt(afcn_id);
+ if(adt->is_buffer_type()){
+ sprintf(tmpstr,"\t%s(&udaf_ret_%d);\n",
+ adt->get_hfta_buffer_destroy().c_str(), a );
+ ret += tmpstr;
+ }
+ }
+ }
+
+ ret += "\treturn retval;\n";
+ ret += "};\n";
+
+
+
+
+//-------------------------------------------------------------------
+// Temporal update functions
+
+ ret+="bool temp_status_received(){return temp_tuple_received;};\n\n";
+
+// create a temp status tuple
+ ret += "int create_temp_status_tuple(host_tuple& result, bool flush_finished) {\n\n";
+
+ ret += gen_init_temp_status_tuple(this->get_node_name());
+
+// Start packing.
+// (Here, offsets are hard-wired. is this a problem?)
+
+ ret += "//\t\tPack the fields into the tuple.\n";
+ for(s=0;s<select_list.size();s++){
+ data_type *sdt = select_list[s]->se->get_data_type();
+ if(sdt->is_temporal()){
+ sprintf(tmpstr,"\ttuple->tuple_var%d = ",s);
+ ret += tmpstr;
+ 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_gb", "", schema).c_str());
+ ret += tmpstr;
+ ret += ";\n";
+ }
+ }
+
+ ret += "\treturn 0;\n";
+ ret += "};};\n\n\n";
+
+
+//----------------------------------------------------------
+// The hash function
+
+ ret += "struct "+generate_functor_name()+"_hash_func{\n";
+ ret += "\tgs_uint32_t operator()(const "+generate_functor_name()+
+ "_groupdef &grp) const{\n";
+ ret += "\t\treturn(0";
+ for(g=0;g<gb_tbl.size();g++){
+ data_type *gdt = gb_tbl.get_data_type(g);
+ if(! gdt->is_temporal()){
+ ret += "^";
+ if(gdt->use_hashfunc()){
+ if(gdt->is_buffer_type())
+ sprintf(tmpstr,"(%s*%s(&(grp.gb_var%d)))",hash_nums[g%NRANDS].c_str(),gdt->get_hfta_hashfunc().c_str(),g);
+ else
+ sprintf(tmpstr,"(%s*%s(grp.gb_var%d))",hash_nums[g%NRANDS].c_str(),gdt->get_hfta_hashfunc().c_str(),g);
+ }else{
+ sprintf(tmpstr,"(%s*grp.gb_var%d)",hash_nums[g%NRANDS].c_str(),g);
+ }
+ ret += tmpstr;
+ }
+ }
+ ret += " >> 32);\n";
+ ret += "\t}\n";
+ ret += "};\n\n";
+
+//----------------------------------------------------------
+// The comparison function
+
+ ret += "struct "+generate_functor_name()+"_equal_func{\n";
+ ret += "\tbool operator()(const "+generate_functor_name()+"_groupdef &grp1, "+
+ "const "+generate_functor_name()+"_groupdef &grp2) const{\n";
+ ret += "\t\treturn( (";
+
+ string hcmpr = "";
+ bool first_exec = true;
+ for(g=0;g<gb_tbl.size();g++){
+ data_type *gdt = gb_tbl.get_data_type(g);
+ if(! gdt->is_temporal()){
+ if(first_exec){first_exec=false;}else{ hcmpr += ") && (";}
+ if(gdt->complex_comparison(gdt)){
+ if(gdt->is_buffer_type())
+ sprintf(tmpstr,"(%s(&(grp1.gb_var%d), &(grp2.gb_var%d))==0)",
+ gdt->get_hfta_equals_fcn(gdt).c_str(),g,g);
+ else
+ sprintf(tmpstr,"(%s((grp1.gb_var%d), (grp2.gb_var%d))==0)",
+ gdt->get_hfta_equals_fcn(gdt).c_str(),g,g);
+ }else{
+ sprintf(tmpstr,"grp1.gb_var%d == grp2.gb_var%d",g,g);
+ }
+ hcmpr += tmpstr;
+ }
+ }
+ if(hcmpr == "")
+ hcmpr = "true";
+ ret += hcmpr;
+
+ ret += ") );\n";
+ ret += "\t}\n";
+ ret += "};\n\n";
+
+
+ return(ret);
+}
+
+string rsgah_qpn::generate_operator(int i, string params){
+
+ return(
+ " running_agg_operator<" +
+ generate_functor_name()+","+
+ generate_functor_name() + "_groupdef, " +
+ generate_functor_name() + "_aggrdef, " +
+ generate_functor_name()+"_hash_func, "+
+ generate_functor_name()+"_equal_func "
+ "> *op"+int_to_string(i)+" = new running_agg_operator<"+
+ generate_functor_name()+","+
+ generate_functor_name() + "_groupdef, " +
+ generate_functor_name() + "_aggrdef, " +
+ generate_functor_name()+"_hash_func, "+
+ generate_functor_name()+"_equal_func "
+ ">("+params+", \"" + get_node_name() + "\");\n"
+ );
+}
+
+
+
+// Split aggregation into two HFTA components - sub and superaggregation
+// If unable to split the aggreagates, empty vector will be returned
+vector<qp_node *> sgah_qpn::split_node_for_hfta(ext_fcn_list *Ext_fcns, table_list *Schema){
+
+ vector<qp_node *> ret_vec;
+ int s, p, g, a, o, i;
+ int si;
+
+ vector<string> fta_flds, stream_flds;
+ int t = table_name->get_schema_ref();
+
+// Get the set of interfaces it accesses.
+ int ierr;
+ vector<string> sel_names;
+
+// Verify that all of the ref'd UDAFs can be split.
+
+ for(a=0;a<aggr_tbl.size();++a){
+ if(! aggr_tbl.is_builtin(a)){
+ int afcn = aggr_tbl.get_fcn_id(a);
+ int hfta_super_id = Ext_fcns->get_hfta_superaggr_id(afcn);
+ int hfta_sub_id = Ext_fcns->get_hfta_subaggr_id(afcn);
+ if(hfta_super_id < 0 || hfta_sub_id < 0){
+ return(ret_vec);
+ }
+ }
+ }
+
+/////////////////////////////////////////////////////
+// Split into aggr/aggr.
+
+
+ sgah_qpn *low_hfta_node = new sgah_qpn();
+ low_hfta_node->table_name = table_name;
+ low_hfta_node->set_node_name( "_"+node_name );
+ low_hfta_node->table_name->set_range_var(table_name->get_var_name());
+
+
+ sgah_qpn *hi_hfta_node = new sgah_qpn();
+ hi_hfta_node->table_name = new tablevar_t( ("_"+node_name).c_str());
+ hi_hfta_node->set_node_name( node_name );
+ hi_hfta_node->table_name->set_range_var(table_name->get_var_name());
+
+// First, process the group-by variables.
+// both low and hi level queries duplicate group-by variables of original query
+
+
+ for(g=0;g<gb_tbl.size();g++){
+// Insert the gbvar into both low- and hi level hfta.
+ scalarexp_t *gbvar_def = dup_se(gb_tbl.get_def(g), &aggr_tbl);
+ low_hfta_node->gb_tbl.add_gb_var(
+ gb_tbl.get_name(g), gb_tbl.get_tblvar_ref(g), gbvar_def, gb_tbl.get_reftype(g)
+ );
+
+// Insert a ref to the value of the gbvar into the low-level hfta select list.
+ colref_t *new_cr = new colref_t(gb_tbl.get_name(g).c_str() );
+ scalarexp_t *gbvar_fta = new scalarexp_t(new_cr);
+ gbvar_fta->set_gb_ref(g);
+ gbvar_fta->set_data_type( gb_tbl.get_def(g)->get_data_type() );
+ scalarexp_t *gbvar_stream = make_fta_se_ref(low_hfta_node->select_list, gbvar_fta,0);
+
+// Insert the corresponding gbvar ref (gbvar_stream) into the stream.
+ gbvar_stream->set_gb_ref(-1); // used as GBvar def
+ hi_hfta_node->gb_tbl.add_gb_var(
+ gbvar_stream->get_colref()->get_field(), -1, gbvar_stream, gb_tbl.get_reftype(g)
+ );
+
+ }
+// hi_hfta_node->gb_tbl.gb_patterns = gb_tbl.gb_patterns; // pattern processing at higtest level
+ hi_hfta_node->gb_tbl.set_pattern_info( &gb_tbl); // pattern processing at higtest level
+
+// SEs in the aggregate definitions.
+// They are all safe, so split them up for later processing.
+ map<int, scalarexp_t *> hfta_aggr_se;
+ for(a=0;a<aggr_tbl.size();++a){
+ split_hfta_aggr( &(aggr_tbl), a,
+ &(hi_hfta_node->aggr_tbl), &(low_hfta_node->aggr_tbl) ,
+ low_hfta_node->select_list,
+ hfta_aggr_se,
+ Ext_fcns
+ );
+ }
+
+
+// Next, the select list.
+
+ for(s=0;s<select_list.size();s++){
+ bool fta_forbidden = false;
+ scalarexp_t *root_se = rehome_fta_se(select_list[s]->se, &hfta_aggr_se);
+ hi_hfta_node->select_list.push_back(
+ new select_element(root_se, select_list[s]->name));
+ }
+
+
+
+// All the predicates in the where clause must execute
+// in the low-level hfta.
+
+ for(p=0;p<where.size();p++){
+ predicate_t *new_pr = dup_pr(where[p]->pr, &aggr_tbl);
+ cnf_elem *new_cnf = new cnf_elem(new_pr);
+ analyze_cnf(new_cnf);
+
+ low_hfta_node->where.push_back(new_cnf);
+ }
+
+// All of the predicates in the having clause must
+// execute in the high-level hfta node.
+
+ for(p=0;p<having.size();p++){
+ predicate_t *pr_root = rehome_fta_pr( having[p]->pr, &hfta_aggr_se);
+ cnf_elem *cnf_root = new cnf_elem(pr_root);
+ analyze_cnf(cnf_root);
+
+ hi_hfta_node->having.push_back(cnf_root);
+ }
+
+
+// Copy parameters to both nodes
+ vector<string> param_names = param_tbl->get_param_names();
+ int pi;
+ for(pi=0;pi<param_names.size();pi++){
+ data_type *dt = param_tbl->get_data_type(param_names[pi]);
+ low_hfta_node->param_tbl->add_param(param_names[pi],dt->duplicate(),
+ param_tbl->handle_access(param_names[pi]));
+ hi_hfta_node->param_tbl->add_param(param_names[pi],dt->duplicate(),
+ param_tbl->handle_access(param_names[pi]));
+ }
+ low_hfta_node->definitions = definitions;
+ hi_hfta_node->definitions = definitions;
+
+
+ low_hfta_node->table_name->set_machine(table_name->get_machine());
+ low_hfta_node->table_name->set_interface(table_name->get_interface());
+ low_hfta_node->table_name->set_ifq(false);
+
+ hi_hfta_node->table_name->set_machine(table_name->get_machine());
+ hi_hfta_node->table_name->set_interface(table_name->get_interface());
+ hi_hfta_node->table_name->set_ifq(false);
+
+ ret_vec.push_back(low_hfta_node);
+ ret_vec.push_back(hi_hfta_node);
+
+
+ return(ret_vec);
+
+
+ // TODO: add splitting into selection/aggregation
+}
+
+
+// Split aggregation into two HFTA components - sub and superaggregation
+// If unable to split the aggreagates, empty vector will be returned
+// Similar to sgah, but super aggregate is rsgah, subaggr is sgah
+vector<qp_node *> rsgah_qpn::split_node_for_hfta(ext_fcn_list *Ext_fcns, table_list *Schema){
+
+ vector<qp_node *> ret_vec;
+ int s, p, g, a, o, i;
+ int si;
+
+ vector<string> fta_flds, stream_flds;
+ int t = table_name->get_schema_ref();
+
+// Get the set of interfaces it accesses.
+ int ierr;
+ vector<string> sel_names;
+
+// Verify that all of the ref'd UDAFs can be split.
+
+ for(a=0;a<aggr_tbl.size();++a){
+ if(! aggr_tbl.is_builtin(a)){
+ int afcn = aggr_tbl.get_fcn_id(a);
+ int hfta_super_id = Ext_fcns->get_hfta_superaggr_id(afcn);
+ int hfta_sub_id = Ext_fcns->get_hfta_subaggr_id(afcn);
+ if(hfta_super_id < 0 || hfta_sub_id < 0){
+ return(ret_vec);
+ }
+ }
+ }
+
+/////////////////////////////////////////////////////
+// Split into aggr/aggr.
+
+
+ sgah_qpn *low_hfta_node = new sgah_qpn();
+ low_hfta_node->table_name = table_name;
+ low_hfta_node->set_node_name( "_"+node_name );
+ low_hfta_node->table_name->set_range_var(table_name->get_var_name());
+
+
+ rsgah_qpn *hi_hfta_node = new rsgah_qpn();
+ hi_hfta_node->table_name = new tablevar_t( ("_"+node_name).c_str());
+ hi_hfta_node->set_node_name( node_name );
+ hi_hfta_node->table_name->set_range_var(table_name->get_var_name());
+
+// First, process the group-by variables.
+// both low and hi level queries duplicate group-by variables of original query
+
+
+ for(g=0;g<gb_tbl.size();g++){
+// Insert the gbvar into both low- and hi level hfta.
+ scalarexp_t *gbvar_def = dup_se(gb_tbl.get_def(g), &aggr_tbl);
+ low_hfta_node->gb_tbl.add_gb_var(
+ gb_tbl.get_name(g), gb_tbl.get_tblvar_ref(g), gbvar_def, gb_tbl.get_reftype(g)
+ );
+
+// Insert a ref to the value of the gbvar into the low-level hfta select list.
+ colref_t *new_cr = new colref_t(gb_tbl.get_name(g).c_str() );
+ scalarexp_t *gbvar_fta = new scalarexp_t(new_cr);
+ gbvar_fta->set_gb_ref(g);
+ gbvar_fta->set_data_type( gb_tbl.get_def(g)->get_data_type() );
+ scalarexp_t *gbvar_stream = make_fta_se_ref(low_hfta_node->select_list, gbvar_fta,0);
+
+// Insert the corresponding gbvar ref (gbvar_stream) into the stream.
+ gbvar_stream->set_gb_ref(-1); // used as GBvar def
+ hi_hfta_node->gb_tbl.add_gb_var(
+ gbvar_stream->get_colref()->get_field(), -1, gbvar_stream, gb_tbl.get_reftype(g)
+ );
+
+ }
+
+// SEs in the aggregate definitions.
+// They are all safe, so split them up for later processing.
+ map<int, scalarexp_t *> hfta_aggr_se;
+ for(a=0;a<aggr_tbl.size();++a){
+ split_hfta_aggr( &(aggr_tbl), a,
+ &(hi_hfta_node->aggr_tbl), &(low_hfta_node->aggr_tbl) ,
+ low_hfta_node->select_list,
+ hfta_aggr_se,
+ Ext_fcns
+ );
+ }
+
+
+// Next, the select list.
+
+ for(s=0;s<select_list.size();s++){
+ bool fta_forbidden = false;
+ scalarexp_t *root_se = rehome_fta_se(select_list[s]->se, &hfta_aggr_se);
+ hi_hfta_node->select_list.push_back(
+ new select_element(root_se, select_list[s]->name));
+ }
+
+
+
+// All the predicates in the where clause must execute
+// in the low-level hfta.
+
+ for(p=0;p<where.size();p++){
+ predicate_t *new_pr = dup_pr(where[p]->pr, &aggr_tbl);
+ cnf_elem *new_cnf = new cnf_elem(new_pr);
+ analyze_cnf(new_cnf);
+
+ low_hfta_node->where.push_back(new_cnf);
+ }
+
+// All of the predicates in the having clause must
+// execute in the high-level hfta node.
+
+ for(p=0;p<having.size();p++){
+ predicate_t *pr_root = rehome_fta_pr( having[p]->pr, &hfta_aggr_se);
+ cnf_elem *cnf_root = new cnf_elem(pr_root);
+ analyze_cnf(cnf_root);
+
+ hi_hfta_node->having.push_back(cnf_root);
+ }
+
+// Similar for closing when
+ for(p=0;p<closing_when.size();p++){
+ predicate_t *pr_root = rehome_fta_pr( closing_when[p]->pr, &hfta_aggr_se);
+ cnf_elem *cnf_root = new cnf_elem(pr_root);
+ analyze_cnf(cnf_root);
+
+ hi_hfta_node->closing_when.push_back(cnf_root);
+ }
+
+
+// Copy parameters to both nodes
+ vector<string> param_names = param_tbl->get_param_names();
+ int pi;
+ for(pi=0;pi<param_names.size();pi++){
+ data_type *dt = param_tbl->get_data_type(param_names[pi]);
+ low_hfta_node->param_tbl->add_param(param_names[pi],dt->duplicate(),
+ param_tbl->handle_access(param_names[pi]));
+ hi_hfta_node->param_tbl->add_param(param_names[pi],dt->duplicate(),
+ param_tbl->handle_access(param_names[pi]));
+ }
+ low_hfta_node->definitions = definitions;
+ hi_hfta_node->definitions = definitions;
+
+
+ low_hfta_node->table_name->set_machine(table_name->get_machine());
+ low_hfta_node->table_name->set_interface(table_name->get_interface());
+ low_hfta_node->table_name->set_ifq(false);
+
+ hi_hfta_node->table_name->set_machine(table_name->get_machine());
+ hi_hfta_node->table_name->set_interface(table_name->get_interface());
+ hi_hfta_node->table_name->set_ifq(false);
+
+ ret_vec.push_back(low_hfta_node);
+ ret_vec.push_back(hi_hfta_node);
+
+
+ return(ret_vec);
+
+
+ // TODO: add splitting into selection/aggregation
+}
+
+//---------------------------------------------------------------
+// Code for propagating Protocol field source information
+
+
+scalarexp_t *resolve_protocol_se(scalarexp_t *se, vector<map<string, scalarexp_t *> *> &src_vec, gb_table *gb_tbl, table_list *Schema){
+ scalarexp_t *rse, *lse,*p_se, *gb_se;
+ int tno, schema_type;
+ map<string, scalarexp_t *> *pse_map;
+
+ switch(se->get_operator_type()){
+ case SE_LITERAL:
+ return new scalarexp_t(se->get_literal());
+ case SE_PARAM:
+ return scalarexp_t::make_param_reference(se->get_op().c_str());
+ case SE_COLREF:
+ if(se->is_gb()){
+ if(gb_tbl == NULL)
+ fprintf(stderr,"INTERNAL ERROR, in resolve_protocol_se, se->gb_ref=%d, but gb_tbl is NULL\n",se->get_gb_ref());
+ gb_se = gb_tbl->get_def(se->get_gb_ref());
+ return resolve_protocol_se(gb_se,src_vec,gb_tbl,Schema);
+ }
+
+ schema_type = Schema->get_schema_type(se->get_colref()->get_schema_ref());
+ if(schema_type == PROTOCOL_SCHEMA)
+ return dup_se(se,NULL);
+
+ tno = se->get_colref()->get_tablevar_ref();
+ if(tno >= src_vec.size()){
+ fprintf(stderr,"INTERNAL ERROR, in resolve_protocol_se, tno=%d, src_vec.size()=%lu\n",tno,src_vec.size());
+ }
+ if(src_vec[tno] == NULL)
+ return NULL;
+
+ pse_map =src_vec[tno];
+ p_se = (*pse_map)[se->get_colref()->get_field()];
+ if(p_se == NULL)
+ return NULL;
+ return dup_se(p_se,NULL);
+ case SE_UNARY_OP:
+ lse = resolve_protocol_se(se->get_left_se(),src_vec,gb_tbl,Schema);
+ if(lse == NULL)
+ return NULL;
+ else
+ return new scalarexp_t(se->get_op().c_str(),lse);
+ case SE_BINARY_OP:
+ lse = resolve_protocol_se(se->get_left_se(),src_vec,gb_tbl,Schema);
+ if(lse == NULL)
+ return NULL;
+ rse = resolve_protocol_se(se->get_right_se(),src_vec,gb_tbl,Schema);
+ if(rse == NULL)
+ return NULL;
+ return new scalarexp_t(se->get_op().c_str(),lse,rse);
+ case SE_AGGR_STAR:
+ return( NULL );
+ case SE_AGGR_SE:
+ return( NULL );
+ case SE_FUNC:
+ return(NULL);
+ default:
+ return(NULL);
+ break;
+ }
+
+}
+
+void spx_qpn::create_protocol_se(vector<qp_node *> q_sources, table_list *Schema){
+ int i;
+ vector<map<string, scalarexp_t *> *> src_vec;
+
+ for(i=0;i<q_sources.size();i++){
+ if(q_sources[i] != NULL)
+ src_vec.push_back(q_sources[i]->get_protocol_se());
+ else
+ src_vec.push_back(NULL);
+ }
+
+ for(i=0;i<select_list.size();i++){
+ protocol_map[select_list[i]->name] = resolve_protocol_se(select_list[i]->se,src_vec,NULL,Schema);
+ }
+}
+
+void join_eq_hash_qpn::create_protocol_se(vector<qp_node *> q_sources, table_list *Schema){
+ int i;
+ vector<map<string, scalarexp_t *> *> src_vec;
+
+ for(i=0;i<q_sources.size();i++){
+ if(q_sources[i] != NULL)
+ src_vec.push_back(q_sources[i]->get_protocol_se());
+ else
+ src_vec.push_back(NULL);
+ }
+
+ for(i=0;i<select_list.size();i++){
+ protocol_map[select_list[i]->name] = resolve_protocol_se(select_list[i]->se,src_vec,NULL,Schema);
+ }
+
+ for(i=0;i<hash_eq.size();i++){
+ hash_src_l.push_back(resolve_protocol_se(hash_eq[i]->pr->get_left_se(),src_vec,NULL,Schema));
+ hash_src_r.push_back(resolve_protocol_se(hash_eq[i]->pr->get_right_se(),src_vec,NULL,Schema));
+ }
+}
+
+void filter_join_qpn::create_protocol_se(vector<qp_node *> q_sources, table_list *Schema){
+ int i;
+ vector<map<string, scalarexp_t *> *> src_vec;
+
+ for(i=0;i<q_sources.size();i++){
+ if(q_sources[i] != NULL)
+ src_vec.push_back(q_sources[i]->get_protocol_se());
+ else
+ src_vec.push_back(NULL);
+ }
+
+ for(i=0;i<select_list.size();i++){
+ protocol_map[select_list[i]->name] = resolve_protocol_se(select_list[i]->se,src_vec,NULL,Schema);
+ }
+
+ for(i=0;i<hash_eq.size();i++){
+ hash_src_l.push_back(resolve_protocol_se(hash_eq[i]->pr->get_left_se(),src_vec,NULL,Schema));
+ hash_src_r.push_back(resolve_protocol_se(hash_eq[i]->pr->get_right_se(),src_vec,NULL,Schema));
+ }
+}
+
+void watch_join_qpn::create_protocol_se(vector<qp_node *> q_sources, table_list *Schema){
+ int i;
+ vector<map<string, scalarexp_t *> *> src_vec;
+
+ for(i=0;i<q_sources.size();i++){
+ if(q_sources[i] != NULL)
+ src_vec.push_back(q_sources[i]->get_protocol_se());
+ else
+ src_vec.push_back(NULL);
+ }
+
+ for(i=0;i<select_list.size();i++){
+ protocol_map[select_list[i]->name] = resolve_protocol_se(select_list[i]->se,src_vec,NULL,Schema);
+ }
+
+ for(i=0;i<key_flds.size();i++){
+ string kfld = key_flds[i];
+ hash_src_l.push_back(resolve_protocol_se(hash_eq[kfld]->pr->get_left_se(),src_vec,NULL,Schema));
+ hash_src_r.push_back(resolve_protocol_se(hash_eq[kfld]->pr->get_right_se(),src_vec,NULL,Schema));
+ }
+}
+
+
+void sgah_qpn::create_protocol_se(vector<qp_node *> q_sources, table_list *Schema){
+ int i;
+ vector<map<string, scalarexp_t *> *> src_vec;
+
+ for(i=0;i<q_sources.size();i++){
+ if(q_sources[i] != NULL)
+ src_vec.push_back(q_sources[i]->get_protocol_se());
+ else
+ src_vec.push_back(NULL);
+ }
+
+ for(i=0;i<select_list.size();i++){
+ protocol_map[select_list[i]->name] = resolve_protocol_se(select_list[i]->se,src_vec,&gb_tbl,Schema);
+ }
+
+ for(i=0;i<gb_tbl.size();i++)
+ gb_sources.push_back(resolve_protocol_se(gb_tbl.get_def(i),src_vec,&gb_tbl,Schema));
+
+}
+
+void rsgah_qpn::create_protocol_se(vector<qp_node *> q_sources, table_list *Schema){
+ int i;
+ vector<map<string, scalarexp_t *> *> src_vec;
+
+ for(i=0;i<q_sources.size();i++){
+ if(q_sources[i] != NULL)
+ src_vec.push_back(q_sources[i]->get_protocol_se());
+ else
+ src_vec.push_back(NULL);
+ }
+
+ for(i=0;i<select_list.size();i++){
+ protocol_map[select_list[i]->name] = resolve_protocol_se(select_list[i]->se,src_vec,&gb_tbl,Schema);
+ }
+
+ for(i=0;i<gb_tbl.size();i++)
+ gb_sources.push_back(resolve_protocol_se(gb_tbl.get_def(i),src_vec,&gb_tbl,Schema));
+}
+
+void sgahcwcb_qpn::create_protocol_se(vector<qp_node *> q_sources, table_list *Schema){
+ int i;
+ vector<map<string, scalarexp_t *> *> src_vec;
+
+ for(i=0;i<q_sources.size();i++){
+ if(q_sources[i] != NULL)
+ src_vec.push_back(q_sources[i]->get_protocol_se());
+ else
+ src_vec.push_back(NULL);
+ }
+
+ for(i=0;i<select_list.size();i++){
+ protocol_map[select_list[i]->name] = resolve_protocol_se(select_list[i]->se,src_vec,&gb_tbl,Schema);
+ }
+
+ for(i=0;i<gb_tbl.size();i++)
+ gb_sources.push_back(resolve_protocol_se(gb_tbl.get_def(i),src_vec,&gb_tbl,Schema));
+}
+
+void mrg_qpn::create_protocol_se(vector<qp_node *> q_sources, table_list *Schema){
+ int f,s,i;
+ scalarexp_t *first_se;
+
+ vector<map<string, scalarexp_t *> *> src_vec;
+ map<string, scalarexp_t *> *pse_map;
+
+ for(i=0;i<q_sources.size();i++){
+ if(q_sources[i] != NULL)
+ src_vec.push_back(q_sources[i]->get_protocol_se());
+ else
+ src_vec.push_back(NULL);
+ }
+
+ if(q_sources.size() == 0){
+ fprintf(stderr,"INTERNAL ERROR in mrg_qpn::create_protocol_se, q_sources.size() == 0\n");
+ exit(1);
+ }
+
+ vector<field_entry *> tbl_flds = table_layout->get_fields();
+ for(f=0;f<tbl_flds.size();f++){
+ bool match = true;
+ string fld_nm = tbl_flds[f]->get_name();
+ pse_map = src_vec[0];
+ first_se = (*pse_map)[fld_nm];
+ if(first_se == NULL)
+ match = false;
+ for(s=1;s<src_vec.size() && match;s++){
+ pse_map = src_vec[s];
+ scalarexp_t *match_se = (*pse_map)[fld_nm];
+ if(match_se == NULL)
+ match = false;
+ else
+ match = is_equivalent_se_base(first_se, match_se, Schema);
+ }
+ if(match)
+ protocol_map[fld_nm] = first_se;
+ else
+ protocol_map[fld_nm] = NULL;
+ }
+}
+
+void watch_tbl_qpn::create_protocol_se(vector<qp_node *> q_sources, table_list *Schema){
+ return;
+}
+