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