This is an automated email from the ASF dual-hosted git repository.
doebele pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/empire-db.git
The following commit(s) were added to refs/heads/master by this push:
new 1d3600b EMPIREDB-362 bugfix DBBeanListFactoryImpl
1d3600b is described below
commit 1d3600bb21fe7eb9b3c60d9cd4740c0c2bf66db2
Author: Rainer Döbele <[email protected]>
AuthorDate: Sun Feb 27 02:41:43 2022 +0100
EMPIREDB-362 bugfix DBBeanListFactoryImpl
---
.../empire/samples/db/advanced/HtmlGenUtil.java | 217 ++++++++++---------
.../empire-db-example-basic/config.xml | 8 +-
.../empire/db/list/DBBeanListFactoryImpl.java | 38 +++-
.../org/apache/empire/dbms/hsql/DBCommandHSql.java | 233 +++++++++++++++++++++
.../apache/empire/dbms/hsql/DBMSHandlerHSql.java | 18 +-
.../apache/empire/dbms/oracle/DBCommandOracle.java | 18 +-
6 files changed, 419 insertions(+), 113 deletions(-)
diff --git
a/empire-db-examples/empire-db-example-advanced/src/main/java/org/apache/empire/samples/db/advanced/HtmlGenUtil.java
b/empire-db-examples/empire-db-example-advanced/src/main/java/org/apache/empire/samples/db/advanced/HtmlGenUtil.java
index bdd1e1a..5ab8c61 100644
---
a/empire-db-examples/empire-db-example-advanced/src/main/java/org/apache/empire/samples/db/advanced/HtmlGenUtil.java
+++
b/empire-db-examples/empire-db-example-advanced/src/main/java/org/apache/empire/samples/db/advanced/HtmlGenUtil.java
@@ -22,6 +22,7 @@ import org.apache.empire.commons.StringUtils;
import org.apache.empire.db.DBColumn;
import org.apache.empire.db.DBDatabase;
import org.apache.empire.db.DBTable;
+import org.apache.empire.exceptions.ItemNotFoundException;
/**
* Temporary class for HTML-generation of code and SQL
@@ -46,7 +47,7 @@ public class HtmlGenUtil
"// Returns a list of Java beans (needs matching fields
constructor or setter methods) \r\n" +
"// This is just one of several options to obtain an process query
results \r\n" +
"List<QueryResult> list = context.getUtils().queryBeanList(cmd,
QueryResult.class, null);\r\n" +
- "log.info(\"queryBeanList returnes {} items\", list.size());";
+ "log.info(\"queryBeanList returned {} items\", list.size());";
public static final String codePriceUpdate = "// create command\r\n" +
"DBCommand cmd = context.createCommand()\r\n" +
@@ -74,9 +75,29 @@ public class HtmlGenUtil
"CodeGenerator app = new CodeGenerator();\r\n" +
"app.generate(dbms, conn, config);\r\n";
+ public static final Object[] codeRecordReadLiterals = new Object[] { 55,
2021, 12, "Anna", "Smith" };
+ public static final String codeRecordRead="DBRecord employee = new
DBRecord(context, db.EMPLOYEES);\r\n" +
+ "SampleDB.Employees EMP = db.EMPLOYEES;\r\n" +
+ "// read record with identity column primary key\r\n" +
+ "employee.read(55);\r\n" +
+ "// read record with multiple column primary key \r\n" +
+ "payment.read(DBRecord.key(55, 2021, 12));\r\n" +
+ "// read with constraints \r\n" +
+
"employee.read(EMP.FIRST_NAME.is(\"Anna\").and(EMP.LAST_NAME.is(\"Smith\")));\r\n"
+
+ "// read record identified by a subquery\r\n" +
+ "DBCommand sel = context.createCommand();\r\n" +
+ "sel.select(db.PAYMENTS.EMPLOYEE_ID);\r\n" +
+ "sel.where(/* some constraints */);\r\n" +
+ "employee.read(EMP.ID.is(sel));\r\n" +
+ "// read record partially with only 3 columns\r\n" +
+ "employee.read(DBRecord.key(55), PartialMode.INCLUDE,
EMP.FIRST_NAME, EMP.LAST_NAME, EMP.SALARY);\r\n";
+
public static String codeToHtml(DBDatabase db, String code, Object...
literals)
{
code = prepareHtml(code);
+ // comment
+ code = replaceFragment(code, "/*", "*/", "<span class=\"comment\">",
"</span>");
+ code = replaceFragment(code, "//", "\r\n", "<span class=\"comment\">",
"</span>");
// replace literals
for (int i=0; i<literals.length; i++)
{
@@ -85,35 +106,43 @@ public class HtmlGenUtil
literal = "\""+((String)literals[i])+"\"";
else
literal = String.valueOf(literals[i]);
- code = replaceWord(code, literal, ' ', "<span class=\"literal\">",
"</span>");
+ code = replaceWord(code, literal, false, "<span
class=\"literal\">", "</span>");
}
// null
- code = replaceWord(code, "null", ' ', "<span class=\"literal\">",
"</span>");
- code = replaceWord(code, "new", ' ', "<span class=\"new\">",
"</span>");
+ code = replaceWord(code, "null", false, "<span class=\"literal\">",
"</span>");
+ code = replaceWord(code, "new", false, "<span class=\"keyword\">",
"</span>");
+ code = replaceWord(code, ".class", true, "<span class=\"keyword\">",
"</span>");
// types
- String[] types = new String[] { "CarSalesDB", "CodeGenerator",
"CodeGenConfig", "DBMSHandlerOracle", "DBMSHandler ", "Connection ",
"DBCommand", "QueryResult", "EngineType", "int ", "long ", "String " };
+ String[] types = new String[] { "int ", "CarSalesDB", "Connection ",
"DBUtils", "DBCommand", "DBRecord", "PartialMode", "EngineType", "long ",
"String ", "List<", "QueryResult" };
for (int i=0; i<types.length; i++)
- code = replaceWord(code, types[i], ' ', "<span class=\"type\">",
"</span>");
+ code = replaceWord(code, types[i], true, "<span class=\"type\">",
"</span>");
+ // variables
+ String[] variables = new String[] { "db_XXX", "context", "cmd",
"record", "utils", "employee", "list", "result"};
+ for (int i=0; i<variables.length; i++)
+ code = replaceWord(code, variables[i], false, "<span
class=\"var\">", "</span>");
// Tables and columns
if (db!=null)
{ for (DBTable t : db.getTables())
{
- code = replaceWord(code, t.getName(), ' ', "<span
class=\"obj\">", "</span>");
+ String table = t.getName();
+ code = replaceWord(code, table, false, "<span class=\"obj\">",
"</span>");
+ code = replaceWord(code, table.substring(0,3)+"_XXX", false,
"<span class=\"obj\">", "</span>");
for (DBColumn c : t.getColumns())
{
- code = replaceWord(code, "."+c.getName(), '.', "<span
class=\"var\">", "</span>");
+ code = replaceWord(code, "."+c.getName(), true, "<span
class=\"field\">", "</span>");
}
}
}
// functions
- code = replaceFragment(code, '.', '(', false, "<span class=\"func\">",
"</span>", new char[] { 'a', 'z' });
- // literals
- return replaceComment(code, "<span class=\"comment\">", "</span>");
+ code = replaceFunction(code, '.', '(', "<span class=\"func\">",
"</span>");
+ // shorten
+ return code.replace("_XXX", "");
}
- public static String sqlToHtml(DBDatabase db, String sql, Number...
literals)
+ public static String sqlToHtml(DBDatabase db, String sql, Object...
literals)
{
sql = prepareHtml(sql);
+ sql = sql.replace("N'", "'");
/*
UPDATE t2
SET BASE_PRICE=round(t2.BASE_PRICE*105/100,0)
@@ -122,19 +151,25 @@ public class HtmlGenUtil
*/
String[] words = new String[] { "SELECT ", "UPDATE ", "INSERT ", "SET"
, "FROM ", "WHERE ", "GROUP BY ", "HAVING ", "ORDER BY", " IN ", " ON ", " AND
", " INNER JOIN ", " LEFT JOIN ", " RIGHT_JOIN " };
for (int i=0; i<words.length; i++)
- sql = replaceWord(sql, words[i], ' ', "<span class=\"word\">",
"</span>");
+ sql = replaceWord(sql, words[i], true, "<span class=\"word\">",
"</span>");
for (DBTable t : db.getTables())
- sql = replaceWord(sql, t.getAlias(), ' ', "<span
class=\"alias\">", "</span>");
+ sql = replaceWord(sql, t.getAlias(), false, "<span
class=\"alias\">", "</span>");
// functions
- String[] func = new String[] { "count", "round", "avg" };
+ String[] func = new String[] { "count(", "round(", "avg(" };
for (int i=0; i<func.length; i++)
- sql = replaceWord(sql, func[i], ' ', "<span class=\"func\">",
"</span>");
+ sql = replaceWord(sql, func[i], true, "<span class=\"func\">",
"</span>");
// finally literals
for (int i=0; i<literals.length; i++)
- sql = replaceWord(sql, literals[i].toString(), ' ', "<span
class=\"literal\">", "</span>");
- // String literals
- sql = sql.replace("N'", "'");
- return replaceFragment(sql, '\'', '\'', true, "<span
class=\"param\"><span class=\"literal\">", "</span></span>", null);
+ {
+ String literal;
+ if (literals[i] instanceof String)
+ literal = "'"+((String)literals[i])+"'";
+ else
+ literal = String.valueOf(literals[i]);
+ sql = replaceWord(sql, literal, false, "<span
class=\"param\"><span class=\"literal\">", "</span></span>");
+ }
+ // done
+ return sql;
}
/*
@@ -148,24 +183,53 @@ public class HtmlGenUtil
str = StringUtils.replace(str, "<", "<");
return StringUtils.replace(str, ">", ">");
}
+
+ public static boolean isCommentLine(String str, int i)
+ {
+ for (;i>0;i--)
+ {
+ char c = str.charAt(i);
+ if (c=='\n')
+ break;
+ if (c=='/' && str.charAt(i-1)=='/')
+ return true;
+ }
+ return false;
+ }
+
+ public static char specialChar(char c)
+ {
+ if ((c>='a' && c<='z') || (c>='A' && c<='Z'))
+ return 0;
+ return c;
+ }
- public static String replaceWord(String str, String word, char intro,
String htmlBeg, String htmlEnd)
+ public static String replaceWord(String str, String word, boolean special,
String htmlBeg, String htmlEnd)
{
+ char intro = (special ? specialChar(word.charAt(0)) : 0);
+ char extro = (special ? specialChar(word.charAt(word.length()-1)) :
0);
// not present
if (str.indexOf(word)<0)
return str;
// replace
- String wtrim = word.trim();
- if (wtrim.charAt(0)==intro)
+ String wtrim = word;
+ if (intro>0)
wtrim = wtrim.substring(1);
+ if (extro>0)
+ wtrim = wtrim.substring(0, wtrim.length()-1);
StringBuilder s = new StringBuilder();
int i = 0;
int p = 0;
while ((i=str.indexOf(word, p))>=0)
{
- if (word.charAt(0)==intro)
- i++;
- s.append(str.substring(p, i));
+ if (isCommentLine(str, i))
+ { // comment: ignore
+ i += word.length();
+ s.append(str.substring(p, i));
+ p = i;
+ continue;
+ }
+ s.append(str.substring(p, (intro>0) ? ++i : i));
s.append(htmlBeg);
s.append(wtrim);
s.append(htmlEnd);
@@ -176,7 +240,7 @@ public class HtmlGenUtil
return s.toString();
}
- public static String replaceFragment(String str, char beg, char end,
boolean include, String htmlBeg, String htmlEnd, char[] nextRange)
+ public static String replaceFunction(String str, char beg, char end,
String htmlBeg, String htmlEnd)
{
StringBuilder s = new StringBuilder();
int i = 0;
@@ -184,50 +248,49 @@ public class HtmlGenUtil
while ((i=str.indexOf(beg, p))>=0)
{
// function special
- if (nextRange!=null)
- { // check range of next char
- char next = str.charAt(i+1);
- if (next<nextRange[0] || next>nextRange[1])
- { // ignore
- s.append(str.substring(p, ++i));
- p = i;
- continue;
- }
+ int j = ++i;
+ while(true)
+ {
+ char c = str.charAt(j);
+ boolean ok = (c>='a' && c<='z') || (c>='A' && c<='Z');
+ if (!ok)
+ break;
+ j++;
}
- int n = str.indexOf('\n', i+1);
- int j = str.indexOf(end, ++i);
- if (n<j)
- { // line-break: ignore
- s.append(str.substring(p, n+1));
- p = n+1;
+ // skip whitespace
+ int k = j;
+ while (str.charAt(k)==' ')
+ k++;
+ // check end
+ if (str.charAt(k)!=end)
+ { // not found, something else
+ s.append(str.substring(p, j));
+ p = j;
continue;
}
- if (!include)
- { // remove whitespace
- while(str.charAt(j-1)==' ') j--;
- }
- int o = (include) ? 1 : 0;
- s.append(str.substring(p, i-o));
+ s.append(str.substring(p, i));
s.append(htmlBeg);
- s.append(str.substring(i-o, j+o));
+ s.append(str.substring(i, j));
s.append(htmlEnd);
// next
- p = j + o;
+ p = j;
}
s.append(str.substring(p));
return s.toString();
}
- public static String replaceComment(String str, String htmlBeg, String
htmlEnd)
+ public static String replaceFragment(String str, String beg, String end,
String htmlBeg, String htmlEnd)
{
StringBuilder s = new StringBuilder();
- String beg = "//";
- String end ="\r\n";
int i = 0;
int p = 0;
while ((i=str.indexOf(beg, p))>=0)
{
int j = str.indexOf(end, i+1);
+ if (j<0)
+ throw new ItemNotFoundException(end);
+ if (!end.equals("\r\n"))
+ j+= end.length();
s.append(str.substring(p, i));
s.append(htmlBeg);
s.append(str.substring(i, j));
@@ -238,53 +301,5 @@ public class HtmlGenUtil
s.append(str.substring(p));
return s.toString();
}
-
- /*
- public static String replaceSqlWord(String sql, String word, String
htmlBeg, String htmlEnd)
- {
- // not present
- if (sql.indexOf(word)<0)
- return sql;
- // replace
- String wtrim = word.trim();
- StringBuilder s = new StringBuilder();
- int i = 0;
- int p = 0;
- while ((i=sql.indexOf(word, p))>=0)
- {
- if (word.charAt(0)==' ')
- i++;
- s.append(sql.substring(p, i));
- s.append(htmlBeg);
- s.append(wtrim);
- s.append(htmlEnd);
- // next
- p = i + wtrim.length();
- }
- s.append(sql.substring(p));
- return s.toString();
- }
- */
-
- /*
- public static String replaceSqlStringLiteral(String sql, String htmlBeg,
String htmlEnd)
- {
- StringBuilder s = new StringBuilder();
- int i = 0;
- int p = 0;
- while ((i=sql.indexOf('\'', p))>=0)
- {
- int j = sql.indexOf('\'', ++i);
- s.append(sql.substring(p, i-1));
- s.append(htmlBeg);
- s.append(sql.substring(i-1, j+1));
- s.append(htmlEnd);
- // next
- p = j + 1;
- }
- s.append(sql.substring(p));
- return s.toString();
- }
- */
}
diff --git a/empire-db-examples/empire-db-example-basic/config.xml
b/empire-db-examples/empire-db-example-basic/config.xml
index 44955f1..3e6bfee 100644
--- a/empire-db-examples/empire-db-example-basic/config.xml
+++ b/empire-db-examples/empire-db-example-basic/config.xml
@@ -21,7 +21,7 @@
<properties>
<!-- provider name must match the property-section containing
the connection data -->
- <databaseProvider>sqlserver</databaseProvider>
+ <databaseProvider>hsqldb</databaseProvider>
</properties>
<properties-hsqldb>
@@ -133,6 +133,12 @@
</layout>
</appender>
+ <appender name="sample"
class="org.apache.log4j.ConsoleAppender">
+ <layout class="org.apache.log4j.PatternLayout">
+ <param name="ConversionPattern" value="%-5p :
*** %m *** %n"/>
+ </layout>
+ </appender>
+
<!-- log detail configuration -->
<logger name="org.apache.empire.xml" additivity="false">
<level value="info"/>
diff --git
a/empire-db/src/main/java/org/apache/empire/db/list/DBBeanListFactoryImpl.java
b/empire-db/src/main/java/org/apache/empire/db/list/DBBeanListFactoryImpl.java
index 8676cef..1724946 100644
---
a/empire-db/src/main/java/org/apache/empire/db/list/DBBeanListFactoryImpl.java
+++
b/empire-db/src/main/java/org/apache/empire/db/list/DBBeanListFactoryImpl.java
@@ -23,6 +23,7 @@ import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
+import org.apache.commons.beanutils.MethodUtils;
import org.apache.empire.commons.ClassUtils;
import org.apache.empire.commons.ObjectUtils;
import org.apache.empire.commons.StringUtils;
@@ -73,10 +74,24 @@ public class DBBeanListFactoryImpl<T> implements
DBBeanListFactory<T>
return ClassUtils.findMatchingConstructor(beanType, 0);
}
+ protected static Class<?>[] getParameterTypes(Constructor<?> constructor)
+ {
+ if (constructor==null)
+ return null;
+ Class<?>[] parameterTypes = constructor.getParameterTypes();
+ for (int i=0; i<parameterTypes.length; i++)
+ { // get wrapper for primitive types
+ if (parameterTypes[i].isPrimitive())
+ parameterTypes[i] =
MethodUtils.getPrimitiveWrapper(parameterTypes[i]);
+ }
+ return parameterTypes;
+ }
+
/*
* Members
*/
protected final Constructor<T> constructor;
+ protected final Class<?>[] parameterTypes;
protected final List<? extends DBColumnExpr> constructorParams;
protected final List<? extends DBColumnExpr> setterColumns;
@@ -89,6 +104,7 @@ public class DBBeanListFactoryImpl<T> implements
DBBeanListFactory<T>
public DBBeanListFactoryImpl(Constructor<T> constructor, List<? extends
DBColumnExpr> constructorParams, List<? extends DBColumnExpr> setterColumns)
{
this.constructor = constructor;
+ this.parameterTypes = getParameterTypes(constructor);
this.constructorParams = constructorParams;
this.setterColumns = setterColumns;
// Check constructor
@@ -122,6 +138,7 @@ public class DBBeanListFactoryImpl<T> implements
DBBeanListFactory<T>
this.setterColumns = selectColumns;
}
this.constructor = constructor;
+ this.parameterTypes = getParameterTypes(constructor);
// log
if (constructor!=null && log.isDebugEnabled())
log.debug("{}: using bean constructor with {} params",
beanType.getName(), constructor.getParameterCount());
@@ -157,6 +174,7 @@ public class DBBeanListFactoryImpl<T> implements
DBBeanListFactory<T>
}
// found one
this.constructor = constructor;
+ this.parameterTypes = getParameterTypes(constructor);
// log
if (constructor!=null && log.isDebugEnabled())
log.debug("{}: using bean constructor with {} params",
beanType.getName(), constructor.getParameterCount());
@@ -225,12 +243,26 @@ public class DBBeanListFactoryImpl<T> implements
DBBeanListFactory<T>
{
Class<Enum<?>> enumType = expr.getEnumType();
if (enumType!=null)
- params[i++] = recData.getEnum(expr, enumType);
+ params[i] = recData.getEnum(expr, enumType);
else
- params[i++] = recData.get(expr);
+ params[i] = recData.get(expr);
+ // check type
+ if (params[i]!=null)
+ { // compare types
+ Class<?> valueType = params[i].getClass();
+ if (!parameterTypes[i].isAssignableFrom(valueType))
+ { // Param type does not match
+ if (log.isDebugEnabled())
+ log.debug("{} type of param {} doesn't match:
expected \"{}\" got \"{}\"", constructor.getDeclaringClass().getName(), i,
parameterTypes[i].getName(), valueType.getName());
+ // convert
+ params[i] = ObjectUtils.convert(parameterTypes[i],
params[i]);
+ }
+ }
// log
if (log.isTraceEnabled())
- log.trace("{}: constructor param '{}' is {}",
constructor.getDeclaringClass().getName(), StringUtils.coalesce(expr.getName(),
String.valueOf(i-1)), params[i-1]);
+ log.trace("{}: constructor param '{}' is {}",
constructor.getDeclaringClass().getName(), StringUtils.coalesce(expr.getName(),
String.valueOf(i)), params[i]);
+ // next
+ i++;
}
// create item
bean = constructor.newInstance(params);
diff --git
a/empire-db/src/main/java/org/apache/empire/dbms/hsql/DBCommandHSql.java
b/empire-db/src/main/java/org/apache/empire/dbms/hsql/DBCommandHSql.java
new file mode 100644
index 0000000..97cace1
--- /dev/null
+++ b/empire-db/src/main/java/org/apache/empire/dbms/hsql/DBCommandHSql.java
@@ -0,0 +1,233 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.empire.dbms.hsql;
+
+import java.util.ArrayList;
+// Imports
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.empire.data.DataType;
+import org.apache.empire.db.DBColumn;
+import org.apache.empire.db.DBColumnExpr;
+import org.apache.empire.db.DBCommand;
+import org.apache.empire.db.DBRowSet;
+import org.apache.empire.db.expr.column.DBAliasExpr;
+import org.apache.empire.db.expr.column.DBValueExpr;
+import org.apache.empire.db.expr.compare.DBCompareColExpr;
+import org.apache.empire.db.expr.compare.DBCompareExpr;
+import org.apache.empire.db.expr.join.DBColumnJoinExpr;
+import org.apache.empire.db.expr.join.DBJoinExpr;
+import org.apache.empire.db.expr.set.DBSetExpr;
+import org.apache.empire.exceptions.ObjectNotValidException;
+
+/**
+ * This class handles the special features of an HSqlDB database.
+ */
+public class DBCommandHSql extends DBCommand
+{
+ // *Deprecated* private static final long serialVersionUID = 1L;
+
+ protected int limitRows = -1;
+ protected int skipRows = 0;
+
+ /**
+ * Constructs an HSqlDB command object.
+ */
+ public DBCommandHSql(boolean autoPrepareStmt)
+ {
+ super(autoPrepareStmt);
+ }
+
+ @Override
+ public DBCommandHSql limitRows(int limitRows)
+ {
+ // set limit
+ this.limitRows = limitRows;
+ return this;
+ }
+
+ @Override
+ public DBCommandHSql skipRows(int skipRows)
+ {
+ // set skip
+ this.skipRows = skipRows;
+ return this;
+ }
+
+ @Override
+ public void clearLimit()
+ {
+ // remove skip and limit
+ this.limitRows = -1;
+ this.skipRows = 0;
+ }
+
+ @Override
+ public void getSelect(StringBuilder buf)
+ { // call base class
+ super.getSelect(buf);
+ // add limit and offset
+ if (limitRows>=0)
+ { buf.append("\r\nLIMIT ");
+ buf.append(String.valueOf(limitRows));
+ // Offset
+ if (skipRows>0)
+ { buf.append(" OFFSET ");
+ buf.append(String.valueOf(skipRows));
+ }
+ }
+ }
+
+ /**
+ * Creates an update statement.
+ * If a join is required, this method creates a "MERGE INTO" expression
+ */
+ @Override
+ public synchronized String getUpdate()
+ {
+ // No Joins: Use Default
+ if (joins==null || set==null)
+ return super.getUpdate();
+ else
+ return getUpdateWithJoins();
+ }
+
+ protected String getUpdateWithJoins()
+ {
+ // Generate Merge expression
+ resetParamUsage();
+ StringBuilder buf = new StringBuilder("MERGE INTO ");
+ DBRowSet table = set.get(0).getTable();
+ table.addSQL(buf, CTX_FULLNAME|CTX_ALIAS);
+ // join (only one allowed yet)
+ DBColumnJoinExpr updateJoin = null;
+ for (DBJoinExpr jex : joins)
+ { // The join
+ if (!(jex instanceof DBColumnJoinExpr))
+ continue;
+ if (jex.isJoinOn(table)==false)
+ continue;
+ // found the join
+ updateJoin = (DBColumnJoinExpr)jex;
+ break;
+ }
+ if (updateJoin==null)
+ throw new ObjectNotValidException(this);
+ Set<DBColumn> joinColumns = new HashSet<DBColumn>();
+ updateJoin.addReferencedColumns(joinColumns);
+ // using
+ buf.append("\r\nUSING ");
+ DBCommand inner = this.clone();
+ inner.clearSelect();
+ inner.clearOrderBy();
+ DBRowSet outerTable = updateJoin.getOuterTable();
+ if (outerTable==null)
+ outerTable=table;
+ for (DBColumn jcol : joinColumns)
+ { // Select join columns
+ if (jcol.getRowSet().equals(outerTable)==false)
+ inner.select(jcol);
+ }
+ // find the source table
+ DBColumnExpr left = updateJoin.getLeft();
+ DBColumnExpr right = updateJoin.getRight();
+ DBRowSet source = right.getUpdateColumn().getRowSet();
+ if (source==table)
+ source = left.getUpdateColumn().getRowSet();
+ // Add set expressions
+ String sourceAliasPrefix = source.getAlias()+".";
+ List<DBSetExpr> mergeSet = new ArrayList<DBSetExpr>(set.size());
+ for (DBSetExpr sex : set)
+ { // Select set expressions
+ Object val = sex.getValue();
+ if (val instanceof DBColumnExpr)
+ {
+ DBColumnExpr expr = ((DBColumnExpr)val);
+ if (!(expr instanceof DBColumn) && !(expr instanceof
DBAliasExpr))
+ { // rename column
+ String name = "COL_"+String.valueOf(mergeSet.size());
+ expr = expr.as(name);
+ }
+ // select
+ inner.select(expr);
+ // Name
+ DBValueExpr NAME_EXPR =
getDatabase().getValueExpr(sourceAliasPrefix+expr.getName(), DataType.UNKNOWN);
+ mergeSet.add(sex.getColumn().to(NAME_EXPR));
+ }
+ else
+ { // add original
+ mergeSet.add(sex);
+ }
+ }
+ // remove join (if not necessary)
+ if (inner.hasConstraintOn(table)==false)
+ inner.removeJoinsOn(table);
+ // add SQL for inner statement
+ inner.addSQL(buf, CTX_DEFAULT);
+ // add Alias
+ buf.append(" ");
+ buf.append(source.getAlias());
+ buf.append("\r\nON (");
+ left.addSQL(buf, CTX_DEFAULT);
+ buf.append(" = ");
+ right.addSQL(buf, CTX_DEFAULT);
+ // Compare Expression
+ if (updateJoin.getWhere() != null)
+ { buf.append(" AND ");
+ updateJoin.getWhere().addSQL(buf, CTX_DEFAULT);
+ }
+ // More constraints
+ for (DBCompareExpr we : this.where)
+ {
+ if (we instanceof DBCompareColExpr)
+ { // a compare column expression
+ DBCompareColExpr cce = (DBCompareColExpr)we;
+ DBColumn ccecol = cce.getColumn().getUpdateColumn();
+ if (table.isKeyColumn(ccecol)&& !isSetColumn(ccecol))
+ {
+ buf.append(" AND ");
+ cce.addSQL(buf, CTX_DEFAULT);
+ }
+ }
+ else
+ { // just add
+ buf.append(" AND ");
+ we.addSQL(buf, CTX_DEFAULT);
+ }
+ }
+ // Set Expressions
+ buf.append(")\r\nWHEN MATCHED THEN UPDATE ");
+ buf.append("\r\nSET ");
+ addListExpr(buf, mergeSet, CTX_DEFAULT, ", ");
+ // done
+ return buf.toString();
+ }
+
+ protected boolean isSetColumn(DBColumn col)
+ {
+ for (DBSetExpr se : this.set)
+ {
+ if (se.getColumn().equals(col))
+ return true;
+ }
+ return false;
+ }
+}
diff --git
a/empire-db/src/main/java/org/apache/empire/dbms/hsql/DBMSHandlerHSql.java
b/empire-db/src/main/java/org/apache/empire/dbms/hsql/DBMSHandlerHSql.java
index b4c0825..494e3ed 100644
--- a/empire-db/src/main/java/org/apache/empire/dbms/hsql/DBMSHandlerHSql.java
+++ b/empire-db/src/main/java/org/apache/empire/dbms/hsql/DBMSHandlerHSql.java
@@ -24,6 +24,7 @@ import java.util.GregorianCalendar;
import org.apache.empire.commons.ObjectUtils;
import org.apache.empire.data.DataType;
import org.apache.empire.db.DBColumnExpr;
+import org.apache.empire.db.DBCommand;
import org.apache.empire.db.DBDDLGenerator;
import org.apache.empire.db.DBDDLGenerator.DDLActionType;
import org.apache.empire.db.DBDatabase;
@@ -72,14 +73,25 @@ public class DBMSHandlerHSql extends DBMSHandlerBase
public boolean isSupported(DBMSFeature type)
{
switch (type)
- { // return support info
- case CREATE_SCHEMA: return false;
- case SEQUENCES: return true;
+ { // return support info
+ case CREATE_SCHEMA: return false;
+ case SEQUENCES: return true;
+ case QUERY_LIMIT_ROWS: return true;
+ case QUERY_SKIP_ROWS: return true;
default:
// All other features are not supported by default
return false;
}
}
+
+ /**
+ * Override standard command
+ */
+ @Override
+ public DBCommand createCommand(boolean autoPrepareStmt)
+ {
+ return new DBCommandHSql(autoPrepareStmt);
+ }
/**
* Gets an sql phrase template for this database system.<br>
diff --git
a/empire-db/src/main/java/org/apache/empire/dbms/oracle/DBCommandOracle.java
b/empire-db/src/main/java/org/apache/empire/dbms/oracle/DBCommandOracle.java
index a8c1406..b7cf772 100644
--- a/empire-db/src/main/java/org/apache/empire/dbms/oracle/DBCommandOracle.java
+++ b/empire-db/src/main/java/org/apache/empire/dbms/oracle/DBCommandOracle.java
@@ -373,12 +373,20 @@ public class DBCommandOracle extends DBCommand
// More constraints
for (DBCompareExpr we : this.where)
{
- DBCompareColExpr cce = (DBCompareColExpr)we;
- DBColumn ccecol = cce.getColumn().getUpdateColumn();
- if (table.isKeyColumn(ccecol)&& !isSetColumn(ccecol))
- {
+ if (we instanceof DBCompareColExpr)
+ { // a compare column expression
+ DBCompareColExpr cce = (DBCompareColExpr)we;
+ DBColumn ccecol = cce.getColumn().getUpdateColumn();
+ if (table.isKeyColumn(ccecol)&& !isSetColumn(ccecol))
+ {
+ buf.append(" AND ");
+ cce.addSQL(buf, CTX_DEFAULT);
+ }
+ }
+ else
+ { // just add
buf.append(" AND ");
- cce.addSQL(buf, CTX_DEFAULT);
+ we.addSQL(buf, CTX_DEFAULT);
}
}
// Set Expressions