-/* ------------------------------------------------\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
-#include <string>\r
-#include"parse_fta.h"\r
-#include "parse_schema.h"\r
-#include "type_objects.h"\r
-#include <stdio.h>\r
-#include <stdlib.h>\r
-// #include <algo.h>\r
-#include<algorithm>\r
-\r
-using namespace std;\r
-\r
-table_list *Schema;\r
-\r
-table_def::table_def(const char *name, param_list *oprop, field_entry_list *fel,\r
- subqueryspec_list *ql, param_list *selp){\r
- table_name =name;\r
- fields = fel->get_list();\r
- schema_type = OPERATOR_VIEW_SCHEMA;\r
- qspec_list = ql->spec_list;\r
-\r
- if(oprop == NULL) op_properties = new param_list();\r
- else op_properties = oprop;\r
- if(selp == NULL) selpush = new param_list();\r
- else selpush = selp;\r
- base_tables = new param_list();\r
-};\r
-\r
-table_def *table_def::make_shallow_copy(string n){\r
- table_def *ret = new table_def();\r
- ret->table_name = n;\r
- ret->fields = fields;\r
- ret->schema_type = schema_type;\r
- ret->base_tables = base_tables;\r
- ret->op_properties = op_properties;\r
- ret->qspec_list = qspec_list;\r
- ret->selpush = selpush;\r
-\r
- return ret;\r
-}\r
-\r
-void table_def::mangle_subq_names(std::string mngl){\r
- int i;\r
- for(i=0;i<qspec_list.size();++i){\r
- subquery_spec *s = qspec_list[i]->duplicate();\r
- s->name += mngl;\r
- qspec_list[i] = s;\r
- }\r
-}\r
-\r
-\r
-\r
-bool table_def::contains_field(string f){\r
- int i;\r
-\r
- for(i=0;i<fields.size();i++){\r
- if(fields[i]->get_name() == f){\r
- return(true);\r
- }\r
- }\r
- return(false);\r
-\r
-}\r
-\r
-int table_def::get_field_idx(std::string f){\r
- int i;\r
- for(i=0;i<fields.size();i++){\r
- if(fields[i]->get_name() == f){\r
- return(i);\r
- }\r
- }\r
- return(-1);\r
-}\r
-\r
-\r
-string table_def::get_type_name(std::string f){\r
- int i;\r
- for(i=0;i<fields.size();i++){\r
- if(fields[i]->get_name() == f){\r
- return(fields[i]->get_type());\r
- }\r
- }\r
- return("INTERNAL ERROR undefined field " + f);\r
-}\r
-\r
-param_list *table_def::get_modifier_list(std::string f){\r
- int i;\r
- for(i=0;i<fields.size();i++){\r
- if(fields[i]->get_name() == f){\r
- return(fields[i]->get_modifier_list());\r
- }\r
- }\r
- fprintf(stderr,"INTERNAL ERROR, no field %s in table %s, call is get_modifier_list.\n",\r
- f.c_str(), table_name.c_str() );\r
- exit(1);\r
- return(NULL);\r
-}\r
-\r
-\r
-string table_def::get_fcn(std::string f){\r
- int i;\r
- for(i=0;i<fields.size();i++){\r
- if(fields[i]->get_name() == f){\r
- return(fields[i]->get_fcn());\r
- }\r
- }\r
- return("INTERNAL ERROR undefined field " + f);\r
-\r
-}\r
-\r
-\r
-string table_def::get_field_basetable(std::string f){\r
- int i;\r
- for(i=0;i<fields.size();i++){\r
- if(fields[i]->get_name() == f){\r
- return(fields[i]->get_basetable());\r
- }\r
- }\r
- return("INTERNAL ERROR undefined field " + f);\r
-\r
-}\r
-\r
-int table_def::verify_no_duplicates(std::string &err){\r
-\r
- int f1, f2;\r
- for(f1=0;f1<fields.size()-1;f1++){\r
- string f1_name = fields[f1]->get_name();\r
- for(f2=f1+1;f2<fields.size();f2++){\r
- if(f1_name == fields[f2]->get_name()){\r
- err.append("Error, table ");\r
- err.append(table_name);\r
- err.append(" has a duplicate field :");\r
- err.append(f1_name);\r
- err.append("\n");\r
- return(1);\r
- }\r
- }\r
- }\r
- return(0);\r
-}\r
-\r
-int table_def::verify_access_fcns(std::string &err){\r
- int retval = 0, f;\r
-\r
- for(f=0;f<fields.size();++f){\r
- if(fields[f]->get_fcn() == ""){\r
- err += "Error, PROTOCOL field "+table_name+"."+fields[f]->get_name()+" has an empty access function.\n";\r
- retval = 1;\r
- }\r
- }\r
-\r
- return(retval);\r
-}\r
-\r
-int table_def::add_field(field_entry *fe){\r
- string fe_name = fe->get_name();\r
- int f;\r
-\r
- for(f=0;f<fields.size();f++){\r
- if(fe_name == fields[f]->get_name()){\r
- return(-1);\r
- }\r
- }\r
- fields.push_back(fe);\r
- return(0);\r
-}\r
-\r
-\r
-vector<string> table_list::get_table_names(){\r
- vector<string> retval;\r
- int i;\r
- for(i=0;i<tbl_list.size();i++){\r
- retval.push_back(tbl_list[i]->get_tbl_name());\r
- }\r
- return(retval);\r
-}\r
-\r
-\r
-int table_list::find_tbl(string t){\r
- int i;\r
- for(i=0;i<tbl_list.size();i++)\r
- if(tbl_list[i]->get_tbl_name() == t)\r
- return(i);\r
-// fprintf(stderr,"INTERNAL ERROR: Could not find table %s in table_list::find_tbl\n",t.c_str());\r
- return(-1);\r
-}\r
-\r
-vector<field_entry *> table_list::get_fields(string t){\r
- int pos = find_tbl(t);\r
- if(pos<0){\r
- vector<field_entry *> r;\r
- return(r);\r
- }\r
- return(tbl_list[pos]->get_fields());\r
-}\r
-\r
-field_entry *table_list::get_field(string t, int i){\r
- int pos = find_tbl(t);\r
- if(pos<0){\r
- return(NULL);\r
- }\r
- return(tbl_list[pos]->get_field(i));\r
-}\r
-\r
-int table_list::get_field_idx(string t, string f){\r
- int pos = find_tbl(t);\r
- if(pos<0){\r
- return(-1);\r
- }\r
- return(tbl_list[pos]->get_field_idx(f));\r
-}\r
-\r
-\r
-vector<int> table_list::get_tblref_of_field(string f){\r
- int i;\r
- vector<int> retval;\r
-\r
- for(i=0;i<tbl_list.size();i++){\r
- if( tbl_list[i]->contains_field(f) ){\r
- retval.push_back(i);\r
- }\r
- }\r
- return(retval);\r
-}\r
-\r
-// TODO: this seems to duplicate find_tbl\r
-int table_list::get_table_ref(string t){\r
- int i;\r
- for(i=0;i<tbl_list.size();i++){\r
- if(tbl_list[i]->get_tbl_name() == t ){\r
- return(i);\r
- }\r
- }\r
- return(-1);\r
-}\r
-\r
-\r
-// Use to unroll hierarchically defined\r
-// tables. Used for source tables.\r
-// Also, do some sanity checking, better\r
-// to find the errors now when its easy to report\r
-// than later when its obscure.\r
-//\r
-// Also, process the unpacking functions.\r
-// and verify that all field unpacking functions\r
-// are listed in the schema.\r
-int table_list::unroll_tables(string &err){\r
-// First, verify there are no repeat field names in any\r
-// of the tables.\r
-\r
- int f, tref, p, t, ret, retval;\r
-\r
- for(t=0;t<tbl_list.size();t++){\r
- if(tbl_list[t]->get_schema_type() == UNPACK_FCNS_SCHEMA){\r
- for(f=0;f<tbl_list[t]->ufcn_list.size();f++){\r
- ufcn_fcn[ tbl_list[t]->ufcn_list[f]->name ] = tbl_list[t]->ufcn_list[f]->fcn;\r
- ufcn_cost[ tbl_list[t]->ufcn_list[f]->name ] = tbl_list[t]->ufcn_list[f]->cost;\r
- \r
- }\r
- }\r
- }\r
-\r
- for(t=0;t<tbl_list.size();t++){\r
- if(tbl_list[t]->get_schema_type() != UNPACK_FCNS_SCHEMA){\r
-// No duplicate field names\r
- ret = tbl_list[t]->verify_no_duplicates(err);\r
- if(ret) retval = ret;\r
-\r
-// every field has an access function\r
- if(tbl_list[t]->get_schema_type() == PROTOCOL_SCHEMA){\r
- retval = tbl_list[t]->verify_access_fcns(err);\r
- if(ret) retval = ret;\r
- }\r
-\r
-// Every type can be parsed\r
- vector<field_entry *> flds = tbl_list[t]->get_fields();\r
- for(f=0;f<flds.size();++f){\r
- data_type dt(flds[f]->get_type());\r
- if(dt.get_type() == undefined_t){\r
- err += "ERROR, field "+flds[f]->get_name()+" of table "+tbl_list[t]->get_tbl_name()+" has unrecognized type "+flds[f]->get_type()+"\n";\r
- retval = 1;\r
- }\r
- if(dt.get_type() == fstring_t){\r
- err += "ERROR, field "+flds[f]->get_name()+" of table "+tbl_list[t]->get_tbl_name()+" has unsupported type "+flds[f]->get_type()+"\n";\r
- retval = 1;\r
- }\r
- }\r
-\r
-// Ensure that the unpack functions, if any, exist.\r
- for(f=0;f<flds.size();++f){\r
- set<string> ufcns = flds[f]->get_unpack_fcns();\r
- set<string>::iterator ssi;\r
- for(ssi=ufcns.begin();ssi!=ufcns.end();ssi++){\r
- if(ufcn_fcn.count((*ssi))==0){\r
- err += "ERROR, field "+flds[f]->get_name()+" of table "+tbl_list[t]->get_tbl_name()+" has unrecognized unpacking function "+(*ssi)+"\n";\r
- retval = 1;\r
- }\r
- }\r
- }\r
-\r
-// annote the original source of the field -- for prefilter\r
- string tbl_name = tbl_list[t]->get_tbl_name();\r
- vector<field_entry *> fev = tbl_list[t]->get_fields();\r
- for(f=0;f<fev.size();++f)\r
- fev[f]->set_basetable(tbl_name);\r
- }\r
- }\r
-\r
- if(retval) return(retval);\r
-\r
-// Next, build a predecessors graph.\r
-// Verify that all referenced tables exist.\r
-\r
- vector< vector<int> > predecessors; // list of tables inherited from.\r
- vector<int> n_pred; // number of (remaining) predecessors.\r
- // -1 indicates a processed table.\r
-\r
- for(t=0;t<tbl_list.size();t++){\r
- if(tbl_list[t]->get_schema_type() != UNPACK_FCNS_SCHEMA){\r
- vector<string> pred_tbls = tbl_list[t]->get_pred_tbls();\r
- vector<int> pred_ref;\r
- for(p=0;p<pred_tbls.size();p++){\r
- tref = this->get_table_ref(pred_tbls[p]);\r
- if(tref < 0){\r
- err.append("Error: table ");\r
- err.append(tbl_list[t]->get_tbl_name());\r
- err.append(" referenced non-existent table ");\r
- err.append(pred_tbls[p]);\r
- err.append("\n");\r
- return(2);\r
- }else{\r
- pred_ref.push_back(tref);\r
- }\r
- }\r
- predecessors.push_back(pred_ref);\r
- n_pred.push_back(pred_ref.size());\r
- }else{\r
- vector<int> tmp_iv;\r
- predecessors.push_back(tmp_iv);\r
- n_pred.push_back(0);\r
- }\r
- }\r
-\r
-\r
- int n_remaining = predecessors.size();\r
- int n_total = n_remaining;\r
-\r
-// Run through the DAG and pull off one root at a time (n_pred == 0).\r
-// there might be a cycle, so iterate until n_remaining == 0.\r
-\r
- while(n_remaining > 0){\r
-\r
-// Find a root\r
- int root;\r
- for(root=0;root < n_total;root++){\r
- if(n_pred[root] == 0)\r
- break;\r
- }\r
- if(root == n_total){ // didn't find a root.\r
- err.append("Error : cycle in inheritance among the following tables:");\r
- int r;\r
- for(r=0;r<n_total;r++){\r
- if(n_pred[r] > 0){\r
- err.append(" ");\r
- err.append(tbl_list[r]->get_tbl_name());\r
- }\r
- }\r
- return(3);\r
- }\r
-\r
-// I'd adding fields from the root table to the\r
- vector<field_entry *> pred_fields = tbl_list[root]->get_fields();\r
-\r
-\r
-// Scan for all successors of the root.\r
- int s, f;\r
- for(s=0;s<n_total;s++){\r
- if(find((predecessors[s]).begin(), (predecessors[s]).end(), root) !=\r
- (predecessors[s]).end() ){\r
-\r
-// s is a successor : add the fields from the root.\r
- for(f=0;f<pred_fields.size();f++){\r
- retval = tbl_list[s]->add_field(pred_fields[f]);\r
- if(retval < 0){\r
- err.append("Warning: field ");\r
- err.append(pred_fields[f]->get_name());\r
- err.append(" already exists in table ");\r
- err.append(tbl_list[s]->get_tbl_name());\r
- err.append(" (inheriting from table ");\r
- err.append(tbl_list[root]->get_tbl_name());\r
- err.append(").\n");\r
- }\r
- }\r
-\r
-// s has one less predecessor.\r
- n_pred[s]--;\r
- }\r
- }\r
-\r
-// Indicate that the root has been processed.\r
- n_pred[root] = -1;\r
- n_remaining--;\r
- }\r
-\r
-\r
-// Done!\r
- return(0);\r
-}\r
-\r
-int table_list::add_table(table_def *td){\r
- int tref = get_table_ref(td->get_tbl_name());\r
- if(tref >= 0) return(tref);\r
- tbl_list.push_back(td);\r
- return(tbl_list.size() - 1);\r
-}\r
-\r
-\r
-\r
-//////////////////////////////////////////////////////\r
-////////// Serialize functions.\r
-////////// The deserialize fcn is the parser.\r
-\r
-\r
-string param_list::to_string(){\r
- string retval;\r
- map<string, string>::iterator mssi;\r
- bool first_exec=true;\r
- for(mssi=pmap.begin();mssi!=pmap.end();++mssi){\r
- if(first_exec){ first_exec=false; }\r
- else{ retval+=","; }\r
- retval += (*mssi).first + " ";\r
- retval += (*mssi).second;\r
- }\r
- return(retval);\r
-}\r
-\r
-string field_entry::to_string(){\r
- string retval = type + " " + name + " " + function;\r
- if(mod_list->size() > 0){\r
- retval += " ( " + mod_list->to_string() + " ) ";\r
- }\r
-\r
- return(retval);\r
-}\r
-\r
-\r
-\r
-\r
-string table_def::to_string(){\r
- int q;\r
- string retval;\r
- switch(schema_type){\r
- case PROTOCOL_SCHEMA:\r
- retval = "TABLE ";\r
- break;\r
- case STREAM_SCHEMA:\r
- retval = "STREAM ";\r
- break;\r
- case OPERATOR_VIEW_SCHEMA:\r
- retval += "OPERATOR_VIEW ";\r
- break;\r
- default:\r
- retval = "ERROR UNKNOWN TABLE TYPE ";\r
- break;\r
- }\r
-\r
- retval += table_name + " ";\r
-\r
- if(base_tables->size() > 0){\r
- retval += "( "+base_tables->to_string() + " ) ";\r
- }\r
-\r
- retval += "{\n";\r
-\r
- if(schema_type == OPERATOR_VIEW_SCHEMA){\r
- retval += "\tOPERATOR ("+op_properties->to_string()+")\n";\r
- retval += "\tFIELDS{\n";\r
- }\r
-\r
- int f;\r
- for(f=0;f<fields.size();f++){\r
- retval += "\t" + fields[f]->to_string() + ";\n";\r
- }\r
-\r
- if(schema_type == OPERATOR_VIEW_SCHEMA){\r
- retval += "\tSUBQUERIES{\n";\r
- for(q=0;q<qspec_list.size();++q){\r
- if(q>0) retval += ";\n";\r
- retval += qspec_list[q]->to_string();\r
- }\r
- retval += "\t}\n";\r
- retval += "\tSELECTION_PUSHDOWN ("+selpush->to_string()+")\n";\r
- }\r
-\r
- \r
-\r
- retval += "}\n";\r
-\r
- return(retval);\r
-}\r
-\r
-string table_list::to_string(){\r
- string retval;\r
- int t;\r
- for(t=0;t<tbl_list.size();t++){\r
- retval += tbl_list[t]->to_string();\r
- retval += "\n";\r
- }\r
- return(retval);\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.
+ ------------------------------------------- */
+
+#include <string>
+#include"parse_fta.h"
+#include "parse_schema.h"
+#include "type_objects.h"
+#include <stdio.h>
+#include <stdlib.h>
+// #include <algo.h>
+#include<algorithm>
+
+using namespace std;
+
+table_list *Schema;
+
+table_def::table_def(const char *name, param_list *oprop, field_entry_list *fel,
+ subqueryspec_list *ql, param_list *selp){
+ table_name =name;
+ fields = fel->get_list();
+ schema_type = OPERATOR_VIEW_SCHEMA;
+ qspec_list = ql->spec_list;
+
+ if(oprop == NULL) op_properties = new param_list();
+ else op_properties = oprop;
+ if(selp == NULL) selpush = new param_list();
+ else selpush = selp;
+ base_tables = new param_list();
+};
+
+table_def *table_def::make_shallow_copy(string n){
+ table_def *ret = new table_def();
+ ret->table_name = n;
+ ret->fields = fields;
+ ret->schema_type = schema_type;
+ ret->base_tables = base_tables;
+ ret->op_properties = op_properties;
+ ret->qspec_list = qspec_list;
+ ret->selpush = selpush;
+
+ return ret;
+}
+
+void table_def::mangle_subq_names(std::string mngl){
+ int i;
+ for(i=0;i<qspec_list.size();++i){
+ subquery_spec *s = qspec_list[i]->duplicate();
+ s->name += mngl;
+ qspec_list[i] = s;
+ }
+}
+
+
+
+bool table_def::contains_field(string f){
+ int i;
+
+ for(i=0;i<fields.size();i++){
+ if(fields[i]->get_name() == f){
+ return(true);
+ }
+ }
+ return(false);
+
+}
+
+int table_def::get_field_idx(std::string f){
+ int i;
+ for(i=0;i<fields.size();i++){
+ if(fields[i]->get_name() == f){
+ return(i);
+ }
+ }
+ return(-1);
+}
+
+
+string table_def::get_type_name(std::string f){
+ int i;
+ for(i=0;i<fields.size();i++){
+ if(fields[i]->get_name() == f){
+ return(fields[i]->get_type());
+ }
+ }
+ return("INTERNAL ERROR undefined field " + f);
+}
+
+param_list *table_def::get_modifier_list(std::string f){
+ int i;
+ for(i=0;i<fields.size();i++){
+ if(fields[i]->get_name() == f){
+ return(fields[i]->get_modifier_list());
+ }
+ }
+ fprintf(stderr,"INTERNAL ERROR, no field %s in table %s, call is get_modifier_list.\n",
+ f.c_str(), table_name.c_str() );
+ exit(1);
+ return(NULL);
+}
+
+
+string table_def::get_fcn(std::string f){
+ int i;
+ for(i=0;i<fields.size();i++){
+ if(fields[i]->get_name() == f){
+ return(fields[i]->get_fcn());
+ }
+ }
+ return("INTERNAL ERROR undefined field " + f);
+
+}
+
+
+string table_def::get_field_basetable(std::string f){
+ int i;
+ for(i=0;i<fields.size();i++){
+ if(fields[i]->get_name() == f){
+ return(fields[i]->get_basetable());
+ }
+ }
+ return("INTERNAL ERROR undefined field " + f);
+
+}
+
+int table_def::verify_no_duplicates(std::string &err){
+
+ int f1, f2;
+ for(f1=0;f1<fields.size()-1;f1++){
+ string f1_name = fields[f1]->get_name();
+ for(f2=f1+1;f2<fields.size();f2++){
+ if(f1_name == fields[f2]->get_name()){
+ err.append("Error, table ");
+ err.append(table_name);
+ err.append(" has a duplicate field :");
+ err.append(f1_name);
+ err.append("\n");
+ return(1);
+ }
+ }
+ }
+ return(0);
+}
+
+int table_def::verify_access_fcns(std::string &err){
+ int retval = 0, f;
+
+ for(f=0;f<fields.size();++f){
+ if(fields[f]->get_fcn() == ""){
+ err += "Error, PROTOCOL field "+table_name+"."+fields[f]->get_name()+" has an empty access function.\n";
+ retval = 1;
+ }
+ }
+
+ return(retval);
+}
+
+int table_def::add_field(field_entry *fe){
+ string fe_name = fe->get_name();
+ int f;
+
+ for(f=0;f<fields.size();f++){
+ if(fe_name == fields[f]->get_name()){
+ return(-1);
+ }
+ }
+ fields.push_back(fe);
+ return(0);
+}
+
+
+vector<string> table_list::get_table_names(){
+ vector<string> retval;
+ int i;
+ for(i=0;i<tbl_list.size();i++){
+ retval.push_back(tbl_list[i]->get_tbl_name());
+ }
+ return(retval);
+}
+
+
+int table_list::find_tbl(string t){
+ int i;
+ for(i=0;i<tbl_list.size();i++)
+ if(tbl_list[i]->get_tbl_name() == t)
+ return(i);
+// fprintf(stderr,"INTERNAL ERROR: Could not find table %s in table_list::find_tbl\n",t.c_str());
+ return(-1);
+}
+
+vector<field_entry *> table_list::get_fields(string t){
+ int pos = find_tbl(t);
+ if(pos<0){
+ vector<field_entry *> r;
+ return(r);
+ }
+ return(tbl_list[pos]->get_fields());
+}
+
+field_entry *table_list::get_field(string t, int i){
+ int pos = find_tbl(t);
+ if(pos<0){
+ return(NULL);
+ }
+ return(tbl_list[pos]->get_field(i));
+}
+
+int table_list::get_field_idx(string t, string f){
+ int pos = find_tbl(t);
+ if(pos<0){
+ return(-1);
+ }
+ return(tbl_list[pos]->get_field_idx(f));
+}
+
+
+vector<int> table_list::get_tblref_of_field(string f){
+ int i;
+ vector<int> retval;
+
+ for(i=0;i<tbl_list.size();i++){
+ if( tbl_list[i]->contains_field(f) ){
+ retval.push_back(i);
+ }
+ }
+ return(retval);
+}
+
+// TODO: this seems to duplicate find_tbl
+int table_list::get_table_ref(string t){
+ int i;
+ for(i=0;i<tbl_list.size();i++){
+ if(tbl_list[i]->get_tbl_name() == t ){
+ return(i);
+ }
+ }
+ return(-1);
+}
+
+
+// Use to unroll hierarchically defined
+// tables. Used for source tables.
+// Also, do some sanity checking, better
+// to find the errors now when its easy to report
+// than later when its obscure.
+//
+// Also, process the unpacking functions.
+// and verify that all field unpacking functions
+// are listed in the schema.
+int table_list::unroll_tables(string &err){
+// First, verify there are no repeat field names in any
+// of the tables.
+
+ int f, tref, p, t, ret, retval;
+
+ for(t=0;t<tbl_list.size();t++){
+ if(tbl_list[t]->get_schema_type() == UNPACK_FCNS_SCHEMA){
+ for(f=0;f<tbl_list[t]->ufcn_list.size();f++){
+ ufcn_fcn[ tbl_list[t]->ufcn_list[f]->name ] = tbl_list[t]->ufcn_list[f]->fcn;
+ ufcn_cost[ tbl_list[t]->ufcn_list[f]->name ] = tbl_list[t]->ufcn_list[f]->cost;
+
+ }
+ }
+ }
+
+ for(t=0;t<tbl_list.size();t++){
+ if(tbl_list[t]->get_schema_type() != UNPACK_FCNS_SCHEMA){
+// No duplicate field names
+ ret = tbl_list[t]->verify_no_duplicates(err);
+ if(ret) retval = ret;
+
+// every field has an access function
+ if(tbl_list[t]->get_schema_type() == PROTOCOL_SCHEMA){
+ retval = tbl_list[t]->verify_access_fcns(err);
+ if(ret) retval = ret;
+ }
+
+// Every type can be parsed
+ vector<field_entry *> flds = tbl_list[t]->get_fields();
+ for(f=0;f<flds.size();++f){
+ data_type dt(flds[f]->get_type());
+ if(dt.get_type() == undefined_t){
+ err += "ERROR, field "+flds[f]->get_name()+" of table "+tbl_list[t]->get_tbl_name()+" has unrecognized type "+flds[f]->get_type()+"\n";
+ retval = 1;
+ }
+ if(dt.get_type() == fstring_t){
+ err += "ERROR, field "+flds[f]->get_name()+" of table "+tbl_list[t]->get_tbl_name()+" has unsupported type "+flds[f]->get_type()+"\n";
+ retval = 1;
+ }
+ }
+
+// Ensure that the unpack functions, if any, exist.
+ for(f=0;f<flds.size();++f){
+ set<string> ufcns = flds[f]->get_unpack_fcns();
+ set<string>::iterator ssi;
+ for(ssi=ufcns.begin();ssi!=ufcns.end();ssi++){
+ if(ufcn_fcn.count((*ssi))==0){
+ err += "ERROR, field "+flds[f]->get_name()+" of table "+tbl_list[t]->get_tbl_name()+" has unrecognized unpacking function "+(*ssi)+"\n";
+ retval = 1;
+ }
+ }
+ }
+
+// annote the original source of the field -- for prefilter
+ string tbl_name = tbl_list[t]->get_tbl_name();
+ vector<field_entry *> fev = tbl_list[t]->get_fields();
+ for(f=0;f<fev.size();++f)
+ fev[f]->set_basetable(tbl_name);
+ }
+ }
+
+ if(retval) return(retval);
+
+// Next, build a predecessors graph.
+// Verify that all referenced tables exist.
+
+ vector< vector<int> > predecessors; // list of tables inherited from.
+ vector<int> n_pred; // number of (remaining) predecessors.
+ // -1 indicates a processed table.
+
+ for(t=0;t<tbl_list.size();t++){
+ if(tbl_list[t]->get_schema_type() != UNPACK_FCNS_SCHEMA){
+ vector<string> pred_tbls = tbl_list[t]->get_pred_tbls();
+ vector<int> pred_ref;
+ for(p=0;p<pred_tbls.size();p++){
+ tref = this->get_table_ref(pred_tbls[p]);
+ if(tref < 0){
+ err.append("Error: table ");
+ err.append(tbl_list[t]->get_tbl_name());
+ err.append(" referenced non-existent table ");
+ err.append(pred_tbls[p]);
+ err.append("\n");
+ return(2);
+ }else{
+ pred_ref.push_back(tref);
+ }
+ }
+ predecessors.push_back(pred_ref);
+ n_pred.push_back(pred_ref.size());
+ }else{
+ vector<int> tmp_iv;
+ predecessors.push_back(tmp_iv);
+ n_pred.push_back(0);
+ }
+ }
+
+
+ int n_remaining = predecessors.size();
+ int n_total = n_remaining;
+
+// Run through the DAG and pull off one root at a time (n_pred == 0).
+// there might be a cycle, so iterate until n_remaining == 0.
+
+ while(n_remaining > 0){
+
+// Find a root
+ int root;
+ for(root=0;root < n_total;root++){
+ if(n_pred[root] == 0)
+ break;
+ }
+ if(root == n_total){ // didn't find a root.
+ err.append("Error : cycle in inheritance among the following tables:");
+ int r;
+ for(r=0;r<n_total;r++){
+ if(n_pred[r] > 0){
+ err.append(" ");
+ err.append(tbl_list[r]->get_tbl_name());
+ }
+ }
+ return(3);
+ }
+
+// I'd adding fields from the root table to the
+ vector<field_entry *> pred_fields = tbl_list[root]->get_fields();
+
+
+// Scan for all successors of the root.
+ int s, f;
+ for(s=0;s<n_total;s++){
+ if(find((predecessors[s]).begin(), (predecessors[s]).end(), root) !=
+ (predecessors[s]).end() ){
+
+// s is a successor : add the fields from the root.
+ for(f=0;f<pred_fields.size();f++){
+ retval = tbl_list[s]->add_field(pred_fields[f]);
+ if(retval < 0){
+ err.append("Warning: field ");
+ err.append(pred_fields[f]->get_name());
+ err.append(" already exists in table ");
+ err.append(tbl_list[s]->get_tbl_name());
+ err.append(" (inheriting from table ");
+ err.append(tbl_list[root]->get_tbl_name());
+ err.append(").\n");
+ }
+ }
+
+// s has one less predecessor.
+ n_pred[s]--;
+ }
+ }
+
+// Indicate that the root has been processed.
+ n_pred[root] = -1;
+ n_remaining--;
+ }
+
+
+// Done!
+ return(0);
+}
+
+int table_list::add_table(table_def *td){
+ int tref = get_table_ref(td->get_tbl_name());
+ if(tref >= 0) return(tref);
+ tbl_list.push_back(td);
+ return(tbl_list.size() - 1);
+}
+
+
+
+//////////////////////////////////////////////////////
+////////// Serialize functions.
+////////// The deserialize fcn is the parser.
+
+
+string param_list::to_string(){
+ string retval;
+ map<string, string>::iterator mssi;
+ bool first_exec=true;
+ for(mssi=pmap.begin();mssi!=pmap.end();++mssi){
+ if(first_exec){ first_exec=false; }
+ else{ retval+=","; }
+ retval += (*mssi).first + " ";
+ retval += (*mssi).second;
+ }
+ return(retval);
+}
+
+string field_entry::to_string(){
+ string retval = type + " " + name + " " + function;
+ if(mod_list->size() > 0){
+ retval += " ( " + mod_list->to_string() + " ) ";
+ }
+
+ return(retval);
+}
+
+
+
+
+string table_def::to_string(){
+ int q;
+ string retval;
+ switch(schema_type){
+ case PROTOCOL_SCHEMA:
+ retval = "TABLE ";
+ break;
+ case STREAM_SCHEMA:
+ retval = "STREAM ";
+ break;
+ case OPERATOR_VIEW_SCHEMA:
+ retval += "OPERATOR_VIEW ";
+ break;
+ default:
+ retval = "ERROR UNKNOWN TABLE TYPE ";
+ break;
+ }
+
+ retval += table_name + " ";
+
+ if(base_tables->size() > 0){
+ retval += "( "+base_tables->to_string() + " ) ";
+ }
+
+ retval += "{\n";
+
+ if(schema_type == OPERATOR_VIEW_SCHEMA){
+ retval += "\tOPERATOR ("+op_properties->to_string()+")\n";
+ retval += "\tFIELDS{\n";
+ }
+
+ int f;
+ for(f=0;f<fields.size();f++){
+ retval += "\t" + fields[f]->to_string() + ";\n";
+ }
+
+ if(schema_type == OPERATOR_VIEW_SCHEMA){
+ retval += "\tSUBQUERIES{\n";
+ for(q=0;q<qspec_list.size();++q){
+ if(q>0) retval += ";\n";
+ retval += qspec_list[q]->to_string();
+ }
+ retval += "\t}\n";
+ retval += "\tSELECTION_PUSHDOWN ("+selpush->to_string()+")\n";
+ }
+
+
+
+ retval += "}\n";
+
+ return(retval);
+}
+
+string table_list::to_string(){
+ string retval;
+ int t;
+ for(t=0;t<tbl_list.size();t++){
+ retval += tbl_list[t]->to_string();
+ retval += "\n";
+ }
+ return(retval);
+}