1 /*
2  Copyright (c) 2013, 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 <string.h>
26 
27 #include <node.h>
28 #include <node_buffer.h>
29 
30 #include "adapter_global.h"
31 #include "KeyOperation.h"
32 #include "BatchImpl.h"
33 #include "NdbWrappers.h"
34 #include "js_wrapper_macros.h"
35 #include "NdbRecordObject.h"
36 #include "TransactionImpl.h"
37 #include "BlobHandler.h"
38 
39 enum {
40   HELPER_ROW_BUFFER = 0,
41   HELPER_KEY_BUFFER,
42   HELPER_ROW_RECORD,
43   HELPER_KEY_RECORD,
44   HELPER_LOCK_MODE,
45   HELPER_COLUMN_MASK,
46   HELPER_VALUE_OBJECT,
47   HELPER_OPCODE,
48   HELPER_IS_VO,
49   HELPER_BLOBS,
50   HELPER_IS_VALID
51 };
52 
53 void DBOperationHelper_VO(Handle<Object>, KeyOperation &);
54 void DBOperationHelper_NonVO(Handle<Object>, KeyOperation &);
55 
56 void setKeysInOp(Handle<Object> spec, KeyOperation & op);
57 
58 
59 /* DBOperationHelper takes an array of HelperSpecs.
60    arg0: Length of Array
61    arg1: Array of HelperSpecs
62    arg2: TransactionImpl *
63    arg3: Old BatchImpl wrapper (for recycling)
64 
65    Returns: BatchImpl
66 */
DBOperationHelper(const Arguments & args)67 void DBOperationHelper(const Arguments &args) {
68   EscapableHandleScope scope(args.GetIsolate());
69 
70   int length = args[0]->Int32Value();
71   const Local<Object> array = args[1]->ToObject();
72   TransactionImpl *txc = unwrapPointer<TransactionImpl *>(args[2]->ToObject());
73   Handle<Value> oldWrapper = args[3];
74 
75   BatchImpl * pendingOps = new BatchImpl(txc, length);
76 
77   for(int i = 0 ; i < length ; i++) {
78     Handle<Object> spec = array->Get(i)->ToObject();
79 
80     int opcode  = spec->Get(HELPER_OPCODE)->Int32Value();
81     bool is_vo  = spec->Get(HELPER_IS_VO)->ToBoolean()->Value();
82     bool op_ok  = spec->Get(HELPER_IS_VALID)->ToBoolean()->Value();
83 
84     KeyOperation * op = pendingOps->getKeyOperation(i);
85 
86     if(op_ok) {
87       op->opcode = opcode;
88       if(is_vo) DBOperationHelper_VO(spec, *op);
89       else      DBOperationHelper_NonVO(spec, *op);
90     }
91   }
92 
93   if(oldWrapper->IsObject()) {
94     args.GetReturnValue().Set(BatchImpl_Recycle(oldWrapper->ToObject(), pendingOps));
95   } else {
96     args.GetReturnValue().Set(BatchImpl_Wrapper(pendingOps));
97   }
98 }
99 
100 
setKeysInOp(Handle<Object> spec,KeyOperation & op)101 void setKeysInOp(Handle<Object> spec, KeyOperation & op) {
102   Local<Value> v;
103   Local<Object> o;
104 
105   v = spec->Get(HELPER_KEY_BUFFER);
106   if(! v->IsNull()) {
107     o = v->ToObject();
108     op.key_buffer = node::Buffer::Data(o);
109   }
110 
111   v = spec->Get(HELPER_KEY_RECORD);
112   if(! v->IsNull()) {
113     o = v->ToObject();
114     op.key_record = unwrapPointer<const Record *>(o);
115   }
116 }
117 
118 
DBOperationHelper_NonVO(Handle<Object> spec,KeyOperation & op)119 void DBOperationHelper_NonVO(Handle<Object> spec, KeyOperation & op) {
120   Local<Value> v;
121   Local<Object> o;
122 
123   setKeysInOp(spec, op);
124 
125   v = spec->Get(HELPER_ROW_BUFFER);
126   if(! v->IsNull()) {
127     o = v->ToObject();
128     op.row_buffer = node::Buffer::Data(o);
129   }
130 
131   v = spec->Get(HELPER_ROW_RECORD);
132   if(! v->IsNull()) {
133     o = v->ToObject();
134     const Record * record = unwrapPointer<const Record *>(o);
135     op.row_record = record;
136 
137     v = spec->Get(HELPER_BLOBS);
138     if(v->IsObject()) {
139       if(op.opcode == 1) {
140         op.nblobs = op.createBlobReadHandles(record);
141       } else {
142         op.nblobs = op.createBlobWriteHandles(v->ToObject(), record);
143       }
144     }
145   }
146 
147   v = spec->Get(HELPER_LOCK_MODE);
148   if(! v->IsNull()) {
149     int intLockMode = v->Int32Value();
150     op.lmode = static_cast<NdbOperation::LockMode>(intLockMode);
151   }
152 
153   v = spec->Get(HELPER_COLUMN_MASK);
154   if(! v->IsNull()) {
155     v8::Array *maskArray = v8::Array::Cast(*v);
156     for(unsigned int m = 0 ; m < maskArray->Length() ; m++) {
157       Local<Value> colId = maskArray->Get(m);
158       op.useColumn(colId->Int32Value());
159     }
160   }
161 
162   DEBUG_PRINT("Non-VO %s -- mask: %u lobs: %d", op.getOperationName(),
163               op.u.maskvalue, op.nblobs);
164 }
165 
166 
DBOperationHelper_VO(Handle<Object> spec,KeyOperation & op)167 void DBOperationHelper_VO(Handle<Object> spec,  KeyOperation & op) {
168   DEBUG_MARKER(UDEB_DETAIL);
169   Local<Value> v;
170   Local<Object> o;
171   Local<Object> valueObj;
172 
173   v = spec->Get(HELPER_VALUE_OBJECT);
174   valueObj = v->ToObject();
175   NdbRecordObject * nro = unwrapPointer<NdbRecordObject *>(valueObj);
176 
177   /* Set the key record and key buffer from the helper spec */
178   setKeysInOp(spec, op);
179 
180   /* Set the row record, row buffer, and mask from the VO */
181   op.row_record = nro->getRecord();
182   op.row_buffer = nro->getBuffer();
183 
184   /* A persist operation must write all columns.
185      A save operation must write all columns only if the PK has changed.
186      Other operations only write columns that have changed since being read.
187   */
188   if(op.opcode == 2)
189     op.setRowMask(op.row_record->getAllColumnMask());
190   else if(op.opcode == 8 && (nro->getMaskValue() & op.row_record->getPkColumnMask()))
191     op.setRowMask(op.row_record->getAllColumnMask());
192   else
193     op.setRowMask(nro->getMaskValue());
194 
195   op.nblobs = nro->createBlobWriteHandles(op);
196 
197   DEBUG_PRINT("  VO   %s -- mask: %u lobs: %d", op.getOperationName(),
198               op.u.maskvalue, op.nblobs);
199   nro->resetMask();
200 }
201 
202 
DBOperationHelper_initOnLoad(Handle<Object> target)203 void DBOperationHelper_initOnLoad(Handle<Object> target) {
204   DEBUG_MARKER(UDEB_DETAIL);
205   DEFINE_JS_FUNCTION(target, "DBOperationHelper", DBOperationHelper);
206   Local<Object> OpHelper = Object::New(Isolate::GetCurrent());
207   Local<Object> LockModes = Object::New(Isolate::GetCurrent());
208 
209   target->Set(NEW_SYMBOL("OpHelper"), OpHelper);
210   DEFINE_JS_INT(OpHelper, "row_buffer",   HELPER_ROW_BUFFER);
211   DEFINE_JS_INT(OpHelper, "key_buffer",   HELPER_KEY_BUFFER);
212   DEFINE_JS_INT(OpHelper, "row_record",   HELPER_ROW_RECORD);
213   DEFINE_JS_INT(OpHelper, "key_record",   HELPER_KEY_RECORD);
214   DEFINE_JS_INT(OpHelper, "lock_mode",    HELPER_LOCK_MODE);
215   DEFINE_JS_INT(OpHelper, "column_mask",  HELPER_COLUMN_MASK);
216   DEFINE_JS_INT(OpHelper, "value_obj",    HELPER_VALUE_OBJECT);
217   DEFINE_JS_INT(OpHelper, "opcode",       HELPER_OPCODE);
218   DEFINE_JS_INT(OpHelper, "is_value_obj", HELPER_IS_VO);
219   DEFINE_JS_INT(OpHelper, "blobs",        HELPER_BLOBS);
220   DEFINE_JS_INT(OpHelper, "is_valid",     HELPER_IS_VALID);
221 
222   target->Set(NEW_SYMBOL("LockModes"), LockModes);
223   DEFINE_JS_INT(LockModes, "EXCLUSIVE", NdbOperation::LM_Exclusive);
224   DEFINE_JS_INT(LockModes, "SHARED", NdbOperation::LM_Read);
225   DEFINE_JS_INT(LockModes, "COMMITTED", NdbOperation::LM_CommittedRead);
226 }
227 
228