MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
NdbScanFilter.cpp
1 /*
2  Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; version 2 of the License.
7 
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License for more details.
12 
13  You should have received a copy of the GNU General Public License
14  along with this program; if not, write to the Free Software
15  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17 
18 #include "API.hpp"
19 #include <NdbScanFilter.hpp>
20 #include <Vector.hpp>
21 #include <NdbOut.hpp>
22 #include <Interpreter.hpp>
23 #include <signaldata/AttrInfo.hpp>
24 
25 #ifdef VM_TRACE
26 #include <NdbEnv.h>
27 #define INT_DEBUG(x) \
28  { const char* tmp = NdbEnv_GetEnv("INT_DEBUG", (char*)0, 0); \
29  if (tmp != 0 && strlen(tmp) != 0) { ndbout << "INT:"; ndbout_c x; } }
30 #else
31 #define INT_DEBUG(x)
32 #endif
33 
35 public:
37  struct State {
38  NdbScanFilter::Group m_group;
39  Uint32 m_popCount;
40  Uint32 m_ownLabel;
41  Uint32 m_trueLabel;
42  Uint32 m_falseLabel;
43  };
44 
45  int m_label;
46  State m_current;
47  Uint32 m_negative; //used for translating NAND/NOR to AND/OR, equal 0 or 1
48  Vector<State> m_stack;
49  Vector<Uint32> m_stack2; //to store info of m_negative
50  NdbInterpretedCode * m_code;
51  NdbError m_error;
52 
53  /* Members for supporting old Api */
54  NdbScanOperation *m_associated_op;
55 
56  int cond_col(Interpreter::UnaryCondition, Uint32 attrId);
57 
58  int cond_col_const(Interpreter::BinaryCondition, Uint32 attrId,
59  const void * value, Uint32 len);
60 
61  /* Method to initialise the members */
62  void init (NdbInterpretedCode *code)
63  {
64  m_current.m_group = (NdbScanFilter::Group)0;
65  m_current.m_popCount = 0;
66  m_current.m_ownLabel = 0;
67  m_current.m_trueLabel = ~0;
68  m_current.m_falseLabel = ~0;
69  m_label = 0;
70  m_negative = 0;
71  m_code= code;
72  m_associated_op= NULL;
73 
74  if (code == NULL)
75  /* NdbInterpretedCode not supported for operation type */
76  m_error.code = 4539;
77  else
78  m_error.code = 0;
79  };
80 
81  /* This method propagates an error code from NdbInterpretedCode
82  * back to the NdbScanFilter object
83  */
84  int propagateErrorFromCode()
85  {
86  NdbError codeError= m_code->getNdbError();
87 
88  /* Map interpreted code's 'Too many instructions in
89  * interpreted program' to FilterTooLarge error for
90  * NdbScanFilter
91  */
92  if (codeError.code == 4518)
93  m_error.code = NdbScanFilter::FilterTooLarge;
94  else
95  m_error.code = codeError.code;
96 
97  return -1;
98  };
99 
100  /* This method performs any steps required once the
101  * filter definition is complete
102  */
103  int handleFilterDefined()
104  {
105  /* Finalise the interpreted program */
106  if (m_code->finalise() != 0)
107  return propagateErrorFromCode();
108 
109  /* For old Api support, we set the passed-in operation's
110  * interpreted code to be the code generated by the
111  * scanfilter
112  */
113  if (m_associated_op != NULL)
114  {
115  m_associated_op->setInterpretedCode(m_code);
116  }
117 
118  return 0;
119  }
120 
121 };
122 
123 const Uint32 LabelExit = ~0;
124 
125 
127  m_impl(* new NdbScanFilterImpl())
128 {
129  DBUG_ENTER("NdbScanFilter::NdbScanFilter(NdbInterpretedCode)");
130  m_impl.init(code);
131  DBUG_VOID_RETURN;
132 }
133 
135  m_impl(* new NdbScanFilterImpl())
136 {
137  DBUG_ENTER("NdbScanFilter::NdbScanFilter(NdbOperation)");
138 
139  NdbInterpretedCode* code= NULL;
140  NdbOperation::Type opType= op->getType();
141 
142  /* If the operation is not of the correct type then
143  * m_impl.init() will set an error on the scan filter
144  */
145  if (likely((opType == NdbOperation::TableScan) ||
146  (opType == NdbOperation::OrderedIndexScan)))
147  {
148  /* We ask the NdbScanOperation to allocate an InterpretedCode
149  * object for us. It will look after freeing it when
150  * necessary. This allows the InterpretedCode object to
151  * survive after the NdbScanFilter has gone out of scope
152  */
153  code= ((NdbScanOperation *)op)->allocInterpretedCodeOldApi();
154  }
155 
156  m_impl.init(code);
157 
158  m_impl.m_associated_op= (NdbScanOperation*) op;
159 
160  DBUG_VOID_RETURN;
161 }
162 
163 NdbScanFilter::~NdbScanFilter()
164 {
165  delete &m_impl;
166 }
167 
168 int
170  if (m_impl.m_error.code != 0) return -1;
171 
172  if (m_impl.m_stack2.push_back(m_impl.m_negative))
173  {
174  /* Memory allocation problem */
175  m_impl.m_error.code= 4000;
176  return -1;
177  }
178  switch(group){
179  case NdbScanFilter::AND:
180  INT_DEBUG(("Begin(AND)"));
181  if(m_impl.m_negative == 1){
182  group = NdbScanFilter::OR;
183  }
184  break;
185  case NdbScanFilter::OR:
186  INT_DEBUG(("Begin(OR)"));
187  if(m_impl.m_negative == 1){
188  group = NdbScanFilter::AND;
189  }
190  break;
191  case NdbScanFilter::NAND:
192  INT_DEBUG(("Begin(NAND)"));
193  if(m_impl.m_negative == 0){
194  group = NdbScanFilter::OR;
195  m_impl.m_negative = 1;
196  }else{
197  group = NdbScanFilter::AND;
198  m_impl.m_negative = 0;
199  }
200  break;
201  case NdbScanFilter::NOR:
202  INT_DEBUG(("Begin(NOR)"));
203  if(m_impl.m_negative == 0){
204  group = NdbScanFilter::AND;
205  m_impl.m_negative = 1;
206  }else{
207  group = NdbScanFilter::OR;
208  m_impl.m_negative = 0;
209  }
210  break;
211  }
212 
213  if(group == m_impl.m_current.m_group){
214  switch(group){
215  case NdbScanFilter::AND:
216  case NdbScanFilter::OR:
217  m_impl.m_current.m_popCount++;
218  return 0;
219  case NdbScanFilter::NOR:
220  case NdbScanFilter::NAND:
221  break;
222  }
223  }
224 
225  NdbScanFilterImpl::State tmp = m_impl.m_current;
226  if (m_impl.m_stack.push_back(m_impl.m_current))
227  {
228  /* Memory allocation problem */
229  m_impl.m_error.code= 4000;
230  return -1;
231  }
232  m_impl.m_current.m_group = group;
233  m_impl.m_current.m_ownLabel = m_impl.m_label++;
234  m_impl.m_current.m_popCount = 0;
235 
236  switch(group){
237  case NdbScanFilter::AND:
238  case NdbScanFilter::NAND:
239  m_impl.m_current.m_falseLabel = m_impl.m_current.m_ownLabel;
240  m_impl.m_current.m_trueLabel = tmp.m_trueLabel;
241  break;
242  case NdbScanFilter::OR:
243  case NdbScanFilter::NOR:
244  m_impl.m_current.m_falseLabel = tmp.m_falseLabel;
245  m_impl.m_current.m_trueLabel = m_impl.m_current.m_ownLabel;
246  break;
247  default:
248  /* Operator is not defined in NdbScanFilter::Group */
249  m_impl.m_error.code= 4260;
250  return -1;
251  }
252 
253  return 0;
254 }
255 
256 int
258  if (m_impl.m_error.code != 0) return -1;
259 
260  if(m_impl.m_stack2.size() == 0){
261  /* Invalid set of range scan bounds */
262  m_impl.m_error.code= 4259;
263  return -1;
264  }
265  m_impl.m_negative = m_impl.m_stack2.back();
266  m_impl.m_stack2.erase(m_impl.m_stack2.size() - 1);
267 
268  switch(m_impl.m_current.m_group){
269  case NdbScanFilter::AND:
270  INT_DEBUG(("End(AND pc=%d)", m_impl.m_current.m_popCount));
271  break;
272  case NdbScanFilter::OR:
273  INT_DEBUG(("End(OR pc=%d)", m_impl.m_current.m_popCount));
274  break;
275  case NdbScanFilter::NAND:
276  INT_DEBUG(("End(NAND pc=%d)", m_impl.m_current.m_popCount));
277  break;
278  case NdbScanFilter::NOR:
279  INT_DEBUG(("End(NOR pc=%d)", m_impl.m_current.m_popCount));
280  break;
281  }
282 
283  if(m_impl.m_current.m_popCount > 0){
284  m_impl.m_current.m_popCount--;
285  return 0;
286  }
287 
288  NdbScanFilterImpl::State tmp = m_impl.m_current;
289  if(m_impl.m_stack.size() == 0){
290  /* Invalid set of range scan bounds */
291  m_impl.m_error.code= 4259;
292  return -1;
293  }
294  m_impl.m_current = m_impl.m_stack.back();
295  m_impl.m_stack.erase(m_impl.m_stack.size() - 1);
296 
297  switch(tmp.m_group){
298  case NdbScanFilter::AND:
299  if(tmp.m_trueLabel == (Uint32)~0){
300  if (m_impl.m_code->interpret_exit_ok() == -1)
301  return m_impl.propagateErrorFromCode();
302  } else {
303  if (m_impl.m_code->branch_label(tmp.m_trueLabel) == -1)
304  return m_impl.propagateErrorFromCode();
305  }
306  break;
307  case NdbScanFilter::NAND:
308  if(tmp.m_trueLabel == (Uint32)~0){
309  if (m_impl.m_code->interpret_exit_nok() == -1)
310  return m_impl.propagateErrorFromCode();
311  } else {
312  if (m_impl.m_code->branch_label(tmp.m_falseLabel) == -1)
313  return m_impl.propagateErrorFromCode();
314  }
315  break;
316  case NdbScanFilter::OR:
317  if(tmp.m_falseLabel == (Uint32)~0){
318  if (m_impl.m_code->interpret_exit_nok() == -1)
319  return m_impl.propagateErrorFromCode();
320  } else {
321  if (m_impl.m_code->branch_label(tmp.m_falseLabel) == -1)
322  return m_impl.propagateErrorFromCode();
323  }
324  break;
325  case NdbScanFilter::NOR:
326  if(tmp.m_falseLabel == (Uint32)~0){
327  if (m_impl.m_code->interpret_exit_ok() == -1)
328  return m_impl.propagateErrorFromCode();
329  } else {
330  if (m_impl.m_code->branch_label(tmp.m_trueLabel) == -1)
331  return m_impl.propagateErrorFromCode();
332  }
333  break;
334  default:
335  /* Operator is not defined in NdbScanFilter::Group */
336  m_impl.m_error.code= 4260;
337  return -1;
338  }
339 
340  if (m_impl.m_code->def_label(tmp.m_ownLabel) == -1)
341  return m_impl.propagateErrorFromCode();
342 
343  if(m_impl.m_stack.size() == 0){
344  switch(tmp.m_group){
345  case NdbScanFilter::AND:
346  case NdbScanFilter::NOR:
347  if (m_impl.m_code->interpret_exit_nok() == -1)
348  return m_impl.propagateErrorFromCode();
349  break;
350  case NdbScanFilter::OR:
351  case NdbScanFilter::NAND:
352  if (m_impl.m_code->interpret_exit_ok() == -1)
353  return m_impl.propagateErrorFromCode();
354  break;
355  default:
356  /* Operator is not defined in NdbScanFilter::Group */
357  m_impl.m_error.code= 4260;
358  return -1;
359  }
360 
361  /* Handle the completion of the filter definition */
362  return m_impl.handleFilterDefined();
363  }
364  return 0;
365 }
366 
367 int
369  if(m_impl.m_error.code != 0) return -1;
370 
371  if(m_impl.m_current.m_group < NdbScanFilter::AND ||
372  m_impl.m_current.m_group > NdbScanFilter::NOR){
373  /* Operator is not defined in NdbScanFilter::Group */
374  m_impl.m_error.code= 4260;
375  return -1;
376  }
377 
378  if(m_impl.m_current.m_trueLabel == (Uint32)~0){
379  if (m_impl.m_code->interpret_exit_ok() == -1)
380  return m_impl.propagateErrorFromCode();
381  } else {
382  if (m_impl.m_code->branch_label(m_impl.m_current.m_trueLabel) == -1)
383  return m_impl.propagateErrorFromCode();
384  }
385 
386  return 0;
387 }
388 
389 int
391  if (m_impl.m_error.code != 0) return -1;
392  if(m_impl.m_current.m_group < NdbScanFilter::AND ||
393  m_impl.m_current.m_group > NdbScanFilter::NOR){
394  /* Operator is not defined in NdbScanFilter::Group */
395  m_impl.m_error.code= 4260;
396  return -1;
397  }
398 
399  if(m_impl.m_current.m_falseLabel == (Uint32)~0){
400  if (m_impl.m_code->interpret_exit_nok() == -1)
401  return m_impl.propagateErrorFromCode();
402  } else {
403  if (m_impl.m_code->branch_label(m_impl.m_current.m_falseLabel) == -1)
404  return m_impl.propagateErrorFromCode();
405  }
406 
407  return 0;
408 }
409 
410 #define action(x, y, z)
411 
412 /* One argument branch definition method signature */
413 typedef int (NdbInterpretedCode:: * Branch1)(Uint32, Uint32 label);
414 /* Two argument branch definition method signature */
415 typedef int (NdbInterpretedCode:: * StrBranch2)(const void*, Uint32, Uint32, Uint32);
416 
417 /* Table of unary branch methods for each group type */
418 struct tab2 {
419  Branch1 m_branches[5];
420 };
421 
422 /* Table of correct branch method to use for group types
423  * and condition type.
424  * In general, AND branches to fail (short circuits) if the
425  * condition is not satisfied, and OR branches to success
426  * (short circuits) if it is satisfied.
427  * NAND is the same as AND, with the branch condition inverted.
428  * NOR is the same as OR, with the branch condition inverted
429  */
430 static const tab2 table2[] = {
434  { { 0,
435  &NdbInterpretedCode::branch_col_ne_null, // AND
436  &NdbInterpretedCode::branch_col_eq_null, // OR
437  &NdbInterpretedCode::branch_col_eq_null, // NAND
438  &NdbInterpretedCode::branch_col_ne_null } } // NOR
439 
443  ,{ { 0,
444  &NdbInterpretedCode::branch_col_eq_null, // AND
445  &NdbInterpretedCode::branch_col_ne_null, // OR
446  &NdbInterpretedCode::branch_col_ne_null, // NAND
447  &NdbInterpretedCode::branch_col_eq_null } } // NOR
448 };
449 
450 const int tab2_sz = sizeof(table2)/sizeof(table2[0]);
451 
452 int
453 NdbScanFilterImpl::cond_col(Interpreter::UnaryCondition op, Uint32 AttrId){
454 
455  if (m_error.code != 0) return -1;
456 
457  if(op < 0 || op >= tab2_sz){
458  /* Condition is out of bounds */
459  m_error.code= 4262;
460  return -1;
461  }
462 
463  if(m_current.m_group < NdbScanFilter::AND ||
464  m_current.m_group > NdbScanFilter::NOR){
465  /* Operator is not defined in NdbScanFilter::Group */
466  m_error.code= 4260;
467  return -1;
468  }
469 
470  Branch1 branch = table2[op].m_branches[m_current.m_group];
471  if ((m_code->* branch)(AttrId, m_current.m_ownLabel) == -1)
472  return propagateErrorFromCode();
473 
474  return 0;
475 }
476 
477 int
479  if (m_impl.m_error.code != 0) return -1;
480 
481  if(m_impl.m_negative == 1)
482  return m_impl.cond_col(Interpreter::IS_NOT_NULL, AttrId);
483  else
484  return m_impl.cond_col(Interpreter::IS_NULL, AttrId);
485 }
486 
487 int
489  if (m_impl.m_error.code != 0) return -1;
490 
491  if(m_impl.m_negative == 1)
492  return m_impl.cond_col(Interpreter::IS_NULL, AttrId);
493  else
494  return m_impl.cond_col(Interpreter::IS_NOT_NULL, AttrId);
495 }
496 
497 /* NdbInterpretedCode two-arg branch method to use for
498  * given logical group type
499  */
500 struct tab3 {
501  StrBranch2 m_branches[5];
502 };
503 
504 /* Table of branch methds to use for each combination of
505  * logical group type (AND, OR, NAND, NOR) and comparison
506  * type.
507  * Generally, AND short circuits by branching to the failure
508  * label when the condition fails, and OR short circuits by
509  * branching to the success label when the condition passes.
510  * NAND and NOR invert these by inverting the 'sense' of the
511  * branch
512  */
513 static const tab3 table3[] = {
517  { { 0,
518  &NdbInterpretedCode::branch_col_ne,
519  &NdbInterpretedCode::branch_col_eq,
520  &NdbInterpretedCode::branch_col_ne,
521  &NdbInterpretedCode::branch_col_eq } }
522 
526  ,{ { 0,
527  &NdbInterpretedCode::branch_col_eq,
528  &NdbInterpretedCode::branch_col_ne,
529  &NdbInterpretedCode::branch_col_eq,
530  &NdbInterpretedCode::branch_col_ne } }
531 
535  ,{ { 0,
536  &NdbInterpretedCode::branch_col_le,
537  &NdbInterpretedCode::branch_col_gt,
538  &NdbInterpretedCode::branch_col_le,
539  &NdbInterpretedCode::branch_col_gt } }
540 
544  ,{ { 0,
545  &NdbInterpretedCode::branch_col_lt,
546  &NdbInterpretedCode::branch_col_ge,
547  &NdbInterpretedCode::branch_col_lt,
548  &NdbInterpretedCode::branch_col_ge } }
549 
553  ,{ { 0,
554  &NdbInterpretedCode::branch_col_ge,
555  &NdbInterpretedCode::branch_col_lt,
556  &NdbInterpretedCode::branch_col_ge,
557  &NdbInterpretedCode::branch_col_lt } }
558 
562  ,{ { 0,
563  &NdbInterpretedCode::branch_col_gt,
564  &NdbInterpretedCode::branch_col_le,
565  &NdbInterpretedCode::branch_col_gt,
566  &NdbInterpretedCode::branch_col_le } }
567 
571  ,{ { 0,
572  &NdbInterpretedCode::branch_col_notlike,
573  &NdbInterpretedCode::branch_col_like,
574  &NdbInterpretedCode::branch_col_notlike,
575  &NdbInterpretedCode::branch_col_like } }
576 
580  ,{ { 0,
581  &NdbInterpretedCode::branch_col_like,
582  &NdbInterpretedCode::branch_col_notlike,
583  &NdbInterpretedCode::branch_col_like,
584  &NdbInterpretedCode::branch_col_notlike } }
585 
589  ,{ { 0,
590  &NdbInterpretedCode::branch_col_and_mask_ne_mask,
591  &NdbInterpretedCode::branch_col_and_mask_eq_mask,
592  &NdbInterpretedCode::branch_col_and_mask_ne_mask,
593  &NdbInterpretedCode::branch_col_and_mask_eq_mask } }
594 
598  ,{ { 0,
599  &NdbInterpretedCode::branch_col_and_mask_eq_mask,
600  &NdbInterpretedCode::branch_col_and_mask_ne_mask,
601  &NdbInterpretedCode::branch_col_and_mask_eq_mask,
602  &NdbInterpretedCode::branch_col_and_mask_ne_mask } }
603 
607  ,{ { 0,
608  &NdbInterpretedCode::branch_col_and_mask_ne_zero,
609  &NdbInterpretedCode::branch_col_and_mask_eq_zero,
610  &NdbInterpretedCode::branch_col_and_mask_ne_zero,
611  &NdbInterpretedCode::branch_col_and_mask_eq_zero } }
612 
616  ,{ { 0,
617  &NdbInterpretedCode::branch_col_and_mask_eq_zero,
618  &NdbInterpretedCode::branch_col_and_mask_ne_zero,
619  &NdbInterpretedCode::branch_col_and_mask_eq_zero,
620  &NdbInterpretedCode::branch_col_and_mask_ne_zero } }
621 };
622 
623 const int tab3_sz = sizeof(table3)/sizeof(table3[0]);
624 
625 int
626 NdbScanFilterImpl::cond_col_const(Interpreter::BinaryCondition op,
627  Uint32 AttrId,
628  const void * value, Uint32 len){
629  if (m_error.code != 0) return -1;
630 
631  if(op < 0 || op >= tab3_sz){
632  /* Condition is out of bounds */
633  m_error.code= 4262;
634  return -1;
635  }
636 
637  if(m_current.m_group < NdbScanFilter::AND ||
638  m_current.m_group > NdbScanFilter::NOR){
639  /* Operator is not defined in NdbScanFilter::Group */
640  m_error.code= 4260;
641  return -1;
642  }
643 
644  StrBranch2 branch;
645  if(m_negative == 1){ //change NdbOperation to its negative
646  if(m_current.m_group == NdbScanFilter::AND)
647  branch = table3[op].m_branches[NdbScanFilter::OR];
648  else if(m_current.m_group == NdbScanFilter::OR)
649  branch = table3[op].m_branches[NdbScanFilter::AND];
650  else
651  {
657  assert(FALSE);
658  m_error.code= 4260;
659  return -1;
660  }
661  }else{
662  branch = table3[op].m_branches[(Uint32)(m_current.m_group)];
663  }
664 
665  const NdbDictionary::Table * table = m_code->getTable();
666 
667  if (table == NULL)
668  {
669  /* NdbInterpretedCode instruction requires that table is set */
670  m_error.code=4538;
671  return -1;
672  }
673 
674  const NdbDictionary::Column * col =
675  table->getColumn(AttrId);
676 
677  if(col == 0){
678  /* Column is NULL */
679  m_error.code= 4261;
680  return -1;
681  }
682 
683  if ((m_code->* branch)(value, len, AttrId, m_current.m_ownLabel) == -1)
684  return propagateErrorFromCode();
685 
686  return 0;
687 }
688 
689 int
691  const void *val, Uint32 len)
692 {
693  switch(cond){
694  case COND_LE:
695  return m_impl.cond_col_const(Interpreter::LE, ColId, val, len);
696  case COND_LT:
697  return m_impl.cond_col_const(Interpreter::LT, ColId, val, len);
698  case COND_GE:
699  return m_impl.cond_col_const(Interpreter::GE, ColId, val, len);
700  case COND_GT:
701  return m_impl.cond_col_const(Interpreter::GT, ColId, val, len);
702  case COND_EQ:
703  return m_impl.cond_col_const(Interpreter::EQ, ColId, val, len);
704  case COND_NE:
705  return m_impl.cond_col_const(Interpreter::NE, ColId, val, len);
706  case COND_LIKE:
707  return m_impl.cond_col_const(Interpreter::LIKE, ColId, val, len);
708  case COND_NOT_LIKE:
709  return m_impl.cond_col_const(Interpreter::NOT_LIKE, ColId, val, len);
710  case COND_AND_EQ_MASK:
711  return m_impl.cond_col_const(Interpreter::AND_EQ_MASK, ColId, val, len);
712  case COND_AND_NE_MASK:
713  return m_impl.cond_col_const(Interpreter::AND_NE_MASK, ColId, val, len);
714  case COND_AND_EQ_ZERO:
715  return m_impl.cond_col_const(Interpreter::AND_EQ_ZERO, ColId, val, len);
716  case COND_AND_NE_ZERO:
717  return m_impl.cond_col_const(Interpreter::AND_NE_ZERO, ColId, val, len);
718  }
719  return -1;
720 }
721 
722 static void
723 update(const NdbError & _err){
724  NdbError & error = (NdbError &) _err;
725  ndberror_struct ndberror = (ndberror_struct)error;
726  ndberror_update(&ndberror);
727  error = NdbError(ndberror);
728 }
729 
730 const NdbError &
732 {
733  update(m_impl.m_error);
734  return m_impl.m_error;
735 }
736 
737 const NdbInterpretedCode*
739 {
740  /* Return nothing if this is an old-style
741  * ScanFilter as the InterpretedCode is
742  * entirely encapsulated
743  */
744  if (m_impl.m_associated_op != NULL)
745  return NULL;
746 
747  return m_impl.m_code;
748 }
749 
752 {
753  /* Return associated NdbOperation (or NULL
754  * if we don't have one)
755  */
756  return m_impl.m_associated_op;
757 }
758 
759 #if 0
760 int
761 main(void){
762  if(0)
763  {
764  ndbout << "a > 7 AND b < 9 AND c = 4" << endl;
765  NdbScanFilter f(0);
766  f.begin(NdbScanFilter::AND);
767  f.gt(0, 7);
768  f.lt(1, 9);
769  f.eq(2, 4);
770  f.end();
771  ndbout << endl;
772  }
773 
774  if(0)
775  {
776  ndbout << "a > 7 OR b < 9 OR c = 4" << endl;
777  NdbScanFilter f(0);
778  f.begin(NdbScanFilter::OR);
779  f.gt(0, 7);
780  f.lt(1, 9);
781  f.eq(2, 4);
782  f.end();
783  ndbout << endl;
784  }
785 
786  if(0)
787  {
788  ndbout << "a > 7 AND (b < 9 OR c = 4)" << endl;
789  NdbScanFilter f(0);
790  f.begin(NdbScanFilter::AND);
791  f.gt(0, 7);
792  f.begin(NdbScanFilter::OR);
793  f.lt(1, 9);
794  f.eq(2, 4);
795  f.end();
796  f.end();
797  ndbout << endl;
798  }
799 
800  if(0)
801  {
802  ndbout << "a > 7 AND (b < 9 AND c = 4)" << endl;
803  NdbScanFilter f(0);
804  f.begin(NdbScanFilter::AND);
805  f.gt(0, 7);
806  f.begin(NdbScanFilter::AND);
807  f.lt(1, 9);
808  f.eq(2, 4);
809  f.end();
810  f.end();
811  ndbout << endl;
812  }
813 
814  if(0)
815  {
816  ndbout << "(a > 7 AND b < 9) AND c = 4" << endl;
817  NdbScanFilter f(0);
818  f.begin(NdbScanFilter::AND);
819  f.begin(NdbScanFilter::AND);
820  f.gt(0, 7);
821  f.lt(1, 9);
822  f.end();
823  f.eq(2, 4);
824  f.end();
825  ndbout << endl;
826  }
827 
828  if(1)
829  {
830  ndbout << "(a > 7 OR b < 9) AND (c = 4 OR c = 5)" << endl;
831  NdbScanFilter f(0);
832  f.begin(NdbScanFilter::AND);
833  f.begin(NdbScanFilter::OR);
834  f.gt(0, 7);
835  f.lt(1, 9);
836  f.end();
837  f.begin(NdbScanFilter::OR);
838  f.eq(2, 4);
839  f.eq(2, 5);
840  f.end();
841  f.end();
842  ndbout << endl;
843  }
844 
845  if(1)
846  {
847  ndbout << "(a > 7 AND b < 9) OR (c = 4 AND c = 5)" << endl;
848  NdbScanFilter f(0);
849  f.begin(NdbScanFilter::OR);
850  f.begin(NdbScanFilter::AND);
851  f.gt(0, 7);
852  f.lt(1, 9);
853  f.end();
854  f.begin(NdbScanFilter::AND);
855  f.eq(2, 4);
856  f.eq(2, 5);
857  f.end();
858  f.end();
859  ndbout << endl;
860  }
861 
862  if(1)
863  {
864  ndbout <<
865  "((a > 7 AND b < 9) OR (c = 4 AND d = 5)) AND "
866  "((e > 6 AND f < 8) OR (g = 2 AND h = 3)) " << endl;
867  NdbScanFilter f(0);
868  f.begin(NdbScanFilter::AND);
869  f.begin(NdbScanFilter::OR);
870  f.begin(NdbScanFilter::AND);
871  f.gt(0, 7);
872  f.lt(1, 9);
873  f.end();
874  f.begin(NdbScanFilter::AND);
875  f.eq(2, 4);
876  f.eq(3, 5);
877  f.end();
878  f.end();
879 
880  f.begin(NdbScanFilter::OR);
881  f.begin(NdbScanFilter::AND);
882  f.gt(4, 6);
883  f.lt(5, 8);
884  f.end();
885  f.begin(NdbScanFilter::AND);
886  f.eq(6, 2);
887  f.eq(7, 3);
888  f.end();
889  f.end();
890  f.end();
891  }
892 
893  return 0;
894 }
895 #endif
896 
897 template class Vector<NdbScanFilterImpl::State>;
898