Skip to content

Commit

Permalink
Improve Teradata support #561
Browse files Browse the repository at this point in the history
  • Loading branch information
timowest committed Nov 18, 2013
1 parent 0d8cda9 commit ae56c42
Show file tree
Hide file tree
Showing 9 changed files with 164 additions and 82 deletions.
78 changes: 41 additions & 37 deletions querydsl-sql/src/main/java/com/mysema/query/sql/SQLSerializer.java
Original file line number Diff line number Diff line change
Expand Up @@ -303,43 +303,7 @@ void serializeForQuery(QueryMetadata metadata, boolean forCountRow) {
if (!orderBy.isEmpty() && !forCountRow) {
stage = Stage.ORDER_BY;
append(templates.getOrderBy());
boolean first = true;
for (final OrderSpecifier<?> os : orderBy) {
if (!first) {
append(COMMA);
}
String order = os.getOrder() == Order.ASC ? templates.getAsc() : templates.getDesc();
if (os.getNullHandling() == OrderSpecifier.NullHandling.NullsFirst) {
if (templates.getNullsFirst() != null) {
handle(os.getTarget());
append(order);
append(templates.getNullsFirst());
} else {
append("(case when ");
handle(os.getTarget());
append(" is null then 0 else 1 end), ");
handle(os.getTarget());
append(order);
}
} else if (os.getNullHandling() == OrderSpecifier.NullHandling.NullsLast) {
if (templates.getNullsLast() != null) {
handle(os.getTarget());
append(order);
append(templates.getNullsLast());
} else {
append("(case when ");
handle(os.getTarget());
append(" is null then 1 else 0 end), ");
handle(os.getTarget());
append(order);
}

} else {
handle(os.getTarget());
append(order);
}
first = false;
}
handleOrderBy(orderBy);
if (hasFlags) {
serialize(Position.AFTER_ORDER, flags);
}
Expand All @@ -356,6 +320,46 @@ void serializeForQuery(QueryMetadata metadata, boolean forCountRow) {

}

protected void handleOrderBy(List<OrderSpecifier<?>> orderBy) {
boolean first = true;
for (final OrderSpecifier<?> os : orderBy) {
if (!first) {
append(COMMA);
}
String order = os.getOrder() == Order.ASC ? templates.getAsc() : templates.getDesc();
if (os.getNullHandling() == OrderSpecifier.NullHandling.NullsFirst) {
if (templates.getNullsFirst() != null) {
handle(os.getTarget());
append(order);
append(templates.getNullsFirst());
} else {
append("(case when ");
handle(os.getTarget());
append(" is null then 0 else 1 end), ");
handle(os.getTarget());
append(order);
}
} else if (os.getNullHandling() == OrderSpecifier.NullHandling.NullsLast) {
if (templates.getNullsLast() != null) {
handle(os.getTarget());
append(order);
append(templates.getNullsLast());
} else {
append("(case when ");
handle(os.getTarget());
append(" is null then 1 else 0 end), ");
handle(os.getTarget());
append(order);
}

} else {
handle(os.getTarget());
append(order);
}
first = false;
}
}

public void serializeForDelete(QueryMetadata metadata, RelationalPath<?> entity) {
this.entity = entity;
serialize(Position.START, metadata.getFlags());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,6 @@ protected SQLTemplates build(char escape, boolean quote) {

private String limitOffsetTemplate = "row_number > {0} and row_number <= {1}";

private String limitTemplate = "row_number <= {0}";

private String offsetTemplate = "row_number > {0}";

private String outerQueryStart = "with inner_query as \n(\n ";
Expand Down Expand Up @@ -86,8 +84,6 @@ public void serialize(QueryMetadata metadata, boolean forCountRow, SQLSerializer
context.append(outerQueryEnd);
if (mod.getLimit() == null) {
context.handle(offsetTemplate, mod.getOffset());
} else if (mod.getOffset() == null) {
context.handle(limitTemplate, mod.getLimit());
} else {
context.handle(limitOffsetTemplate, mod.getOffset(), mod.getLimit() + mod.getOffset());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@
*/
package com.mysema.query.sql;

import com.mysema.query.QueryMetadata;
import com.mysema.query.QueryModifiers;
import com.mysema.query.types.Ops;
import com.mysema.query.types.Ops.MathOps;


/**
* TeradataTemplates is a SQL dialect for Teradata
Expand All @@ -31,6 +36,14 @@ protected SQLTemplates build(char escape, boolean quote) {
};
}

private String limitOffsetStart = "\nqualify row_number() over (order by ";

private String limitTemplate = " <= {0}";

private String limitOffsetTemplate = " between {0} and {1}";

private String offsetTemplate = " > {0}";

public TeradataTemplates() {
this('\\', false);
}
Expand All @@ -41,8 +54,70 @@ public TeradataTemplates(boolean quote) {

public TeradataTemplates(char escape, boolean quote) {
super("\"", escape, quote);
setNullsFirst(null);
setNullsLast(null);
setDummyTable(null);
addClass2TypeMappings("double precision", Double.class);
addClass2TypeMappings("byteint", Byte.class);
addClass2TypeMappings("byteint", Byte.class);
addClass2TypeMappings("varchar(4000)", String.class);

add(Ops.NE, "{0} <> {1}");

// Math
add(Ops.MOD, "{0} mod {1}");
add(Ops.MathOps.LOG, "(log({0}) / log({1}))");
add(MathOps.RANDOM, "(cast(random(0, 10000) as float) / 10000.0)");

// String
add(Ops.INDEX_OF, "position({1} in {0})-1");
//add(Ops.INDEX_OF_2ARGS, // TODO
add(Ops.STRING_CAST, "cast({0} as varchar(255))");
add(Ops.STRING_LENGTH, "character_length({0})");
add(Ops.StringOps.LOCATE, "position({0} in {1})");
add(Ops.StringOps.LOCATE2, "(position({0} in substr({1}, {2})) + {2})");
add(Ops.StringOps.LEFT, "substr({0}, 1, {1})");
add(Ops.StringOps.RIGHT, "substr({0}, (character_length({0})-{1s}) + 1, {1})");
add(Ops.MATCHES, "regex_instr({0}, {1}) = 1");
// add(Ops.MATCHES_IC, "regex_instr({0}, {1}) = 1"); TODO

// Number
add(Ops.MathOps.COT, "(cos({0}) / sin({0}))");
add(Ops.MathOps.COTH, "(exp({0} * 2) + 1) / (exp({0} * 2) - 1)");

// Date / time
add(Ops.DateTimeOps.DATE, "cast({0} as date)");
add(Ops.DateTimeOps.YEAR, "extract(year from {0})");
add(Ops.DateTimeOps.MONTH, "extract(month from {0})");
add(Ops.DateTimeOps.WEEK, "extract(week from {0})");
add(Ops.DateTimeOps.DAY_OF_MONTH, "extract(day from {0})");
add(Ops.DateTimeOps.DAY_OF_WEEK, "extract(dow from {0}) + 1");
add(Ops.DateTimeOps.DAY_OF_YEAR, "extract(doy from {0})");
add(Ops.DateTimeOps.HOUR, "extract(hour from {0})");
add(Ops.DateTimeOps.MINUTE, "extract(minute from {0})");
add(Ops.DateTimeOps.SECOND, "extract(second from {0})");

add(Ops.DateTimeOps.YEAR_MONTH, "extract(year from {0}) * 100 + extract(month from {0})");
add(Ops.DateTimeOps.YEAR_WEEK, "(extract(year from {0}) * 100 + extract(week from {0}))");
}

@Override
protected void serializeModifiers(QueryMetadata metadata, SQLSerializer context) {
QueryModifiers mod = metadata.getModifiers();
context.append(limitOffsetStart);
if (!metadata.getOrderBy().isEmpty()) {
context.handleOrderBy(metadata.getOrderBy());
} else {
context.append("1");
}
context.append(")");
if (mod.getLimit() == null) {
context.handle(offsetTemplate, mod.getOffset());
} else if (mod.getOffset() == null) {
context.handle(limitTemplate, mod.getLimit());
} else {
context.handle(limitOffsetTemplate, mod.getOffset() + 1, mod.getOffset() + mod.getLimit());
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import static com.mysema.query.Target.POSTGRES;
import static com.mysema.query.Target.SQLITE;
import static com.mysema.query.Target.SQLSERVER;
import static com.mysema.query.Target.TERADATA;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

Expand All @@ -30,7 +31,7 @@
import com.mysema.query.sql.domain.QEmployee;
import com.mysema.testutil.ExcludeIn;

@ExcludeIn({CUBRID, DERBY, ORACLE, SQLSERVER, POSTGRES, SQLITE})
@ExcludeIn({CUBRID, DERBY, ORACLE, SQLSERVER, POSTGRES, SQLITE, TERADATA})
public class BeanPopulationBase extends AbstractBaseTest{

private final QEmployee e = new QEmployee("e");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -758,7 +758,7 @@ public static void initTeradata() throws SQLException, ClassNotFoundException{
// employee
dropTable(templates, "EMPLOYEE");
stmt.execute("create table EMPLOYEE (\n" +
"ID INTEGER NOT NULL " + identity + " PRIMARY KEY, \n" +
"ID INTEGER NOT NULL PRIMARY KEY, \n" +
"FIRSTNAME VARCHAR(50),\n" +
"LASTNAME VARCHAR(50),\n" +
"SALARY DOUBLE PRECISION,\n" +
Expand Down
17 changes: 9 additions & 8 deletions querydsl-sql/src/test/java/com/mysema/query/SelectBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import static com.mysema.query.Target.POSTGRES;
import static com.mysema.query.Target.SQLITE;
import static com.mysema.query.Target.SQLSERVER;
import static com.mysema.query.Target.TERADATA;
import static com.mysema.query.sql.mssql.SQLServerGrammar.rn;
import static com.mysema.query.sql.mssql.SQLServerGrammar.rowNumber;
import static com.mysema.query.sql.oracle.OracleGrammar.level;
Expand Down Expand Up @@ -194,13 +195,13 @@ public void Beans() {
}

@Test
@ExcludeIn({ORACLE, CUBRID, DERBY, SQLSERVER, SQLITE})
@ExcludeIn({ORACLE, CUBRID, DERBY, SQLSERVER, SQLITE, TERADATA})
public void Boolean_All() {
assertTrue(query().from(employee).uniqueResult(SQLExpressions.all(employee.firstname.isNotNull())));
}

@Test
@ExcludeIn({ORACLE, CUBRID, DERBY, SQLSERVER, SQLITE})
@ExcludeIn({ORACLE, CUBRID, DERBY, SQLSERVER, SQLITE, TERADATA})
public void Boolean_Any() {
assertTrue(query().from(employee).uniqueResult(SQLExpressions.any(employee.firstname.isNotNull())));
}
Expand Down Expand Up @@ -505,7 +506,7 @@ public void Date_Diff2_Oracle() {
}

@Test
@ExcludeIn({CUBRID, DERBY, H2, HSQLDB, MYSQL, SQLSERVER, SQLITE})
@ExcludeIn({CUBRID, DERBY, H2, HSQLDB, MYSQL, SQLSERVER, SQLITE, TERADATA})
public void Date_Trunc() {
DateTimeExpression<java.util.Date> expr = DateTimeExpression.currentTimestamp();

Expand Down Expand Up @@ -703,7 +704,7 @@ public void Limit() throws SQLException {
}

@Test
public void Limit_And_Offset() throws SQLException {
public void Limit_and_Offset() throws SQLException {
// limit and offset
query().from(employee)
.orderBy(employee.firstname.asc())
Expand Down Expand Up @@ -754,7 +755,7 @@ public void Limit_and_Offset_In_Oracle() throws SQLException {
}

@Test
@ExcludeIn({ORACLE, DERBY, SQLSERVER, CUBRID})
@ExcludeIn({ORACLE, DERBY, SQLSERVER, CUBRID, TERADATA})
@SkipForQuoted
public void Limit_and_Offset2() throws SQLException {
// limit
Expand Down Expand Up @@ -1119,7 +1120,7 @@ public void Random() {
}

@Test
@ExcludeIn({ORACLE, POSTGRES, SQLITE})
@ExcludeIn({ORACLE, POSTGRES, SQLITE, TERADATA})
public void Random2() {
query().uniqueResult(MathExpressions.random(10));
}
Expand Down Expand Up @@ -1182,13 +1183,13 @@ public void Select_Concat() throws SQLException {
}

@Test
@ExcludeIn({SQLITE, SQLSERVER, CUBRID})
@ExcludeIn({SQLITE, SQLSERVER, CUBRID, TERADATA})
public void Select_For_Update() {
query().from(survey).forUpdate().list(survey.id);
}

@Test
@ExcludeIn({SQLITE, SQLSERVER, CUBRID})
@ExcludeIn({SQLITE, SQLSERVER, CUBRID, TERADATA})
public void Select_For_Update_UniqueResult() {
query().from(survey).forUpdate().uniqueResult(survey.id);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import static com.mysema.query.Target.POSTGRES;
import static com.mysema.query.Target.SQLITE;
import static com.mysema.query.Target.SQLSERVER;
import static com.mysema.query.Target.TERADATA;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;

Expand Down Expand Up @@ -113,7 +114,7 @@ public void SubQuery_LeftJoin() {
}

@Test
@ExcludeIn({MYSQL, POSTGRES, DERBY, SQLSERVER})
@ExcludeIn({MYSQL, POSTGRES, DERBY, SQLSERVER, TERADATA})
public void SubQuery_Params() {
Param<String> aParam = new Param<String>(String.class, "param");
SQLSubQuery subQuery = new SQLSubQuery().from(employee).where(employee.firstname.eq(aParam));
Expand Down
22 changes: 12 additions & 10 deletions querydsl-sql/src/test/java/com/mysema/query/TypesBase.java
Original file line number Diff line number Diff line change
@@ -1,41 +1,43 @@
package com.mysema.query;

import static com.mysema.query.Target.CUBRID;
import static com.mysema.query.Target.POSTGRES;
import static com.mysema.query.Target.TERADATA;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;

import static com.mysema.query.Target.*;

import org.junit.Test;

import com.mysema.testutil.ExcludeIn;

public class TypesBase extends AbstractBaseTest {

@Test
@ExcludeIn({CUBRID, POSTGRES})
@ExcludeIn({CUBRID, POSTGRES, TERADATA})
public void DumpTypes() throws SQLException {
Connection conn = Connections.getConnection();
DatabaseMetaData md = conn.getMetaData();

// types
ResultSet rs = md.getUDTs(null, null, null, null);
try {
while (rs.next()) {
// cat, schema, name, classname, datatype, remarks, base_type
// cat, schema, name, classname, datatype, remarks, base_type
String cat = rs.getString(1);
String schema = rs.getString(2);
String name = rs.getString(3);
String classname = rs.getString(4);
String datatype = rs.getString(5);
String remarks = rs.getString(6);
String base_type = rs.getString(7);
System.out.println(name + " " + classname + " " + datatype + " " +
System.out.println(name + " " + classname + " " + datatype + " " +
remarks + " " + base_type);

// attributes
ResultSet rs2 = md.getAttributes(cat, schema, name, null);
ResultSet rs2 = md.getAttributes(cat, schema, name, null);
try {
while (rs2.next()) {
// cat, schema, name, attr_name, data_type, attr_type_name, attr_size
Expand All @@ -48,7 +50,7 @@ public void DumpTypes() throws SQLException {
String _data_type = rs2.getString(5);
String _attr_type_name = rs2.getString(6);
String _attr_size = rs2.getString(7);

System.out.println(" " + _attr_name + " " + _data_type + " " + _attr_type_name + " " + _attr_size);
}
} finally {
Expand Down
Loading

0 comments on commit ae56c42

Please sign in to comment.