1 10 11 package com.triactive.jdo.store; 12 13 import com.triactive.jdo.model.ColumnOptions; 14 import java.sql.Types ; 15 import java.util.StringTokenizer ; 16 17 18 32 33 public class Column 34 { 35 public static final int LENGTH_NOT_SET = 0; 36 public static final int FIXED_LENGTH = 1; 37 public static final int MAXIMUM_LENGTH = 2; 38 public static final int UNLIMITED_LENGTH = 3; 39 40 protected static final int LENGTH_TYPE_MASK = 3; 41 protected static final int PRIMARY_KEY_PART = 4; 42 protected static final int EXACT_PRECISION = 8; 43 protected static final int NULLABLE = 16; 44 protected static final int UNIQUE = 32; 45 46 protected final Table table; 47 protected final Class type; 48 protected final SQLIdentifier name; 49 50 protected int precision = 0; 51 protected int scale = 0; 52 protected int flags = 0; 53 54 protected TypeInfo typeInfo = null; 55 protected String constraints = null; 56 57 public Column(Table table, Class type, SQLIdentifier name) 58 { 59 this.table = table; 60 this.type = type; 61 this.name = name; 62 } 63 64 public Table getTable() 65 { 66 return table; 67 } 68 69 public StoreManager getStoreManager() 70 { 71 return table.getStoreManager(); 72 } 73 74 public SQLIdentifier getName() 75 { 76 return name; 77 } 78 79 public Class getType() 80 { 81 return type; 82 } 83 84 private void assertSQLTypeEstablished() 85 { 86 if (typeInfo == null) 87 throw new IllegalStateException ("SQL type not yet established"); 88 } 89 90 private int getSQLPrecision() 91 { 92 DatabaseAdapter dba = getStoreManager().getDatabaseAdapter(); 93 int sqlPrecision = precision; 94 95 if (getLengthType() == UNLIMITED_LENGTH) 96 { 97 int ulpv = dba.getUnlimitedLengthPrecisionValue(typeInfo); 98 99 if (ulpv > 0) 100 sqlPrecision = ulpv; 101 } 102 103 107 if (typeInfo.typeName.toLowerCase().startsWith("bit")) 108 return sqlPrecision * 8; 109 else 110 return sqlPrecision; 111 } 112 113 114 121 122 public String getSQLDefinition() 123 { 124 assertSQLTypeEstablished(); 125 126 StringBuffer def = new StringBuffer (name.toString()); 127 StringBuffer typeSpec = new StringBuffer (typeInfo.typeName); 128 129 137 if (typeInfo.createParams != null && 138 typeInfo.createParams.indexOf('(') >= 0 && 139 typeInfo.typeName.indexOf('(') < 0) 140 { 141 StringTokenizer toks = new StringTokenizer (typeInfo.createParams); 142 143 while (toks.hasMoreTokens()) 144 { 145 String tok = toks.nextToken(); 146 147 if (tok.startsWith("[") && tok.endsWith("]")) 148 { 149 153 continue; 154 } 155 156 typeSpec.append(' ').append(tok); 157 } 158 } 159 160 StringBuffer precSpec = new StringBuffer (); 161 int sqlPrecision = getSQLPrecision(); 162 163 if (sqlPrecision > 0) 164 { 165 precSpec.append(sqlPrecision); 166 167 if (scale > 0) 168 precSpec.append(",").append(scale); 169 } 170 171 175 int lParenIdx = typeSpec.toString().indexOf('('); 176 int rParenIdx = typeSpec.toString().indexOf(')', lParenIdx); 177 178 if (lParenIdx > 0 && rParenIdx > 0) 179 { 180 if (precSpec.length() > 0) 181 typeSpec.replace(lParenIdx + 1, rParenIdx, precSpec.toString()); 182 else if (rParenIdx == lParenIdx + 1) 183 throw new ColumnDefinitionException("Invalid precision, column = " + this); 184 } 185 else if (precSpec.length() > 0) 186 typeSpec.append('(').append(precSpec).append(')'); 187 188 def.append(" ").append(typeSpec); 189 190 if (!isNullable()) 191 def.append(" NOT NULL"); 192 193 if (isUnique()) 194 def.append(" UNIQUE"); 195 196 if (constraints != null) 197 def.append(' ').append(constraints); 198 199 return def.toString(); 200 } 201 202 203 213 214 public void validate(ColumnInfo ci) 215 { 216 assertSQLTypeEstablished(); 217 218 if (!typeInfo.isCompatibleWith(ci)) 219 throw new IncompatibleDataTypeException(this, typeInfo.dataType, ci.dataType); 220 221 if (table instanceof BaseTable) 222 { 223 227 int actualPrecision = ci.columnSize; 228 int actualScale = ci.decimalDigits; 229 String actualIsNullable = ci.isNullable; 230 231 int sqlPrecision = getSQLPrecision(); 232 233 if (sqlPrecision > 0 && actualPrecision > 0) 234 { 235 if (sqlPrecision != actualPrecision) 236 throw new WrongPrecisionException(this, sqlPrecision, actualPrecision); 237 } 238 239 if (scale >= 0 && actualScale >= 0) 240 { 241 if (scale != actualScale) 242 throw new WrongScaleException(this, scale, actualScale); 243 } 244 245 if (actualIsNullable.length() > 0) 246 { 247 switch (Character.toUpperCase(actualIsNullable.charAt(0))) 248 { 249 case 'Y': 250 if (!isNullable()) 251 throw new IsNullableException(this); 252 break; 253 254 case 'N': 255 if (isNullable()) 256 throw new IsNotNullableException(this); 257 break; 258 259 default: 260 break; 261 } 262 } 263 } 264 } 265 266 267 public void setOptions(ColumnOptions co) 268 { 269 String option = co.getLength(); 270 271 if (option != null) 272 { 273 try 274 { 275 if (option.toLowerCase().equals("unlimited")) 276 setUnlimitedLength(); 277 else if (option.startsWith("max")) 278 setMaximumLength(Integer.parseInt(option.substring(3).trim())); 279 else 280 setFixedLength(Integer.parseInt(option)); 281 } 282 catch (NumberFormatException e) 283 { 284 throw new ColumnDefinitionException("Invalid length option for field " + toString() + ": " + option); 285 } 286 } 287 288 option = co.getPrecision(); 289 290 if (option != null) 291 { 292 try 293 { 294 if (option.startsWith("min")) 295 setMinimumPrecision(Integer.parseInt(option.substring(3).trim())); 296 else 297 setExactPrecision(Integer.parseInt(option)); 298 } 299 catch (NumberFormatException e) 300 { 301 throw new ColumnDefinitionException("Invalid precision option for field " + toString() + ": " + option); 302 } 303 } 304 305 option = co.getScale(); 306 307 if (option != null) 308 { 309 try 310 { 311 setScale(Integer.parseInt(option)); 312 } 313 catch (NumberFormatException e) 314 { 315 throw new ColumnDefinitionException("Invalid scale option for field " + toString() + ": " + option); 316 } 317 } 318 } 319 320 public final Column setTypeInfo(TypeInfo typeInfo) 321 { 322 this.typeInfo = typeInfo; 323 return this; 324 } 325 326 public final Column setConstraints(String constraints) 327 { 328 this.constraints = constraints; 329 return this; 330 } 331 332 private void setLengthType(int type) 333 { 334 flags &= ~LENGTH_TYPE_MASK; 335 flags |= type; 336 } 337 338 public final Column setFixedLength(int length) 339 { 340 precision = length; 341 setLengthType(FIXED_LENGTH); 342 return this; 343 } 344 345 public final Column setMaximumLength(int length) 346 { 347 precision = length; 348 setLengthType(MAXIMUM_LENGTH); 349 return this; 350 } 351 352 public final Column setUnlimitedLength() 353 { 354 precision = 0; 355 setLengthType(UNLIMITED_LENGTH); 356 return this; 357 } 358 359 public final Column setPrimaryKeyPart() 360 { 361 flags |= PRIMARY_KEY_PART; 362 return this; 363 } 364 365 public final Column setExactPrecision(int precision) 366 { 367 this.precision = precision; 368 flags |= EXACT_PRECISION; 369 return this; 370 } 371 372 public final Column setMinimumPrecision(int precision) 373 { 374 this.precision = precision; 375 flags &= ~EXACT_PRECISION; 376 return this; 377 } 378 379 public final Column setScale(int scale) 380 { 381 this.scale = scale; 382 return this; 383 } 384 385 public final Column setNullable() 386 { 387 flags |= NULLABLE; 388 return this; 389 } 390 391 public final Column setUnique() 392 { 393 flags |= UNIQUE; 394 return this; 395 } 396 397 public final int getPrecision() 398 { 399 return precision; 400 } 401 402 public final int getScale() 403 { 404 return scale; 405 } 406 407 public int getLengthType() 408 { 409 return (flags & LENGTH_TYPE_MASK); 410 } 411 412 public final boolean isPrimaryKeyPart() 413 { 414 return ((flags & PRIMARY_KEY_PART) != 0); 415 } 416 417 public final boolean isExactPrecision() 418 { 419 return ((flags & EXACT_PRECISION) != 0); 420 } 421 422 public final boolean isNullable() 423 { 424 return ((flags & NULLABLE) != 0); 425 } 426 427 public final boolean isUnique() 428 { 429 return ((flags & UNIQUE) != 0); 430 } 431 432 public final void checkPrimitive() throws ColumnDefinitionException 433 { 434 if (getLengthType() != LENGTH_NOT_SET) 435 throw new ColumnDefinitionException("You cannot set a length on this data type, column = " + this); 436 437 if (scale != 0) 438 throw new ColumnDefinitionException("You cannot set a scale on this data type, column = " + this); 439 } 440 441 public final void checkInteger() throws ColumnDefinitionException 442 { 443 if (getLengthType() != LENGTH_NOT_SET) 444 throw new ColumnDefinitionException("You cannot set a length on this data type, column = " + this); 445 446 if (precision <= 0) 447 throw new ColumnDefinitionException("Invalid precision, column = " + this); 448 449 if (scale != 0) 450 throw new ColumnDefinitionException("You cannot set a scale on this data type, column = " + this); 451 } 452 453 public final void checkDecimal() throws ColumnDefinitionException 454 { 455 if (getLengthType() != LENGTH_NOT_SET) 456 throw new ColumnDefinitionException("You cannot set a length on this data type, column = " + this); 457 458 if (precision <= 0) 459 throw new ColumnDefinitionException("Invalid precision, column = " + this); 460 461 if (scale < 0) 462 throw new ColumnDefinitionException("Invalid scale, column = " + this); 463 } 464 465 public final void checkString() throws ColumnDefinitionException 466 { 467 if (getLengthType() == LENGTH_NOT_SET) 468 throw new ColumnDefinitionException("You must set a length on this data type, column = " + this); 469 470 if (precision <= 0 && getLengthType() != UNLIMITED_LENGTH) 471 throw new ColumnDefinitionException("Invalid length, column = " + this); 472 473 if (scale != 0) 474 throw new ColumnDefinitionException("You cannot set a scale on this data type, column = " + this); 475 } 476 477 public boolean equals(Object obj) 478 { 479 if (obj == this) 480 return true; 481 482 if (!(obj instanceof Column)) 483 return false; 484 485 Column col = (Column)obj; 486 487 return table.equals(col.table) && name.equals(col.name); 488 } 489 490 491 public int hashCode() 492 { 493 return table.hashCode() ^ name.hashCode(); 494 } 495 496 public String toString() 497 { 498 return table.getName() + "." + name; 499 } 500 } 501 | Popular Tags |