1 21 22 package org.apache.derby.iapi.types; 23 24 import org.apache.derby.iapi.services.io.Formatable; 25 import org.apache.derby.iapi.error.StandardException; 26 import org.apache.derby.iapi.services.loader.ClassFactory; 27 28 import org.apache.derby.catalog.TypeDescriptor; 29 import org.apache.derby.catalog.types.TypeDescriptorImpl; 30 31 import org.apache.derby.iapi.services.sanity.SanityManager; 32 33 import org.apache.derby.iapi.services.io.StoredFormatIds; 34 import org.apache.derby.iapi.services.io.FormatIdUtil; 35 import org.apache.derby.iapi.services.io.Formatable; 36 37 import org.apache.derby.iapi.error.StandardException; 38 39 import org.apache.derby.iapi.types.RowLocation; 40 41 import org.apache.derby.iapi.services.loader.ClassFactory; 42 import org.apache.derby.iapi.services.loader.ClassInspector; 43 44 45 import org.apache.derby.iapi.reference.SQLState; 46 47 import java.io.ObjectOutput ; 48 import java.io.ObjectInput ; 49 import java.io.IOException ; 50 51 import java.sql.Types ; 52 53 60 61 public final class DataTypeDescriptor implements TypeDescriptor, Formatable 62 { 63 76 77 80 89 public static DataTypeDescriptor getBuiltInDataTypeDescriptor 90 ( 91 int jdbcType 92 ) 93 { 94 return DataTypeDescriptor.getBuiltInDataTypeDescriptor(jdbcType, true); 95 } 96 public static DataTypeDescriptor getBuiltInDataTypeDescriptor 97 ( 98 int jdbcType, 99 int length 100 ) 101 { 102 return DataTypeDescriptor.getBuiltInDataTypeDescriptor(jdbcType, true, length); 103 } 104 105 116 public static DataTypeDescriptor getBuiltInDataTypeDescriptor 117 ( 118 int jdbcType, 119 boolean isNullable 120 ) 121 { 122 TypeId typeId = TypeId.getBuiltInTypeId(jdbcType); 123 if (typeId == null) 124 { 125 return null; 126 } 127 128 return new DataTypeDescriptor(typeId, isNullable); 129 } 130 141 public static DataTypeDescriptor getBuiltInDataTypeDescriptor 142 ( 143 int jdbcType, 144 boolean isNullable, 145 int maxLength 146 ) 147 { 148 TypeId typeId = TypeId.getBuiltInTypeId(jdbcType); 149 if (typeId == null) 150 { 151 return null; 152 } 153 154 return new DataTypeDescriptor(typeId, isNullable, maxLength); 155 } 156 165 public static DataTypeDescriptor getBuiltInDataTypeDescriptor 166 ( 167 String sqlTypeName 168 ) 169 { 170 return new DataTypeDescriptor(TypeId.getBuiltInTypeId(sqlTypeName), true); 171 } 172 181 public static DataTypeDescriptor getBuiltInDataTypeDescriptor 182 ( 183 String sqlTypeName, 184 int length 185 ) 186 { 187 return new DataTypeDescriptor(TypeId.getBuiltInTypeId(sqlTypeName), true, length); 188 } 189 198 public static DataTypeDescriptor getSQLDataTypeDescriptor 199 ( 200 String javaTypeName 201 ) 202 { 203 return DataTypeDescriptor.getSQLDataTypeDescriptor(javaTypeName, true); 204 } 205 206 217 public static DataTypeDescriptor getSQLDataTypeDescriptor 218 ( 219 String javaTypeName, 220 boolean isNullable 221 ) 222 { 223 TypeId typeId = TypeId.getSQLTypeForJavaType(javaTypeName); 224 if (typeId == null) 225 { 226 return null; 227 } 228 229 return new DataTypeDescriptor(typeId, isNullable); 230 } 231 232 247 public static DataTypeDescriptor getSQLDataTypeDescriptor 248 ( 249 String javaTypeName, 250 int precision, 251 int scale, 252 boolean isNullable, 253 int maximumWidth 254 ) 255 { 256 TypeId typeId = TypeId.getSQLTypeForJavaType(javaTypeName); 257 if (typeId == null) 258 { 259 return null; 260 } 261 262 return new DataTypeDescriptor(typeId, 263 precision, 264 scale, 265 isNullable, 266 maximumWidth); 267 } 268 271 272 private TypeDescriptorImpl typeDescriptor; 273 private TypeId typeId; 274 275 279 public DataTypeDescriptor() {} 280 281 291 public DataTypeDescriptor(TypeId typeId, int precision, int scale, 292 boolean isNullable, int maximumWidth) 293 { 294 this.typeId = typeId; 295 typeDescriptor = new TypeDescriptorImpl(typeId.getBaseTypeId(), 296 precision, 297 scale, 298 isNullable, 299 maximumWidth); 300 } 301 302 310 public DataTypeDescriptor(TypeId typeId, boolean isNullable, 311 int maximumWidth) 312 { 313 this.typeId = typeId; 314 typeDescriptor = new TypeDescriptorImpl(typeId.getBaseTypeId(), 315 isNullable, 316 maximumWidth); 317 } 318 319 320 public DataTypeDescriptor(TypeId typeId, boolean isNullable) { 321 322 this.typeId = typeId; 323 typeDescriptor = new TypeDescriptorImpl(typeId.getBaseTypeId(), 324 typeId.getMaximumPrecision(), 325 typeId.getMaximumScale(), 326 isNullable, 327 typeId.getMaximumMaximumWidth()); 328 } 329 public DataTypeDescriptor(DataTypeDescriptor source, boolean isNullable) 330 { 331 this.typeId = source.typeId; 332 typeDescriptor = new TypeDescriptorImpl(source.typeDescriptor, 333 source.getPrecision(), 334 source.getScale(), 335 isNullable, 336 source.getMaximumWidth()); 337 } 338 339 351 public DataTypeDescriptor(DataTypeDescriptor source, 352 int precision, 353 int scale, 354 boolean isNullable, 355 int maximumWidth) 356 { 357 this.typeId = source.typeId; 358 typeDescriptor = new TypeDescriptorImpl(source.typeDescriptor, 359 precision, 360 scale, 361 isNullable, 362 maximumWidth); 363 } 364 365 373 public DataTypeDescriptor(DataTypeDescriptor source, boolean isNullable, 374 int maximumWidth) 375 { 376 this.typeId = source.typeId; 377 typeDescriptor = new TypeDescriptorImpl(source.typeDescriptor, 378 isNullable, 379 maximumWidth); 380 } 381 382 388 public DataTypeDescriptor(TypeDescriptorImpl source, TypeId typeId) 389 { 390 typeDescriptor = source; 391 this.typeId = typeId;; 392 } 393 394 395 public DataValueDescriptor normalize(DataValueDescriptor source, 396 DataValueDescriptor cachedDest) 397 throws StandardException 398 { 399 if (SanityManager.DEBUG) { 400 if (cachedDest != null) { 401 if (!getTypeId().isUserDefinedTypeId()) { 402 String t1 = getTypeName(); 403 String t2 = cachedDest.getTypeName(); 404 if (!t1.equals(t2)) { 405 406 if (!(((t1.equals("DECIMAL") || t1.equals("NUMERIC")) 407 && (t2.equals("DECIMAL") || t2.equals("NUMERIC"))) || 408 (t1.startsWith("INT") && t2.startsWith("INT")))) 410 SanityManager.THROWASSERT( 411 "Normalization of " + t2 + " being asked to convert to " + t1); 412 } 413 } 414 } 415 } 416 417 if (source.isNull()) 418 { 419 if (!isNullable()) 420 throw StandardException.newException(SQLState.LANG_NULL_INTO_NON_NULL,""); 421 422 if (cachedDest == null) 423 cachedDest = getNull(); 424 else 425 cachedDest.setToNull(); 426 } else { 427 428 if (cachedDest == null) 429 cachedDest = getNull(); 430 431 int jdbcId = getJDBCTypeId(); 432 433 cachedDest.normalize(this, source); 434 if ((jdbcId == Types.LONGVARCHAR) || (jdbcId == Types.LONGVARBINARY)) { 437 if (source.getClass() == cachedDest.getClass()) 439 return source; 440 } 441 442 } 443 return cachedDest; 444 } 445 446 459 public DataTypeDescriptor getDominantType(DataTypeDescriptor otherDTS, ClassFactory cf) 460 throws StandardException 461 { 462 boolean nullable; 463 TypeId thisType; 464 TypeId otherType; 465 DataTypeDescriptor higherType = null; 466 DataTypeDescriptor lowerType = null; 467 int maximumWidth; 468 int precision = getPrecision(); 469 int scale = getScale(); 470 471 thisType = getTypeId(); 472 otherType = otherDTS.getTypeId(); 473 474 475 nullable = isNullable() || otherDTS.isNullable(); 476 477 480 maximumWidth = (getMaximumWidth() > otherDTS.getMaximumWidth()) 481 ? getMaximumWidth() : otherDTS.getMaximumWidth(); 482 483 487 if (!thisType.userType() && !otherType.userType()) 488 { 489 TypeId higherTypeId; 490 TypeId lowerTypeId; 491 if (thisType.typePrecedence() > otherType.typePrecedence()) 492 { 493 higherType = this; 494 lowerType = otherDTS; 495 higherTypeId = thisType; 496 lowerTypeId = otherType; 497 } 498 else 499 { 500 higherType = otherDTS; 501 lowerType = this; 502 higherTypeId = otherType; 503 lowerTypeId = thisType; 504 } 505 506 if (higherTypeId.isRealTypeId() && (!lowerTypeId.isRealTypeId()) && lowerTypeId.isNumericTypeId()) 509 { 510 higherType = DataTypeDescriptor.getBuiltInDataTypeDescriptor(Types.DOUBLE); 511 higherTypeId = TypeId.getBuiltInTypeId(Types.DOUBLE); 512 } 513 524 if (higherTypeId.isDecimalTypeId() && (!lowerTypeId.isStringTypeId())) 525 { 526 precision = higherTypeId.getPrecision(this, otherDTS); 527 if (precision > 31) precision = 31; scale = higherTypeId.getScale(this, otherDTS); 529 530 534 maximumWidth = (scale > 0) ? precision + 3 : precision + 1; 535 } 536 else if (thisType.typePrecedence() != otherType.typePrecedence()) 537 { 538 precision = higherType.getPrecision(); 539 scale = higherType.getScale(); 540 541 555 if (lowerTypeId.isStringTypeId()) 556 { 557 if (higherTypeId.isBitTypeId() && 558 ! (higherTypeId.isLongConcatableTypeId())) 559 { 560 if (lowerTypeId.isLongConcatableTypeId()) 561 { 562 if (maximumWidth > (Integer.MAX_VALUE / 16)) 563 maximumWidth = Integer.MAX_VALUE; 564 else 565 maximumWidth *= 16; 566 } 567 else 568 { 569 int charMaxWidth; 570 571 int fromWidth = lowerType.getMaximumWidth(); 572 if (fromWidth > (Integer.MAX_VALUE / 16)) 573 charMaxWidth = Integer.MAX_VALUE; 574 else 575 charMaxWidth = 16 * fromWidth; 576 577 maximumWidth = (maximumWidth >= charMaxWidth) ? 578 maximumWidth : charMaxWidth; 579 } 580 } 581 } 582 583 600 if (lowerTypeId.isStringTypeId() && 601 ! (lowerTypeId.isLongConcatableTypeId()) && 602 higherTypeId.isDecimalTypeId() ) 603 { 604 int charMaxWidth = lowerType.getMaximumWidth(); 605 int charPrecision; 606 607 612 if (charMaxWidth > (Integer.MAX_VALUE - 3) / 2) 613 charPrecision = Integer.MAX_VALUE - 3; 614 else 615 charPrecision = charMaxWidth * 2; 616 617 if (precision < charPrecision) 618 precision = charPrecision; 619 620 if (scale < charMaxWidth) 621 scale = charMaxWidth; 622 623 maximumWidth = precision + 3; 624 } 625 } 626 } 627 else 628 { 629 630 ClassInspector cu = cf.getClassInspector(); 631 632 TypeId thisCompType = (TypeId) thisType; 633 TypeId otherCompType = (TypeId) otherType; 634 635 if (cu.assignableTo(thisCompType.getCorrespondingJavaTypeName(), 636 otherCompType.getCorrespondingJavaTypeName())) 637 { 638 higherType = otherDTS; 639 } 640 else 641 { 642 if (SanityManager.DEBUG) 643 SanityManager.ASSERT( 644 cu.assignableTo(otherCompType.getCorrespondingJavaTypeName(), 645 thisCompType.getCorrespondingJavaTypeName()), 646 otherCompType.getCorrespondingJavaTypeName() + 647 " expected to be assignable to " + 648 thisCompType.getCorrespondingJavaTypeName()); 649 650 higherType = this; 651 } 652 precision = higherType.getPrecision(); 653 scale = higherType.getScale(); 654 } 655 656 higherType = new DataTypeDescriptor(higherType, 657 precision, scale, nullable, maximumWidth); 658 659 return higherType; 660 } 661 662 672 public boolean isExactTypeAndLengthMatch(DataTypeDescriptor otherDTS) 673 { 674 675 if (getMaximumWidth() != otherDTS.getMaximumWidth()) 676 { 677 return false; 678 } 679 if (getScale() != otherDTS.getScale()) 680 { 681 return false; 682 } 683 684 if (getPrecision() != otherDTS.getPrecision()) 685 { 686 return false; 687 } 688 689 TypeId thisType = getTypeId(); 690 TypeId otherType = otherDTS.getTypeId(); 691 692 693 if ( ! thisType.equals(otherType)) 694 { 695 return false; 696 } 697 698 return true; 699 } 700 701 704 public int getMaximumWidth() 705 { 706 return typeDescriptor.getMaximumWidth(); 707 } 708 709 712 public int getMaximumWidthInBytes() 713 { 714 return typeDescriptor.getMaximumWidthInBytes(); 715 } 716 717 722 public TypeId getTypeId() 723 { 724 return typeId; 725 } 726 727 730 public DataValueDescriptor getNull() { 731 return typeId.getNull(); 732 } 733 734 740 public String getTypeName() 741 { 742 return typeId.getSQLTypeName(); 743 } 744 745 753 public int getJDBCTypeId() 754 { 755 return typeId.getJDBCTypeId(); 756 } 757 758 764 public int getPrecision() 765 { 766 return typeDescriptor.getPrecision(); 767 } 768 769 776 public int getScale() 777 { 778 return typeDescriptor.getScale(); 779 } 780 781 788 public boolean isNullable() 789 { 790 return typeDescriptor.isNullable(); 791 } 792 793 799 public void setNullability(boolean nullable) 800 { 801 typeDescriptor.setNullability(nullable); 802 } 803 804 808 public boolean equals(Object aTypeDescriptor) 809 { 810 return typeDescriptor.equals(aTypeDescriptor); 811 } 812 813 826 public String getSQLstring() 827 { 828 return typeId.toParsableString( this ); 829 } 830 831 835 public TypeDescriptorImpl getCatalogType() 836 { 837 return typeDescriptor; 838 } 839 840 843 public double estimatedMemoryUsage() { 844 switch (typeId.getTypeFormatId()) 845 { 846 case StoredFormatIds.LONGVARBIT_TYPE_ID: 847 848 return 10000.0; 849 850 case StoredFormatIds.BIT_TYPE_ID: 851 return (double) ( ( ((float) getMaximumWidth()) / 8.0) + 0.5); 852 853 case StoredFormatIds.BOOLEAN_TYPE_ID: 854 return 4.0; 855 856 case StoredFormatIds.CHAR_TYPE_ID: 857 case StoredFormatIds.VARCHAR_TYPE_ID: 858 case StoredFormatIds.NATIONAL_CHAR_TYPE_ID: 859 case StoredFormatIds.NATIONAL_VARCHAR_TYPE_ID: 860 return (double) (2.0 * getMaximumWidth()); 861 862 case StoredFormatIds.LONGVARCHAR_TYPE_ID: 863 case StoredFormatIds.NATIONAL_LONGVARCHAR_TYPE_ID: 864 865 return 10000.0; 866 867 case StoredFormatIds.DECIMAL_TYPE_ID: 868 872 return (double) ( (getPrecision() * 0.415) + 1.5 ); 873 874 case StoredFormatIds.DOUBLE_TYPE_ID: 875 return 8.0; 876 877 case StoredFormatIds.INT_TYPE_ID: 878 return 4.0; 879 880 case StoredFormatIds.LONGINT_TYPE_ID: 881 return 8.0; 882 883 case StoredFormatIds.REAL_TYPE_ID: 884 return 4.0; 885 886 case StoredFormatIds.SMALLINT_TYPE_ID: 887 return 2.0; 888 889 case StoredFormatIds.TINYINT_TYPE_ID: 890 return 1.0; 891 892 case StoredFormatIds.REF_TYPE_ID: 893 894 return 12.0; 895 896 case StoredFormatIds.USERDEFINED_TYPE_ID_V3: 897 if (typeId.userType()) { 898 899 return 256.0; 900 } 901 case StoredFormatIds.DATE_TYPE_ID: 902 case StoredFormatIds.TIME_TYPE_ID: 903 case StoredFormatIds.TIMESTAMP_TYPE_ID: 904 return 12.0; 905 906 default: 907 return 0.0; 908 } 909 } 910 911 921 922 public static boolean isJDBCTypeEquivalent(int existingType, int jdbcTypeId) 923 { 924 if (existingType == jdbcTypeId) 926 return true; 927 928 if (DataTypeDescriptor.isNumericType(existingType)) { 930 if (DataTypeDescriptor.isNumericType(jdbcTypeId)) 931 return true; 932 933 if (DataTypeDescriptor.isCharacterType(jdbcTypeId)) 934 return true; 935 936 return false; 937 } 938 939 if (DataTypeDescriptor.isCharacterType(existingType)) { 941 942 if (DataTypeDescriptor.isCharacterType(jdbcTypeId)) 943 return true; 944 945 if (DataTypeDescriptor.isNumericType(jdbcTypeId)) 946 return true; 947 948 949 switch (jdbcTypeId) { 950 case Types.DATE: 951 case Types.TIME: 952 case Types.TIMESTAMP: 953 return true; 954 default: 955 break; 956 } 957 958 959 return false; 960 961 } 962 963 if (DataTypeDescriptor.isBinaryType(existingType)) { 965 966 if (DataTypeDescriptor.isBinaryType(jdbcTypeId)) 967 return true; 968 969 return false; 970 } 971 972 if (existingType == Types.DATE || existingType == Types.TIME) { 974 if (DataTypeDescriptor.isCharacterType(jdbcTypeId)) 975 return true; 976 977 if (jdbcTypeId == Types.TIMESTAMP) 978 return true; 979 980 return false; 981 } 982 983 if (existingType == Types.TIMESTAMP) { 985 if (DataTypeDescriptor.isCharacterType(jdbcTypeId)) 986 return true; 987 988 if (jdbcTypeId == Types.DATE) 989 return true; 990 991 return false; 992 } 993 994 if (existingType == Types.CLOB && DataTypeDescriptor.isCharacterType(jdbcTypeId)) 996 return true; 997 998 return false; 999 } 1000 1001 public static boolean isNumericType(int jdbcType) { 1002 1003 switch (jdbcType) { 1004 case Types.BIT: 1005 case org.apache.derby.iapi.reference.JDBC30Translation.SQL_TYPES_BOOLEAN: 1006 case Types.TINYINT: 1007 case Types.SMALLINT: 1008 case Types.INTEGER: 1009 case Types.BIGINT: 1010 case Types.REAL: 1011 case Types.FLOAT: 1012 case Types.DOUBLE: 1013 case Types.DECIMAL: 1014 case Types.NUMERIC: 1015 return true; 1016 default: 1017 return false; 1018 } 1019 } 1020 1021 1038 private static boolean isCharacterType(int jdbcType) { 1039 1040 switch (jdbcType) { 1041 case Types.CHAR: 1042 case Types.VARCHAR: 1043 case Types.LONGVARCHAR: 1044 return true; 1045 default: 1046 return false; 1047 } 1048 } 1049 1050 1063 private static boolean isBinaryType(int jdbcType) { 1064 switch (jdbcType) { 1065 case Types.BINARY: 1066 case Types.VARBINARY: 1067 case Types.LONGVARBINARY: 1068 return true; 1069 default: 1070 return false; 1071 } 1072 } 1073 1074 1082 public static boolean isAsciiStreamAssignable(int jdbcType) { 1083 return jdbcType == Types.CLOB || isCharacterType(jdbcType); 1084 } 1085 1086 1094 public static boolean isBinaryStreamAssignable(int jdbcType) { 1095 return jdbcType == Types.BLOB || isBinaryType(jdbcType); 1096 } 1097 1098 1106 public static boolean isCharacterStreamAssignable(int jdbcType) { 1107 return isAsciiStreamAssignable(jdbcType); 1110 } 1111 1112 public String toString() 1113 { 1114 return typeDescriptor.toString(); 1115 } 1116 1117 1119 1127 public void readExternal( ObjectInput in ) 1128 throws IOException , ClassNotFoundException 1129 { 1130 1135 typeId = (TypeId) in.readObject(); 1136 typeDescriptor = (TypeDescriptorImpl) in.readObject(); 1137 } 1138 1139 1146 public void writeExternal( ObjectOutput out ) 1147 throws IOException 1148 { 1149 out.writeObject( typeId ); 1150 out.writeObject( typeDescriptor ); 1151 } 1152 1153 1158 public int getTypeFormatId() { return StoredFormatIds.DATA_TYPE_SERVICES_IMPL_V01_ID; } 1159} 1160 1161 | Popular Tags |