1 /*
2  *  Copyright (c) 2010, 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 com.mysql.ndbjtie.mysql.CharsetMap;
28 import com.mysql.ndbjtie.ndbapi.NdbDictionary.ColumnConst;
29 
30 import com.mysql.clusterj.ClusterJDatastoreException;
31 import com.mysql.clusterj.ClusterJFatalInternalException;
32 
33 import com.mysql.clusterj.ColumnType;
34 
35 import com.mysql.clusterj.core.store.Column;
36 
37 import com.mysql.clusterj.core.util.I18NHelper;
38 import com.mysql.clusterj.core.util.Logger;
39 import com.mysql.clusterj.core.util.LoggerFactoryService;
40 
41 /**
42  *
43  */
44 class ColumnImpl implements Column {
45 
46     /** My message translator */
47     static final I18NHelper local = I18NHelper
48             .getInstance(ColumnImpl.class);
49 
50     /** My logger */
51     static final Logger logger = LoggerFactoryService.getFactory()
52             .getInstance(ColumnImpl.class);
53 
54     /** The CharsetMap */
55     static final CharsetMap charsetMap = Utility.getCharsetMap();
56 
57     /** The native charset name */
58     private String nativeCharsetName;
59 
60     /** The charset name */
61     private String charsetName;
62 
63     /** The charset number */
64     private int charsetNumber = 0;
65 
66     /** The ndb column type for the column */
67     private ColumnType columnType;
68 
69     /** The prefix length for variable size columns */
70     private int prefixLength = -1;
71 
72     /** The space required for storage of data including the prefix length */
73     private int columnSpace = 0;
74 
75     /** The name of the column */
76     private String columnName;
77 
78     /** The name of the table */
79     private String tableName;
80 
81     /** The column id */
82     private int columnId;
83 
84     /** Is this column a primary key column? */
85     private boolean primaryKey;
86 
87     /** Is this column a partition key column? */
88     private boolean partitionKey;
89 
90     private int length;
91 
92     private int inlineSize;
93 
94     private int precision;
95 
96     private int scale;
97 
98     private int size;
99 
100     private boolean nullable;
101 
102     private boolean lob = false;
103 
ColumnImpl(String tableName, ColumnConst ndbColumn)104     public ColumnImpl(String tableName, ColumnConst ndbColumn) {
105         this.columnName = ndbColumn.getName();
106         this.columnId = ndbColumn.getColumnNo();
107         this.tableName = tableName;
108         int ndbType = ndbColumn.getType();
109         this.columnType = convertType(ndbType);
110         this.primaryKey = ndbColumn.getPrimaryKey();
111         this.partitionKey = ndbColumn.getPartitionKey();
112         this.nullable = ndbColumn.getNullable();
113         this.length = ndbColumn.getLength();
114         this.inlineSize = ndbColumn.getInlineSize();
115         this.precision = ndbColumn.getPrecision();
116         this.scale = ndbColumn.getScale();
117         this.size = ndbColumn.getSize();
118         logger.detail("ColumnImpl column type: " + this.columnType);
119         switch(ndbColumn.getType()) {
120             case ColumnConst.Type.Tinyint:
121             case ColumnConst.Type.Tinyunsigned:
122                 this.prefixLength = 0;
123                 this.columnSpace = 0;
124                 break;
125             case ColumnConst.Type.Smallint:
126             case ColumnConst.Type.Smallunsigned:
127                 this.prefixLength = 0;
128                 this.columnSpace = 0;
129                 break;
130             case ColumnConst.Type.Mediumint:
131             case ColumnConst.Type.Mediumunsigned:
132                 this.prefixLength = 0;
133                 this.columnSpace = 0;
134                 break;
135             case ColumnConst.Type.Int:
136             case ColumnConst.Type.Unsigned:
137                 this.prefixLength = 0;
138                 this.columnSpace = 0;
139                 break;
140             case ColumnConst.Type.Bigint:
141             case ColumnConst.Type.Bigunsigned:
142                 this.prefixLength = 0;
143                 this.columnSpace = 0;
144                 break;
145             case ColumnConst.Type.Float:
146                 this.prefixLength = 0;
147                 this.columnSpace = 0;
148                 break;
149             case ColumnConst.Type.Double:
150                 this.prefixLength = 0;
151                 this.columnSpace = 0;
152                 break;
153             case ColumnConst.Type.Olddecimal:
154             case ColumnConst.Type.Olddecimalunsigned:
155             case ColumnConst.Type.Decimal:
156             case ColumnConst.Type.Decimalunsigned:
157                 this.prefixLength = 0;
158                 this.columnSpace = alignTo4(Utility.getDecimalColumnSpace(precision, scale));
159                 break;
160             case ColumnConst.Type.Char:
161                 this.prefixLength = 0;
162                 this.columnSpace = length;
163                 this.charsetNumber = ndbColumn.getCharsetNumber();
164                 mapCharsetName();
165                 break;
166             case ColumnConst.Type.Varchar:
167                 prefixLength = 1;
168                 this.columnSpace = alignTo4(length + prefixLength);
169                 this.charsetNumber = ndbColumn.getCharsetNumber();
170                 mapCharsetName();
171                 break;
172             case ColumnConst.Type.Binary:
173                 this.prefixLength = 0;
174                 this.columnSpace = length;
175                 break;
176             case ColumnConst.Type.Varbinary:
177                 this.prefixLength = 1;
178                 this.columnSpace = alignTo4(length + prefixLength);
179                 break;
180             case ColumnConst.Type.Datetime:
181                 this.prefixLength = 0;
182                 this.columnSpace = 0;
183                 break;
184             case ColumnConst.Type.Date:
185                 this.prefixLength = 0;
186                 this.columnSpace = 0;
187                 break;
188             case ColumnConst.Type.Blob:
189                 this.prefixLength = 0;
190                 // space is reserved for a pointer to the blob header, 8 bytes for today's architecture
191                 this.columnSpace = 8; // only the blob header has space in the record
192                 this.lob = true;
193                 break;
194             case ColumnConst.Type.Text:
195                 this.prefixLength = 0;
196                 // space is reserved for a pointer to the blob header, 8 bytes for today's architecture
197                 this.columnSpace = 8; // only the blob header has space in the record
198                 this.charsetNumber = ndbColumn.getCharsetNumber();
199                 this.lob = true;
200                 mapCharsetName();
201                 break;
202             case ColumnConst.Type.Bit:
203                 this.prefixLength = 0;
204                 this.columnSpace = 0;
205                 break;
206             case ColumnConst.Type.Longvarchar:
207                 this.prefixLength = 2;
208                 this.columnSpace = alignTo4(length + prefixLength);
209                 this.charsetNumber = ndbColumn.getCharsetNumber();
210                 mapCharsetName();
211                 break;
212             case ColumnConst.Type.Longvarbinary:
213                 this.prefixLength = 2;
214                 this.columnSpace = alignTo4(length + prefixLength);
215                 break;
216             case ColumnConst.Type.Time:
217                 this.prefixLength = 0;
218                 this.columnSpace = 0;
219                 break;
220             case ColumnConst.Type.Year:
221                 this.prefixLength = 0;
222                 this.columnSpace = 4;
223                 break;
224             case ColumnConst.Type.Timestamp:
225                 this.prefixLength = 0;
226                 this.columnSpace = 0;
227                 break;
228             case 31: // Time2
229                 this.prefixLength = 0;
230                 this.columnSpace = 0;
231                 break;
232             case 32: // DateTime2
233                 this.prefixLength = 0;
234                 this.columnSpace = 0;
235                 break;
236             case 33: // Timestamp2
237                 this.prefixLength = 0;
238                 this.columnSpace = 0;
239                 break;
240             default:
241                 String message =
242                     local.message("ERR_Unknown_Column_Type",
243                     tableName, ndbColumn.getName(), ndbType);
244                 logger.warn(message);
245                 throw new ClusterJFatalInternalException(message);
246         }
247         if (logger.isDetailEnabled()) logger.detail("Column " + columnName
248                 + " columnSpace: " + columnSpace + " prefixLength: " + prefixLength
249                 + " inlineSize: " + inlineSize + " length: " + length + " size: " + size
250                 + " charsetNumber: " + charsetNumber + " charsetName: " + charsetName
251                 + " nativeCharsetNumber: " + nativeCharsetName);
252     }
253 
alignTo4(int size)254     private int alignTo4(int size) {
255         int extra = 4 - ((size % 4) % 4);
256         int result = size + extra;
257         return result;
258     }
259 
mapCharsetName()260     private void mapCharsetName() {
261         this.nativeCharsetName = charsetMap.getName(charsetNumber);
262         this.charsetName = charsetMap.getMysqlName(charsetNumber);
263         if (charsetName == null) {
264             throw new ClusterJDatastoreException(
265                     local.message("ERR_Unknown_Charset_Name",
266                     tableName, columnName, nativeCharsetName));
267         }
268     }
269 
getType()270     public ColumnType getType() {
271         return columnType;
272     }
273 
convertType(int type)274     private ColumnType convertType(int type) {
275         switch (type) {
276             case ColumnConst.Type.Bigint: return ColumnType.Bigint;
277             case ColumnConst.Type.Bigunsigned: return ColumnType.Bigunsigned;
278             case ColumnConst.Type.Binary: return ColumnType.Binary;
279             case ColumnConst.Type.Bit: return ColumnType.Bit;
280             case ColumnConst.Type.Blob: return ColumnType.Blob;
281             case ColumnConst.Type.Char: return ColumnType.Char;
282             case ColumnConst.Type.Date: return ColumnType.Date;
283             case ColumnConst.Type.Datetime: return ColumnType.Datetime;
284             case ColumnConst.Type.Decimal: return ColumnType.Decimal;
285             case ColumnConst.Type.Decimalunsigned: return ColumnType.Decimalunsigned;
286             case ColumnConst.Type.Double: return ColumnType.Double;
287             case ColumnConst.Type.Float: return ColumnType.Float;
288             case ColumnConst.Type.Int: return ColumnType.Int;
289             case ColumnConst.Type.Longvarbinary: return ColumnType.Longvarbinary;
290             case ColumnConst.Type.Longvarchar: return ColumnType.Longvarchar;
291             case ColumnConst.Type.Mediumint: return ColumnType.Mediumint;
292             case ColumnConst.Type.Mediumunsigned: return ColumnType.Mediumunsigned;
293             case ColumnConst.Type.Olddecimal: return ColumnType.Olddecimal;
294             case ColumnConst.Type.Olddecimalunsigned: return ColumnType.Olddecimalunsigned;
295             case ColumnConst.Type.Smallint: return ColumnType.Smallint;
296             case ColumnConst.Type.Smallunsigned: return ColumnType.Smallunsigned;
297             case ColumnConst.Type.Text: return ColumnType.Text;
298             case ColumnConst.Type.Time: return ColumnType.Time;
299             case ColumnConst.Type.Timestamp: return ColumnType.Timestamp;
300             case ColumnConst.Type.Tinyint: return ColumnType.Tinyint;
301             case ColumnConst.Type.Tinyunsigned: return ColumnType.Tinyunsigned;
302             case ColumnConst.Type.Undefined: return ColumnType.Undefined;
303             case ColumnConst.Type.Unsigned: return ColumnType.Unsigned;
304             case ColumnConst.Type.Varbinary: return ColumnType.Varbinary;
305             case ColumnConst.Type.Varchar: return ColumnType.Varchar;
306             case ColumnConst.Type.Year: return ColumnType.Year;
307             case 31: return ColumnType.Time2; // ColumnConst.Type.Time2:
308             case 32: return ColumnType.Datetime2; // ColumnConst.Type.Datetime2
309             case 33: return ColumnType.Timestamp2; // ColumnConst.Type.Timestamp2
310             default:
311                 String message =
312                     local.message("ERR_Unknown_Column_Type",
313                     tableName, columnName, type);
314                 logger.warn(message);
315                 throw new ClusterJFatalInternalException(message);
316         }
317     }
318 
getCharsetName()319     public String getCharsetName() {
320         return charsetName;
321     }
322 
getName()323     public String getName() {
324         return columnName;
325     }
326 
isPrimaryKey()327     public boolean isPrimaryKey() {
328         return primaryKey;
329     }
330 
isPartitionKey()331     public boolean isPartitionKey() {
332         return partitionKey;
333     }
334 
getLength()335     public int getLength() {
336         return length;
337     }
338 
getPrefixLength()339     public int getPrefixLength() {
340         if (prefixLength != -1) {
341             return prefixLength;
342         } else {
343             throw new ClusterJFatalInternalException(local.message(
344                     "ERR_Prefix_Length_Not_Defined", tableName, columnName));
345         }
346     }
347 
getSize()348     public int getSize() {
349         return size;
350     }
351 
getColumnId()352     public int getColumnId() {
353         return columnId;
354     }
355 
getColumnSpace()356     public int getColumnSpace() {
357         return columnSpace;
358     }
359 
getPrecision()360     public int getPrecision() {
361         return precision;
362     }
363 
getScale()364     public int getScale() {
365         return scale;
366     }
367 
getCharsetNumber()368     public int getCharsetNumber() {
369         return charsetNumber;
370     }
371 
decode(byte[] array)372     public String decode(byte[] array) {
373         return Utility.decode(array, charsetNumber);
374     }
375 
encode(String string)376     public byte[] encode(String string) {
377         return Utility.encode(string, charsetNumber);
378     }
379 
380     @Override
toString()381     public String toString() {
382         return columnName;
383     }
384 
getNullable()385     public boolean getNullable() {
386         return nullable;
387     }
388 
isLob()389     public boolean isLob() {
390         return lob;
391     }
392 
393 }
394