Fixed newline characters throughout the code
[com/gs-lite.git] / src / ftacmp / generate_nic_code.cc
1 /* ------------------------------------------------
2 Copyright 2014 AT&T Intellectual Property
3    Licensed under the Apache License, Version 2.0 (the "License");
4    you may not use this file except in compliance with the License.
5    You may obtain a copy of the License at
6
7      http://www.apache.org/licenses/LICENSE-2.0
8
9    Unless required by applicable law or agreed to in writing, software
10    distributed under the License is distributed on an "AS IS" BASIS,
11    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12    See the License for the specific language governing permissions and
13    limitations under the License.
14  ------------------------------------------- */
15
16 #include <string>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <algorithm>
20
21 #include "parse_fta.h"
22 #include "parse_schema.h"
23 #include "analyze_fta.h"
24 #include "generate_utils.h"
25 #include "query_plan.h"
26 #include "generate_nic_code.h"
27 #include"analyze_fta.h"
28
29 #define LEFT 1
30 #define RIGHT 2
31
32 using namespace std;
33
34 static const char *fcn_for_op[] = {
35         "+", "plus",
36         "-", "minus",
37         "|", "bitwise_or",
38         "*", "multiply",
39         "/", "divide",
40         "&", "bitwise_and",
41         "%", "modulo",
42         ">>", "shift_right",
43         "<<", "shift_left",
44         "AND", "AND",
45         "OR", "OR",
46         "=", "equal",
47         ">", "greater",
48         "<", "less",
49         ">=", "greater_equal",
50         "<=", "less_equal",
51         "<>", "not_equal",
52         "END"
53 };
54
55 static const char *fcn_for_unary_op[]= {
56         "+", "unary_plus",
57         "-", "unary_minus",
58         "!", "integer_not",
59         "~", "bitwise_not",
60         "NOT", "logical_not",
61         "END"
62 };
63
64 static string nic_fcn(string op){
65 int i = 0;
66 bool done = false;
67
68   while(!done){
69         if(string(fcn_for_op[i]) == string("END")){
70                 done = true;
71                 break;
72         }
73         if(string(fcn_for_op[i]) == op){
74                 return string(fcn_for_op[i+1]);
75         }
76         i++;
77   }
78   fprintf(stderr,"INTERNAL ERROR, operator %s not found in nic_fcn\n",op.c_str());
79   return string("ERROR");
80 }
81
82
83 static string unary_nic_fcn(string op){
84 int i = 0;
85 bool done = false;
86
87   while(!done){
88         if(string(fcn_for_unary_op[i]) == string("END")){
89                 done = true;
90                 break;
91         }
92         if(string(fcn_for_unary_op[i]) == op){
93                 return string(fcn_for_unary_op[i+1]);
94         }
95         i++;
96   }
97   fprintf(stderr,"INTERNAL ERROR, operator %s not found in unary_nic_fcn\n",op.c_str());
98   return string("ERROR");
99 }
100
101
102
103
104 //                      Generate code that makes reference
105 //                      to the tuple, and not to any aggregates.
106 static string generate_nic_se_code(scalarexp_t *se,
107                 map<string, string> &constants,
108                 int &copy_var_cnt,
109                 set<string> &no_copy_vars,
110                 string *retvar, int lr,
111                 gb_table *gbt  ){
112
113         string ret = "";
114         string l,cid;
115     data_type *ldt, *rdt;
116         int o;
117         vector<scalarexp_t *> operands;
118         string lvar, rvar;
119         int gbref;
120
121         string op = se->get_op();
122 //printf("op_type=%d op=%s\n",se->get_operator_type(),op.c_str());
123
124         switch(se->get_operator_type()){
125         case SE_LITERAL:
126                 l = se->get_literal()->to_query_string();
127                 if(constants.count(l)){
128                         cid = constants[l];
129                 }else{
130                         cid = "constant"+int_to_string(constants.size());
131                         constants[cid] = l;
132                 }
133                 *retvar = cid;
134                 if(lr == LEFT){
135                         *retvar = "copyvar_"+int_to_string(copy_var_cnt);
136                         copy_var_cnt++;
137                         ret += "load_with_copy("+*retvar+","+cid+")\n";
138                 }
139                 return(ret);
140         case SE_PARAM:
141                 fprintf(stderr,"INTERNAL ERROR, param ref'd in generate_nic_se_code\n");
142                 *retvar = "error";
143                 return("ERROR in generate_nic_se_code");
144         case SE_UNARY_OP:
145                 ret += generate_nic_se_code(se->get_left_se(),
146                         constants, copy_var_cnt, no_copy_vars, &lvar,LEFT,gbt);
147                 ret += unary_nic_fcn(op)+"("+lvar+")\n";
148                 *retvar = lvar;
149                 return(ret);
150         case SE_BINARY_OP:
151                 ret += generate_nic_se_code(se->get_left_se(),
152                         constants, copy_var_cnt, no_copy_vars, &lvar,LEFT,gbt);
153                 ret += generate_nic_se_code(se->get_right_se(),
154                         constants, copy_var_cnt, no_copy_vars, &rvar,RIGHT,gbt);
155                 ret += nic_fcn(op)+"("+lvar+","+rvar+")\n";
156                 *retvar = lvar;
157 //printf("op %s; lvar=%s, rvar=%s, retvar=%s\n",op.c_str(), lvar.c_str(), rvar.c_str(), retvar->c_str());
158                 return(ret);
159         case SE_COLREF:
160                 if(se->is_gb()){
161                         gbref = se->get_gb_ref();
162 /*
163                         if(gbt->get_reftype(gbref) != GBVAR_COLREF){
164                                 fprintf(stderr,"INTERNAL ERROR, non-colref gbvar in generate_nic_se_code\n");
165                                 exit(1);
166                         }
167 */
168                         ret = generate_nic_se_code(gbt->get_def(gbref),constants,copy_var_cnt, no_copy_vars, &lvar,LEFT,gbt);
169                         *retvar = lvar;
170                         return ret;
171                 }
172                 if(lr == LEFT){
173                         *retvar = "copyvar_"+int_to_string(copy_var_cnt);
174                         copy_var_cnt++;
175                         ret += "load_with_copy("+*retvar+","+se->get_colref()->get_field()+")\n";
176                 }else{
177                         *retvar = "nocopyvar_"+se->get_colref()->get_field();
178                         if(no_copy_vars.count(*retvar) == 0){
179                                 no_copy_vars.insert(*retvar);
180                                 ret += "load("+*retvar+","+se->get_colref()->get_field()+")\n";
181                         }
182                 }
183                 return ret;
184
185         case SE_FUNC:
186                 fprintf(stderr,"CONFIG ERROR, fcn reference in generate_nic_se_code, not yet implemented.\n");
187                 *retvar = "error";
188                 return(ret);
189         default:
190                 fprintf(stderr,"INTERNAL ERROR in generate_nic_se_code (lfta), line %d, character %d: unknown operator type %d\n",
191                                 se->get_lineno(), se->get_charno(),se->get_operator_type());
192                 *retvar = "error";
193                 return("ERROR in generate_nic_se_code");
194         }
195 }
196
197
198 static string generate_nic_predicate_code(predicate_t *pr,
199                 map<string, string> &constants,
200                 int &copy_var_cnt,
201                 set<string> &no_copy_vars,
202                 string *retvar, gb_table *gbt  ){
203         string ret;
204         vector<literal_t *>  litv;
205         int i;
206     data_type *ldt, *rdt;
207         vector<scalarexp_t *> op_list;
208         int o;
209         string lvar, rvar;
210         string l,cid;
211         string op = pr->get_op();
212
213         switch(pr->get_operator_type()){
214         case PRED_IN:
215                 fprintf(stderr,"CONFIG ERROR: IN not supported in generate_nic_predicate_code\n");
216                 *retvar = "error";
217                 return("ERROR in generate_nic_predicate_code");
218
219         case PRED_COMPARE:
220                 ret += generate_nic_se_code(pr->get_left_se(),
221                         constants, copy_var_cnt, no_copy_vars, &lvar,LEFT,gbt);
222                 ret += generate_nic_se_code(pr->get_right_se(),
223                         constants, copy_var_cnt, no_copy_vars, &rvar,RIGHT,gbt);
224                 ret += nic_fcn(op)+"("+lvar+","+rvar+")\n";
225                 *retvar = lvar;
226                 return(ret);
227         case PRED_UNARY_OP:
228                 ret += generate_nic_predicate_code(pr->get_left_pr(),
229                         constants, copy_var_cnt, no_copy_vars, &lvar,gbt);
230                 ret += unary_nic_fcn(op)+"("+lvar+")\n";
231                 *retvar = lvar;
232                 return(ret);
233         case PRED_BINARY_OP:
234                 ret += generate_nic_predicate_code(pr->get_left_pr(),
235                         constants, copy_var_cnt, no_copy_vars, &lvar,gbt);
236                 ret += generate_nic_predicate_code(pr->get_right_pr(),
237                         constants, copy_var_cnt, no_copy_vars, &rvar,gbt);
238                 ret += nic_fcn(op)+"("+lvar+","+rvar+")\n";
239                 *retvar = lvar;
240                 return(ret);
241         case PRED_FUNC:
242                 fprintf(stderr,"CONFIG ERROR, fcn reference in generate_nic_pred_code, not yet implemented.\n");
243                 *retvar = "error";
244                 return(ret);
245                 ret += " )";
246                 return(ret);
247         default:
248                 fprintf(stderr,"INTERNAL ERROR in generate_predicate_nic_code, line %d, character %d, unknown predicate operator type %d\n",
249                         pr->get_lineno(), pr->get_charno(), pr->get_operator_type() );
250                 return("ERROR in generate_nic_predicate_code");
251         }
252 }
253
254
255 bool se_is_nic_safe(scalarexp_t *se, nic_property *nicp, gb_table *gbt){
256   string dts, colname;
257   bool rs, ls;
258   int gbref;
259
260         switch(se->get_operator_type()){
261         case SE_LITERAL:
262                 dts = se->get_data_type()->get_type_str();
263                 if(nicp->legal_type(dts))
264                         return true;
265                 return false;
266                 break;
267         case SE_PARAM:
268                 return false;
269                 break;
270         case SE_UNARY_OP:
271                 if(!se_is_nic_safe(se->get_left_se(), nicp, gbt)) return false;
272                 return(nicp->legal_unary_op(se->get_op()));
273                 break;
274         case SE_BINARY_OP:
275                 if(!se_is_nic_safe(se->get_left_se(), nicp, gbt)) return false;
276                 if(!se_is_nic_safe(se->get_right_se(), nicp, gbt)) return false;
277                 return(nicp->legal_binary_op(se->get_op()));
278                 break;
279         case SE_COLREF:
280                 if(se->is_gb()){
281                         gbref = se->get_gb_ref();
282 /*
283                         if(gbt->get_reftype(gbref) != GBVAR_COLREF){
284                                 return false;
285                         }
286 */
287                         return se_is_nic_safe(gbt->get_def(gbref),nicp,gbt);
288                 }
289                 dts = se->get_data_type()->get_type_str();
290                 if(! nicp->legal_type(dts))
291                         return false;
292                 colname = se->get_colref()->get_field();
293                 if(! nicp->illegal_field(colname))
294                         return true;
295                 return false;
296                 break;
297         case SE_FUNC:
298                 return false;
299     default:
300                 return false;
301         }
302
303         return false;
304 }
305
306
307 bool pr_is_nic_safe(predicate_t *pr, nic_property *nicp, gb_table *gbt){
308   string dts, colname;
309   bool rs, ls;
310         switch(pr->get_operator_type()){
311         case PRED_IN:
312                 return false;
313         case PRED_COMPARE:
314                 if(!se_is_nic_safe(pr->get_left_se(), nicp, gbt)) return false;
315                 if(!se_is_nic_safe(pr->get_right_se(), nicp, gbt)) return false;
316                 return(nicp->legal_binary_op(pr->get_op()));
317         case PRED_UNARY_OP:
318                 if(!pr_is_nic_safe(pr->get_left_pr(),nicp, gbt)) return false;
319                 return(nicp->legal_unary_op(pr->get_op()));
320         case PRED_BINARY_OP:
321                 if(!pr_is_nic_safe(pr->get_left_pr(),nicp, gbt)) return false;
322                 if(!pr_is_nic_safe(pr->get_right_pr(),nicp, gbt)) return false;
323                 return(nicp->legal_binary_op(pr->get_op()));
324         case PRED_FUNC:
325                 return false;
326         default:
327                 return false;
328         }
329
330         return false;
331 }
332
333
334 void gather_nicsafe_cols(scalarexp_t *se, vector<string> &cols, nic_property *nicp, gb_table *gbt){
335         int i, gbref;
336         string colname;
337         vector<scalarexp_t *> operands;
338
339         switch(se->get_operator_type()){
340         case SE_LITERAL:
341         case SE_PARAM:
342                 return;
343         case SE_UNARY_OP:
344                 gather_nicsafe_cols(se->get_left_se(),cols,nicp, gbt);
345                 return;
346         case SE_BINARY_OP:
347                 gather_nicsafe_cols(se->get_left_se(),cols,nicp, gbt);
348                 gather_nicsafe_cols(se->get_right_se(),cols,nicp, gbt);
349                 return;
350         case SE_COLREF:
351                 if(se->is_gb()){
352                         gbref = se->get_gb_ref();
353                         return gather_nicsafe_cols(gbt->get_def(gbref),cols,nicp, gbt);
354                 }
355                 colname = se->get_colref()->get_field();
356                 if(! nicp->illegal_field(colname)){
357                   for(i=0;i<cols.size();++i){
358                         if(colname == cols[i])
359                                 break;
360                   }
361                   if(i==cols.size())
362                         cols.push_back(colname);
363                 }
364                 return;
365         case SE_FUNC:
366                 operands = se->get_operands();
367                 for(i=0;i<operands.size();++i)
368                         gather_nicsafe_cols(operands[i],cols,nicp,gbt);
369                 return;
370         default:
371                 return;
372         }
373         return;
374 }
375
376 void gather_nicsafe_cols(predicate_t *pr, vector<string> &cols, nic_property *nicp, gb_table *gbt){
377   string dts, colname;
378   bool rs, ls;
379         vector<scalarexp_t *> operands;
380         int i;
381
382         switch(pr->get_operator_type()){
383         case PRED_IN:
384                 gather_nicsafe_cols(pr->get_left_se(), cols, nicp, gbt);
385                 return ;
386         case PRED_COMPARE:
387                 gather_nicsafe_cols(pr->get_left_se(), cols, nicp, gbt);
388                 gather_nicsafe_cols(pr->get_right_se(), cols, nicp, gbt);
389                 return;
390         case PRED_UNARY_OP:
391                 gather_nicsafe_cols(pr->get_left_pr(),cols, nicp, gbt);
392                 return;
393         case PRED_BINARY_OP:
394                 gather_nicsafe_cols(pr->get_left_pr(),cols, nicp, gbt);
395                 gather_nicsafe_cols(pr->get_right_pr(),cols, nicp, gbt);
396                 return;
397         case PRED_FUNC:
398                 operands = pr->get_op_list();
399                 for(i=0;i<operands.size();++i)
400                         gather_nicsafe_cols(operands[i],cols,nicp, gbt);
401                 return ;
402         default:
403                 return ;
404         }
405
406         return ;
407 }
408
409
410 string generate_nic_code(vector<stream_query *> lftas, nic_property *nicp){
411   int i,p,s,g;
412   string ret = "";
413   string vars = "";
414   gb_table *gbtbl;
415
416   bool packed_return = false;
417
418         if(nicp->option_exists("Return")){
419                 if(nicp->option_value("Return") == "Packed"){
420 //printf("val of Return is %s\n",nicp->option_value("Return").c_str());
421                         packed_return = true;
422                 }else{
423                         fprintf(stderr,"Warning, nic option value of Return=%s is not recognized, ignoring\n",nicp->option_value("Return").c_str());
424                 }
425         }
426
427         vector<vector<predicate_t *> > nicsafe_preds;
428         vector<predicate_t *> empty_list;
429         for(i=0;i<lftas.size();i++){
430                 qp_node *qpn = lftas[i]->get_query_head();
431                 if(qpn->node_type() == "sgah_qpn"){
432                         gbtbl = ((sgah_qpn *)(qpn))->get_gb_tbl();
433                 }else{
434                         gbtbl = NULL;
435                 }
436                 nicsafe_preds.push_back(empty_list);
437                 vector<cnf_elem *> lfta_cnfs = qpn->get_filter_clause();
438                 for(p=0;p<lfta_cnfs.size();++p){
439                         if(pr_is_nic_safe(lfta_cnfs[p]->pr,nicp,gbtbl)){
440                                 nicsafe_preds[i].push_back(lfta_cnfs[p]->pr);
441                         }
442                 }
443         }
444
445         map<string, string> consts;
446         int n_copyvar = 0;
447         set<string> nocopy_vars;
448         string retvar;
449
450         if(packed_return){
451 //printf("dping packed return\n");
452                 for(i=0;i<lftas.size();++i){
453                         qp_node *qpn = lftas[i]->get_query_head();
454                         ret += "comment( lfta "+qpn->get_node_name() + " )\n";
455                         if(qpn->node_type() == "sgah_qpn"){
456                                 gbtbl = ((sgah_qpn *)(qpn))->get_gb_tbl();
457                         }else{
458                                 gbtbl = NULL;
459                         }
460                         ret += "\nlabel(lfta"+int_to_string(i)+")\n";
461                         for(p=0;p<nicsafe_preds[i].size();++p){
462                                 ret += generate_nic_predicate_code(nicsafe_preds[i][p],
463                                                 consts, n_copyvar, nocopy_vars, &retvar, gbtbl);
464                                 ret += "jump_if_zero("+retvar+",lfta"+int_to_string(i+1)+")\n";
465                         }
466                         vector<scalarexp_t *> se_list;
467                         if(qpn->node_type() == "sgah_qpn"){
468                                 se_list =((sgah_qpn *)(qpn))->get_select_se_list();
469                         }else{
470                                 se_list =((spx_qpn *)(qpn))->get_select_se_list();
471                         }
472
473                         vector<string> refd_cols;
474                         for(s=0;s<se_list.size();++s){
475                                 gather_nicsafe_cols(se_list[s],refd_cols, nicp, gbtbl);
476                         }
477                         vector<cnf_elem *> lfta_cnfs = qpn->get_where_clause();
478                         for(p=0;p<lfta_cnfs.size();++p){
479                                 gather_nicsafe_cols(lfta_cnfs[p]->pr,refd_cols, nicp, gbtbl);
480                         }
481                         if(gbtbl){
482                                 for(g=0;g<gbtbl->size();++g){
483 //printf("gathering gbvar %d\n",g);
484                                   gather_nicsafe_cols(gbtbl->get_def(g),refd_cols, nicp, gbtbl);
485                                 }
486                         }
487                         sort(refd_cols.begin(), refd_cols.end());
488
489                         ret += "pack_and_send(const_id"+int_to_string(i);
490                         consts["const_id"+int_to_string(i)] = int_to_string(lftas[i]->get_gid());
491                         for(s=0;s<refd_cols.size();++s){
492                                 ret += ",";
493                                 ret += refd_cols[s];
494                         }
495                         ret += ")\n\n";
496                 }
497                 ret += "\nlabel(lfta"+int_to_string(i)+")\n";
498         }else{
499                 for(i=0;i<lftas.size();++i){
500                         qp_node *qpn = lftas[i]->get_query_head();
501                         ret += "comment( lfta "+qpn->get_node_name() + " )\n";
502                         if(qpn->node_type() == "sgah_qpn"){
503                                 gbtbl = ((sgah_qpn *)(qpn))->get_gb_tbl();
504                         }else{
505                                 gbtbl = NULL;
506                         }
507                         ret += "\nlabel(lfta"+int_to_string(i)+")\n";
508                         for(p=0;p<nicsafe_preds[i].size();++p){
509                                 ret += generate_nic_predicate_code(nicsafe_preds[i][p],
510                                                 consts, n_copyvar, nocopy_vars, &retvar, gbtbl);
511                                 if(p<nicsafe_preds[i].size()-1){
512                                         ret += "jump_if_zero("+retvar+",lfta"+int_to_string(i+1)+")\n\n";
513                                 }else{
514                                         ret += "jump_if_notzero("+retvar+",pass)\n\n";
515                                 }
516                         }
517                 }
518                 ret += "label(pass)\n";
519                 ret += "send_packet()\n";
520                 ret += "\nlabel(lfta"+int_to_string(i)+")\n";
521         }
522     ret += "label(exit)\n";
523         ret += "exit()\n";
524
525         map<string, string>::iterator mssi;
526         for(mssi=consts.begin();mssi!=consts.end();++mssi){
527                 vars += "constant( "+(*mssi).first+" , "+(*mssi).second+")\n";
528         }
529         for(i=0;i<n_copyvar;++i){
530                 vars += "variable( copyvar_"+int_to_string(i)+" )\n";
531         }
532         set<string>::iterator ssi;
533         for(ssi=nocopy_vars.begin(); ssi!=nocopy_vars.end(); ++ssi){
534                 vars += "variable( "+(*ssi)+" )\n";
535         }
536
537         ret = "BEGIN\n"+vars + "\n"+ret + "END\n";
538
539         return ret;
540
541 }
542
543