/* * JEF - Copyright 2009-2010 Jiyi (mr.jiyi@gmail.com) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jef.database.dialect; import java.sql.SQLException; import java.sql.Types; import java.util.Arrays; import jef.common.log.LogUtil; import jef.database.ConnectInfo; import jef.database.DbMetaData; import jef.database.dialect.handler.DerbyLimitHandler; import jef.database.dialect.handler.LimitHandler; import jef.database.jsqlparser.expression.LongValue; import jef.database.meta.DbProperty; import jef.database.meta.Feature; import jef.database.query.Func; import jef.database.query.Scientific; import jef.database.query.function.EmuDateAddSubByTimesatmpadd; import jef.database.query.function.EmuDatediffByTimestampdiff; import jef.database.query.function.EmuDecodeWithDerbyCase; import jef.database.query.function.EmuDerbyCast; import jef.database.query.function.EmuDerbyUserFunction; import jef.database.query.function.EmuJDBCTimestampFunction; import jef.database.query.function.NoArgSQLFunction; import jef.database.query.function.StandardSQLFunction; import jef.database.query.function.TemplateFunction; import jef.database.query.function.VarArgsSQLFunction; import jef.database.support.RDBMS; import jef.tools.StringUtils; import jef.tools.collection.CollectionUtils; import jef.tools.string.JefStringReader; /** * Derby的dialet,用于derby的嵌入式模式 * * @author Administrator * */ public class DerbyDialect extends AbstractDialect { public DerbyDialect() { features = CollectionUtils.identityHashSet(); features.addAll(Arrays.asList( Feature.USER_AS_SCHEMA, Feature.BATCH_GENERATED_KEY_ONLY_LAST, Feature.ONE_COLUMN_IN_SINGLE_DDL, Feature.SUPPORT_CONCAT, Feature.COLUMN_ALTERATION_SYNTAX, Feature.CASE_WITHOUT_SWITCH, Feature.NOT_FETCH_NEXT_AUTOINCREAMENTD, Feature.UNION_WITH_BUCK )); loadKeywords("derby_keywords.properties"); setProperty(DbProperty.ADD_COLUMN, "ADD COLUMN"); setProperty(DbProperty.MODIFY_COLUMN, "ALTER"); setProperty(DbProperty.DROP_COLUMN, "DROP COLUMN"); setProperty(DbProperty.CHECK_SQL, "values 1"); setProperty(DbProperty.SELECT_EXPRESSION, "values %s"); setProperty(DbProperty.WRAP_FOR_KEYWORD, "\"\""); setProperty(DbProperty.GET_IDENTITY_FUNCTION, "IDENTITY_VAL_LOCAL()"); registerNative(Func.abs,"absval"); registerNative(Func.mod); registerNative(Func.coalesce); registerNative(Func.locate); registerNative(Func.ceil, "ceiling"); registerNative(Func.floor); registerNative(Func.round); registerNative(Func.nullif); registerNative(Func.length); registerAlias(Func.lengthb, "length");//FIXME length is a function to get unicode char length, not byte length. registerNative(Func.cast, new EmuDerbyCast()); registerAlias(Func.nvl, "coalesce"); registerCompatible(Func.str, new TemplateFunction("str", "rtrim(char(%s))")); registerNative(Scientific.cot);// 三角余切 registerNative(Scientific.exp); registerNative(Scientific.ln,"log"); registerNative(Scientific.log10); registerNative(Scientific.radians); registerNative(Scientific.degrees); registerNative(new NoArgSQLFunction("random")); registerAlias( Scientific.rand, "random"); registerNative(Scientific.soundex); registerNative(new StandardSQLFunction("stddev")); registerNative(new StandardSQLFunction("variance"));// 标准方差 registerNative(new StandardSQLFunction("nullif")); registerNative(new StandardSQLFunction("monthname")); registerNative(new StandardSQLFunction("quarter")); //date extract functions registerNative(Func.second); registerNative(Func.minute); registerNative(Func.hour); registerNative(Func.day); registerNative(Func.month); registerNative(Func.year); registerNative(new NoArgSQLFunction("current_time", false)); registerAlias(Func.current_time,"current_time"); registerNative(new NoArgSQLFunction("current_date", false)); registerAlias(Func.current_date, "current_date"); registerNative(new NoArgSQLFunction("current_timestamp", false)); registerAlias(Func.now,"current_timestamp"); registerAlias(Func.current_timestamp,"current_timestamp"); registerAlias("sysdate","current_timestamp"); registerNative(new StandardSQLFunction("dayname")); registerNative(new StandardSQLFunction("dayofyear")); registerNative(new StandardSQLFunction("days")); //derby timestamp Compatiable functions registerCompatible(Func.adddate, new EmuDateAddSubByTimesatmpadd(Func.adddate)); registerCompatible(Func.subdate, new EmuDateAddSubByTimesatmpadd(Func.subdate)); registerCompatible(Func.datediff,new EmuDatediffByTimestampdiff()); registerCompatible(Func.timestampdiff, new EmuJDBCTimestampFunction(Func.timestampdiff,this)); registerCompatible(Func.timestampadd, new EmuJDBCTimestampFunction(Func.timestampadd,this)); registerCompatible(Func.replace, new EmuDerbyUserFunction("replace","replace")); registerCompatible(Func.lpad, new EmuDerbyUserFunction("lpad","USR_LEFTPAD")); registerCompatible(Func.rpad, new EmuDerbyUserFunction("rpad","USR_RIGHTPAD")); EmuDerbyUserFunction trunc=new EmuDerbyUserFunction("trunc","USR_TRUNC"); trunc.setPadParam(2, LongValue.L0); registerCompatible(Func.trunc, trunc); registerCompatible(Func.translate, new EmuDerbyUserFunction("translate","USR_TRANSLATE")); //cast functions registerNative(Func.date); registerNative(Func.time); registerNative(new StandardSQLFunction("timestamp")); registerNative(new StandardSQLFunction("timestamp_iso")); registerNative(new StandardSQLFunction("week")); registerNative(new StandardSQLFunction("week_iso")); registerNative(new StandardSQLFunction("double")); registerNative(new StandardSQLFunction("varchar")); registerNative(new StandardSQLFunction("real")); registerNative(new StandardSQLFunction("bigint")); registerNative(new StandardSQLFunction("char")); registerNative(new StandardSQLFunction("integer"),"int"); registerNative(new StandardSQLFunction("smallint")); registerNative(new StandardSQLFunction("digits")); registerNative(new StandardSQLFunction("chr")); //string functions registerNative(Func.upper,"ucase"); registerNative(Func.lower,"lcase"); registerNative(Func.ltrim); registerNative(Func.rtrim); registerNative(Func.trim); registerNative(new StandardSQLFunction("substr")); registerAlias(Func.substring,"substr"); registerCompatible(Func.concat,new VarArgsSQLFunction("", "||", "")); //Derby是没有concat函数的,要改写为相加 registerCompatible(Func.decode,new EmuDecodeWithDerbyCase()); registerCompatible(null,new TemplateFunction("power", "exp(%2$s * ln(%1$s))"),"power");//power(b, x) = exp(x * ln(b)) registerCompatible(Func.add_months, new TemplateFunction("add_months","{fn timestampadd(SQL_TSI_MONTH,%2$s,%1$s)}")); // Derby是从10.7版本才开始支持boolean类型的 // registerColumnType( Types.BLOB, "blob" ); // determineDriverVersion(); // if ( driverVersionMajor > 10 || ( driverVersionMajor == 10 && // driverVersionMinor >= 7 ) ) { // registerColumnType( Types.BOOLEAN, "boolean" ); // } typeNames.put(Types.BOOLEAN, "boolean", 0,"bool"); //Derby中,Float是double的同义词 typeNames.put(Types.FLOAT, "double", Types.DOUBLE); } @Override public String getDefaultSchema() { return "APP"; } public String getDriverClass(String url) { if(url!=null && url.startsWith("jdbc:derby://")){ return "org.apache.derby.jdbc.ClientDriver"; }else{ return "org.apache.derby.jdbc.EmbeddedDriver"; } } @Override public String generateUrl(String host, int port, String pathOrName) { if(StringUtils.isEmpty(host)){ return super.generateUrl(host, port, pathOrName)+";create=true"; } if(port<=0)port=1527; String result= "jdbc:derby://"+host+":"+port+"/"+pathOrName+";create=true"; return result; } public RDBMS getName() { return RDBMS.derby; } @Override public void accept(DbMetaData db) { super.accept(db); try { ensureUserFunction(this.functions.get("trunc"), db); } catch (SQLException e) { LogUtil.exception("Initlize user function error.",e); } } /** * {@inheritDoc} * Like * <ul> * <li>jdbc:derby://localhost:1527/databaseName;create=true</li> * <li>jdbc:derby:./db1;create=true</li> * <li>jdbc:derby://localhost:1527/ij_cmd_test_db</li> * </ul> */ public void parseDbInfo(ConnectInfo connectInfo) { JefStringReader reader = new JefStringReader(connectInfo.getUrl()); reader.setIgnoreChars(' ', ';'); reader.consume("jdbc:derby:"); if (reader.matchNext("//") == -1) {// 本地 String path = reader.readToken(';'); path.replace('\\', '/'); String dbname = StringUtils.substringAfterLast(path, "/"); connectInfo.setDbname(dbname); } else {// 网 reader.omitChars('/'); connectInfo.setHost(reader.readToken('/', ' ')); connectInfo.setDbname(reader.readToken(';')); } reader.close(); } private final LimitHandler limit=new DerbyLimitHandler(); @Override public LimitHandler getLimitHandler() { return limit; } }