1 /*
2    Copyright (c) 2009, 2011, 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 package com.mysql.clusterj.tie;
26 
27 import java.math.BigDecimal;
28 import java.math.BigInteger;
29 import java.nio.ByteBuffer;
30 import java.util.ArrayList;
31 import java.util.Arrays;
32 import java.util.List;
33 
34 import com.mysql.clusterj.core.store.Blob;
35 import com.mysql.clusterj.core.store.Column;
36 import com.mysql.clusterj.core.store.Operation;
37 import com.mysql.clusterj.core.store.ResultData;
38 import com.mysql.clusterj.core.store.Table;
39 
40 import com.mysql.clusterj.core.util.I18NHelper;
41 import com.mysql.clusterj.core.util.Logger;
42 import com.mysql.clusterj.core.util.LoggerFactoryService;
43 import com.mysql.clusterj.tie.DbImpl.BufferManager;
44 
45 import com.mysql.ndbjtie.ndbapi.NdbBlob;
46 import com.mysql.ndbjtie.ndbapi.NdbOperation;
47 
48 /**
49  *
50  */
51 class OperationImpl implements Operation {
52 
53     /** My message translator */
54     static final I18NHelper local = I18NHelper
55             .getInstance(OperationImpl.class);
56 
57     /** My logger */
58     static final Logger logger = LoggerFactoryService.getFactory()
59             .getInstance(OperationImpl.class);
60 
61     private NdbOperation ndbOperation;
62 
63     protected List<Column> storeColumns = new ArrayList<Column>();
64 
65     protected ClusterTransactionImpl clusterTransaction;
66 
67     /** The size of the receive buffer for this operation (may be zero for non-read operations) */
68     protected int bufferSize;
69 
70     /** The maximum column id for this operation (may be zero for non-read operations) */
71     protected int maximumColumnId;
72 
73     /** The offsets into the buffer for each column (may be null for non-read operations) */
74     protected int[] offsets;
75 
76     /** The lengths of fields in the buffer for each column (may be null for non-read operations) */
77     protected int[] lengths;
78 
79     /** The maximum length of any column in this operation */
80     protected int maximumColumnLength;
81 
82     protected BufferManager bufferManager;
83 
84     /** Constructor used for insert and delete operations that do not need to read data.
85      *
86      * @param operation the operation
87      * @param transaction the transaction
88      */
OperationImpl(NdbOperation operation, ClusterTransactionImpl transaction)89     public OperationImpl(NdbOperation operation, ClusterTransactionImpl transaction) {
90         this.ndbOperation = operation;
91         this.clusterTransaction = transaction;
92         this.bufferManager = clusterTransaction.getBufferManager();
93     }
94 
95     /** Constructor used for read operations. The table is used to obtain data used
96      * to lay out memory for the result.
97      * @param storeTable the table
98      * @param operation the operation
99      * @param transaction the transaction
100      */
OperationImpl(Table storeTable, NdbOperation operation, ClusterTransactionImpl transaction)101     public OperationImpl(Table storeTable, NdbOperation operation, ClusterTransactionImpl transaction) {
102         this(operation, transaction);
103         TableImpl tableImpl = (TableImpl)storeTable;
104         this.maximumColumnId = tableImpl.getMaximumColumnId();
105         this.bufferSize = tableImpl.getBufferSize();
106         this.offsets = tableImpl.getOffsets();
107         this.lengths = tableImpl.getLengths();
108         this.maximumColumnLength = tableImpl.getMaximumColumnLength();
109     }
110 
equalBigInteger(Column storeColumn, BigInteger value)111     public void equalBigInteger(Column storeColumn, BigInteger value) {
112         ByteBuffer buffer = Utility.convertValue(storeColumn, value);
113         int returnCode = ndbOperation.equal(storeColumn.getName(), buffer);
114         handleError(returnCode, ndbOperation);
115     }
116 
equalBoolean(Column storeColumn, boolean booleanValue)117     public void equalBoolean(Column storeColumn, boolean booleanValue) {
118         byte value = (booleanValue?(byte)0x01:(byte)0x00);
119         int returnCode = ndbOperation.equal(storeColumn.getName(), value);
120         handleError(returnCode, ndbOperation);
121     }
122 
equalByte(Column storeColumn, byte value)123     public void equalByte(Column storeColumn, byte value) {
124         int storeValue = Utility.convertByteValueForStorage(storeColumn, value);
125         int returnCode = ndbOperation.equal(storeColumn.getName(), storeValue);
126         handleError(returnCode, ndbOperation);
127     }
128 
equalBytes(Column storeColumn, byte[] value)129     public void equalBytes(Column storeColumn, byte[] value) {
130         if (logger.isDetailEnabled()) logger.detail("Column: " + storeColumn.getName() + " columnId: " + storeColumn.getColumnId() + " data length: " + value.length);
131         ByteBuffer buffer = Utility.convertValue(storeColumn, value);
132         int returnCode = ndbOperation.equal(storeColumn.getName(), buffer);
133         handleError(returnCode, ndbOperation);
134    }
135 
equalDecimal(Column storeColumn, BigDecimal value)136     public void equalDecimal(Column storeColumn, BigDecimal value) {
137         ByteBuffer buffer = Utility.convertValue(storeColumn, value);
138         int returnCode = ndbOperation.equal(storeColumn.getName(), buffer);
139         handleError(returnCode, ndbOperation);
140     }
141 
equalDouble(Column storeColumn, double value)142     public void equalDouble(Column storeColumn, double value) {
143         ByteBuffer buffer = Utility.convertValue(storeColumn, value);
144         int returnCode = ndbOperation.equal(storeColumn.getName(), buffer);
145         handleError(returnCode, ndbOperation);
146     }
147 
equalFloat(Column storeColumn, float value)148     public void equalFloat(Column storeColumn, float value) {
149         ByteBuffer buffer = Utility.convertValue(storeColumn, value);
150         int returnCode = ndbOperation.equal(storeColumn.getName(), buffer);
151         handleError(returnCode, ndbOperation);
152     }
153 
equalInt(Column storeColumn, int value)154     public void equalInt(Column storeColumn, int value) {
155         int returnCode = ndbOperation.equal(storeColumn.getName(), value);
156         handleError(returnCode, ndbOperation);
157     }
158 
equalShort(Column storeColumn, short value)159     public void equalShort(Column storeColumn, short value) {
160         int storeValue = Utility.convertShortValueForStorage(storeColumn, value);
161         int returnCode = ndbOperation.equal(storeColumn.getName(), storeValue);
162         handleError(returnCode, ndbOperation);
163     }
164 
equalLong(Column storeColumn, long value)165     public void equalLong(Column storeColumn, long value) {
166         long storeValue = Utility.convertLongValueForStorage(storeColumn, value);
167         int returnCode = ndbOperation.equal(storeColumn.getName(), storeValue);
168         handleError(returnCode, ndbOperation);
169     }
170 
equalString(Column storeColumn, String value)171     public void equalString(Column storeColumn, String value) {
172         ByteBuffer stringStorageBuffer = Utility.encode(value, storeColumn, bufferManager);
173         int returnCode = ndbOperation.equal(storeColumn.getName(), stringStorageBuffer);
174         bufferManager.clearStringStorageBuffer();
175         handleError(returnCode, ndbOperation);
176     }
177 
getBlob(Column storeColumn)178     public void getBlob(Column storeColumn) {
179         NdbBlob ndbBlob = ndbOperation.getBlobHandleM(storeColumn.getColumnId());
180         handleError(ndbBlob, ndbOperation);
181     }
182 
getBlobHandle(Column storeColumn)183     public Blob getBlobHandle(Column storeColumn) {
184         NdbBlob blobHandle = ndbOperation.getBlobHandleM(storeColumn.getColumnId());
185         handleError(blobHandle, ndbOperation);
186         return new BlobImpl(blobHandle);
187     }
188 
189     /** Specify the columns to be used for the operation.
190      * For now, just save the columns. When resultData is called, pass the columns
191      * to the ResultData constructor and then execute the operation.
192      *
193      */
getValue(Column storeColumn)194     public void getValue(Column storeColumn) {
195         storeColumns.add(storeColumn);
196     }
197 
postExecuteCallback(Runnable callback)198     public void postExecuteCallback(Runnable callback) {
199         clusterTransaction.postExecuteCallback(callback);
200     }
201 
202     /** Construct a new ResultData using the saved column data and then execute the operation.
203      *
204      */
resultData()205     public ResultData resultData() {
206         return resultData(true);
207     }
208 
209     /** Construct a new ResultData and if requested, execute the operation.
210      *
211      */
resultData(boolean execute)212     public ResultData resultData(boolean execute) {
213         if (logger.isDetailEnabled()) logger.detail("storeColumns: " + Arrays.toString(storeColumns.toArray()));
214         ResultDataImpl result;
215         if (execute) {
216             result = new ResultDataImpl(ndbOperation, storeColumns, maximumColumnId, bufferSize,
217                     offsets, lengths, bufferManager, false);
218             clusterTransaction.executeNoCommit(false, true);
219         } else {
220             result = new ResultDataImpl(ndbOperation, storeColumns, maximumColumnId, bufferSize,
221                     offsets, lengths, bufferManager, true);
222         }
223         return result;
224     }
225 
setBigInteger(Column storeColumn, BigInteger value)226     public void setBigInteger(Column storeColumn, BigInteger value) {
227         ByteBuffer buffer = Utility.convertValue(storeColumn, value);
228         int returnCode = ndbOperation.setValue(storeColumn.getColumnId(), buffer);
229         handleError(returnCode, ndbOperation);
230     }
231 
setBoolean(Column storeColumn, Boolean value)232     public void setBoolean(Column storeColumn, Boolean value) {
233         byte byteValue = (value?(byte)0x01:(byte)0x00);
234         setByte(storeColumn, byteValue);
235     }
236 
setByte(Column storeColumn, byte value)237     public void setByte(Column storeColumn, byte value) {
238         int storeValue = Utility.convertByteValueForStorage(storeColumn, value);
239         int returnCode = ndbOperation.setValue(storeColumn.getColumnId(), storeValue);
240         handleError(returnCode, ndbOperation);
241     }
242 
setBytes(Column storeColumn, byte[] value)243     public void setBytes(Column storeColumn, byte[] value) {
244         // TODO use the string storage buffer instead of allocating a new buffer for each value
245         ByteBuffer buffer = Utility.convertValue(storeColumn, value);
246         int returnCode = ndbOperation.setValue(storeColumn.getColumnId(), buffer);
247         handleError(returnCode, ndbOperation);
248     }
249 
setDecimal(Column storeColumn, BigDecimal value)250     public void setDecimal(Column storeColumn, BigDecimal value) {
251         ByteBuffer buffer = Utility.convertValue(storeColumn, value);
252         int returnCode = ndbOperation.setValue(storeColumn.getColumnId(), buffer);
253         handleError(returnCode, ndbOperation);
254     }
255 
setDouble(Column storeColumn, Double value)256     public void setDouble(Column storeColumn, Double value) {
257         int returnCode = ndbOperation.setValue(storeColumn.getColumnId(), value);
258         handleError(returnCode, ndbOperation);
259     }
260 
setFloat(Column storeColumn, Float value)261     public void setFloat(Column storeColumn, Float value) {
262         int returnCode = ndbOperation.setValue(storeColumn.getColumnId(), value);
263         handleError(returnCode, ndbOperation);
264     }
265 
setInt(Column storeColumn, Integer value)266     public void setInt(Column storeColumn, Integer value) {
267         int returnCode = ndbOperation.setValue(storeColumn.getColumnId(), value);
268         handleError(returnCode, ndbOperation);
269     }
270 
setLong(Column storeColumn, long value)271     public void setLong(Column storeColumn, long value) {
272         long storeValue = Utility.convertLongValueForStorage(storeColumn, value);
273         int returnCode = ndbOperation.setValue(storeColumn.getName(), storeValue);
274         handleError(returnCode, ndbOperation);
275     }
276 
setNull(Column storeColumn)277     public void setNull(Column storeColumn) {
278         int returnCode = ndbOperation.setValue(storeColumn.getColumnId(), null);
279         handleError(returnCode, ndbOperation);
280     }
281 
setShort(Column storeColumn, Short value)282     public void setShort(Column storeColumn, Short value) {
283         int storeValue = Utility.convertShortValueForStorage(storeColumn, value);
284         int returnCode = ndbOperation.setValue(storeColumn.getName(), storeValue);
285         handleError(returnCode, ndbOperation);
286     }
287 
setString(Column storeColumn, String value)288     public void setString(Column storeColumn, String value) {
289         ByteBuffer stringStorageBuffer = Utility.encode(value, storeColumn, bufferManager);
290         int returnCode = ndbOperation.setValue(storeColumn.getColumnId(), stringStorageBuffer);
291         bufferManager.clearStringStorageBuffer();
292         handleError(returnCode, ndbOperation);
293     }
294 
errorCode()295     public int errorCode() {
296         return ndbOperation.getNdbError().code();
297     }
298 
handleError(int returnCode, NdbOperation ndbOperation)299     protected void handleError(int returnCode, NdbOperation ndbOperation) {
300         if (returnCode == 0) {
301             return;
302         } else {
303             Utility.throwError(returnCode, ndbOperation.getNdbError());
304         }
305     }
306 
handleError(Object object, NdbOperation ndbOperation)307     protected static void handleError(Object object, NdbOperation ndbOperation) {
308         if (object != null) {
309             return;
310         } else {
311             Utility.throwError(null, ndbOperation.getNdbError());
312         }
313     }
314 
315 }
316