1 /*
2    Copyright (c) 2012, 2021, Oracle and/or its affiliates.
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 package com.mysql.clusterj.tie;
26 
27 import java.math.BigDecimal;
28 import java.math.BigInteger;
29 
30 import java.nio.ByteBuffer;
31 import java.util.ArrayList;
32 import java.util.List;
33 
34 import com.mysql.clusterj.ClusterJFatalInternalException;
35 
36 import com.mysql.clusterj.core.store.Blob;
37 import com.mysql.clusterj.core.store.Column;
38 import com.mysql.clusterj.core.store.Db;
39 import com.mysql.clusterj.core.store.Operation;
40 import com.mysql.clusterj.core.store.ResultData;
41 import com.mysql.clusterj.core.store.Table;
42 
43 import com.mysql.clusterj.core.util.I18NHelper;
44 import com.mysql.clusterj.core.util.Logger;
45 import com.mysql.clusterj.core.util.LoggerFactoryService;
46 
47 import com.mysql.clusterj.tie.DbImpl.BufferManager;
48 
49 import com.mysql.ndbjtie.ndbapi.NdbBlob;
50 import com.mysql.ndbjtie.ndbapi.NdbOperationConst;
51 import com.mysql.ndbjtie.ndbapi.NdbDictionary.Dictionary;
52 
53 /**
54  * Implementation of store operation that uses NdbRecord.
55  * Operations of the "equal" variety delegate to the key NdbRecordImpl.
56  * Operations of the "set" and "get" varieties delegate to the value NdbRecordImpl.
57  */
58 public class NdbRecordOperationImpl implements Operation {
59 
60     /** My message translator */
61     static final I18NHelper local = I18NHelper
62             .getInstance(NdbRecordOperationImpl.class);
63 
64     /** My logger */
65     static final Logger logger = LoggerFactoryService.getFactory()
66             .getInstance(NdbRecordOperationImpl.class);
67 
68     /** The ClusterTransaction that this operation belongs to */
69     protected ClusterTransactionImpl clusterTransaction = null;
70 
71     /** The NdbOperation wrapped by this object */
72     protected NdbOperationConst ndbOperation = null;
73 
74     /** The NdbRecord for keys */
75     protected NdbRecordImpl ndbRecordKeys = null;
76 
77     /** The NdbRecord for values */
78     protected NdbRecordImpl ndbRecordValues = null;
79 
80     /** The ByteBuffer pool for handling blob operations */
81     protected VariableByteBufferPoolImpl byteBufferPool;
82 
83     /** The mask for this operation, which contains a bit set for each column referenced.
84      * For insert, this contains a bit for each column to be inserted.
85      * For update, this contains a bit for each column to be updated.
86      * For read/scan operations, this contains a bit for each column to be read.
87      */
88     byte[] mask;
89 
90     /** The ByteBuffer containing keys */
91     ByteBuffer keyBuffer = null;
92 
93     /** The ByteBuffer containing values */
94     ByteBuffer valueBuffer = null;
95 
96     /** Blobs for this NdbRecord */
97     protected NdbRecordBlobImpl[] blobs = null;
98 
99     /** Blobs that have been accessed for this operation */
100     protected List<NdbRecordBlobImpl> activeBlobs = new ArrayList<NdbRecordBlobImpl>();
101 
102     /** The size of the key buffer for this operation */
103     protected int keyBufferSize;
104 
105     /** The size of the value buffer for this operation */
106     protected int valueBufferSize;
107 
108     /** The buffer manager for string encode and decode */
109     protected BufferManager bufferManager;
110 
111     /** The table name */
112     protected String tableName;
113 
114     /** The store table */
115     protected Table storeTable;
116 
117     /** The store columns. */
118     protected Column[] storeColumns;
119 
120     /** The number of columns */
121     int numberOfColumns;
122 
123     /** The db for this operation */
124     protected DbImpl db;
125 
126     /** If autoincrement is defined for any column */
127     protected boolean autoIncrement = false;
128 
129     /** The autoincrement column id or zero if none */
130     protected int autoIncrementColumnId = 0;
131 
132     /** Constructor used for smart value handler for new instances,
133      * and the cluster transaction is not yet known. There is only one
134      * NdbRecord and one buffer, so all operations result in using
135      * the same buffer.
136      *
137      * @param clusterConnection the cluster connection
138      * @param db the Db
139      * @param storeTable the store table
140      */
NdbRecordOperationImpl(ClusterConnectionImpl clusterConnection, Db db, Table storeTable)141     public NdbRecordOperationImpl(ClusterConnectionImpl clusterConnection, Db db, Table storeTable) {
142         byteBufferPool = clusterConnection.getByteBufferPool();
143         this.db = (DbImpl)db;
144         this.storeTable = storeTable;
145         Column autoIncrementColumn = storeTable.getAutoIncrementColumn();
146         if (autoIncrementColumn != null) {
147             this.autoIncrement = true;
148             this.autoIncrementColumnId = autoIncrementColumn.getColumnId();
149         }
150         logger.detail("autoIncrement for " + storeTable.getName() + " is: " + autoIncrement);
151         this.tableName = storeTable.getName();
152         this.ndbRecordValues = clusterConnection.getCachedNdbRecordImpl(storeTable);
153         this.ndbRecordKeys = ndbRecordValues;
154         this.valueBufferSize = ndbRecordValues.getBufferSize();
155         this.keyBufferSize = ndbRecordKeys.getBufferSize();
156         this.valueBuffer = ndbRecordValues.newBuffer();
157         this.keyBuffer = valueBuffer;
158         this.storeColumns = ndbRecordValues.storeColumns;
159         this.numberOfColumns = storeColumns.length;
160         this.blobs = new NdbRecordBlobImpl[this.numberOfColumns];
161         this.bufferManager = ((DbImpl)db).getBufferManager();
162         resetMask();
163     }
164 
165     /** Constructor used when the transaction is known.
166      *
167      * @param clusterTransaction the cluster transaction
168      */
NdbRecordOperationImpl(ClusterTransactionImpl clusterTransaction, Table storeTable)169     public NdbRecordOperationImpl(ClusterTransactionImpl clusterTransaction, Table storeTable) {
170         this.byteBufferPool = clusterTransaction.getClusterConnection().getByteBufferPool();
171         this.clusterTransaction = clusterTransaction;
172         this.db = clusterTransaction.db;
173         this.bufferManager = clusterTransaction.getBufferManager();
174         this.storeTable = storeTable;
175         Column autoIncrementColumn = storeTable.getAutoIncrementColumn();
176         if (autoIncrementColumn != null) {
177             this.autoIncrement = true;
178             this.autoIncrementColumnId = autoIncrementColumn.getColumnId();
179         }
180         logger.detail("autoIncrement for " + storeTable.getName() + " is: " + autoIncrement);
181         this.tableName = storeTable.getName();
182         this.ndbRecordValues = clusterTransaction.getCachedNdbRecordImpl(storeTable);
183         this.valueBufferSize = ndbRecordValues.getBufferSize();
184         this.valueBuffer = ndbRecordValues.newBuffer();
185         this.storeColumns = ndbRecordValues.storeColumns;
186         this.numberOfColumns = ndbRecordValues.getNumberOfColumns();
187         this.blobs = new NdbRecordBlobImpl[this.numberOfColumns];
188         resetMask();
189     }
190 
191     /** Constructor used to copy an existing NdbRecordOperationImpl for use with a SmartValueHandler.
192      * The value buffer is copied and cannot be used by the existing NdbRecordOperationImpl.
193      *
194      * @param ndbRecordOperationImpl2 the existing NdbRecordOperationImpl with value buffer
195      */
NdbRecordOperationImpl(NdbRecordOperationImpl ndbRecordOperationImpl2)196     public NdbRecordOperationImpl(NdbRecordOperationImpl ndbRecordOperationImpl2) {
197         this.byteBufferPool = ndbRecordOperationImpl2.byteBufferPool;
198         this.ndbRecordValues = ndbRecordOperationImpl2.ndbRecordValues;
199         this.valueBufferSize = ndbRecordOperationImpl2.valueBufferSize;
200         this.ndbRecordKeys = ndbRecordValues;
201         this.keyBufferSize = ndbRecordKeys.bufferSize;
202         this.valueBuffer = ndbRecordOperationImpl2.valueBuffer;
203         this.keyBuffer = this.valueBuffer;
204         this.bufferManager = ndbRecordOperationImpl2.bufferManager;
205         this.tableName = ndbRecordOperationImpl2.tableName;
206         this.storeColumns = ndbRecordOperationImpl2.ndbRecordValues.storeColumns;
207         this.numberOfColumns = this.storeColumns.length;
208         this.blobs = new NdbRecordBlobImpl[this.numberOfColumns];
209         // copy the blob data from the original but leave out the NdbBlob part
210         // which is bound to the NdbOperation and is not suitable
211         for (int i = 0; i < ndbRecordOperationImpl2.blobs.length; ++i) {
212             if (ndbRecordOperationImpl2.blobs[i] != null) {
213               this.blobs[i] = new NdbRecordBlobImpl(this, ndbRecordOperationImpl2.blobs[i]);
214             }
215         }
216         resetMask();
217     }
218 
219     /** Release any resources associated with this object.
220      * This method is called by the owner of this object.
221      */
release()222     public void release() {
223         if (logger.isDetailEnabled()) logger.detail("NdbRecordOperationImpl.release");
224         if (keyBuffer != null && keyBuffer != valueBuffer) {
225             ndbRecordKeys.returnBuffer(keyBuffer);
226             this.keyBuffer = null;
227         }
228         if (valueBuffer != null) {
229             ndbRecordValues.returnBuffer(valueBuffer);
230             this.valueBuffer = null;
231         }
232         this.ndbRecordValues = null;
233         this.ndbRecordKeys = null;
234         this.bufferManager = null;
235         if (this.blobs != null) {
236             for (int i = 0; i < this.blobs.length; ++i) {
237                 if (this.blobs[i] != null) {
238                   this.blobs[i].release();
239                   this.blobs[i] = null;
240                 }
241             }
242             this.blobs = null;
243         }
244     }
245 
insert(ClusterTransactionImpl clusterTransactionImpl)246     public NdbOperationConst insert(ClusterTransactionImpl clusterTransactionImpl) {
247         // (only) if the autoincrement column has not been set by the user, get the autoincrement value
248         if (autoIncrement && !isModified(autoIncrementColumnId)) {
249             long value = db.getAutoincrementValue(storeTable);
250             if (logger.isDebugEnabled()) {
251                 logger.debug("insert for " + storeTable.getName() + " autoincrement value: " + value);
252             }
253             ndbRecordValues.setAutoIncrementValue(valueBuffer, value);
254             columnSet(autoIncrementColumnId);
255         }
256         // position the buffer at the beginning for ndbjtie
257         valueBuffer.limit(valueBufferSize);
258         valueBuffer.position(0);
259         ndbOperation = clusterTransactionImpl.insertTuple(ndbRecordValues.getNdbRecord(), valueBuffer, mask, null);
260         clusterTransactionImpl.addOperationToCheck(this);
261         // for each blob column set, get the blob handle and write the values
262         for (NdbRecordBlobImpl blob: activeBlobs) {
263             // activate the blob by getting the NdbBlob
264             blob.setNdbBlob();
265             // set values into the blob
266             blob.setValue();
267         }
268         return ndbOperation;
269     }
270 
delete(ClusterTransactionImpl clusterTransactionImpl)271     public NdbOperationConst delete(ClusterTransactionImpl clusterTransactionImpl) {
272         // position the buffer at the beginning for ndbjtie
273         keyBuffer.limit(keyBufferSize);
274         keyBuffer.position(0);
275         ndbOperation = clusterTransactionImpl.deleteTuple(ndbRecordKeys.getNdbRecord(), keyBuffer, mask, null);
276         return ndbOperation;
277     }
278 
update(ClusterTransactionImpl clusterTransactionImpl)279     public void update(ClusterTransactionImpl clusterTransactionImpl) {
280         // position the buffer at the beginning for ndbjtie
281         valueBuffer.limit(valueBufferSize);
282         valueBuffer.position(0);
283         ndbOperation = clusterTransactionImpl.updateTuple(ndbRecordValues.getNdbRecord(), valueBuffer, mask, null);
284         clusterTransactionImpl.addOperationToCheck(this);
285         // calculate the active blobs
286         activeBlobs.clear();
287         for (NdbRecordBlobImpl blob: blobs) {
288             if (blob != null && isColumnSet(blob.getColumnId())) {
289                 activeBlobs.add(blob);
290                 blob.setNdbBlob();
291                 blob.setValue();
292             }
293         }
294         if (!activeBlobs.isEmpty()) {
295             // if any blobs, execute the transaction to enable the blob values to be updated
296             clusterTransactionImpl.executeNoCommit();
297         }
298         return;
299     }
300 
write(ClusterTransactionImpl clusterTransactionImpl)301     public void write(ClusterTransactionImpl clusterTransactionImpl) {
302         // position the buffer at the beginning for ndbjtie
303         valueBuffer.limit(valueBufferSize);
304         valueBuffer.position(0);
305         ndbOperation = clusterTransactionImpl.writeTuple(ndbRecordValues.getNdbRecord(), valueBuffer, mask, null);
306         clusterTransactionImpl.addOperationToCheck(this);
307         // for each blob column set, get the blob handle and write the values
308         for (NdbRecordBlobImpl blob: activeBlobs) {
309             // activate the blob by getting the NdbBlob
310             blob.setNdbBlob();
311             // set values into the blob
312             blob.setValue();
313         }
314         return;
315     }
316 
load(ClusterTransactionImpl clusterTransactionImpl)317     public void load(ClusterTransactionImpl clusterTransactionImpl) {
318         // position the buffer at the beginning for ndbjtie
319         valueBuffer.limit(valueBufferSize);
320         valueBuffer.position(0);
321         ndbOperation = clusterTransactionImpl.readTuple(ndbRecordKeys.getNdbRecord(), keyBuffer, ndbRecordValues.getNdbRecord(), valueBuffer, mask, null);
322         // for each blob column set, get the blob handle
323         for (NdbRecordBlobImpl blob: activeBlobs) {
324             // activate the blob by getting the NdbBlob
325             blob.setNdbBlob();
326         }
327     }
328 
resetMask()329     protected void resetMask() {
330         this.mask = new byte[1 + (numberOfColumns/8)];
331     }
332 
allocateValueBuffer()333     public void allocateValueBuffer() {
334         this.valueBuffer = ndbRecordValues.newBuffer();
335     }
336 
activateBlobs()337     protected void activateBlobs() {
338         for (NdbRecordBlobImpl blob: activeBlobs) {
339             blob.setNdbBlob();
340         }
341     }
342 
equalBigInteger(Column storeColumn, BigInteger value)343     public void equalBigInteger(Column storeColumn, BigInteger value) {
344         int columnId = ndbRecordKeys.setBigInteger(keyBuffer, storeColumn, value);
345         columnSet(columnId);
346     }
347 
equalBoolean(Column storeColumn, boolean booleanValue)348     public void equalBoolean(Column storeColumn, boolean booleanValue) {
349         byte value = (booleanValue?(byte)0x01:(byte)0x00);
350         equalByte(storeColumn, value);
351     }
352 
equalByte(Column storeColumn, byte value)353     public void equalByte(Column storeColumn, byte value) {
354         int columnId = ndbRecordKeys.setByte(keyBuffer, storeColumn, value);
355         columnSet(columnId);
356     }
357 
equalBytes(Column storeColumn, byte[] value)358     public void equalBytes(Column storeColumn, byte[] value) {
359         int columnId = ndbRecordKeys.setBytes(keyBuffer, storeColumn, value);
360         columnSet(columnId);
361    }
362 
equalDecimal(Column storeColumn, BigDecimal value)363     public void equalDecimal(Column storeColumn, BigDecimal value) {
364         int columnId = ndbRecordKeys.setDecimal(keyBuffer, storeColumn, value);
365         columnSet(columnId);
366     }
367 
equalDouble(Column storeColumn, double value)368     public void equalDouble(Column storeColumn, double value) {
369         int columnId = ndbRecordKeys.setDouble(keyBuffer, storeColumn, value);
370         columnSet(columnId);
371     }
372 
equalFloat(Column storeColumn, float value)373     public void equalFloat(Column storeColumn, float value) {
374         int columnId = ndbRecordKeys.setFloat(keyBuffer, storeColumn, value);
375         columnSet(columnId);
376     }
377 
equalInt(Column storeColumn, int value)378     public void equalInt(Column storeColumn, int value) {
379         int columnId = ndbRecordKeys.setInt(keyBuffer, storeColumn, value);
380         columnSet(columnId);
381     }
382 
equalLong(Column storeColumn, long value)383     public void equalLong(Column storeColumn, long value) {
384         int columnId = ndbRecordKeys.setLong(keyBuffer, storeColumn, value);
385         columnSet(columnId);
386     }
387 
equalShort(Column storeColumn, short value)388     public void equalShort(Column storeColumn, short value) {
389         int columnId = ndbRecordKeys.setShort(keyBuffer, storeColumn, value);
390         columnSet(columnId);
391     }
392 
equalString(Column storeColumn, String value)393     public void equalString(Column storeColumn, String value) {
394         int columnId = ndbRecordKeys.setString(keyBuffer, bufferManager, storeColumn, value);
395         columnSet(columnId);
396     }
397 
getBlob(Column storeColumn)398     public void getBlob(Column storeColumn) {
399         getBlobHandle(storeColumn);
400     }
401 
402     /**
403      * Get the blob handle for this column. The same column will return the same blob handle
404      * regardless of how many times it is called.
405      * @param storeColumn the store column
406      * @return the blob handle
407      */
getBlobHandle(Column storeColumn)408     public Blob getBlobHandle(Column storeColumn) {
409         if (logger.isDetailEnabled()) {
410             logger.detail("column: " + storeColumn.getName());
411         }
412         int columnId = storeColumn.getColumnId();
413         NdbRecordBlobImpl result = blobs[columnId];
414         if (result == null) {
415             if (logger.isDetailEnabled()) {
416                 logger.detail("column: " + storeColumn.getName() + " was null; activating.");
417             }
418             columnSet(columnId);
419             result = new NdbRecordBlobImpl(this, storeColumn, byteBufferPool);
420             blobs[columnId] = result;
421             activeBlobs.add(result);
422         }
423         return result;
424     }
425 
426     /** Specify the columns to be used for the operation.
427      */
getValue(Column storeColumn)428     public void getValue(Column storeColumn) {
429         int columnId = storeColumn.getColumnId();
430         columnSet(columnId);
431     }
432 
postExecuteCallback(Runnable callback)433     public void postExecuteCallback(Runnable callback) {
434         clusterTransaction.postExecuteCallback(callback);
435     }
436 
437     /** Construct a new ResultData using the saved column data and then execute the operation.
438      */
resultData()439     public ResultData resultData() {
440         return resultData(true);
441     }
442 
443     /** Construct a new ResultData and if requested, execute the operation.
444      */
resultData(boolean execute)445     public ResultData resultData(boolean execute) {
446         NdbRecordResultDataImpl result =
447             new NdbRecordResultDataImpl(this);
448         if (execute) {
449             clusterTransaction.executeNoCommit(false, true);
450         }
451         return result;
452     }
453 
setBigInteger(Column storeColumn, BigInteger value)454     public void setBigInteger(Column storeColumn, BigInteger value) {
455         if (value == null) {
456             setNull(storeColumn);
457         } else {
458             int columnId = ndbRecordValues.setBigInteger(valueBuffer, storeColumn, value);
459             columnSet(columnId);
460         }
461     }
462 
setBigInteger(int columnId, BigInteger value)463     public void setBigInteger(int columnId, BigInteger value) {
464         setBigInteger(storeColumns[columnId], value);
465     }
466 
setBoolean(Column storeColumn, Boolean booleanValue)467     public void setBoolean(Column storeColumn, Boolean booleanValue) {
468         byte value = (booleanValue?(byte)0x01:(byte)0x00);
469         setByte(storeColumn, value);
470     }
471 
setBoolean(int columnId, boolean value)472     public void setBoolean(int columnId, boolean value) {
473         setBoolean(storeColumns[columnId], value);
474     }
475 
setByte(Column storeColumn, byte value)476     public void setByte(Column storeColumn, byte value) {
477         int columnId = ndbRecordValues.setByte(valueBuffer, storeColumn, value);
478         columnSet(columnId);
479     }
480 
setByte(int columnId, byte value)481     public void setByte(int columnId, byte value) {
482         setByte(storeColumns[columnId], value);
483     }
484 
setBytes(Column storeColumn, byte[] value)485     public void setBytes(Column storeColumn, byte[] value) {
486         if (logger.isDetailEnabled()) {
487             logger.detail("NdbRecordOperationImpl.setBytes for: " + storeColumn.getName() + " value: " +
488                     Utility.dumpBytes(value));
489         }
490         if (value == null) {
491             setNull(storeColumn);
492         } else {
493             int columnId = ndbRecordValues.setBytes(valueBuffer, storeColumn, value);
494             columnSet(columnId);
495         }
496     }
497 
setBytes(int columnId, byte[] value)498     public void setBytes(int columnId, byte[] value) {
499         setBytes(storeColumns[columnId], value);
500     }
501 
setDecimal(Column storeColumn, BigDecimal value)502     public void setDecimal(Column storeColumn, BigDecimal value) {
503         if (value == null) {
504             setNull(storeColumn);
505         } else {
506             int columnId = ndbRecordValues.setDecimal(valueBuffer, storeColumn, value);
507             columnSet(columnId);
508         }
509     }
510 
setDecimal(int columnId, BigDecimal value)511     public void setDecimal(int columnId, BigDecimal value) {
512         setDecimal(storeColumns[columnId], value);
513     }
514 
setDouble(Column storeColumn, Double value)515     public void setDouble(Column storeColumn, Double value) {
516         int columnId = ndbRecordValues.setDouble(valueBuffer, storeColumn, value);
517         columnSet(columnId);
518     }
519 
setDouble(int columnId, double value)520     public void setDouble(int columnId, double value) {
521         setDouble(storeColumns[columnId], value);
522     }
523 
setFloat(Column storeColumn, Float value)524     public void setFloat(Column storeColumn, Float value) {
525         int columnId = ndbRecordValues.setFloat(valueBuffer, storeColumn, value);
526         columnSet(columnId);
527     }
528 
setFloat(int columnId, float value)529     public void setFloat(int columnId, float value) {
530         setFloat(storeColumns[columnId], value);
531     }
532 
setInt(Column storeColumn, Integer value)533     public void setInt(Column storeColumn, Integer value) {
534         int columnId = ndbRecordValues.setInt(valueBuffer, storeColumn, value);
535         columnSet(columnId);
536     }
537 
setInt(int columnId, int value)538     public void setInt(int columnId, int value) {
539         setInt(storeColumns[columnId], value);
540     }
541 
setLong(Column storeColumn, long value)542     public void setLong(Column storeColumn, long value) {
543         int columnId = ndbRecordValues.setLong(valueBuffer, storeColumn, value);
544         columnSet(columnId);
545     }
546 
setLong(int columnId, long value)547     public void setLong(int columnId, long value) {
548         setLong(storeColumns[columnId], value);
549     }
550 
setNull(Column storeColumn)551     public void setNull(Column storeColumn) {
552         int columnId = ndbRecordValues.setNull(valueBuffer, storeColumn);
553         columnSet(columnId);
554     }
555 
setNull(int columnId)556     public void setNull(int columnId) {
557         setNull(storeColumns[columnId]);
558     }
559 
setShort(Column storeColumn, Short value)560     public void setShort(Column storeColumn, Short value) {
561         int columnId = ndbRecordValues.setShort(valueBuffer, storeColumn, value);
562         columnSet(columnId);
563     }
564 
setShort(int columnId, short value)565     public void setShort(int columnId, short value) {
566         setShort(storeColumns[columnId], value);
567     }
568 
setObjectBoolean(int columnId, Boolean value)569     public void setObjectBoolean(int columnId, Boolean value) {
570         Column storeColumn = storeColumns[columnId];
571         if (value == null) {
572             setNull(storeColumn);
573         } else {
574             setBoolean(storeColumn, value);
575         }
576     }
577 
setObjectByte(int columnId, Byte value)578     public void setObjectByte(int columnId, Byte value) {
579         Column storeColumn = storeColumns[columnId];
580         if (value == null) {
581             setNull(storeColumn);
582         } else {
583             setByte(storeColumn, value);
584         }
585     }
586 
setObjectDouble(int columnId, Double value)587     public void setObjectDouble(int columnId, Double value) {
588         Column storeColumn = storeColumns[columnId];
589         if (value == null) {
590             setNull(storeColumn);
591         } else {
592             setDouble(storeColumn, value);
593         }
594     }
595 
setObjectFloat(int columnId, Float value)596     public void setObjectFloat(int columnId, Float value) {
597         Column storeColumn = storeColumns[columnId];
598         if (value == null) {
599             setNull(storeColumn);
600         } else {
601             setFloat(storeColumn, value);
602         }
603     }
604 
setObjectInt(int columnId, Integer value)605     public void setObjectInt(int columnId, Integer value) {
606         Column storeColumn = storeColumns[columnId];
607         if (value == null) {
608             setNull(storeColumn);
609         } else {
610             setInt(storeColumn, value);
611         }
612     }
613 
setObjectLong(int columnId, Long value)614     public void setObjectLong(int columnId, Long value) {
615         Column storeColumn = storeColumns[columnId];
616         if (value == null) {
617             setNull(storeColumn);
618         } else {
619             setLong(storeColumn, value);
620         }
621     }
622 
setObjectShort(int columnId, Short value)623     public void setObjectShort(int columnId, Short value) {
624         Column storeColumn = storeColumns[columnId];
625         if (value == null) {
626             setNull(storeColumn);
627         } else {
628             setShort(storeColumn, value);
629         }
630     }
631 
setString(Column storeColumn, String value)632     public void setString(Column storeColumn, String value) {
633         if (value == null) {
634             setNull(storeColumn);
635         } else {
636             int columnId = ndbRecordValues.setString(valueBuffer, bufferManager, storeColumn, value);
637             columnSet(columnId);
638         }
639     }
640 
setString(int columnId, String value)641     public void setString(int columnId, String value) {
642         setString(storeColumns[columnId], value);
643     }
644 
errorCode()645     public int errorCode() {
646         return ndbOperation.getNdbError().code();
647     }
648 
handleError(int returnCode, NdbOperationConst ndbOperation2)649     protected static void handleError(int returnCode, NdbOperationConst ndbOperation2) {
650         if (returnCode == 0) {
651             return;
652         } else {
653             Utility.throwError(returnCode, ndbOperation2.getNdbError());
654         }
655     }
656 
handleError(Object object, NdbOperationConst ndbOperation)657     protected static void handleError(Object object, NdbOperationConst ndbOperation) {
658         if (object != null) {
659             return;
660         } else {
661             Utility.throwError(null, ndbOperation.getNdbError());
662         }
663     }
664 
handleError(Object object, Dictionary ndbDictionary)665     protected static void handleError(Object object, Dictionary ndbDictionary) {
666         if (object != null) {
667             return;
668         } else {
669             Utility.throwError(null, ndbDictionary.getNdbError());
670         }
671     }
672 
getNdbBlob(Column storeColumn)673     public NdbBlob getNdbBlob(Column storeColumn) {
674         if (ndbOperation == null) {
675             throw new ClusterJFatalInternalException("NdbRecordOperationImpl.getNdbBlob with no ndbOperation.");
676         } else {
677             NdbBlob result = ndbOperation.getBlobHandle(storeColumn.getColumnId());
678             handleError(result, ndbOperation);
679         return result;
680         }
681     }
682 
683     /** Activate blob/text columns just read
684      *
685      */
activateBlobColumns()686     public void activateBlobColumns() {
687         for (Column storeColumn: storeColumns) {
688             if (storeColumn.isLob()) {
689                 getBlobHandle(storeColumn);
690             }
691         }
692     }
693 
694     /**
695      * Set this column into the mask for NdbRecord operation.
696      * @param columnId the column id
697      */
columnSet(int columnId)698     protected void columnSet(int columnId) {
699         int byteOffset = columnId / 8;
700         int bitInByte = columnId - (byteOffset * 8);
701         mask[byteOffset] |= NdbRecordImpl.BIT_IN_BYTE_MASK[bitInByte];
702     }
703 
isColumnSet(int columnId)704     protected boolean isColumnSet(int columnId) {
705         int byteOffset = columnId / 8;
706         int bitInByte = columnId - (byteOffset * 8);
707         byte testMask = NdbRecordImpl.BIT_IN_BYTE_MASK[bitInByte];
708         return (mask[byteOffset] & testMask) == testMask;
709     }
710 
getValueNdbRecord()711     public NdbRecordImpl getValueNdbRecord() {
712         return ndbRecordValues;
713     }
714 
getBoolean(int columnId)715     public boolean getBoolean(int columnId) {
716         return ndbRecordValues.getBoolean(valueBuffer, columnId);
717     }
718 
getBoolean(Column storeColumn)719     public boolean getBoolean(Column storeColumn) {
720         return ndbRecordValues.getBoolean(valueBuffer, storeColumn.getColumnId());
721     }
722 
getBooleans(int column)723     public boolean[] getBooleans(int column) {
724         throw new ClusterJFatalInternalException(local.message("ERR_Method_Not_Implemented",
725                 "NdbRecordResultDataImpl.getBooleans(int)"));
726     }
727 
getBooleans(Column storeColumn)728     public boolean[] getBooleans(Column storeColumn) {
729         throw new ClusterJFatalInternalException(local.message("ERR_Method_Not_Implemented",
730                 "NdbRecordResultDataImpl.getBooleans(Column)"));
731     }
732 
getByte(int columnId)733     public byte getByte(int columnId) {
734         return ndbRecordValues.getByte(valueBuffer, columnId);
735     }
736 
getByte(Column storeColumn)737     public byte getByte(Column storeColumn) {
738         return ndbRecordValues.getByte(valueBuffer, storeColumn.getColumnId());
739     }
740 
getShort(int columnId)741     public short getShort(int columnId) {
742         return ndbRecordValues.getShort(valueBuffer, columnId);
743     }
744 
getShort(Column storeColumn)745     public short getShort(Column storeColumn) {
746         return ndbRecordValues.getShort(valueBuffer, storeColumn.getColumnId());
747      }
748 
getInt(int columnId)749     public int getInt(int columnId) {
750         return ndbRecordValues.getInt(valueBuffer, columnId);
751     }
752 
getInt(Column storeColumn)753     public int getInt(Column storeColumn) {
754         return getInt(storeColumn.getColumnId());
755     }
756 
getLong(int columnId)757     public long getLong(int columnId) {
758         return ndbRecordValues.getLong(valueBuffer, columnId);
759     }
760 
getFloat(int columnId)761     public float getFloat(int columnId) {
762         return ndbRecordValues.getFloat(valueBuffer, columnId);
763     }
764 
getFloat(Column storeColumn)765     public float getFloat(Column storeColumn) {
766         return getFloat(storeColumn.getColumnId());
767     }
768 
getDouble(int columnId)769     public double getDouble(int columnId) {
770         return ndbRecordValues.getDouble(valueBuffer, columnId);
771     }
772 
getDouble(Column storeColumn)773     public double getDouble(Column storeColumn) {
774         return getDouble(storeColumn.getColumnId());
775     }
776 
getString(int columnId)777     public String getString(int columnId) {
778         return ndbRecordValues.getString(valueBuffer, columnId, bufferManager);
779     }
780 
getString(Column storeColumn)781     public String getString(Column storeColumn) {
782         return ndbRecordValues.getString(valueBuffer, storeColumn.getColumnId(), bufferManager);
783     }
784 
getBytes(int column)785     public byte[] getBytes(int column) {
786         return ndbRecordValues.getBytes(valueBuffer, column);
787     }
788 
getBytes(Column storeColumn)789     public byte[] getBytes(Column storeColumn) {
790         return ndbRecordValues.getBytes(valueBuffer, storeColumn);
791      }
792 
getObject(int column)793     public Object getObject(int column) {
794         throw new ClusterJFatalInternalException(local.message("ERR_Method_Not_Implemented",
795         "NdbRecordResultDataImpl.getObject(int)"));
796     }
797 
getObject(Column storeColumn)798     public Object getObject(Column storeColumn) {
799         throw new ClusterJFatalInternalException(local.message("ERR_Method_Not_Implemented",
800         "NdbRecordResultDataImpl.getObject(Column)"));
801     }
802 
wasNull(Column storeColumn)803     public boolean wasNull(Column storeColumn) {
804         throw new ClusterJFatalInternalException(local.message("ERR_Method_Not_Implemented",
805         "NdbRecordResultDataImpl.wasNull(Column)"));
806     }
807 
getObjectBoolean(int column)808     public Boolean getObjectBoolean(int column) {
809         return ndbRecordValues.getObjectBoolean(valueBuffer, column);
810     }
811 
getObjectBoolean(Column storeColumn)812     public Boolean getObjectBoolean(Column storeColumn) {
813         return ndbRecordValues.getObjectBoolean(valueBuffer, storeColumn.getColumnId());
814     }
815 
getObjectByte(int columnId)816     public Byte getObjectByte(int columnId) {
817         return ndbRecordValues.getObjectByte(valueBuffer, columnId);
818     }
819 
getObjectByte(Column storeColumn)820     public Byte getObjectByte(Column storeColumn) {
821         return ndbRecordValues.getObjectByte(valueBuffer, storeColumn.getColumnId());
822     }
823 
getObjectFloat(int column)824     public Float getObjectFloat(int column) {
825         return ndbRecordValues.getObjectFloat(valueBuffer, column);
826     }
827 
getObjectFloat(Column storeColumn)828     public Float getObjectFloat(Column storeColumn) {
829         return ndbRecordValues.getObjectFloat(valueBuffer, storeColumn.getColumnId());
830     }
831 
getObjectDouble(int column)832     public Double getObjectDouble(int column) {
833         return ndbRecordValues.getObjectDouble(valueBuffer, column);
834     }
835 
getObjectDouble(Column storeColumn)836     public Double getObjectDouble(Column storeColumn) {
837         return ndbRecordValues.getObjectDouble(valueBuffer, storeColumn.getColumnId());
838     }
839 
getObjectInteger(int columnId)840     public Integer getObjectInteger(int columnId) {
841         return ndbRecordValues.getObjectInteger(valueBuffer, columnId);
842     }
843 
getObjectInteger(Column storeColumn)844     public Integer getObjectInteger(Column storeColumn) {
845         return ndbRecordValues.getObjectInteger(valueBuffer, storeColumn.getColumnId());
846     }
847 
getObjectLong(int column)848     public Long getObjectLong(int column) {
849         return ndbRecordValues.getObjectLong(valueBuffer, column);
850     }
851 
getObjectLong(Column storeColumn)852     public Long getObjectLong(Column storeColumn) {
853         return ndbRecordValues.getObjectLong(valueBuffer, storeColumn.getColumnId());
854     }
855 
getObjectShort(int columnId)856     public Short getObjectShort(int columnId) {
857         return ndbRecordValues.getObjectShort(valueBuffer, columnId);
858     }
859 
getObjectShort(Column storeColumn)860     public Short getObjectShort(Column storeColumn) {
861         return ndbRecordValues.getObjectShort(valueBuffer, storeColumn.getColumnId());
862     }
863 
getBigInteger(int column)864     public BigInteger getBigInteger(int column) {
865         return ndbRecordValues.getBigInteger(valueBuffer, column);
866     }
867 
getBigInteger(Column storeColumn)868     public BigInteger getBigInteger(Column storeColumn) {
869         return ndbRecordValues.getBigInteger(valueBuffer, storeColumn);
870     }
871 
getDecimal(int column)872     public BigDecimal getDecimal(int column) {
873         return ndbRecordValues.getDecimal(valueBuffer, column);
874     }
875 
getDecimal(Column storeColumn)876     public BigDecimal getDecimal(Column storeColumn) {
877         return ndbRecordValues.getDecimal(valueBuffer, storeColumn);
878     }
879 
beginDefinition()880     public void beginDefinition() {
881         // by default, nothing to do
882     }
883 
endDefinition()884     public void endDefinition() {
885         // by default, nothing to do
886     }
887 
freeResourcesAfterExecute()888     public void freeResourcesAfterExecute() {
889         // by default, nothing to do
890     }
891 
dumpValues()892     public String dumpValues() {
893         return ndbRecordValues.dumpValues(valueBuffer, mask);
894     }
895 
dumpKeys()896     public String dumpKeys() {
897         return ndbRecordKeys.dumpValues(keyBuffer, null);
898     }
899 
isModified(int columnId)900     public boolean isModified(int columnId) {
901         return ndbRecordValues.isPresent(mask, columnId);
902     }
903 
isNull(int columnId)904     public boolean isNull(int columnId) {
905         return ndbRecordValues.isNull(valueBuffer, columnId);
906     }
907 
markModified(int columnId)908     public void markModified(int columnId) {
909         ndbRecordValues.markPresent(mask, columnId);
910     }
911 
resetModified()912     public void resetModified() {
913         this.mask = new byte[1 + (numberOfColumns/8)];
914     }
915 
getBlobHandle(int columnId)916     public NdbRecordBlobImpl getBlobHandle(int columnId) {
917         return (NdbRecordBlobImpl) getBlobHandle(storeColumns[columnId]);
918     }
919 
getErrorCode()920     public int getErrorCode() {
921         return ndbOperation.getNdbError().code();
922     }
923 
getClassification()924     public int getClassification() {
925         return ndbOperation.getNdbError().classification();
926     }
927 
getMysqlCode()928     public int getMysqlCode() {
929         return ndbOperation.getNdbError().mysql_code();
930     }
931 
getStatus()932     public int getStatus() {
933         return ndbOperation.getNdbError().status();
934     }
935 
936     @Override
toString()937     public String toString() {
938         return " NdbRecordOperationImpl for table " + tableName;
939     }
940 
941     /** After executing the operation, fetch the blob values into each blob's data holder.
942      *
943      */
loadBlobValues()944     public void loadBlobValues() {
945         for (NdbRecordBlobImpl ndbRecordBlobImpl: activeBlobs) {
946             ndbRecordBlobImpl.readData();
947         }
948     }
949 
950     /** Transform this NdbRecordOperationImpl into one that can be used to back a SmartValueHandler.
951      * For instances that are used in primary key or unique key operations, the same instance is used.
952      * Scans are handled by a subclass that overrides this method.
953      *
954      * @return this NdbRecordOperationImpl
955      */
transformNdbRecordOperationImpl()956     public NdbRecordOperationImpl transformNdbRecordOperationImpl() {
957         this.keyBuffer = valueBuffer;
958         resetModified();
959         return this;
960     }
961 
962     /** Check the NdbRecord buffer guard */
checkGuard(String where)963     protected void checkGuard(String where) {
964         if (ndbRecordValues != null) {
965             ndbRecordValues.checkGuard(this.valueBuffer, where);
966         }
967     }
968 
969 }
970