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