1 /*
2  Copyright (c) 2014, 2018, 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, version 2.0,
6  as published by the Free Software Foundation.
7 
8  This program is also distributed with certain software (including
9  but not limited to OpenSSL) that is licensed under separate terms,
10  as designated in a particular file or component or in included license
11  documentation.  The authors of MySQL hereby grant you an additional
12  permission to link the program and your derivative works with the
13  separately licensed software that they have included with MySQL.
14 
15  This program is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  GNU General Public License, version 2.0, for more details.
19 
20  You should have received a copy of the GNU General Public License
21  along with this program; if not, write to the Free Software
22  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
23 */
24 
25 #include <NdbApi.hpp>
26 
27 #include "NdbQueryBuilder.hpp"
28 #include "NdbQueryOperation.hpp"
29 
30 #include "adapter_global.h"
31 #include "js_wrapper_macros.h"
32 #include "NdbWrapperErrors.h"
33 #include "NativeMethodCall.h"
34 #include "ScanOperation.h"
35 #include "TransactionImpl.h"
36 
37 using namespace v8;
38 
debug_print_flags_and_options(const NdbScanOperation::ScanOptions & opts)39 void debug_print_flags_and_options(const NdbScanOperation::ScanOptions & opts) {
40   char flags[128];
41   char optstring[80];
42   snprintf(flags, sizeof(flags), "%s%s%s%s%s%s%s%s%s",
43     opts.scan_flags & NdbScanOperation::SF_TupScan     ? " TupScan"       : "",
44     opts.scan_flags & NdbScanOperation::SF_DiskScan    ? " DiskScan"      : "",
45     opts.scan_flags & NdbScanOperation::SF_OrderBy     ? " OrderBy"       : "",
46     opts.scan_flags & NdbScanOperation::SF_OrderByFull ? " OrderByFull"   : "",
47     opts.scan_flags & NdbScanOperation::SF_Descending  ? " Descending"    : "",
48     opts.scan_flags & NdbScanOperation::SF_ReadRangeNo ? " ReadRangeNo"   : "",
49     opts.scan_flags & NdbScanOperation::SF_MultiRange  ? " MultiRange"    : "",
50     opts.scan_flags & NdbScanOperation::SF_KeyInfo     ? " KeyInfo"       : "",
51     opts.scan_flags ? "" : " [None]");
52   snprintf(optstring, sizeof(optstring), "%s%s%s%s",
53     opts.optionsPresent & NdbScanOperation::ScanOptions::SO_SCANFLAGS   ? " HasScanFlags": "",
54     opts.optionsPresent & NdbScanOperation::ScanOptions::SO_BATCH       ? " Batch"       : "",
55     opts.optionsPresent & NdbScanOperation::ScanOptions::SO_INTERPRETED ? " Interpreted" : "",
56     opts.optionsPresent & NdbScanOperation::ScanOptions::SO_PARALLEL    ? " Parallel"    : "");
57 
58   DEBUG_PRINT("Scan flags:%s  options:%s", flags, optstring);
59 }
60 
ScanOperation(const Arguments & args)61 ScanOperation::ScanOperation(const Arguments &args) :
62   KeyOperation(),
63   scan_op(0),
64   index_scan_op(0),
65   nbounds(0),
66   isIndexScan(false)
67 {
68   DEBUG_MARKER(UDEB_DEBUG);
69 
70   Local<Value> v;
71 
72   const Local<Object> spec = args[0]->ToObject();
73   opcode = args[1]->Int32Value();
74   ctx = unwrapPointer<TransactionImpl *>(args[2]->ToObject());
75 
76   lmode = NdbOperation::LM_CommittedRead;
77   scan_options.scan_flags = 0;
78   scan_options.optionsPresent = 0ULL;
79 
80   v = spec->Get(SCAN_TABLE_RECORD);
81   if(! v->IsNull()) {
82     Local<Object> o = v->ToObject();
83     row_record = unwrapPointer<const Record *>(o);
84     createBlobReadHandles(row_record);
85   }
86 
87   v = spec->Get(SCAN_INDEX_RECORD);
88   if(! v->IsNull()) {
89     Local<Object> o = v->ToObject();
90     isIndexScan = true;
91     key_record = unwrapPointer<const Record *>(o);
92   }
93 
94   v = spec->Get(SCAN_LOCK_MODE);
95   if(! v->IsNull()) {
96     int intLockMode = v->Int32Value();
97     DEBUG_PRINT("Scan lock mode %d", intLockMode);
98     lmode = static_cast<NdbOperation::LockMode>(intLockMode);
99   }
100 
101   // SCAN_BOUNDS is an array of BoundHelpers
102   v = spec->Get(SCAN_BOUNDS);
103   if(v->IsArray()) {
104     Local<Object> o = v->ToObject();
105     while(o->Has(nbounds)) {
106       nbounds++;
107     }
108     DEBUG_PRINT("Index Scan with %d IndexBounds", nbounds);
109     bounds = new NdbIndexScanOperation::IndexBound *[nbounds];
110     for(int i = 0 ; i < nbounds ; i++) {
111       Local<Object> b = o->Get(i)->ToObject();
112       bounds[i] = unwrapPointer<NdbIndexScanOperation::IndexBound *>(b);
113     }
114   }
115 
116   v = spec->Get(SCAN_OPTION_FLAGS);
117   if(! v->IsNull()) {
118     scan_options.scan_flags = v->Uint32Value();
119   }
120 
121   v = spec->Get(SCAN_OPTION_BATCH_SIZE);
122   if(! v->IsNull()) {
123     scan_options.batch = v->Uint32Value();
124     scan_options.optionsPresent |= NdbScanOperation::ScanOptions::SO_BATCH;
125   }
126 
127   v = spec->Get(SCAN_OPTION_PARALLELISM);
128   if(! v->IsNull()) {
129     scan_options.parallel = v->Uint32Value();
130     scan_options.optionsPresent |= NdbScanOperation::ScanOptions::SO_PARALLEL;
131   }
132 
133   v = spec->Get(SCAN_FILTER_CODE);
134   if(! v->IsNull()) {
135     Local<Object> o = v->ToObject();
136     scan_options.interpretedCode = unwrapPointer<NdbInterpretedCode *>(o);
137     scan_options.optionsPresent |= NdbScanOperation::ScanOptions::SO_INTERPRETED;
138   }
139 
140   /* Scanning delete requires key info */
141   if(opcode == OP_SCAN_DELETE) {
142     scan_options.scan_flags |= NdbScanOperation::SF_KeyInfo;
143   }
144 
145   /* If any flags were set, also set SO_SCANFLAGS options */
146   if(scan_options.scan_flags != 0) {
147     scan_options.optionsPresent |= NdbScanOperation::ScanOptions::SO_SCANFLAGS;
148   }
149 
150   /* Done defining the object */
151   debug_print_flags_and_options(scan_options);
152 }
153 
~ScanOperation()154 ScanOperation::~ScanOperation() {
155   if(bounds) delete[] bounds;
156 }
157 
prepareAndExecute()158 int ScanOperation::prepareAndExecute() {
159   return ctx->prepareAndExecuteScan(this);
160 }
161 
prepareScan(NdbTransaction * tx)162 void ScanOperation::prepareScan(NdbTransaction *tx) {
163   DEBUG_MARKER(UDEB_DEBUG);
164   if(! scan_op) {  // don't re-prepare if retrying
165     if(isIndexScan) {
166       scan_op = index_scan_op = scanIndex(tx);
167       if(index_scan_op) {
168         for(int i = 0 ; i < nbounds ; i++) {
169          index_scan_op->setBound(key_record->getNdbRecord(), * bounds[i]);
170         }
171       } else {
172         DEBUG_PRINT("Error code: %d %s", tx->getNdbError().code, tx->getNdbError().message);
173       }
174     }
175     else {
176       scan_op = scanTable(tx);
177     }
178     if(blobHandler) {
179       blobHandler->prepare(scan_op);
180     }
181   }
182 }
183 
fetchResults(char * buffer,bool forceSend)184 int ScanOperation::fetchResults(char * buffer, bool forceSend) {
185   int r = scan_op->nextResultCopyOut(buffer, true, forceSend);
186   DEBUG_PRINT("fetchResults: %d", r);
187   return r;
188 }
189 
nextResult(char * buffer)190 int ScanOperation::nextResult(char * buffer) {
191   return scan_op->nextResultCopyOut(buffer, false, false);
192 }
193 
close()194 void ScanOperation::close() {
195   scan_op->close();
196   scan_op = index_scan_op = 0;
197 }
198 
getNdbError()199 const NdbError & ScanOperation::getNdbError() {
200   return scan_op ? scan_op->getNdbError() : ctx->getNdbError();
201 }
202 
203