package jef.database.dialect; import java.sql.SQLException; import java.util.Date; import java.util.List; import jef.codegen.EntityEnhancer; import jef.common.log.LogUtil; import jef.database.DbClient; import jef.database.NativeQuery; import jef.database.QB; import jef.database.VarObject; import jef.database.dialect.type.ColumnMappings; import jef.database.meta.TupleMetadata; import jef.database.query.Func; import jef.database.query.Query; import jef.database.query.Selects; import jef.database.support.RDBMS; import jef.database.test.DataSource; import jef.database.test.DataSourceContext; import jef.database.test.DatabaseInit; import jef.database.test.IgnoreOn; import jef.database.test.JefJUnit4DatabaseTestRunner; import jef.orm.onetable.model.Foo; import jef.script.javascript.Var; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; /** * 这个类测试各个数据库方言的兼容性 * * @author jiyi * */ @RunWith(JefJUnit4DatabaseTestRunner.class) @DataSourceContext({ @DataSource(name="oracle",url="${oracle.url}",user="${oracle.user}",password="${oracle.password}"), @DataSource(name = "mysql", url = "${mysql.url}", user = "${mysql.user}", password = "${mysql.password}"), @DataSource(name="postgresql",url="${postgresql.url}",user="${postgresql.user}",password="${postgresql.password}"), @DataSource(name="derby",url="jdbc:derby:./db;create=true"), @DataSource(name = "hsqldb", url = "jdbc:hsqldb:mem:testhsqldb", user = "sa", password = ""), @DataSource(name = "sqlserver", url = "${sqlserver.url}",user="${sqlserver.user}",password="${sqlserver.password}"), @DataSource(name = "sqlite", url = "jdbc:sqlite:test.db?date_string_format=yyyy-MM-dd HH:mm:ss")// }) public class DialectFunctionTest extends org.junit.Assert { private DbClient db; private TupleMetadata tuple; public DialectFunctionTest() { tuple = new TupleMetadata("tuple_table"); tuple.addColumn("id", new ColumnType.AutoIncrement(8)); tuple.addColumn("name", new ColumnType.Varchar(100)); tuple.addColumn("pname", new ColumnType.Varchar(100).notNull().defaultIs("N/A")); tuple.addColumn("flag", new ColumnType.Boolean().notNull().defaultIs(true)); tuple.addColumn("age", new ColumnType.Int(8)); tuple.addColumn("pid", new ColumnType.Int(8).defaultIs(0)); tuple.addColumn("percent", new ColumnType.Double(8, 4)); tuple.addColumn("photo", new ColumnType.Blob()); tuple.addColumn("DOB", new ColumnType.Date().notNull()); tuple.addColumn("DOD", new ColumnType.TimeStamp().notNull().defaultIs(Func.now)); } @DatabaseInit public void parepare() throws SQLException { db.dropTable(tuple); db.dropTable(Foo.class); db.createTable(tuple); db.createTable(Foo.class); db.getSequenceManager().clearHolders(); Foo foo = new Foo(); foo.setModified(new Date()); foo.setName("Test"); db.insert(foo); VarObject tupleObj = tuple.newInstance(); tupleObj.set("name", "tuple"); tupleObj.set("pname", "Not Parent"); tupleObj.set("DOB", new Date()); tupleObj.set("age", 100); db.insert(tupleObj, true); } @IgnoreOn(allButExcept="mysql") @Test public void testColumnAccessor() { NativeQuery<Var> query = db.createNativeQuery("select 1 as bool_column from foo", Var.class); query.setColumnAccessor("bool_column", ColumnMappings.BOOLEAN); Boolean flag = (Boolean)query.getSingleResult().get("bool_column"); Assert.assertTrue(flag); System.out.println(flag.getClass()+" "+flag); } /** * 测试NativeQuery形式 * * @throws SQLException * */ @Test public void testNativeQuery1() throws SQLException { parepare(); NativeQuery<Var> query = db.createNativeQuery("select (select name from foo f where f.id=t1.id) foo_name,t1.name,t1.flag,t1.age from" + " tuple_table t1 where pname like 'N%' and upper(name)||'A'!='A' order by t1.id", Var.class); if (db.getProfile().getName() == RDBMS.oracle || db.getProfile().getName() == RDBMS.mysql || db.getProfile().getName()==RDBMS.sqlite) {// // 对于不支持boolean类型的数据库,设置一个转换器,让其将制定(char类型)格式化成需要的类型(boolean) query.setColumnAccessor("flag", ColumnMappings.CHAR_BOOLEAN); query.setColumnAccessor("age", ColumnMappings.INT); } List<Var> result = query.getResultList(); Var var = result.get(0); assertEquals(true, var.get("flag")); assertEquals("Test", var.get("foo_name")); assertEquals(100, var.get("age")); assertEquals("tuple", var.get("name")); } @Test public void testNativeQuery2() throws SQLException { NativeQuery<Var> query = db.createNativeQuery("select (select nvl(name,'N/A') from foo f where f.id=t1.id),t1.name,t1.flag,t1.age from" + " tuple_table t1 where pname like 'N%' and upper(name)||'A'='A'", Var.class); LogUtil.show(query.getResultList()); } /** * Sqlite无法通过,因为不支持instr函数且暂无替代方案 * @throws SQLException */ @Test @IgnoreOn("sqlite") public void testNativeQuery3() throws SQLException { NativeQuery<Var> query = db.createNativeQuery("select (select locate(':',t1.name) from foo f where f.id=t1.id),t1.name,t1.flag,t1.age from" + " tuple_table t1 where pname like 'N%' and upper(name)||'A'='A'", Var.class); LogUtil.show(query.getResultList()); } @Test public void testNativeQuery4() throws SQLException { NativeQuery<Var> query = db.createNativeQuery("select concat(substr(t1.name,2,4),lcase(t1.pname)) from tuple_table t1", Var.class); LogUtil.show(query.getResultList()); } /** * replace和translate在不同数据库下的表现 * * @throws SQLException */ @Test public void testReplaceTranslate() throws SQLException { db.delete(QB.create(Foo.class)); Foo foo = new Foo(); foo.setName("abcd1234abcd"); db.insert(foo); NativeQuery<Var> query = db.createNativeQuery("select translate(name,'4321','abcd') A,replace(name,'abc','efg') B from foo t1", Var.class); Var var = query.getSingleResult(); assertEquals("abcddcbaabcd", var.get("A")); assertEquals("efgd1234efgd", var.get("B")); db.delete(foo); } /** * Oracle的decode函数,在其他三种数据库下都有不同的表现。 在PG下, case when. 在derby下, case * when。但是注意看,derby和PG的语法是不同的。 在mySQL下, if函数 * * @throws SQLException */ @Test public void testDecode() throws SQLException { Foo foo = new Foo(); foo.setName("abcd1234abcd"); db.insert(foo); db.select(foo); NativeQuery<Var> query = db.createNativeQuery("select decode(ID,1,'壹',2,'贰',3,'叁',4,'肆',5,'伍',6,'陆',7,'柒',8,'捌',9,'玖',str(ID)) as C from foo t1", Var.class); LogUtil.show(query.getResultList()); } /** * 测试add_month和str函数混用 * * @throws SQLException */ @Test public void testAdd_month() throws SQLException { // 准备数据 db.delete(QB.create(tuple));// 删除全部数据 VarObject record = tuple.newInstance(); record.set("name", "1"); record.set("pname", "test"); record.set("DOB", new Date()); record.set("DOD", new Date()); db.insert(record, null, true); // 开始 Query<VarObject> q = QB.create(tuple); Selects select = QB.selectFrom(q); select.columns("dob,dod"); select.sqlExpression("str(add_months(dob,12)) as pname"); List<VarObject> result = db.select(q); LogUtil.show(result); } /** * 测试trunc函数,这里对Trunc日期的用法不符合除了Oracle以外数据库的预期,所以不支持。 参见 * {@linkplain Func#trunc} */ @Test @IgnoreOn({ "derby", "mysql", "postgresql" ,"sqlserver"}) public void testOracleTrunc() throws SQLException { // 准备数据 db.delete(QB.create(tuple));// 删除全部数据 VarObject record = tuple.newInstance(); record.set("name", "1"); record.set("pname", "test"); record.set("DOB", new Date()); record.set("DOD", new Date()); db.insert(record, null, true); // 开始 Query<VarObject> q = QB.create(tuple); Selects select = QB.selectFrom(q); select.columns("dob,dod"); select.sqlExpression("trunc(dob) as pname"); List<VarObject> result = db.select(q); LogUtil.show(result); } /** * 对数字进行trunc,可以支持 * * @throws SQLException */ @Test public void testTrunc() throws SQLException { // 准备数据 db.delete(QB.create(tuple));// 删除全部数据 VarObject tupleObj = tuple.newInstance(); tupleObj.set("name", "tuple"); tupleObj.set("pname", "Not Parent"); tupleObj.set("DOB", new Date()); tupleObj.set("DOD", new Date()); tupleObj.set("age", 100); tupleObj.set("percent", 100.789f); db.insert(tupleObj, null, true); // 开始 Query<VarObject> q = QB.create(tuple); Selects select = QB.selectFrom(q); select.columns("dob,dod"); select.sqlExpression("trunc(percent) as pname"); List<VarObject> result = db.select(q); LogUtil.show(result); } }