1 /* Copyright (c) 2003-2007 MySQL AB
2 Use is subject to license terms
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 Street, Fifth Floor, Boston, MA 02110-1301, USA */
16
17 #include <NdbScanFilter.hpp>
18 #include <Ndb.hpp>
19 #include <NdbOperation.hpp>
20 #include "NdbDictionaryImpl.hpp"
21 #include <Vector.hpp>
22 #include <NdbOut.hpp>
23 #include <Interpreter.hpp>
24 #include <signaldata/AttrInfo.hpp>
25 #include "NdbApiSignal.hpp"
26 #include "NdbUtil.hpp"
27
28 #ifdef VM_TRACE
29 #include <NdbEnv.h>
30 #define INT_DEBUG(x) \
31 { const char* tmp = NdbEnv_GetEnv("INT_DEBUG", (char*)0, 0); \
32 if (tmp != 0 && strlen(tmp) != 0) { ndbout << "INT:"; ndbout_c x; } }
33 #else
34 #define INT_DEBUG(x)
35 #endif
36
37 class NdbScanFilterImpl {
38 public:
NdbScanFilterImpl()39 NdbScanFilterImpl() {}
40 struct State {
41 NdbScanFilter::Group m_group;
42 Uint32 m_popCount;
43 Uint32 m_ownLabel;
44 Uint32 m_trueLabel;
45 Uint32 m_falseLabel;
46 };
47
48 int m_label;
49 State m_current;
50 Uint32 m_negative; //used for translating NAND/NOR to AND/OR, equal 0 or 1
51 Vector<State> m_stack;
52 Vector<Uint32> m_stack2; //to store info of m_negative
53 NdbOperation * m_operation;
54 Uint32 m_latestAttrib;
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 bool m_abort_on_too_large;
62
63 NdbOperation::OperationStatus m_initial_op_status;
64 Uint32 m_initial_AI_size;
65 Uint32 m_max_size;
66
get_size()67 Uint32 get_size() {
68 assert(m_operation->theTotalCurrAI_Len >= m_initial_AI_size);
69 return m_operation->theTotalCurrAI_Len - m_initial_AI_size;
70 }
check_size()71 bool check_size() {
72 if (get_size() <= m_max_size)
73 return true;
74 handle_filter_too_large();
75 return false;
76 }
77 void handle_filter_too_large();
78
79 NdbError m_error;
80 };
81
82 const Uint32 LabelExit = ~0;
83
84
NdbScanFilter(class NdbOperation * op,bool abort_on_too_large,Uint32 max_size)85 NdbScanFilter::NdbScanFilter(class NdbOperation * op,
86 bool abort_on_too_large,
87 Uint32 max_size)
88 : m_impl(* new NdbScanFilterImpl())
89 {
90 DBUG_ENTER("NdbScanFilter::NdbScanFilter");
91 m_impl.m_current.m_group = (NdbScanFilter::Group)0;
92 m_impl.m_current.m_popCount = 0;
93 m_impl.m_current.m_ownLabel = 0;
94 m_impl.m_current.m_trueLabel = ~0;
95 m_impl.m_current.m_falseLabel = ~0;
96 m_impl.m_label = 0;
97 m_impl.m_latestAttrib = ~0;
98 m_impl.m_operation = op;
99 m_impl.m_negative = 0;
100
101 DBUG_PRINT("info", ("op status: %d tot AI: %u in curr: %u",
102 op->theStatus,
103 op->theTotalCurrAI_Len, op->theAI_LenInCurrAI));
104
105 m_impl.m_abort_on_too_large = abort_on_too_large;
106
107 m_impl.m_initial_op_status = op->theStatus;
108 m_impl.m_initial_AI_size = op->theTotalCurrAI_Len;
109 if (max_size > NDB_MAX_SCANFILTER_SIZE_IN_WORDS)
110 max_size = NDB_MAX_SCANFILTER_SIZE_IN_WORDS;
111 m_impl.m_max_size = max_size;
112
113 m_impl.m_error.code = 0;
114 DBUG_VOID_RETURN;
115 }
116
~NdbScanFilter()117 NdbScanFilter::~NdbScanFilter(){
118 delete &m_impl;
119 }
120
121 int
begin(Group group)122 NdbScanFilter::begin(Group group){
123
124 if (m_impl.m_stack2.push_back(m_impl.m_negative))
125 {
126 m_impl.m_operation->setErrorCodeAbort(4000);
127 return -1;
128 }
129 switch(group){
130 case NdbScanFilter::AND:
131 INT_DEBUG(("Begin(AND)"));
132 if(m_impl.m_negative == 1){
133 group = NdbScanFilter::OR;
134 }
135 break;
136 case NdbScanFilter::OR:
137 INT_DEBUG(("Begin(OR)"));
138 if(m_impl.m_negative == 1){
139 group = NdbScanFilter::AND;
140 }
141 break;
142 case NdbScanFilter::NAND:
143 INT_DEBUG(("Begin(NAND)"));
144 if(m_impl.m_negative == 0){
145 group = NdbScanFilter::OR;
146 m_impl.m_negative = 1;
147 }else{
148 group = NdbScanFilter::AND;
149 m_impl.m_negative = 0;
150 }
151 break;
152 case NdbScanFilter::NOR:
153 INT_DEBUG(("Begin(NOR)"));
154 if(m_impl.m_negative == 0){
155 group = NdbScanFilter::AND;
156 m_impl.m_negative = 1;
157 }else{
158 group = NdbScanFilter::OR;
159 m_impl.m_negative = 0;
160 }
161 break;
162 }
163
164 if(group == m_impl.m_current.m_group){
165 switch(group){
166 case NdbScanFilter::AND:
167 case NdbScanFilter::OR:
168 m_impl.m_current.m_popCount++;
169 return 0;
170 case NdbScanFilter::NOR:
171 case NdbScanFilter::NAND:
172 break;
173 }
174 }
175
176 NdbScanFilterImpl::State tmp = m_impl.m_current;
177 if (m_impl.m_stack.push_back(m_impl.m_current))
178 {
179 m_impl.m_operation->setErrorCodeAbort(4000);
180 return -1;
181 }
182 m_impl.m_current.m_group = group;
183 m_impl.m_current.m_ownLabel = m_impl.m_label++;
184 m_impl.m_current.m_popCount = 0;
185
186 switch(group){
187 case NdbScanFilter::AND:
188 case NdbScanFilter::NAND:
189 m_impl.m_current.m_falseLabel = m_impl.m_current.m_ownLabel;
190 m_impl.m_current.m_trueLabel = tmp.m_trueLabel;
191 break;
192 case NdbScanFilter::OR:
193 case NdbScanFilter::NOR:
194 m_impl.m_current.m_falseLabel = tmp.m_falseLabel;
195 m_impl.m_current.m_trueLabel = m_impl.m_current.m_ownLabel;
196 break;
197 default:
198 m_impl.m_operation->setErrorCodeAbort(4260);
199 return -1;
200 }
201
202 return 0;
203 }
204
205 int
end()206 NdbScanFilter::end(){
207
208 if(m_impl.m_stack2.size() == 0){
209 m_impl.m_operation->setErrorCodeAbort(4259);
210 return -1;
211 }
212 m_impl.m_negative = m_impl.m_stack2.back();
213 m_impl.m_stack2.erase(m_impl.m_stack2.size() - 1);
214
215 switch(m_impl.m_current.m_group){
216 case NdbScanFilter::AND:
217 INT_DEBUG(("End(AND pc=%d)", m_impl.m_current.m_popCount));
218 break;
219 case NdbScanFilter::OR:
220 INT_DEBUG(("End(OR pc=%d)", m_impl.m_current.m_popCount));
221 break;
222 case NdbScanFilter::NAND:
223 INT_DEBUG(("End(NAND pc=%d)", m_impl.m_current.m_popCount));
224 break;
225 case NdbScanFilter::NOR:
226 INT_DEBUG(("End(NOR pc=%d)", m_impl.m_current.m_popCount));
227 break;
228 }
229
230 if(m_impl.m_current.m_popCount > 0){
231 m_impl.m_current.m_popCount--;
232 return 0;
233 }
234
235 NdbScanFilterImpl::State tmp = m_impl.m_current;
236 if(m_impl.m_stack.size() == 0){
237 m_impl.m_operation->setErrorCodeAbort(4259);
238 return -1;
239 }
240 m_impl.m_current = m_impl.m_stack.back();
241 m_impl.m_stack.erase(m_impl.m_stack.size() - 1);
242
243 switch(tmp.m_group){
244 case NdbScanFilter::AND:
245 if(tmp.m_trueLabel == (Uint32)~0){
246 if (m_impl.m_operation->interpret_exit_ok() == -1)
247 return -1;
248 } else {
249 if (m_impl.m_operation->branch_label(tmp.m_trueLabel) == -1)
250 return -1;
251 }
252 break;
253 case NdbScanFilter::NAND:
254 if(tmp.m_trueLabel == (Uint32)~0){
255 if (m_impl.m_operation->interpret_exit_nok() == -1)
256 return -1;
257 } else {
258 if (m_impl.m_operation->branch_label(tmp.m_falseLabel) == -1)
259 return -1;
260 }
261 break;
262 case NdbScanFilter::OR:
263 if(tmp.m_falseLabel == (Uint32)~0){
264 if (m_impl.m_operation->interpret_exit_nok() == -1)
265 return -1;
266 } else {
267 if (m_impl.m_operation->branch_label(tmp.m_falseLabel) == -1)
268 return -1;
269 }
270 break;
271 case NdbScanFilter::NOR:
272 if(tmp.m_falseLabel == (Uint32)~0){
273 if (m_impl.m_operation->interpret_exit_ok() == -1)
274 return -1;
275 } else {
276 if (m_impl.m_operation->branch_label(tmp.m_trueLabel) == -1)
277 return -1;
278 }
279 break;
280 default:
281 m_impl.m_operation->setErrorCodeAbort(4260);
282 return -1;
283 }
284
285 if (m_impl.m_operation->def_label(tmp.m_ownLabel) == -1)
286 return -1;
287
288 if(m_impl.m_stack.size() == 0){
289 switch(tmp.m_group){
290 case NdbScanFilter::AND:
291 case NdbScanFilter::NOR:
292 if (m_impl.m_operation->interpret_exit_nok() == -1)
293 return -1;
294 break;
295 case NdbScanFilter::OR:
296 case NdbScanFilter::NAND:
297 if (m_impl.m_operation->interpret_exit_ok() == -1)
298 return -1;
299 break;
300 default:
301 m_impl.m_operation->setErrorCodeAbort(4260);
302 return -1;
303 }
304 }
305
306 if (!m_impl.check_size())
307 return -1;
308 return 0;
309 }
310
311 int
istrue()312 NdbScanFilter::istrue(){
313 if(m_impl.m_current.m_group < NdbScanFilter::AND ||
314 m_impl.m_current.m_group > NdbScanFilter::NOR){
315 m_impl.m_operation->setErrorCodeAbort(4260);
316 return -1;
317 }
318
319 if(m_impl.m_current.m_trueLabel == (Uint32)~0){
320 if (m_impl.m_operation->interpret_exit_ok() == -1)
321 return -1;
322 } else {
323 if (m_impl.m_operation->branch_label(m_impl.m_current.m_trueLabel) == -1)
324 return -1;
325 }
326
327 if (!m_impl.check_size())
328 return -1;
329 return 0;
330 }
331
332 int
isfalse()333 NdbScanFilter::isfalse(){
334 if(m_impl.m_current.m_group < NdbScanFilter::AND ||
335 m_impl.m_current.m_group > NdbScanFilter::NOR){
336 m_impl.m_operation->setErrorCodeAbort(4260);
337 return -1;
338 }
339
340 if(m_impl.m_current.m_falseLabel == (Uint32)~0){
341 if (m_impl.m_operation->interpret_exit_nok() == -1)
342 return -1;
343 } else {
344 if (m_impl.m_operation->branch_label(m_impl.m_current.m_falseLabel) == -1)
345 return -1;
346 }
347
348 if (!m_impl.check_size())
349 return -1;
350 return 0;
351 }
352
353 NdbOperation *
getNdbOperation()354 NdbScanFilter::getNdbOperation(){
355 return m_impl.m_operation;
356 }
357
358 #define action(x, y, z)
359
360
361 typedef int (NdbOperation:: * Branch1)(Uint32, Uint32 label);
362 typedef int (NdbOperation:: * StrBranch2)(Uint32, const void*, Uint32, bool, Uint32);
363
364 struct tab2 {
365 Branch1 m_branches[5];
366 };
367
368 static const tab2 table2[] = {
369 /**
370 * IS NULL
371 */
372 { { 0,
373 &NdbOperation::branch_col_ne_null,
374 &NdbOperation::branch_col_eq_null,
375 &NdbOperation::branch_col_eq_null,
376 &NdbOperation::branch_col_ne_null } }
377
378 /**
379 * IS NOT NULL
380 */
381 ,{ { 0,
382 &NdbOperation::branch_col_eq_null,
383 &NdbOperation::branch_col_ne_null,
384 &NdbOperation::branch_col_ne_null,
385 &NdbOperation::branch_col_eq_null } }
386 };
387
388 const int tab2_sz = sizeof(table2)/sizeof(table2[0]);
389
390 int
cond_col(Interpreter::UnaryCondition op,Uint32 AttrId)391 NdbScanFilterImpl::cond_col(Interpreter::UnaryCondition op, Uint32 AttrId){
392
393 if(op < 0 || op >= tab2_sz){
394 m_operation->setErrorCodeAbort(4262);
395 return -1;
396 }
397
398 if(m_current.m_group < NdbScanFilter::AND ||
399 m_current.m_group > NdbScanFilter::NOR){
400 m_operation->setErrorCodeAbort(4260);
401 return -1;
402 }
403
404 Branch1 branch = table2[op].m_branches[m_current.m_group];
405 if ((m_operation->* branch)(AttrId, m_current.m_ownLabel) == -1)
406 return -1;
407
408 if (!check_size())
409 return -1;
410 return 0;
411 }
412
413 int
isnull(int AttrId)414 NdbScanFilter::isnull(int AttrId){
415 if(m_impl.m_negative == 1)
416 return m_impl.cond_col(Interpreter::IS_NOT_NULL, AttrId);
417 else
418 return m_impl.cond_col(Interpreter::IS_NULL, AttrId);
419 }
420
421 int
isnotnull(int AttrId)422 NdbScanFilter::isnotnull(int AttrId){
423 if(m_impl.m_negative == 1)
424 return m_impl.cond_col(Interpreter::IS_NULL, AttrId);
425 else
426 return m_impl.cond_col(Interpreter::IS_NOT_NULL, AttrId);
427 }
428
429 struct tab3 {
430 StrBranch2 m_branches[5];
431 };
432
433 static const tab3 table3[] = {
434 /**
435 * EQ (AND, OR, NAND, NOR)
436 */
437 { { 0,
438 &NdbOperation::branch_col_ne,
439 &NdbOperation::branch_col_eq,
440 &NdbOperation::branch_col_ne,
441 &NdbOperation::branch_col_eq } }
442
443 /**
444 * NEQ
445 */
446 ,{ { 0,
447 &NdbOperation::branch_col_eq,
448 &NdbOperation::branch_col_ne,
449 &NdbOperation::branch_col_eq,
450 &NdbOperation::branch_col_ne } }
451
452 /**
453 * LT
454 */
455 ,{ { 0,
456 &NdbOperation::branch_col_le,
457 &NdbOperation::branch_col_gt,
458 &NdbOperation::branch_col_le,
459 &NdbOperation::branch_col_gt } }
460
461 /**
462 * LE
463 */
464 ,{ { 0,
465 &NdbOperation::branch_col_lt,
466 &NdbOperation::branch_col_ge,
467 &NdbOperation::branch_col_lt,
468 &NdbOperation::branch_col_ge } }
469
470 /**
471 * GT
472 */
473 ,{ { 0,
474 &NdbOperation::branch_col_ge,
475 &NdbOperation::branch_col_lt,
476 &NdbOperation::branch_col_ge,
477 &NdbOperation::branch_col_lt } }
478
479 /**
480 * GE
481 */
482 ,{ { 0,
483 &NdbOperation::branch_col_gt,
484 &NdbOperation::branch_col_le,
485 &NdbOperation::branch_col_gt,
486 &NdbOperation::branch_col_le } }
487
488 /**
489 * LIKE
490 */
491 ,{ { 0,
492 &NdbOperation::branch_col_notlike,
493 &NdbOperation::branch_col_like,
494 &NdbOperation::branch_col_notlike,
495 &NdbOperation::branch_col_like } }
496
497 /**
498 * NOT LIKE
499 */
500 ,{ { 0,
501 &NdbOperation::branch_col_like,
502 &NdbOperation::branch_col_notlike,
503 &NdbOperation::branch_col_like,
504 &NdbOperation::branch_col_notlike } }
505 };
506
507 const int tab3_sz = sizeof(table3)/sizeof(table3[0]);
508
509 int
cond_col_const(Interpreter::BinaryCondition op,Uint32 AttrId,const void * value,Uint32 len)510 NdbScanFilterImpl::cond_col_const(Interpreter::BinaryCondition op,
511 Uint32 AttrId,
512 const void * value, Uint32 len){
513 if(op < 0 || op >= tab3_sz){
514 m_operation->setErrorCodeAbort(4260);
515 return -1;
516 }
517
518 if(m_current.m_group < NdbScanFilter::AND ||
519 m_current.m_group > NdbScanFilter::NOR){
520 m_operation->setErrorCodeAbort(4260);
521 return -1;
522 }
523
524 StrBranch2 branch;
525 if(m_negative == 1){ //change NdbOperation to its negative
526 if(m_current.m_group == NdbScanFilter::AND)
527 branch = table3[op].m_branches[(Uint32)(m_current.m_group) + 1];
528 if(m_current.m_group == NdbScanFilter::OR)
529 branch = table3[op].m_branches[(Uint32)(m_current.m_group) - 1];
530 }else{
531 branch = table3[op].m_branches[(Uint32)(m_current.m_group)];
532 }
533
534 const NdbDictionary::Column * col =
535 m_operation->m_currentTable->getColumn(AttrId);
536
537 if(col == 0){
538 m_operation->setErrorCodeAbort(4261);
539 return -1;
540 }
541
542 if ((m_operation->* branch)(AttrId, value, len, false, m_current.m_ownLabel) == -1)
543 return -1;
544
545 if (!check_size())
546 return -1;
547 return 0;
548 }
549
550 int
cmp(BinaryCondition cond,int ColId,const void * val,Uint32 len)551 NdbScanFilter::cmp(BinaryCondition cond, int ColId,
552 const void *val, Uint32 len)
553 {
554 switch(cond){
555 case COND_LE:
556 return m_impl.cond_col_const(Interpreter::LE, ColId, val, len);
557 case COND_LT:
558 return m_impl.cond_col_const(Interpreter::LT, ColId, val, len);
559 case COND_GE:
560 return m_impl.cond_col_const(Interpreter::GE, ColId, val, len);
561 case COND_GT:
562 return m_impl.cond_col_const(Interpreter::GT, ColId, val, len);
563 case COND_EQ:
564 return m_impl.cond_col_const(Interpreter::EQ, ColId, val, len);
565 case COND_NE:
566 return m_impl.cond_col_const(Interpreter::NE, ColId, val, len);
567 case COND_LIKE:
568 return m_impl.cond_col_const(Interpreter::LIKE, ColId, val, len);
569 case COND_NOT_LIKE:
570 return m_impl.cond_col_const(Interpreter::NOT_LIKE, ColId, val, len);
571 }
572 return -1;
573 }
574
575 void
handle_filter_too_large()576 NdbScanFilterImpl::handle_filter_too_large()
577 {
578 DBUG_ENTER("NdbScanFilterImpl::handle_filter_too_large");
579
580 NdbOperation* const op = m_operation;
581 m_error.code = NdbScanFilter::FilterTooLarge;
582 if (m_abort_on_too_large)
583 op->setErrorCodeAbort(m_error.code);
584
585 /*
586 * Possible interpreted parts at this point are:
587 *
588 * 1. initial read
589 * 2. interpreted program
590 *
591 * It is assumed that NdbScanFilter has created all of 2
592 * so that we don't have to save interpreter state.
593 */
594
595 const Uint32 size = get_size();
596 assert(size != 0);
597
598 // new ATTRINFO size
599 const Uint32 new_size = m_initial_AI_size;
600
601 // find last signal for new size
602 assert(op->theFirstATTRINFO != NULL);
603 NdbApiSignal* lastSignal = op->theFirstATTRINFO;
604 Uint32 n = 0;
605 while (n + AttrInfo::DataLength < new_size) {
606 lastSignal = lastSignal->next();
607 assert(lastSignal != NULL);
608 n += AttrInfo::DataLength;
609 }
610 assert(n < size);
611
612 // release remaining signals
613 NdbApiSignal* tSignal = lastSignal->next();
614 op->theNdb->releaseSignalsInList(&tSignal);
615 lastSignal->next(NULL);
616
617 // length of lastSignal
618 const Uint32 new_curr = AttrInfo::HeaderLength + new_size - n;
619 assert(new_curr <= 25);
620
621 DBUG_PRINT("info", ("op status: %d->%d tot AI: %u->%u in curr: %u->%u",
622 op->theStatus, m_initial_op_status,
623 op->theTotalCurrAI_Len, new_size,
624 op->theAI_LenInCurrAI, new_curr));
625
626 // reset op state
627 op->theStatus = m_initial_op_status;
628
629 // reset interpreter state to initial
630
631 NdbBranch* tBranch = op->theFirstBranch;
632 while (tBranch != NULL) {
633 NdbBranch* tmp = tBranch;
634 tBranch = tBranch->theNext;
635 op->theNdb->releaseNdbBranch(tmp);
636 }
637 op->theFirstBranch = NULL;
638 op->theLastBranch = NULL;
639
640 NdbLabel* tLabel = op->theFirstLabel;
641 while (tLabel != NULL) {
642 NdbLabel* tmp = tLabel;
643 tLabel = tLabel->theNext;
644 op->theNdb->releaseNdbLabel(tmp);
645 }
646 op->theFirstLabel = NULL;
647 op->theLastLabel = NULL;
648
649 NdbCall* tCall = op->theFirstCall;
650 while (tCall != NULL) {
651 NdbCall* tmp = tCall;
652 tCall = tCall->theNext;
653 op->theNdb->releaseNdbCall(tmp);
654 }
655 op->theFirstCall = NULL;
656 op->theLastCall = NULL;
657
658 NdbSubroutine* tSubroutine = op->theFirstSubroutine;
659 while (tSubroutine != NULL) {
660 NdbSubroutine* tmp = tSubroutine;
661 tSubroutine = tSubroutine->theNext;
662 op->theNdb->releaseNdbSubroutine(tmp);
663 }
664 op->theFirstSubroutine = NULL;
665 op->theLastSubroutine = NULL;
666
667 op->theNoOfLabels = 0;
668 op->theNoOfSubroutines = 0;
669
670 // reset AI size
671 op->theTotalCurrAI_Len = new_size;
672 op->theAI_LenInCurrAI = new_curr;
673
674 // reset signal pointers
675 op->theCurrentATTRINFO = lastSignal;
676 op->theATTRINFOptr = &lastSignal->getDataPtrSend()[new_curr];
677
678 // interpreter sizes are set later somewhere
679
680 DBUG_VOID_RETURN;
681 }
682
683 static void
update(const NdbError & _err)684 update(const NdbError & _err){
685 NdbError & error = (NdbError &) _err;
686 ndberror_struct ndberror = (ndberror_struct)error;
687 ndberror_update(&ndberror);
688 error = NdbError(ndberror);
689 }
690
691 const NdbError &
getNdbError() const692 NdbScanFilter::getNdbError() const
693 {
694 update(m_impl.m_error);
695 return m_impl.m_error;
696 }
697
698
699 #if 0
700 int
701 main(void){
702 if(0)
703 {
704 ndbout << "a > 7 AND b < 9 AND c = 4" << endl;
705 NdbScanFilter f(0);
706 f.begin(NdbScanFilter::AND);
707 f.gt(0, 7);
708 f.lt(1, 9);
709 f.eq(2, 4);
710 f.end();
711 ndbout << endl;
712 }
713
714 if(0)
715 {
716 ndbout << "a > 7 OR b < 9 OR c = 4" << endl;
717 NdbScanFilter f(0);
718 f.begin(NdbScanFilter::OR);
719 f.gt(0, 7);
720 f.lt(1, 9);
721 f.eq(2, 4);
722 f.end();
723 ndbout << endl;
724 }
725
726 if(0)
727 {
728 ndbout << "a > 7 AND (b < 9 OR c = 4)" << endl;
729 NdbScanFilter f(0);
730 f.begin(NdbScanFilter::AND);
731 f.gt(0, 7);
732 f.begin(NdbScanFilter::OR);
733 f.lt(1, 9);
734 f.eq(2, 4);
735 f.end();
736 f.end();
737 ndbout << endl;
738 }
739
740 if(0)
741 {
742 ndbout << "a > 7 AND (b < 9 AND c = 4)" << endl;
743 NdbScanFilter f(0);
744 f.begin(NdbScanFilter::AND);
745 f.gt(0, 7);
746 f.begin(NdbScanFilter::AND);
747 f.lt(1, 9);
748 f.eq(2, 4);
749 f.end();
750 f.end();
751 ndbout << endl;
752 }
753
754 if(0)
755 {
756 ndbout << "(a > 7 AND b < 9) AND c = 4" << endl;
757 NdbScanFilter f(0);
758 f.begin(NdbScanFilter::AND);
759 f.begin(NdbScanFilter::AND);
760 f.gt(0, 7);
761 f.lt(1, 9);
762 f.end();
763 f.eq(2, 4);
764 f.end();
765 ndbout << endl;
766 }
767
768 if(1)
769 {
770 ndbout << "(a > 7 OR b < 9) AND (c = 4 OR c = 5)" << endl;
771 NdbScanFilter f(0);
772 f.begin(NdbScanFilter::AND);
773 f.begin(NdbScanFilter::OR);
774 f.gt(0, 7);
775 f.lt(1, 9);
776 f.end();
777 f.begin(NdbScanFilter::OR);
778 f.eq(2, 4);
779 f.eq(2, 5);
780 f.end();
781 f.end();
782 ndbout << endl;
783 }
784
785 if(1)
786 {
787 ndbout << "(a > 7 AND b < 9) OR (c = 4 AND c = 5)" << endl;
788 NdbScanFilter f(0);
789 f.begin(NdbScanFilter::OR);
790 f.begin(NdbScanFilter::AND);
791 f.gt(0, 7);
792 f.lt(1, 9);
793 f.end();
794 f.begin(NdbScanFilter::AND);
795 f.eq(2, 4);
796 f.eq(2, 5);
797 f.end();
798 f.end();
799 ndbout << endl;
800 }
801
802 if(1)
803 {
804 ndbout <<
805 "((a > 7 AND b < 9) OR (c = 4 AND d = 5)) AND "
806 "((e > 6 AND f < 8) OR (g = 2 AND h = 3)) " << endl;
807 NdbScanFilter f(0);
808 f.begin(NdbScanFilter::AND);
809 f.begin(NdbScanFilter::OR);
810 f.begin(NdbScanFilter::AND);
811 f.gt(0, 7);
812 f.lt(1, 9);
813 f.end();
814 f.begin(NdbScanFilter::AND);
815 f.eq(2, 4);
816 f.eq(3, 5);
817 f.end();
818 f.end();
819
820 f.begin(NdbScanFilter::OR);
821 f.begin(NdbScanFilter::AND);
822 f.gt(4, 6);
823 f.lt(5, 8);
824 f.end();
825 f.begin(NdbScanFilter::AND);
826 f.eq(6, 2);
827 f.eq(7, 3);
828 f.end();
829 f.end();
830 f.end();
831 }
832
833 return 0;
834 }
835 #endif
836
837 template class Vector<NdbScanFilterImpl::State>;
838
839