This is an automated email from the ASF dual-hosted git repository.
doebele pushed a commit to branch version3
in repository https://gitbox.apache.org/repos/asf/empire-db.git
The following commit(s) were added to refs/heads/version3 by this push:
new cd505b5 EMPIREDB-362 AliasExpression handling
cd505b5 is described below
commit cd505b506427e83a87a094b9f1bab43ab440535a
Author: Rainer Döbele <[email protected]>
AuthorDate: Thu Jan 27 14:09:11 2022 +0100
EMPIREDB-362 AliasExpression handling
---
.../empire/jsf2/utils/TagEncodingHelper.java | 13 +-
.../org/apache/empire/commons/ObjectUtils.java | 47 +++----
.../org/apache/empire/commons/Unwrappable.java | 19 +++
.../java/org/apache/empire/data/ColumnExpr.java | 8 +-
.../org/apache/empire/data/bean/BeanProperty.java | 10 +-
.../java/org/apache/empire/db/DBColumnExpr.java | 12 +-
.../main/java/org/apache/empire/db/DBQuery.java | 30 ++++-
.../main/java/org/apache/empire/db/DBReader.java | 2 +-
.../main/java/org/apache/empire/db/DBRecord.java | 3 +-
.../main/java/org/apache/empire/db/DBRowSet.java | 15 ++-
.../apache/empire/db/expr/column/DBAliasExpr.java | 15 ++-
.../java/org/apache/empire/dbms/DBSqlPhrase.java | 4 +-
.../org/apache/empire/db/AliasExpressionTest.java | 147 +++++++++++++++++++++
.../test/java/org/apache/empire/db/MockDriver.java | 11 +-
14 files changed, 283 insertions(+), 53 deletions(-)
diff --git
a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/utils/TagEncodingHelper.java
b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/utils/TagEncodingHelper.java
index eb999cb..ede9cc8 100644
---
a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/utils/TagEncodingHelper.java
+++
b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/utils/TagEncodingHelper.java
@@ -149,9 +149,18 @@ public class TagEncodingHelper implements NamingContainer
}
@Override
+ public boolean isWrapper()
+ {
+ return true;
+ }
+
+ @Override
public ColumnExpr unwrap()
- {
- return expr.unwrap();
+ { // unwrap the expression
+ if (expr.isWrapper())
+ return expr.unwrap();
+ // the wrapped expression
+ return expr;
}
@Override
diff --git a/empire-db/src/main/java/org/apache/empire/commons/ObjectUtils.java
b/empire-db/src/main/java/org/apache/empire/commons/ObjectUtils.java
index 79eb745..a755f49 100644
--- a/empire-db/src/main/java/org/apache/empire/commons/ObjectUtils.java
+++ b/empire-db/src/main/java/org/apache/empire/commons/ObjectUtils.java
@@ -942,24 +942,40 @@ public final class ObjectUtils
*
* @return true if the array contains the item or false otherwise
*/
- public static <T> boolean contains(T[] array, T item)
+ @SuppressWarnings("unchecked")
+ public static <T> int indexOf(T[] array, T item)
{
if (array==null)
- return false;
+ return -1;
// 1st try (quick)
for (int i=0; i<array.length; i++)
{
if (array[i]==item)
- return true;
+ return i;
}
// 2nd try (thorough)
for (int i=0; i<array.length; i++)
{
- if (array[i]!=null && array[i].equals(item))
- return true;
+ if (array[i]==null)
+ continue; // alredy checked
+ // compare directly
+ if (array[i].equals(item))
+ return i;
+ // check wrapper
+ if ((array[i] instanceof Unwrappable) &&
((Unwrappable<?>)array[i]).isWrapper())
+ { // unwrap
+ Object unwrapped = ((Unwrappable<?>)array[i]).unwrap();
+ if (unwrapped==item || unwrapped.equals(item))
+ return i;
+ }
+ }
+ // 3rd try (unwrap)
+ if ((item instanceof Unwrappable) &&
((Unwrappable<?>)item).isWrapper())
+ { // unwrap
+ return indexOf(array, ((Unwrappable<T>)item).unwrap());
}
// not found
- return false;
+ return -1;
}
/**
@@ -971,24 +987,9 @@ public final class ObjectUtils
*
* @return true if the array contains the item or false otherwise
*/
- public static <T> int indexOf(T[] array, T item)
+ public static <T> boolean contains(T[] array, T item)
{
- if (array==null)
- return -1;
- // 1st try (quick)
- for (int i=0; i<array.length; i++)
- {
- if (array[i]==item)
- return i;
- }
- // 2nd try (thorough)
- for (int i=0; i<array.length; i++)
- {
- if (array[i]!=null && array[i].equals(item))
- return i;
- }
- // not found
- return -1;
+ return (indexOf(array, item)>=0);
}
}
diff --git a/empire-db/src/main/java/org/apache/empire/commons/Unwrappable.java
b/empire-db/src/main/java/org/apache/empire/commons/Unwrappable.java
new file mode 100644
index 0000000..6bb9610
--- /dev/null
+++ b/empire-db/src/main/java/org/apache/empire/commons/Unwrappable.java
@@ -0,0 +1,19 @@
+/*
+ * ESTEAM Software GmbH, 27.01.2022
+ */
+package org.apache.empire.commons;
+
+public interface Unwrappable<T>
+{
+ /**
+ * Returns true if the object is a wrapper for another object
+ */
+ boolean isWrapper();
+
+ /**
+ * Unwrapps am object that is wrapped by this object
+ * If the object is not a wrapper then it must return itself (this)!
+ * @return the original object
+ */
+ T unwrap();
+}
diff --git a/empire-db/src/main/java/org/apache/empire/data/ColumnExpr.java
b/empire-db/src/main/java/org/apache/empire/data/ColumnExpr.java
index e092a54..3fde592 100644
--- a/empire-db/src/main/java/org/apache/empire/data/ColumnExpr.java
+++ b/empire-db/src/main/java/org/apache/empire/data/ColumnExpr.java
@@ -19,12 +19,13 @@
package org.apache.empire.data;
import org.apache.empire.commons.Options;
+import org.apache.empire.commons.Unwrappable;
/**
* The column interface provides methods for accessing metadata that is
relevant for managing
* and displaying data available through the RecordData interface.
*/
-public interface ColumnExpr
+public interface ColumnExpr extends Unwrappable<ColumnExpr>
{
/**
* Returns the column's data type.
@@ -77,10 +78,5 @@ public interface ColumnExpr
* @return the column on which this expression is based or null if not
applicable.
*/
Column getSourceColumn();
-
- /**
- * This helper function unwraps an alias expression
- * @return the original expresion before renaming
- */
ColumnExpr unwrap();
}
diff --git
a/empire-db/src/main/java/org/apache/empire/data/bean/BeanProperty.java
b/empire-db/src/main/java/org/apache/empire/data/bean/BeanProperty.java
index b417375..0df3dec 100644
--- a/empire-db/src/main/java/org/apache/empire/data/bean/BeanProperty.java
+++ b/empire-db/src/main/java/org/apache/empire/data/bean/BeanProperty.java
@@ -199,10 +199,12 @@ public class BeanProperty implements Column
return this;
}
- /**
- * This helper function unwraps an alias expression
- * @return the original expresion before renaming
- */
+ @Override
+ public boolean isWrapper()
+ { // Nope
+ return false;
+ }
+
@Override
public ColumnExpr unwrap()
{ // Nothing to unwrap
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBColumnExpr.java
b/empire-db/src/main/java/org/apache/empire/db/DBColumnExpr.java
index 7192abc..29c3ede 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBColumnExpr.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBColumnExpr.java
@@ -110,8 +110,16 @@ public abstract class DBColumnExpr extends DBExpr
public abstract Element addXml(Element parent, long flags);
/**
- * This helper function unwraps an alias expression
- * @return the original expresion before renaming
+ * @link {#org.apache.empire.commons.Unwrappable#isWrapper()}
+ */
+ @Override
+ public boolean isWrapper()
+ { // Nope
+ return false;
+ }
+
+ /**
+ * @link {#org.apache.empire.commons.Unwrappable#unwrap()}
*/
@Override
public DBColumnExpr unwrap()
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBQuery.java
b/empire-db/src/main/java/org/apache/empire/db/DBQuery.java
index e8bf8df..0d6e3c1 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBQuery.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBQuery.java
@@ -26,6 +26,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import org.apache.empire.commons.ObjectUtils;
import org.apache.empire.commons.StringUtils;
+import org.apache.empire.data.ColumnExpr;
import org.apache.empire.db.exceptions.InvalidKeyException;
import org.apache.empire.db.exceptions.NoPrimaryKeyException;
import org.apache.empire.db.exceptions.QueryNoResultException;
@@ -121,7 +122,7 @@ public class DBQuery extends DBRowSet
// add column
DBColumn column = exprList[i].getUpdateColumn();
if (column==null || (exprList[i] instanceof DBAliasExpr))
- { // user QueryColumn
+ { // use QueryColumn
column = new DBQueryExprColumn(this,
queryColumns[i].getName(), exprList[i]);
}
columns.add(column);
@@ -656,6 +657,33 @@ public class DBQuery extends DBRowSet
// create wrapper
return new DBQueryColumn(this, name, expr);
}
+
+ /**
+ * Gets the index of a particular column expression.
+ * <P>
+ * @param column the Column to get the index for
+ *
+ * @return the position of a column expression
+ */
+ @Override
+ public int getColumnIndex(ColumnExpr columnExpr)
+ {
+ if (columnExpr instanceof DBColumn)
+ return getColumnIndex((DBColumn)columnExpr);
+ else
+ for (int i=0; i<queryColumns.length; i++)
+ { // find expression in QueryColumns
+ DBColumnExpr expr = queryColumns[i].getExpr();
+ if (expr.equals(columnExpr))
+ return i; // found
+ }
+ // try unwrap
+ ColumnExpr unwrapped = columnExpr.unwrap();
+ if (unwrapped!=columnExpr)
+ return getColumnIndex(unwrapped);
+ // not found
+ return -1;
+ }
@Override
public int getColumnIndex(DBColumn column)
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBReader.java
b/empire-db/src/main/java/org/apache/empire/db/DBReader.java
index e80cfd8..5ebd1c8 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBReader.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBReader.java
@@ -891,7 +891,7 @@ public class DBReader extends DBRecordData implements
DBContextAware, Closeable
{
if (columns == null)
return -1;
- // First chance: Try to find an exact match
+ // First chance: Try to find an expression match
int index = ObjectUtils.indexOf(columns, column);
if (index>= 0)
return index;
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBRecord.java
b/empire-db/src/main/java/org/apache/empire/db/DBRecord.java
index 81cbc04..e52189a 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBRecord.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBRecord.java
@@ -486,8 +486,7 @@ public class DBRecord extends DBRecordData implements
DBContextAware, Record, Cl
@Override
public int getFieldIndex(ColumnExpr column)
{
- DBColumnExpr expr = (DBColumnExpr)column;
- return (rowset != null) ?
rowset.getColumnIndex(expr.getUpdateColumn()) : -1;
+ return (rowset != null) ? rowset.getColumnIndex(column) : -1;
}
/**
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBRowSet.java
b/empire-db/src/main/java/org/apache/empire/db/DBRowSet.java
index 61b353a..b5fcf38 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBRowSet.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBRowSet.java
@@ -31,6 +31,7 @@ import java.util.Set;
import org.apache.empire.commons.ObjectUtils;
import org.apache.empire.commons.StringUtils;
import org.apache.empire.data.Column;
+import org.apache.empire.data.ColumnExpr;
import org.apache.empire.data.DataType;
import org.apache.empire.data.Entity;
import org.apache.empire.db.DBRelation.DBCascadeAction;
@@ -301,9 +302,17 @@ public abstract class DBRowSet extends DBExpr implements
Entity
*
* @return the position of a column expression
*/
- public final int getColumnIndex(Column column)
+ public int getColumnIndex(ColumnExpr columnExpr)
{
- return getColumnIndex((DBColumn)column);
+ if (columnExpr instanceof DBColumn)
+ return getColumnIndex((DBColumn)columnExpr);
+ else {
+ Column source = columnExpr.getSourceColumn();
+ if (source instanceof DBColumn)
+ return getColumnIndex((DBColumn)source);
+ }
+ // not found
+ return -1;
}
/**
@@ -520,7 +529,7 @@ public abstract class DBRowSet extends DBExpr implements
Entity
throw new InvalidArgumentException("keyValues", keyValues);
for (int i = 0; i < keyColumns.length; i++)
{ // check
- Column keyColumn = keyColumns[i];
+ DBColumn keyColumn = keyColumns[i];
if (newRecord && keyColumn.isAutoGenerated())
throw new FieldIsReadOnlyException(keyColumn);
// Ignore Validity Checks
diff --git
a/empire-db/src/main/java/org/apache/empire/db/expr/column/DBAliasExpr.java
b/empire-db/src/main/java/org/apache/empire/db/expr/column/DBAliasExpr.java
index 1ca4c46..e34ab90 100644
--- a/empire-db/src/main/java/org/apache/empire/db/expr/column/DBAliasExpr.java
+++ b/empire-db/src/main/java/org/apache/empire/db/expr/column/DBAliasExpr.java
@@ -103,10 +103,19 @@ public class DBAliasExpr extends DBColumnExpr
{
return expr.getUpdateColumn();
}
+
+ /**
+ * Indicates that we are actually an expression wrapper
+ * @return true
+ */
+ @Override
+ public boolean isWrapper()
+ { // Yep
+ return true;
+ }
/**
- * This helper function returns the underlying column expression.
- *
+ * Returns the underlying column expression.
* @return the underlying column expression
*/
@Override
@@ -188,7 +197,7 @@ public class DBAliasExpr extends DBColumnExpr
@Override
public boolean equals(Object other)
{
- if (other==this || expr.equals(other))
+ if (other==this)
return true;
// Check for another Alias Expression
if (other instanceof DBAliasExpr)
diff --git a/empire-db/src/main/java/org/apache/empire/dbms/DBSqlPhrase.java
b/empire-db/src/main/java/org/apache/empire/dbms/DBSqlPhrase.java
index ebb8a9e..bca9a1a 100644
--- a/empire-db/src/main/java/org/apache/empire/dbms/DBSqlPhrase.java
+++ b/empire-db/src/main/java/org/apache/empire/dbms/DBSqlPhrase.java
@@ -9,8 +9,8 @@ public enum DBSqlPhrase
// sql-phrases
SQL_NULL ("null"),
SQL_PARAMETER ("?"),
- SQL_RENAME_TABLE ("AS"),
- SQL_RENAME_COLUMN ("AS"),
+ SQL_RENAME_TABLE (" "),
+ SQL_RENAME_COLUMN (" AS "),
SQL_DATABASE_LINK ("@"), // Oracle
SQL_QUOTES_OPEN ("\""), // MSSQL: [
SQL_QUOTES_CLOSE ("\""), // MSSQL: ]
diff --git
a/empire-db/src/test/java/org/apache/empire/db/AliasExpressionTest.java
b/empire-db/src/test/java/org/apache/empire/db/AliasExpressionTest.java
new file mode 100644
index 0000000..1f8efa9
--- /dev/null
+++ b/empire-db/src/test/java/org/apache/empire/db/AliasExpressionTest.java
@@ -0,0 +1,147 @@
+/*
+ * 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.db;
+
+import org.apache.empire.data.DataType;
+import org.apache.empire.data.list.DataListEntry;
+import org.apache.empire.data.list.DataListHead;
+import org.apache.empire.db.context.DBContextStatic;
+import org.junit.Test;
+
+import junit.framework.Assert;
+
+/**
+ * @author rainer
+ * @since 23.01.22
+ */
+public class AliasExpressionTest
+{
+ /**
+ * Test Standard DBRecord with Serializable Context
+ */
+ @Test
+ public void testSerializationWithSerializableContext()
+ throws Exception
+ {
+ final TestDatabase db = new TestDatabase();
+
+ DBContext context = new DBContextStatic(new MockDriver(), null);
+ db.open(context);
+
+ TestDatabase.TestTable t = db.T_TEST;
+ DBColumnExpr ALIAS_1 = t.C_TEXT.as("ALIAS_1");
+ DBColumnExpr ALIAS_2 = t.C_TEXT.as("ALIAS_2");
+ DBColumnExpr ALIAS_2_NEU = t.C_TEXT.as("ALIAS_2");
+ DBColumnExpr ALIAS_X = t.C_TEXT.as("ALIAS_X");
+ DBColumnExpr AMOUNT = t.C_NUMBER.as("AMOUNT");
+
+ // Table Record
+ DBRecord record = new DBRecord(context, t);
+ int textIndex = record.getFieldIndex(t.C_TEXT);
+ Assert.assertEquals(record.getFieldIndex(ALIAS_1), textIndex);
+ Assert.assertEquals(record.getFieldIndex(ALIAS_2), textIndex);
+ Assert.assertEquals(record.getFieldIndex(ALIAS_2_NEU), textIndex);
+ Assert.assertEquals(record.getFieldIndex(ALIAS_X), textIndex);
+ int numberIndex = record.getFieldIndex(t.C_NUMBER);
+ Assert.assertEquals(record.getFieldIndex(AMOUNT), numberIndex);
+
+ DBCommand cmd = db.createCommand();
+ cmd.select(ALIAS_1, t.C_TEXT, ALIAS_2, ALIAS_2_NEU, AMOUNT); /* Don't
select ALIAS_X */
+ DBColumnExpr[] expr = cmd.getSelectExprList();
+ // Hint: ALIAS_2_NEU is not a separate column
+ Assert.assertEquals(expr.length, 4);
+
+ // Query Record
+ DBQuery q = new DBQuery(cmd);
+ record = new DBRecord(context, q);
+ Assert.assertEquals(record.getFieldIndex(t.C_TEXT), 1);
+ Assert.assertEquals(record.getFieldIndex(ALIAS_1), 0);
+ Assert.assertEquals(record.getFieldIndex(ALIAS_2), 2);
+ Assert.assertEquals(record.getFieldIndex(ALIAS_2_NEU), 2);
+ Assert.assertEquals(record.getFieldIndex(ALIAS_X), 1);
+ Assert.assertEquals(record.getFieldIndex(AMOUNT), 3);
+ Assert.assertEquals(record.getFieldIndex(t.C_NUMBER), 3);
+
+ // Reader
+ DBReader reader = new MyReader(context);
+ reader.open(cmd);
+ Assert.assertEquals(reader.getFieldIndex(t.C_TEXT), 1);
+ Assert.assertEquals(reader.getFieldIndex(ALIAS_1), 0);
+ Assert.assertEquals(reader.getFieldIndex(ALIAS_2), 2);
+ Assert.assertEquals(reader.getFieldIndex(ALIAS_2_NEU), 2);
+ Assert.assertEquals(reader.getFieldIndex(ALIAS_X), 1);
+ Assert.assertEquals(reader.getFieldIndex(AMOUNT), 3);
+ Assert.assertEquals(reader.getFieldIndex(t.C_NUMBER), 3);
+ reader.close();
+
+ // DataListEntry
+ DataListHead head = new DataListHead(cmd.getSelectExprList());
+ Object[] values = new Object[head.getColumns().length];
+ for (int i=0; i<values.length; i++)
+ values[i] = head.getColumns()[i].getName();
+ DataListEntry dle = new DataListEntry(head, 0, values);
+ Assert.assertEquals(dle.getString(t.C_TEXT), values[1]);
+ Assert.assertEquals(dle.getString(ALIAS_1), values[0]);
+ Assert.assertEquals(dle.getString(ALIAS_2), values[2]);
+ Assert.assertEquals(dle.getString(ALIAS_2_NEU), values[2]);
+ Assert.assertEquals(dle.getString(ALIAS_X), values[1]);
+ Assert.assertEquals(dle.getString(AMOUNT), values[3]);
+ Assert.assertEquals(dle.getString(t.C_NUMBER), values[3]);
+
+ // done
+ }
+
+ static class MyReader extends DBReader
+ {
+ public MyReader(DBContext context)
+ {
+ super(context, false);
+ }
+
+ @Override
+ public void open(DBCommandExpr cmd, boolean scrollable)
+ {
+ super.init(cmd.getDatabase(), cmd.getSelectExprList(), null);
+ }
+ }
+
+ /**
+ * Databae
+ */
+ static class TestDatabase extends DBDatabase
+ {
+ public final TestTable T_TEST = new TestTable(this);
+ static class TestTable extends DBTable
+ {
+ public final DBTableColumn C_ID;
+ public final DBTableColumn C_TEXT;
+ public final DBTableColumn C_NUMBER;
+
+ TestTable(DBDatabase db)
+ {
+ super("testtable", db);
+ this.C_ID = addColumn("id", DataType.INTEGER, 0, true);
+ this.C_TEXT = addColumn("TEXT", DataType.VARCHAR, 255, false);
+ this.C_NUMBER = addColumn("NUMBER", DataType.DECIMAL, 10.2,
false);
+ setPrimaryKey(C_ID);
+ }
+ }
+ }
+}
diff --git a/empire-db/src/test/java/org/apache/empire/db/MockDriver.java
b/empire-db/src/test/java/org/apache/empire/db/MockDriver.java
index 1e37cd2..8724e6a 100644
--- a/empire-db/src/test/java/org/apache/empire/db/MockDriver.java
+++ b/empire-db/src/test/java/org/apache/empire/db/MockDriver.java
@@ -22,13 +22,16 @@ import java.sql.Connection;
import org.apache.empire.data.DataType;
import org.apache.empire.db.DBDDLGenerator.DDLActionType;
-import org.apache.empire.dbms.DBMSHandlerBase;
+import org.apache.empire.db.expr.column.DBFuncExpr;
import org.apache.empire.dbms.DBMSFeature;
+import org.apache.empire.dbms.DBMSHandlerBase;
import org.apache.empire.dbms.DBSqlPhrase;
import org.apache.empire.exceptions.NotImplementedException;
public class MockDriver extends DBMSHandlerBase {
// *Deprecated* private static final long serialVersionUID = 1L;
+
+ int seqValue = 0;
class MockCommand extends DBCommand{
// *Deprecated* private static final long serialVersionUID = 1L;
@@ -53,19 +56,19 @@ public class MockDriver extends DBMSHandlerBase {
@Override
public Object getNextSequenceValue(DBDatabase db, String SeqName, int
minValue, Connection conn)
{
- return null;
+ return ++seqValue;
}
@Override
public DBColumnExpr getNextSequenceValueExpr(DBTableColumn column)
{
- return null;
+ return new DBFuncExpr(column, "nextval()", null, column, false,
DataType.INTEGER);
}
@Override
public String getSQLPhrase(DBSqlPhrase phrase)
{
- return null;
+ return phrase.getSqlDefault();
}
@Override