Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -830,6 +830,14 @@ default String timestampTypeName() {
return "TIMESTAMP";
}

/**
* The type of a binary column of {@code size} bytes, any length when empty. {@code VARBINARY} by default; Derby
* has none and writes {@code VARCHAR (n) FOR BIT DATA}, or a {@code BLOB} beyond its limit.
*/
default String binaryTypeName(OptionalInt size) {
return "VARBINARY";
}

/**
* How this dialect spells a 64-bit integer column.
*
Expand Down Expand Up @@ -976,7 +984,7 @@ private String defaultTypeName(ColumnMetaData meta) {
case CHAR -> size.isPresent() ? "CHAR(" + size.getAsInt() + ")" : "CHAR(1)";
case VARCHAR, LONGVARCHAR, NVARCHAR, LONGNVARCHAR, NCHAR ->
size.isPresent() ? "VARCHAR(" + size.getAsInt() + ")" : "VARCHAR(255)";
case BINARY, VARBINARY, LONGVARBINARY, BLOB -> "VARBINARY";
case BINARY, VARBINARY, LONGVARBINARY, BLOB -> binaryTypeName(size);
case CLOB, NCLOB -> "CLOB";
case null, default -> "VARCHAR(255)";
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ public StringBuilder generateKnownFunction(org.eclipse.daanse.sql.dialect.api.ge
case YEAR, MONTH, DAY, HOUR, MINUTE, SECOND -> arguments.size() == 1
? new StringBuilder(function.name()).append("(").append(arguments.get(0)).append(")")
: super.generateKnownFunction(function, arguments);
// Derby casts no number to VARCHAR ("Cannot convert types 'INTEGER' to 'VARCHAR'"), but to CHAR, which it pads
case TO_TEXT -> arguments.size() == 1
? new StringBuilder("TRIM(CAST(").append(arguments.get(0)).append(" AS CHAR(254)))")
: super.generateKnownFunction(function, arguments);
default -> super.generateKnownFunction(function, arguments);
};
}
Expand Down Expand Up @@ -174,6 +178,16 @@ public boolean supportsDropTableIfExists() {
return false;
}

/** Derby's longest {@code VARCHAR FOR BIT DATA}; a binary column without a length or beyond it is a BLOB. */
private static final int MAX_BIT_DATA = 32_672;

/** Derby has no {@code VARBINARY}: its variable binary is {@code VARCHAR (n) FOR BIT DATA}. */
@Override
public String binaryTypeName(java.util.OptionalInt size) {
return size.isPresent() && size.getAsInt() > 0 && size.getAsInt() <= MAX_BIT_DATA
? "VARCHAR (" + size.getAsInt() + ") FOR BIT DATA" : "BLOB";
}

/** Derby has no {@code IF NOT EXISTS} on {@code CREATE SCHEMA} — strip it. */
@Override
public String createSchema(String schemaName, boolean ifNotExists) {
Expand All @@ -196,6 +210,27 @@ protected void quoteDateLiteral(StringBuilder buf, Date date) {
buf.append(")");
}

@Override
protected void quoteTimestampLiteral(StringBuilder buf, String value, java.sql.Timestamp timestamp) {
// Derby accepts TIMESTAMP('1997-01-01 00:00:00.0') but not the SQL:2003 literal
buf.append("TIMESTAMP(");
DialectUtil.singleQuoteString(value, buf);
buf.append(")");
}

@Override
public void quoteTimeLiteral(StringBuilder buf, String value) {
try {
java.sql.Time.valueOf(value);
} catch (IllegalArgumentException ex) {
throw new NumberFormatException("Illegal TIME literal: " + value);
}
// Derby accepts TIME('12:30:00') but not the SQL:2003 literal
buf.append("TIME(");
DialectUtil.singleQuoteString(value, buf);
buf.append(")");
}

@Override
public boolean requiresAliasForFromQuery() {
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,22 @@

class DerbyDialectTest {

/** Derby casts a number to text only through CHAR. */
@Test
void aNumberAsTextGoesThroughChar() {
assertEquals("TRIM(CAST(x AS CHAR(254)))", new DerbyDialect().generateKnownFunction(
org.eclipse.daanse.sql.dialect.api.generator.KnownFunction.TO_TEXT, java.util.List.of("x")).toString());
}

/** Derby has no VARBINARY: a binary of a length is VARCHAR FOR BIT DATA, one without a length or beyond it a BLOB. */
@Test
void aBinaryColumnIsBitDataOrABlob() {
DerbyDialect derby = new DerbyDialect();
assertEquals("VARCHAR (100) FOR BIT DATA", derby.binaryTypeName(java.util.OptionalInt.of(100)));
assertEquals("BLOB", derby.binaryTypeName(java.util.OptionalInt.empty()));
assertEquals("BLOB", derby.binaryTypeName(java.util.OptionalInt.of(100_000)));
}

/** Derby sums an INTEGER column as an INTEGER: the engine widens the operand to BIGINT. */
@Test
void aSumKeepsTheTypeOfItsOperand() {
Expand Down Expand Up @@ -63,6 +79,20 @@ void aNullOfAKnownTypeIsSpelledTyped() {
assertEquals("null", text.toString().toLowerCase(java.util.Locale.ROOT));
}

/**
* Derby has no SQL-standard time literal ("Syntax error: Encountered '1997-01-01 00:00:00.0'" after TIMESTAMP): a
* time and a timestamp are written as the functions TIME and TIMESTAMP, as a date is written as DATE.
*/
@Test
void aTimeAndATimestampAreWrittenAsFunctions() {
StringBuilder timestamp = new StringBuilder();
new DerbyDialect().quoteTimestampLiteral(timestamp, "1997-01-01 00:00:00.0");
assertEquals("TIMESTAMP('1997-01-01 00:00:00.0')", timestamp.toString());
StringBuilder time = new StringBuilder();
new DerbyDialect().quoteTimeLiteral(time, "12:30:00");
assertEquals("TIME('12:30:00')", time.toString());
}

private Connection connection = mock(Connection.class);
private DatabaseMetaData metaData = mock(DatabaseMetaData.class);
private DerbyDialect dialect;
Expand Down
Loading