protected TInstance typeForSQLType(
     TypeId typeId,
     DataTypeDescriptor sqlType,
     int defaultCharsetId,
     int defaultCollationId,
     String schemaName,
     String tableName,
     String columnName) {
   switch (typeId.getTypeFormatId()) {
       /* No attribute types. */
     case TypeId.FormatIds.TINYINT_TYPE_ID:
       return typeForJDBCType(
           Types.TINYINT, sqlType.isNullable(), schemaName, tableName, columnName);
     case TypeId.FormatIds.SMALLINT_TYPE_ID:
       return typeForJDBCType(
           Types.SMALLINT, sqlType.isNullable(), schemaName, tableName, columnName);
     case TypeId.FormatIds.MEDIUMINT_ID:
     case TypeId.FormatIds.INT_TYPE_ID:
       return typeForJDBCType(
           Types.INTEGER, sqlType.isNullable(), schemaName, tableName, columnName);
     case TypeId.FormatIds.LONGINT_TYPE_ID:
       return typeForJDBCType(
           Types.BIGINT, sqlType.isNullable(), schemaName, tableName, columnName);
     case TypeId.FormatIds.DATE_TYPE_ID:
       return typeForJDBCType(Types.DATE, sqlType.isNullable(), schemaName, tableName, columnName);
     case TypeId.FormatIds.TIME_TYPE_ID:
       return typeForJDBCType(Types.TIME, sqlType.isNullable(), schemaName, tableName, columnName);
     case TypeId.FormatIds.TIMESTAMP_TYPE_ID:
       return typeForJDBCType(
           Types.TIMESTAMP, sqlType.isNullable(), schemaName, tableName, columnName);
     case TypeId.FormatIds.REAL_TYPE_ID:
       return typeForJDBCType(Types.REAL, sqlType.isNullable(), schemaName, tableName, columnName);
     case TypeId.FormatIds.DOUBLE_TYPE_ID:
       return typeForJDBCType(
           Types.DOUBLE, sqlType.isNullable(), schemaName, tableName, columnName);
     case TypeId.FormatIds.BLOB_TYPE_ID:
       return typeForJDBCType(
           Types.LONGVARBINARY,
           sqlType.isNullable(), // TODO: Types.BLOB
           schemaName,
           tableName,
           columnName);
       /* Width attribute types. */
     case TypeId.FormatIds.BIT_TYPE_ID:
       return typeForJDBCType(
           Types.BIT,
           sqlType.getMaximumWidth(),
           sqlType.isNullable(),
           schemaName,
           tableName,
           columnName);
     case TypeId.FormatIds.VARBIT_TYPE_ID:
       return typeForJDBCType(
           Types.VARBINARY,
           sqlType.getMaximumWidth(),
           sqlType.isNullable(),
           schemaName,
           tableName,
           columnName);
     case TypeId.FormatIds.LONGVARBIT_TYPE_ID:
       return typeForJDBCType(
           Types.LONGVARBINARY, sqlType.isNullable(), schemaName, tableName, columnName);
       /* Precision, scale attribute types. */
     case TypeId.FormatIds.DECIMAL_TYPE_ID:
       return typeForJDBCType(
           Types.DECIMAL,
           sqlType.getPrecision(),
           sqlType.getScale(),
           sqlType.isNullable(),
           schemaName,
           tableName,
           columnName);
     case TypeId.FormatIds.NUMERIC_TYPE_ID:
       return typeForJDBCType(
           Types.NUMERIC,
           sqlType.getPrecision(),
           sqlType.getScale(),
           sqlType.isNullable(),
           schemaName,
           tableName,
           columnName);
       /* String (charset, collation) attribute types. */
     case TypeId.FormatIds.CHAR_TYPE_ID:
       return typeForStringType(
           Types.CHAR,
           sqlType,
           defaultCharsetId,
           defaultCollationId,
           schemaName,
           tableName,
           columnName);
     case TypeId.FormatIds.VARCHAR_TYPE_ID:
       return typeForStringType(
           Types.VARCHAR,
           sqlType,
           defaultCharsetId,
           defaultCollationId,
           schemaName,
           tableName,
           columnName);
     case TypeId.FormatIds.LONGVARCHAR_TYPE_ID:
       return typeForStringType(
           Types.LONGVARCHAR,
           sqlType,
           defaultCharsetId,
           defaultCollationId,
           schemaName,
           tableName,
           columnName);
     case TypeId.FormatIds.CLOB_TYPE_ID:
       return typeForStringType(
           Types.LONGVARCHAR,
           sqlType, // TODO: Types.CLOB
           defaultCharsetId,
           defaultCollationId,
           schemaName,
           tableName,
           columnName);
     case TypeId.FormatIds.XML_TYPE_ID:
       return typeForStringType(
           Types.SQLXML,
           sqlType,
           defaultCharsetId,
           defaultCollationId,
           schemaName,
           tableName,
           columnName);
       /* Special case AkSQL types. */
     case TypeId.FormatIds.BOOLEAN_TYPE_ID:
       return AkBool.INSTANCE.instance(sqlType.isNullable());
     case TypeId.FormatIds.INTERVAL_DAY_SECOND_ID:
       return AkInterval.SECONDS.typeFrom(sqlType);
     case TypeId.FormatIds.INTERVAL_YEAR_MONTH_ID:
       return AkInterval.MONTHS.typeFrom(sqlType);
     case TypeId.FormatIds.ROW_MULTISET_TYPE_ID_IMPL:
       {
         TypeId.RowMultiSetTypeId rmsTypeId = (TypeId.RowMultiSetTypeId) typeId;
         String[] columnNames = rmsTypeId.getColumnNames();
         DataTypeDescriptor[] columnTypes = rmsTypeId.getColumnTypes();
         List<AkResultSet.Column> columns = new ArrayList<>(columnNames.length);
         for (int i = 0; i < columnNames.length; i++) {
           columns.add(new AkResultSet.Column(columnNames[i], typeForSQLType(columnTypes[i])));
         }
         return AkResultSet.INSTANCE.instance(columns);
       }
     case TypeId.FormatIds.GUID_TYPE_ID:
       return AkGUID.INSTANCE.instance(sqlType.isNullable());
     case TypeId.FormatIds.USERDEFINED_TYPE_ID:
       {
         String name = typeId.getSQLTypeName();
         TClass tclass = typeClassForUserDefined(name);
         return tclass.instance(sqlType.isNullable());
       }
     default:
       if (columnName != null) {
         throw new UnsupportedColumnDataTypeException(
             schemaName, tableName, columnName, sqlType.toString());
       } else {
         throw new UnsupportedDataTypeException(sqlType.toString());
       }
   }
 }
  /**
   * Creates a Value from the given object, deriving the type from the object.
   *
   * @throws java.lang.UnsupportedOperationException if the type cannot be inferred
   */
  public static Value fromObject(Object object) {
    final TInstance type;
    Value value = null;
    if (object == null) {
      value = new Value(null);
      value.putNull();
    } else if (object instanceof String) {
      String s = (String) object;
      type =
          MString.VARCHAR.instance(
              s.length(),
              StringFactory.DEFAULT_CHARSET.ordinal(),
              StringFactory.NULL_COLLATION_ID,
              false);
      value = new Value(type, s);
    } else if (object instanceof Long) {
      type = MNumeric.BIGINT.instance(false);
      value = new Value(type, (Long) object);
    } else if (object instanceof Integer) {
      type = MNumeric.INT.instance(false);
      value = new Value(type, (Integer) object);
    } else if (object instanceof Double) {
      type = MApproximateNumber.DOUBLE.instance(false);
      value = new Value(type, (Double) object);
    } else if (object instanceof Float) {
      type = MApproximateNumber.FLOAT.instance(false);
      value = new Value(type, (Float) object);
    } else if (object instanceof BigDecimalWrapper) {
      BigDecimalWrapper bdw = (BigDecimalWrapper) object;
      type = MNumeric.DECIMAL.instance(bdw.getPrecision(), bdw.getScale(), false);
      value = new Value(type);
      value.putObject(bdw);
    } else if (object instanceof BigDecimal) {
      BigDecimal bd = (BigDecimal) object;
      type =
          MNumeric.DECIMAL.instance(
              BigDecimalWrapperImpl.sqlPrecision(bd), BigDecimalWrapperImpl.sqlScale(bd), false);
      value = new Value(type);
      value.putObject(new BigDecimalWrapperImpl(bd));
    } else if (object instanceof ByteSource || object instanceof byte[]) {
      byte[] bytes;
      if (object instanceof byte[]) {
        bytes = (byte[]) object;
      } else {
        ByteSource source = (ByteSource) object;
        byte[] srcArray = source.byteArray();
        int offset = source.byteArrayOffset();
        int end = offset + source.byteArrayLength();
        bytes = Arrays.copyOfRange(srcArray, offset, end);
      }
      type = MBinary.VARBINARY.instance(bytes.length, false);
      value = new Value(type, bytes);
    } else if (object instanceof BigInteger) {
      type = MNumeric.BIGINT_UNSIGNED.instance(false);
      BigInteger bi = (BigInteger) object;
      value = new Value(type, bi.longValue());
    } else if (object instanceof Boolean) {
      type = AkBool.INSTANCE.instance(false);
      value = new Value(type, (Boolean) object);
    } else if (object instanceof Character) {
      type = MString.VARCHAR.instance(1, false);
      value = new Value(type, object.toString());
    } else if (object instanceof Short) {
      type = MNumeric.SMALLINT.instance(false);
      value = new Value(type, (Short) object);
    } else if (object instanceof Byte) {
      type = MNumeric.TINYINT.instance(false);
      value = new Value(type, (Byte) object);
    } else if (object instanceof UUID) {
      type = AkGUID.INSTANCE.instance(false);
      value = new Value(type);
      value.putObject(object);
    } else if (object instanceof BlobRef) {
      type = AkBlob.INSTANCE.instance(false);
      value = new Value(type);
      value.putObject(type);
    } else {
      throw new UnsupportedOperationException(
          "can't convert " + object + " of type " + object.getClass());
    }

    return value;
  }