1 /*
2  Copyright (c) 2014, 2016, 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 <node_buffer.h>
26 
27 #include "adapter_global.h"
28 #include "unified_debug.h"
29 #include "KeyOperation.h"
30 
31 using namespace v8;
32 
33 const char * opcode_strings[17] =
34  { 0, "read  ", "insert", 0, "update", 0, 0, 0, "write ",
35    0, 0, 0, 0, 0, 0, 0, "delete" };
36 
getOperationName()37 const char * KeyOperation::getOperationName() {
38   return opcode < 17 ? opcode_strings[opcode] : 0;
39 }
40 
41 // Call the right destructor for a chain of blob handlers,
42 // where B is either BlobReadHandler or BlobWriteHandler
deleteBlobChain(BlobHandler * b)43 template <typename B> void deleteBlobChain(BlobHandler *b) {
44   do {
45     B * blobHandler = static_cast<B *>(b);
46     b = blobHandler->getNext();
47     delete blobHandler;
48   } while(b);
49 }
50 
~KeyOperation()51 KeyOperation::~KeyOperation() {
52   if(isBlobReadOperation()) {
53     deleteBlobChain<BlobReadHandler>(blobHandler);
54   } else if(blobHandler) {
55     deleteBlobChain<BlobWriteHandler>(blobHandler);
56   }
57 }
58 
readTuple(NdbTransaction * tx)59 const NdbOperation * KeyOperation::readTuple(NdbTransaction *tx) {
60   const NdbOperation *op;
61   op = tx->readTuple(key_record->getNdbRecord(), key_buffer,
62                      row_record->getNdbRecord(), row_buffer, lmode, read_mask_ptr);
63   if(blobHandler) blobHandler->prepare(op);
64   return op;
65 }
66 
deleteTuple(NdbTransaction * tx)67 const NdbOperation * KeyOperation::deleteTuple(NdbTransaction *tx) {
68   return tx->deleteTuple(key_record->getNdbRecord(), key_buffer,
69                          row_record->getNdbRecord(), 0, 0, options);
70 }
71 
writeTuple(NdbTransaction * tx)72 const NdbOperation * KeyOperation::writeTuple(NdbTransaction *tx) {
73   const NdbOperation *op;
74   op = tx->writeTuple(key_record->getNdbRecord(), key_buffer,
75                       row_record->getNdbRecord(), row_buffer, u.row_mask);
76   if(blobHandler) blobHandler->prepare(op);
77   return op;
78 }
79 
insertTuple(NdbTransaction * tx)80 const NdbOperation * KeyOperation::insertTuple(NdbTransaction *tx) {
81   const NdbOperation *op;
82   op = tx->insertTuple(row_record->getNdbRecord(), row_buffer,
83                        u.row_mask, options);
84   if(blobHandler) blobHandler->prepare(op);
85   return op;
86 }
87 
updateTuple(NdbTransaction * tx)88 const NdbOperation * KeyOperation::updateTuple(NdbTransaction *tx) {
89   const NdbOperation *op;
90   op = tx->updateTuple(key_record->getNdbRecord(), key_buffer,
91                        row_record->getNdbRecord(), row_buffer,
92                        u.row_mask, options);
93   if(blobHandler) blobHandler->prepare(op);
94   return op;
95 }
96 
97 
prepare(NdbTransaction * tx)98 const NdbOperation * KeyOperation::prepare(NdbTransaction *tx) {
99   switch(opcode) {
100     case 1:  // OP_READ:
101       return readTuple(tx);
102     case 2:  // OP_INSERT:
103       return insertTuple(tx);
104     case 4:  // OP_UPDATE:
105       return updateTuple(tx);
106     case 8:  // OP_WRITE:
107       return writeTuple(tx);
108     case 16: // OP_DELETE:
109       return deleteTuple(tx);
110     default:
111       return NULL;
112   }
113 }
114 
setBlobHandler(BlobHandler * b)115 void KeyOperation::setBlobHandler(BlobHandler *b) {
116   b->setNext(blobHandler);
117   blobHandler = b;
118 }
119 
createBlobReadHandles(const Record * rowRecord)120 int KeyOperation::createBlobReadHandles(const Record * rowRecord) {
121   DEBUG_MARKER(UDEB_DEBUG);
122   int ncreated = 0;
123   int ncol = rowRecord->getNoOfColumns();
124   for(int i = 0 ; i < ncol ; i++) {
125     const NdbDictionary::Column * col = rowRecord->getColumn(i);
126     if((col->getType() ==  NdbDictionary::Column::Blob) ||
127        (col->getType() ==  NdbDictionary::Column::Text))
128     {
129       setBlobHandler(new BlobReadHandler(i, col->getColumnNo()));
130       ncreated++;
131     }
132   }
133   return ncreated;
134 }
135 
136 
createBlobWriteHandles(Handle<Object> blobsArray,const Record * rowRecord)137 int KeyOperation::createBlobWriteHandles(Handle<Object> blobsArray,
138                                          const Record * rowRecord) {
139   DEBUG_MARKER(UDEB_DEBUG);
140   int ncreated = 0;
141   int ncol = rowRecord->getNoOfColumns();
142   for(int i = 0 ; i < ncol ; i++) {
143     if(blobsArray->Get(i)->IsObject()) {
144       Local<Object> blobValue = blobsArray->Get(i)->ToObject();
145       assert(node::Buffer::HasInstance(blobValue));
146       const NdbDictionary::Column * col = rowRecord->getColumn(i);
147       assert( (col->getType() ==  NdbDictionary::Column::Blob) ||
148               (col->getType() ==  NdbDictionary::Column::Text));
149       ncreated++;
150       setBlobHandler(new BlobWriteHandler(i, col->getColumnNo(), blobValue));
151     }
152   }
153   return ncreated;
154 }
155 
156 
readBlobResults(const Arguments & args)157 void KeyOperation::readBlobResults(const Arguments & args) {
158   DEBUG_MARKER(UDEB_DEBUG);
159   v8::Isolate * isolate = args.GetIsolate();
160   EscapableHandleScope scope(isolate);
161 
162   args.GetReturnValue().SetUndefined();
163   if(isBlobReadOperation()) {
164     Local<Object> results = Array::New(isolate);
165     BlobReadHandler * readHandler = static_cast<BlobReadHandler *>(blobHandler);
166     while(readHandler) {
167       Local<Value> buffer = readHandler->getResultBuffer(isolate);
168       if(buffer.IsEmpty()) {
169         buffer = Null(isolate);
170       }
171       results->ToObject()->Set(readHandler->getFieldNumber(), buffer);
172       readHandler = static_cast<BlobReadHandler *>(readHandler->getNext());
173     }
174     args.GetReturnValue().Set(scope.Escape(results));
175   }
176 }
177