<author email="jahlborn@users.sf.net">James Ahlborn</author>
</properties>
<body>
+ <release version="1.1.19" date="TBD">
+ <action dev="jahlborn" type="add">
+ Add Query reading support.
+ </action>
+ </release>
<release version="1.1.18" date="2008-11-08">
<action dev="jahlborn" type="add">
Add ErrorHandler utility for customizing error handling during row
--- /dev/null
+/*
+Copyright (c) 2008 Health Market Science, Inc.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+USA
+
+You can contact Health Market Science at info@healthmarketscience.com
+or at the following address:
+
+Health Market Science
+2700 Horizon Drive
+Suite 200
+King of Prussia, PA 19406
+*/
+
+package com.healthmarketscience.jackcess.query;
+
+import java.util.List;
+
+import static com.healthmarketscience.jackcess.query.QueryFormat.*;
+
+
+/**
+ * @author James Ahlborn
+ */
+public class AppendQuery extends BaseSelectQuery
+{
+
+ public AppendQuery(String name, List<Row> rows, int objectId) {
+ super(name, rows, objectId, Type.APPEND);
+ }
+
+ public String getTargetTable() {
+ return getTypeRow().name1;
+ }
+
+ public String getRemoteDb() {
+ return getTypeRow().name2;
+ }
+
+ protected List<Row> getValueRows() {
+ return filterRowsByFlag(super.getColumnRows(), APPEND_VALUE_FLAG);
+ }
+
+ @Override
+ protected List<Row> getColumnRows() {
+ return filterRowsByNotFlag(super.getColumnRows(), APPEND_VALUE_FLAG);
+ }
+
+ public List<String> getValues() {
+ return new RowFormatter(getValueRows()) {
+ @Override protected void format(StringBuilder builder, Row row) {
+ builder.append(row.expression);
+ }
+ }.format();
+ }
+
+ @Override
+ protected void toSQLString(StringBuilder builder)
+ {
+ builder.append("INSERT INTO ").append(getTargetTable());
+ toRemoteDb(builder, getRemoteDb());
+ builder.append(NEWLINE);
+ List<String> values = getValues();
+ if(!values.isEmpty()) {
+ builder.append("VALUES (").append(values).append(")");
+ } else {
+ toSQLSelectString(builder, true);
+ }
+ }
+
+}
--- /dev/null
+/*
+Copyright (c) 2008 Health Market Science, Inc.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+USA
+
+You can contact Health Market Science at info@healthmarketscience.com
+or at the following address:
+
+Health Market Science
+2700 Horizon Drive
+Suite 200
+King of Prussia, PA 19406
+*/
+
+package com.healthmarketscience.jackcess.query;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import static com.healthmarketscience.jackcess.query.QueryFormat.*;
+
+
+/**
+ * @author James Ahlborn
+ */
+public abstract class BaseSelectQuery extends Query
+{
+
+ protected BaseSelectQuery(String name, List<Row> rows, int objectId,
+ Type type) {
+ super(name, rows, objectId, type);
+ }
+
+ protected void toSQLSelectString(StringBuilder builder,
+ boolean useSelectPrefix)
+ {
+ if(useSelectPrefix) {
+ builder.append("SELECT ");
+ String selectType = getSelectType();
+ if(!DEFAULT_TYPE.equals(selectType)) {
+ builder.append(selectType).append(" ");
+ }
+ }
+
+ builder.append(getSelectColumns());
+ toSelectInto(builder);
+
+ List<String> fromTables = getFromTables();
+ if(!fromTables.isEmpty()) {
+ builder.append(NEWLINE).append("FROM ").append(fromTables);
+ toRemoteDb(builder, getFromRemoteDb());
+ }
+
+ String whereExpr = getWhereExpression();
+ if(whereExpr != null) {
+ builder.append(NEWLINE).append("WHERE ").append(whereExpr);
+ }
+
+ List<String> groupings = getGroupings();
+ if(!groupings.isEmpty()) {
+ builder.append(NEWLINE).append("GROUP BY ").append(groupings);
+ }
+
+ String havingExpr = getHavingExpression();
+ if(havingExpr != null) {
+ builder.append(NEWLINE).append("HAVING ").append(havingExpr);
+ }
+
+ List<String> orderings = getOrderings();
+ if(!orderings.isEmpty()) {
+ builder.append(NEWLINE).append("ORDER BY ").append(orderings);
+ }
+ }
+
+ public String getSelectType()
+ {
+ if(hasFlag(DISTINCT_SELECT_TYPE)) {
+ return "DISTINCT";
+ }
+
+ if(hasFlag(DISTINCT_ROW_SELECT_TYPE)) {
+ return "DISTINCTROW";
+ }
+
+ if(hasFlag(TOP_SELECT_TYPE)) {
+ StringBuilder builder = new StringBuilder();
+ builder.append("TOP ").append(getFlagRow().name1);
+ if(hasFlag(PERCENT_SELECT_TYPE)) {
+ builder.append(" PERCENT");
+ }
+ return builder.toString();
+ }
+
+ return DEFAULT_TYPE;
+ }
+
+ public List<String> getSelectColumns()
+ {
+ List<String> result = (new RowFormatter(getColumnRows()) {
+ @Override protected void format(StringBuilder builder, Row row) {
+ // note column expression are always quoted appropriately
+ builder.append(row.expression);
+ toAlias(builder, row.name1);
+ }
+ }).format();
+ if(hasFlag(SELECT_STAR_SELECT_TYPE)) {
+ result.add("*");
+ }
+ return result;
+ }
+
+ protected void toSelectInto(StringBuilder builder)
+ {
+ // base does nothing
+ }
+
+ @Override
+ public List<String> getFromTables()
+ {
+ return super.getFromTables();
+ }
+
+ @Override
+ public String getFromRemoteDb()
+ {
+ return super.getFromRemoteDb();
+ }
+
+ @Override
+ public String getWhereExpression()
+ {
+ return super.getWhereExpression();
+ }
+
+ public List<String> getGroupings()
+ {
+ return (new RowFormatter(getGroupByRows()) {
+ @Override protected void format(StringBuilder builder, Row row) {
+ builder.append(row.expression);
+ }
+ }).format();
+ }
+
+ public String getHavingExpression()
+ {
+ return getHavingRow().expression;
+ }
+
+ @Override
+ public List<String> getOrderings()
+ {
+ return super.getOrderings();
+ }
+
+}
--- /dev/null
+/*
+Copyright (c) 2008 Health Market Science, Inc.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+USA
+
+You can contact Health Market Science at info@healthmarketscience.com
+or at the following address:
+
+Health Market Science
+2700 Horizon Drive
+Suite 200
+King of Prussia, PA 19406
+*/
+
+package com.healthmarketscience.jackcess.query;
+
+import java.util.List;
+
+import static com.healthmarketscience.jackcess.query.QueryFormat.*;
+
+
+/**
+ * @author James Ahlborn
+ */
+public class CrossTabQuery extends BaseSelectQuery
+{
+
+ public CrossTabQuery(String name, List<Row> rows, int objectId) {
+ super(name, rows, objectId, Type.CROSS_TAB);
+ }
+
+ protected Row getTransformRow() {
+ return getUniqueRow(
+ filterRowsByNotFlag(super.getColumnRows(),
+ (short)(CROSSTAB_PIVOT_FLAG |
+ CROSSTAB_NORMAL_FLAG)));
+ }
+
+ @Override
+ protected List<Row> getColumnRows() {
+ return filterRowsByFlag(super.getColumnRows(), CROSSTAB_NORMAL_FLAG);
+ }
+
+ @Override
+ protected List<Row> getGroupByRows() {
+ return filterRowsByFlag(super.getGroupByRows(), CROSSTAB_NORMAL_FLAG);
+ }
+
+ protected Row getPivotRow() {
+ return getUniqueRow(filterRowsByFlag(super.getColumnRows(),
+ CROSSTAB_PIVOT_FLAG));
+ }
+
+ public String getTransformExpression() {
+ Row row = getTransformRow();
+ if(row.expression == null) {
+ return null;
+ }
+ // note column expression are always quoted appropriately
+ StringBuilder builder = new StringBuilder(row.expression);
+ return toAlias(builder, row.name1).toString();
+ }
+
+ public String getPivotExpression() {
+ return getPivotRow().expression;
+ }
+
+ @Override
+ protected void toSQLString(StringBuilder builder)
+ {
+ String transformExpr = getTransformExpression();
+ if(transformExpr != null) {
+ builder.append("TRANSFORM ").append(transformExpr).append(NEWLINE);
+ }
+
+ toSQLSelectString(builder, true);
+
+ builder.append(NEWLINE).append("PIVOT ")
+ .append(getPivotExpression());
+ }
+
+}
--- /dev/null
+/*
+Copyright (c) 2008 Health Market Science, Inc.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+USA
+
+You can contact Health Market Science at info@healthmarketscience.com
+or at the following address:
+
+Health Market Science
+2700 Horizon Drive
+Suite 200
+King of Prussia, PA 19406
+*/
+
+package com.healthmarketscience.jackcess.query;
+
+import java.util.List;
+
+
+/**
+ * SQL query which represents a DDL query.
+ *
+ * @author James Ahlborn
+ */
+public class DataDefinitionQuery extends Query
+{
+
+ public DataDefinitionQuery(String name, List<Row> rows, int objectId) {
+ super(name, rows, objectId, Type.DATA_DEFINITION);
+ }
+
+ public String getDDLString() {
+ return getTypeRow().expression;
+ }
+
+ @Override
+ protected boolean supportsStandardClauses() {
+ return false;
+ }
+
+ @Override
+ protected void toSQLString(StringBuilder builder)
+ {
+ String ddl = getDDLString();
+ if(ddl != null) {
+ builder.append(ddl);
+ }
+ }
+
+}
--- /dev/null
+/*
+Copyright (c) 2008 Health Market Science, Inc.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+USA
+
+You can contact Health Market Science at info@healthmarketscience.com
+or at the following address:
+
+Health Market Science
+2700 Horizon Drive
+Suite 200
+King of Prussia, PA 19406
+*/
+
+package com.healthmarketscience.jackcess.query;
+
+import java.util.List;
+
+
+/**
+ * @author James Ahlborn
+ */
+public class DeleteQuery extends BaseSelectQuery
+{
+
+ public DeleteQuery(String name, List<Row> rows, int objectId) {
+ super(name, rows, objectId, Type.DELETE);
+ }
+
+ @Override
+ protected void toSQLString(StringBuilder builder)
+ {
+ builder.append("DELETE ");
+ toSQLSelectString(builder, false);
+ }
+
+}
--- /dev/null
+/*
+Copyright (c) 2008 Health Market Science, Inc.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+USA
+
+You can contact Health Market Science at info@healthmarketscience.com
+or at the following address:
+
+Health Market Science
+2700 Horizon Drive
+Suite 200
+King of Prussia, PA 19406
+*/
+
+package com.healthmarketscience.jackcess.query;
+
+import java.util.List;
+
+import static com.healthmarketscience.jackcess.query.QueryFormat.*;
+
+
+/**
+ * @author James Ahlborn
+ */
+public class MakeTableQuery extends BaseSelectQuery
+{
+
+ public MakeTableQuery(String name, List<Row> rows, int objectId) {
+ super(name, rows, objectId, Type.MAKE_TABLE);
+ }
+
+ public String getTargetTable() {
+ return getTypeRow().name1;
+ }
+
+ public String getRemoteDb() {
+ return getTypeRow().name2;
+ }
+
+ @Override
+ protected void toSelectInto(StringBuilder builder)
+ {
+ builder.append(" INTO ").append(getTargetTable());
+ toRemoteDb(builder, getRemoteDb());
+ }
+
+ @Override
+ protected void toSQLString(StringBuilder builder)
+ {
+ toSQLSelectString(builder, true);
+ }
+
+}
--- /dev/null
+/*
+Copyright (c) 2008 Health Market Science, Inc.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+USA
+
+You can contact Health Market Science at info@healthmarketscience.com
+or at the following address:
+
+Health Market Science
+2700 Horizon Drive
+Suite 200
+King of Prussia, PA 19406
+*/
+
+package com.healthmarketscience.jackcess.query;
+
+import java.util.List;
+
+
+/**
+ * SQL query which represents a query which will be executed via ODBC.
+ *
+ * @author James Ahlborn
+ */
+public class PassthroughQuery extends Query
+{
+
+ public PassthroughQuery(String name, List<Row> rows, int objectId) {
+ super(name, rows, objectId, Type.PASSTHROUGH);
+ }
+
+ public String getConnectionString() {
+ return getTypeRow().name1;
+ }
+
+ public String getPassthroughString() {
+ return getTypeRow().expression;
+ }
+
+ @Override
+ protected boolean supportsStandardClauses() {
+ return false;
+ }
+
+ @Override
+ protected void toSQLString(StringBuilder builder)
+ {
+ String pt = getPassthroughString();
+ if(pt != null) {
+ builder.append(pt);
+ }
+ }
+
+}
--- /dev/null
+/*
+Copyright (c) 2008 Health Market Science, Inc.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+USA
+
+You can contact Health Market Science at info@healthmarketscience.com
+or at the following address:
+
+Health Market Science
+2700 Horizon Drive
+Suite 200
+King of Prussia, PA 19406
+*/
+
+package com.healthmarketscience.jackcess.query;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang.builder.ToStringBuilder;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import static com.healthmarketscience.jackcess.query.QueryFormat.*;
+
+
+/**
+ * @author James Ahlborn
+ */
+public abstract class Query
+{
+ protected static final Log LOG = LogFactory.getLog(Query.class);
+
+ private static final Row EMPTY_ROW =
+ new Row(Collections.<String,Object>emptyMap());
+
+ public enum Type
+ {
+ SELECT(SELECT_QUERY_OBJECT_FLAG, 1),
+ MAKE_TABLE(MAKE_TABLE_QUERY_OBJECT_FLAG, 2),
+ APPEND(APPEND_QUERY_OBJECT_FLAG, 3),
+ UPDATE(UPDATE_QUERY_OBJECT_FLAG, 4),
+ DELETE(DELETE_QUERY_OBJECT_FLAG, 5),
+ CROSS_TAB(CROSS_TAB_QUERY_OBJECT_FLAG, 6),
+ DATA_DEFINITION(DATA_DEF_QUERY_OBJECT_FLAG, 7),
+ PASSTHROUGH(PASSTHROUGH_QUERY_OBJECT_FLAG, 8),
+ UNION(UNION_QUERY_OBJECT_FLAG, 9),
+ UNKNOWN(-1, -1);
+
+ private final int _objectFlag;
+ private final short _value;
+
+ private Type(int objectFlag, int value) {
+ _objectFlag = objectFlag;
+ _value = (short)value;
+ }
+
+ public int getObjectFlag() {
+ return _objectFlag;
+ }
+
+ public short getValue() {
+ return _value;
+ }
+ }
+
+ private final String _name;
+ private final List<Row> _rows;
+ private final int _objectId;
+ private final Type _type;
+
+ protected Query(String name, List<Row> rows, int objectId, Type type) {
+ _name = name;
+ _rows = rows;
+ _objectId = objectId;
+ _type = type;
+
+ if(type != Type.UNKNOWN) {
+ short foundType = getShortValue(getQueryType(rows),
+ _type.getValue());
+ if(foundType != _type.getValue()) {
+ throw new IllegalStateException("Unexpected query type " + foundType);
+ }
+ }
+ }
+
+ public String getName() {
+ return _name;
+ }
+
+ public Type getType() {
+ return _type;
+ }
+
+ public int getObjectId() {
+ return _objectId;
+ }
+
+ public int getObjectFlag() {
+ return getType().getObjectFlag();
+ }
+
+ public List<Row> getRows() {
+ return _rows;
+ }
+
+ protected List<Row> getRowsByAttribute(Byte attribute) {
+ return getRowsByAttribute(getRows(), attribute);
+ }
+
+ protected Row getRowByAttribute(Byte attribute) {
+ return getUniqueRow(getRowsByAttribute(getRows(), attribute));
+ }
+
+ protected Row getTypeRow() {
+ return getRowByAttribute(TYPE_ATTRIBUTE);
+ }
+
+ protected List<Row> getParameterRows() {
+ return getRowsByAttribute(PARAMETER_ATTRIBUTE);
+ }
+
+ protected Row getFlagRow() {
+ return getRowByAttribute(FLAG_ATTRIBUTE);
+ }
+
+ protected Row getRemoteDatabaseRow() {
+ return getRowByAttribute(REMOTEDB_ATTRIBUTE);
+ }
+
+ protected List<Row> getTableRows() {
+ return getRowsByAttribute(TABLE_ATTRIBUTE);
+ }
+
+ protected List<Row> getColumnRows() {
+ return getRowsByAttribute(COLUMN_ATTRIBUTE);
+ }
+
+ protected List<Row> getJoinRows() {
+ return getRowsByAttribute(JOIN_ATTRIBUTE);
+ }
+
+ protected Row getWhereRow() {
+ return getRowByAttribute(WHERE_ATTRIBUTE);
+ }
+
+ protected List<Row> getGroupByRows() {
+ return getRowsByAttribute(GROUPBY_ATTRIBUTE);
+ }
+
+ protected Row getHavingRow() {
+ return getRowByAttribute(HAVING_ATTRIBUTE);
+ }
+
+ protected List<Row> getOrderByRows() {
+ return getRowsByAttribute(ORDERBY_ATTRIBUTE);
+ }
+
+ protected abstract void toSQLString(StringBuilder builder);
+
+ protected void toSQLParameterString(StringBuilder builder) {
+ // handle any parameters
+ List<String> params = getParameters();
+ if(!params.isEmpty()) {
+ builder.append("PARAMETERS ").append(params)
+ .append(";").append(NEWLINE);
+ }
+ }
+
+ public List<String> getParameters()
+ {
+ return (new RowFormatter(getParameterRows()) {
+ @Override protected void format(StringBuilder builder, Row row) {
+ String name = row.name1;
+ String typeName = PARAM_TYPE_MAP.get(row.flag);
+ if(typeName == null) {
+ throw new IllegalStateException("Unknown param type " + row.flag);
+ }
+
+ builder.append(name).append(" ").append(typeName);
+ if((TEXT_FLAG.equals(row.flag)) && (getIntValue(row.extra, 0) > 0)) {
+ builder.append("(").append(row.extra).append(")");
+ }
+ }
+ }).format();
+ }
+
+ protected List<String> getFromTables()
+ {
+ List<Join> joinExprs = new ArrayList<Join>();
+ for(Row table : getTableRows()) {
+ StringBuilder builder = new StringBuilder();
+
+ if(table.expression != null) {
+ toQuotedExpr(builder, table.expression).append(IDENTIFIER_SEP_CHAR);
+ }
+ if(table.name1 != null) {
+ toOptionalQuotedExpr(builder, table.name1, true);
+ }
+ toAlias(builder, table.name2);
+
+ String key = ((table.name2 != null) ? table.name2 : table.name1);
+ joinExprs.add(new Join(key, builder.toString()));
+ }
+
+
+ List<Row> joins = getJoinRows();
+ if(!joins.isEmpty()) {
+
+ for(Row join : joins) {
+
+ String fromTable = join.name1;
+ String toTable = join.name2;
+
+ Join fromExpr = getJoinExpr(fromTable, joinExprs);
+ Join toExpr = getJoinExpr(toTable, joinExprs);
+ String joinType = JOIN_TYPE_MAP.get(join.flag);
+ if(joinType == null) {
+ throw new IllegalStateException("Unknown join type " + join.flag);
+ }
+
+ String expr = new StringBuilder().append(fromExpr)
+ .append(joinType).append(toExpr).append(" ON ")
+ .append(join.expression).toString();
+
+ fromExpr.join(toExpr, expr);
+ joinExprs.add(fromExpr);
+ }
+ }
+
+ List<String> result = new AppendableList<String>();
+ for(Join joinExpr : joinExprs) {
+ result.add(joinExpr.expression);
+ }
+
+ return result;
+ }
+
+ private Join getJoinExpr(String table, List<Join> joinExprs)
+ {
+ for(Iterator<Join> iter = joinExprs.iterator(); iter.hasNext(); ) {
+ Join joinExpr = iter.next();
+ if(joinExpr.tables.contains(table)) {
+ iter.remove();
+ return joinExpr;
+ }
+ }
+ throw new IllegalStateException("Cannot find join table " + table);
+ }
+
+ protected String getFromRemoteDb()
+ {
+ return getRemoteDatabaseRow().name1;
+ }
+
+ protected String getWhereExpression()
+ {
+ return getWhereRow().expression;
+ }
+
+ protected List<String> getOrderings()
+ {
+ return (new RowFormatter(getOrderByRows()) {
+ @Override protected void format(StringBuilder builder, Row row) {
+ builder.append(row.expression);
+ if(DESCENDING_FLAG.equalsIgnoreCase(row.name1)) {
+ builder.append(" DESC");
+ }
+ }
+ }).format();
+ }
+
+ public String getOwnerAccessType() {
+ return(hasFlag(OWNER_ACCESS_SELECT_TYPE) ?
+ "WITH OWNERACCESS OPTION" : DEFAULT_TYPE);
+ }
+
+ protected boolean hasFlag(int flagMask)
+ {
+ return hasFlag(getFlagRow(), flagMask);
+ }
+
+ protected boolean supportsStandardClauses() {
+ return true;
+ }
+
+ public String toSQLString()
+ {
+ StringBuilder builder = new StringBuilder();
+ if(supportsStandardClauses()) {
+ toSQLParameterString(builder);
+ }
+
+ toSQLString(builder);
+
+ if(supportsStandardClauses()) {
+
+ String accessType = getOwnerAccessType();
+ if(!DEFAULT_TYPE.equals(accessType)) {
+ builder.append(NEWLINE).append(accessType);
+ }
+
+ builder.append(";");
+ }
+ return builder.toString();
+ }
+
+ @Override
+ public String toString() {
+ return ToStringBuilder.reflectionToString(this);
+ }
+
+ public static Query create(int objectFlag, String name, List<Row> rows,
+ int objectId)
+ {
+ try {
+ switch(objectFlag) {
+ case SELECT_QUERY_OBJECT_FLAG:
+ return new SelectQuery(name, rows, objectId);
+ case MAKE_TABLE_QUERY_OBJECT_FLAG:
+ return new MakeTableQuery(name, rows, objectId);
+ case APPEND_QUERY_OBJECT_FLAG:
+ return new AppendQuery(name, rows, objectId);
+ case UPDATE_QUERY_OBJECT_FLAG:
+ return new UpdateQuery(name, rows, objectId);
+ case DELETE_QUERY_OBJECT_FLAG:
+ return new DeleteQuery(name, rows, objectId);
+ case CROSS_TAB_QUERY_OBJECT_FLAG:
+ return new CrossTabQuery(name, rows, objectId);
+ case DATA_DEF_QUERY_OBJECT_FLAG:
+ return new DataDefinitionQuery(name, rows, objectId);
+ case PASSTHROUGH_QUERY_OBJECT_FLAG:
+ return new PassthroughQuery(name, rows, objectId);
+ case UNION_QUERY_OBJECT_FLAG:
+ return new UnionQuery(name, rows, objectId);
+ default:
+ // unknown querytype
+ throw new IllegalStateException(
+ "unknown query object flag " + objectFlag);
+ }
+ } catch(IllegalStateException e) {
+ LOG.warn("Failed parsing query", e);
+ }
+
+ // return unknown query
+ return new UnknownQuery(name, rows, objectId, objectFlag);
+ }
+
+ private static Short getQueryType(List<Row> rows)
+ {
+ return getUniqueRow(getRowsByAttribute(rows, TYPE_ATTRIBUTE)).flag;
+ }
+
+ private static List<Row> getRowsByAttribute(List<Row> rows, Byte attribute) {
+ List<Row> result = new ArrayList<Row>();
+ for(Row row : rows) {
+ if(attribute.equals(row.attribute)) {
+ result.add(row);
+ }
+ }
+ return result;
+ }
+
+ protected static Row getUniqueRow(List<Row> rows) {
+ if(rows.size() == 1) {
+ return rows.get(0);
+ }
+ if(rows.isEmpty()) {
+ return EMPTY_ROW;
+ }
+ throw new IllegalStateException("Unexpected number of rows for" + rows);
+ }
+
+ protected static List<Row> filterRowsByFlag(
+ List<Row> rows, final short flag)
+ {
+ return new RowFilter() {
+ @Override protected boolean keep(Row row) {
+ return hasFlag(row, flag);
+ }
+ }.filter(rows);
+ }
+
+ protected static List<Row> filterRowsByNotFlag(
+ List<Row> rows, final short flag)
+ {
+ return new RowFilter() {
+ @Override protected boolean keep(Row row) {
+ return !hasFlag(row, flag);
+ }
+ }.filter(rows);
+ }
+
+ protected static boolean hasFlag(Row row, int flagMask)
+ {
+ return((getShortValue(row.flag, 0) & flagMask) != 0);
+ }
+
+ protected static short getShortValue(Short s, int def) {
+ return ((s != null) ? (short)s : (short)def);
+ }
+
+ protected static int getIntValue(Integer i, int def) {
+ return ((i != null) ? (int)i : def);
+ }
+
+ protected static StringBuilder toOptionalQuotedExpr(StringBuilder builder,
+ String fullExpr,
+ boolean isIdentifier)
+ {
+ String[] exprs = (isIdentifier ?
+ IDENTIFIER_SEP_PAT.split(fullExpr) :
+ new String[]{fullExpr});
+ for(int i = 0; i < exprs.length; ++i) {
+ String expr = exprs[i];
+ if(QUOTABLE_CHAR_PAT.matcher(expr).find()) {
+ toQuotedExpr(builder, expr);
+ } else {
+ builder.append(expr);
+ }
+ if(i < (exprs.length - 1)) {
+ builder.append(IDENTIFIER_SEP_CHAR);
+ }
+ }
+ return builder;
+ }
+
+ protected static StringBuilder toQuotedExpr(StringBuilder builder,
+ String expr)
+ {
+ return builder.append("[").append(expr).append("]");
+ }
+
+ protected static StringBuilder toRemoteDb(StringBuilder builder,
+ String remoteDb) {
+ if(remoteDb != null) {
+ builder.append(" IN ").append(remoteDb);
+ }
+ return builder;
+ }
+
+ protected static StringBuilder toAlias(StringBuilder builder,
+ String alias) {
+ if(alias != null) {
+ toOptionalQuotedExpr(builder.append(" AS "), alias, false);
+ }
+ return builder;
+ }
+
+ private static class UnknownQuery extends Query
+ {
+ private final int _objectFlag;
+
+ private UnknownQuery(String name, List<Row> rows, int objectId,
+ int objectFlag)
+ {
+ super(name, rows, objectId, Type.UNKNOWN);
+ _objectFlag = objectFlag;
+ }
+
+ @Override
+ public int getObjectFlag() {
+ return _objectFlag;
+ }
+
+ @Override
+ protected void toSQLString(StringBuilder builder) {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ public static class Row
+ {
+ public final Byte attribute;
+ public final String expression;
+ public final Short flag;
+ public final Integer extra;
+ public final String name1;
+ public final String name2;
+ public final Integer objectId;
+ public final byte[] order;
+
+ public Row(Map<String,Object> tableRow) {
+ this((Byte)tableRow.get(COL_ATTRIBUTE),
+ (String)tableRow.get(COL_EXPRESSION),
+ (Short)tableRow.get(COL_FLAG),
+ (Integer)tableRow.get(COL_EXTRA),
+ (String)tableRow.get(COL_NAME1),
+ (String)tableRow.get(COL_NAME2),
+ (Integer)tableRow.get(COL_OBJECTID),
+ (byte[])tableRow.get(COL_ORDER));
+ }
+
+ public Row(Byte attribute, String expression, Short flag,
+ Integer extra, String name1, String name2,
+ Integer objectId, byte[] order)
+ {
+ this.attribute = attribute;
+ this.expression = expression;
+ this.flag = flag;
+ this.extra = extra;
+ this.name1 = name1;
+ this.name2= name2;
+ this.objectId = objectId;
+ this.order = order;
+ }
+
+ public Map<String,Object> toTableRow()
+ {
+ Map<String,Object> tableRow = new HashMap<String,Object>();
+
+ tableRow.put(COL_ATTRIBUTE, attribute);
+ tableRow.put(COL_EXPRESSION, expression);
+ tableRow.put(COL_FLAG, flag);
+ tableRow.put(COL_EXTRA, extra);
+ tableRow.put(COL_NAME1, name1);
+ tableRow.put(COL_NAME2, name2);
+ tableRow.put(COL_OBJECTID, objectId);
+ tableRow.put(COL_ORDER, order);
+
+ return tableRow;
+ }
+
+ @Override
+ public String toString() {
+ return ToStringBuilder.reflectionToString(this);
+ }
+ }
+
+ protected static abstract class RowFormatter
+ {
+ private final List<Row> _list;
+
+ protected RowFormatter(List<Row> list) {
+ _list = list;
+ }
+
+ public List<String> format() {
+ return format(new AppendableList<String>());
+ }
+
+ public List<String> format(List<String> strs) {
+ for(Row row : _list) {
+ StringBuilder builder = new StringBuilder();
+ format(builder, row);
+ strs.add(builder.toString());
+ }
+ return strs;
+ }
+
+ protected abstract void format(StringBuilder builder, Row row);
+ }
+
+ protected static abstract class RowFilter
+ {
+ protected RowFilter() {
+ }
+
+ public List<Row> filter(List<Row> list) {
+ for(Iterator<Row> iter = list.iterator(); iter.hasNext(); ) {
+ if(!keep(iter.next())) {
+ iter.remove();
+ }
+ }
+ return list;
+ }
+
+ protected abstract boolean keep(Row row);
+ }
+
+ protected static class AppendableList<E> extends ArrayList<E>
+ {
+ private static final long serialVersionUID = 0L;
+
+ protected AppendableList() {
+ }
+
+ protected AppendableList(Collection<? extends E> c) {
+ super(c);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ for(Iterator<E> iter = iterator(); iter.hasNext(); ) {
+ builder.append(iter.next().toString());
+ if(iter.hasNext()) {
+ builder.append(", ");
+ }
+ }
+ return builder.toString();
+ }
+ }
+
+ private static class Join
+ {
+ public final List<String> tables = new ArrayList<String>();
+ public boolean isJoin;
+ public String expression;
+
+ private Join(String table, String expr) {
+ tables.add(table);
+ expression = expr;
+ }
+
+ public void join(Join other, String newExpr) {
+ tables.addAll(other.tables);
+ isJoin = true;
+ expression = newExpr;
+ }
+
+ @Override
+ public String toString() {
+ return (isJoin ? ("(" + expression + ")") : expression);
+ }
+ }
+
+}
--- /dev/null
+/*
+Copyright (c) 2008 Health Market Science, Inc.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+USA
+
+You can contact Health Market Science at info@healthmarketscience.com
+or at the following address:
+
+Health Market Science
+2700 Horizon Drive
+Suite 200
+King of Prussia, PA 19406
+*/
+
+package com.healthmarketscience.jackcess.query;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import com.healthmarketscience.jackcess.DataType;
+import org.apache.commons.lang.SystemUtils;
+
+/**
+ * @author James Ahlborn
+ */
+public class QueryFormat
+{
+
+ private QueryFormat() {}
+
+ public static final int SELECT_QUERY_OBJECT_FLAG = 0;
+ public static final int MAKE_TABLE_QUERY_OBJECT_FLAG = 80;
+ public static final int APPEND_QUERY_OBJECT_FLAG = 64;
+ public static final int UPDATE_QUERY_OBJECT_FLAG = 48;
+ public static final int DELETE_QUERY_OBJECT_FLAG = 32;
+ public static final int CROSS_TAB_QUERY_OBJECT_FLAG = 16;
+ public static final int DATA_DEF_QUERY_OBJECT_FLAG = 96;
+ public static final int PASSTHROUGH_QUERY_OBJECT_FLAG = 112;
+ public static final int UNION_QUERY_OBJECT_FLAG = 128;
+
+ public static final String COL_ATTRIBUTE = "Attribute";
+ public static final String COL_EXPRESSION = "Expression";
+ public static final String COL_FLAG = "Flag";
+ public static final String COL_EXTRA = "LvExtra";
+ public static final String COL_NAME1 = "Name1";
+ public static final String COL_NAME2 = "Name2";
+ public static final String COL_OBJECTID = "ObjectId";
+ public static final String COL_ORDER = "Order";
+
+ public static final Byte START_ATTRIBUTE = 0;
+ public static final Byte TYPE_ATTRIBUTE = 1;
+ public static final Byte PARAMETER_ATTRIBUTE = 2;
+ public static final Byte FLAG_ATTRIBUTE = 3;
+ public static final Byte REMOTEDB_ATTRIBUTE = 4;
+ public static final Byte TABLE_ATTRIBUTE = 5;
+ public static final Byte COLUMN_ATTRIBUTE = 6;
+ public static final Byte JOIN_ATTRIBUTE = 7;
+ public static final Byte WHERE_ATTRIBUTE = 8;
+ public static final Byte GROUPBY_ATTRIBUTE = 9;
+ public static final Byte HAVING_ATTRIBUTE = 10;
+ public static final Byte ORDERBY_ATTRIBUTE = 11;
+ public static final Byte END_ATTRIBUTE = (byte)255;
+
+ public static final short UNION_FLAG = 0x02;
+
+ public static final Short TEXT_FLAG = (short)DataType.TEXT.getValue();
+
+ public static final String DESCENDING_FLAG = "D";
+
+ public static final short SELECT_STAR_SELECT_TYPE = 0x01;
+ public static final short DISTINCT_SELECT_TYPE = 0x02;
+ public static final short OWNER_ACCESS_SELECT_TYPE = 0x04;
+ public static final short DISTINCT_ROW_SELECT_TYPE = 0x08;
+ public static final short TOP_SELECT_TYPE = 0x10;
+ public static final short PERCENT_SELECT_TYPE = 0x20;
+
+ public static final short APPEND_VALUE_FLAG = (short)0x8000;
+
+ public static final short CROSSTAB_PIVOT_FLAG = 0x01;
+ public static final short CROSSTAB_NORMAL_FLAG = 0x02;
+
+ public static final String UNION_PART1 = "X7YZ_____1";
+ public static final String UNION_PART2 = "X7YZ_____2";
+
+ public static final String DEFAULT_TYPE = "";
+
+ public static final Pattern QUOTABLE_CHAR_PAT = Pattern.compile("\\W");
+
+ public static final Pattern IDENTIFIER_SEP_PAT = Pattern.compile("\\.");
+ public static final char IDENTIFIER_SEP_CHAR = '.';
+
+ public static final String NEWLINE = SystemUtils.LINE_SEPARATOR;
+
+
+ public static final Map<Short,String> PARAM_TYPE_MAP =
+ new HashMap<Short,String>();
+ static {
+ PARAM_TYPE_MAP.put((short)0, "Value");
+ PARAM_TYPE_MAP.put((short)DataType.BOOLEAN.getValue(), "Bit");
+ PARAM_TYPE_MAP.put((short)DataType.TEXT.getValue(), "Text");
+ PARAM_TYPE_MAP.put((short)DataType.BYTE.getValue(), "Byte");
+ PARAM_TYPE_MAP.put((short)DataType.INT.getValue(), "Short");
+ PARAM_TYPE_MAP.put((short)DataType.LONG.getValue(), "Long");
+ PARAM_TYPE_MAP.put((short)DataType.MONEY.getValue(), "Currency");
+ PARAM_TYPE_MAP.put((short)DataType.FLOAT.getValue(), "IEEESingle");
+ PARAM_TYPE_MAP.put((short)DataType.DOUBLE.getValue(), "IEEEDouble");
+ PARAM_TYPE_MAP.put((short)DataType.SHORT_DATE_TIME.getValue(), "DateTime");
+ PARAM_TYPE_MAP.put((short)DataType.BINARY.getValue(), "Binary");
+ PARAM_TYPE_MAP.put((short)DataType.OLE.getValue(), "LongBinary");
+ PARAM_TYPE_MAP.put((short)DataType.GUID.getValue(), "Guid");
+ }
+
+ public static final Map<Short,String> JOIN_TYPE_MAP =
+ new HashMap<Short,String>();
+ static {
+ JOIN_TYPE_MAP.put((short)1, " INNER JOIN ");
+ JOIN_TYPE_MAP.put((short)2, " LEFT OUTER JOIN ");
+ JOIN_TYPE_MAP.put((short)3, " RIGHT OUTER JOIN ");
+ }
+
+}
--- /dev/null
+/*
+Copyright (c) 2008 Health Market Science, Inc.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+USA
+
+You can contact Health Market Science at info@healthmarketscience.com
+or at the following address:
+
+Health Market Science
+2700 Horizon Drive
+Suite 200
+King of Prussia, PA 19406
+*/
+
+package com.healthmarketscience.jackcess.query;
+
+import java.util.List;
+
+
+/**
+ * @author James Ahlborn
+ */
+public class SelectQuery extends BaseSelectQuery
+{
+
+ public SelectQuery(String name, List<Row> rows, int objectId) {
+ super(name, rows, objectId, Type.SELECT);
+ }
+
+ @Override
+ protected void toSQLString(StringBuilder builder)
+ {
+ toSQLSelectString(builder, true);
+ }
+
+}
--- /dev/null
+/*
+Copyright (c) 2008 Health Market Science, Inc.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+USA
+
+You can contact Health Market Science at info@healthmarketscience.com
+or at the following address:
+
+Health Market Science
+2700 Horizon Drive
+Suite 200
+King of Prussia, PA 19406
+*/
+
+package com.healthmarketscience.jackcess.query;
+
+import java.util.List;
+
+import static com.healthmarketscience.jackcess.query.QueryFormat.*;
+
+
+/**
+ * SQL query which represents a UNION query.
+ *
+ * @author James Ahlborn
+ */
+public class UnionQuery extends Query
+{
+ public UnionQuery(String name, List<Row> rows, int objectId) {
+ super(name, rows, objectId, Type.UNION);
+ }
+
+ public String getUnionType() {
+ return(hasFlag(UNION_FLAG) ? DEFAULT_TYPE : "ALL");
+ }
+
+ public String getUnionString1() {
+ return getUnionString(UNION_PART1);
+ }
+
+ public String getUnionString2() {
+ return getUnionString(UNION_PART2);
+ }
+
+ @Override
+ public List<String> getOrderings() {
+ return super.getOrderings();
+ }
+
+ private String getUnionString(String id) {
+ for(Row row : getTableRows()) {
+ if(id.equals(row.name2)) {
+ return row.expression;
+ }
+ }
+ throw new IllegalStateException(
+ "Could not find union query with id " + id);
+ }
+
+ @Override
+ protected void toSQLString(StringBuilder builder)
+ {
+ builder.append(getUnionString1()).append(NEWLINE)
+ .append("UNION ");
+ String unionType = getUnionType();
+ if(!DEFAULT_TYPE.equals(unionType)) {
+ builder.append(unionType).append(" ");
+ }
+ builder.append(getUnionString2());
+ List<String> orderings = getOrderings();
+ if(!orderings.isEmpty()) {
+ builder.append(NEWLINE).append("ORDER BY ").append(orderings);
+ }
+ }
+
+}
--- /dev/null
+/*
+Copyright (c) 2008 Health Market Science, Inc.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+USA
+
+You can contact Health Market Science at info@healthmarketscience.com
+or at the following address:
+
+Health Market Science
+2700 Horizon Drive
+Suite 200
+King of Prussia, PA 19406
+*/
+
+package com.healthmarketscience.jackcess.query;
+
+import java.util.List;
+
+import static com.healthmarketscience.jackcess.query.QueryFormat.*;
+
+
+/**
+ * @author James Ahlborn
+ */
+public class UpdateQuery extends Query
+{
+
+ public UpdateQuery(String name, List<Row> rows, int objectId) {
+ super(name, rows, objectId, Type.UPDATE);
+ }
+
+ public List<String> getTargetTables()
+ {
+ return super.getFromTables();
+ }
+
+ public String getRemoteDb()
+ {
+ return super.getFromRemoteDb();
+ }
+
+ public List<String> getNewValues()
+ {
+ return (new RowFormatter(getColumnRows()) {
+ @Override protected void format(StringBuilder builder, Row row) {
+ toOptionalQuotedExpr(builder, row.name2, true)
+ .append(" = ").append(row.expression);
+ }
+ }).format();
+ }
+
+ @Override
+ public String getWhereExpression()
+ {
+ return super.getWhereExpression();
+ }
+
+ @Override
+ protected void toSQLString(StringBuilder builder)
+ {
+ builder.append("UPDATE ").append(getTargetTables());
+ toRemoteDb(builder, getRemoteDb());
+
+ builder.append(NEWLINE).append("SET ").append(getNewValues());
+
+ String whereExpr = getWhereExpression();
+ if(whereExpr != null) {
+ builder.append(NEWLINE).append("WHERE ").append(whereExpr);
+ }
+ }
+
+}
--- /dev/null
+/*
+Copyright (c) 2007 Health Market Science, Inc.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+USA
+
+You can contact Health Market Science at info@healthmarketscience.com
+or at the following address:
+
+Health Market Science
+2700 Horizon Drive
+Suite 200
+King of Prussia, PA 19406
+*/
+
+package com.healthmarketscience.jackcess.query;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+import com.healthmarketscience.jackcess.query.Query.Row;
+import junit.framework.TestCase;
+import org.apache.commons.lang.StringUtils;
+
+import static org.apache.commons.lang.SystemUtils.LINE_SEPARATOR;
+import static com.healthmarketscience.jackcess.query.QueryFormat.*;
+
+
+/**
+ * @author James Ahlborn
+ */
+public class QueryTest extends TestCase
+{
+
+ public QueryTest(String name) throws Exception {
+ super(name);
+ }
+
+ public void testUnionQuery() throws Exception
+ {
+ String expr1 = "Select * from Table1";
+ String expr2 = "Select * from Table2";
+
+ UnionQuery query = (UnionQuery)newQuery(
+ Query.Type.UNION,
+ newRow(TABLE_ATTRIBUTE, expr1, null, UNION_PART1),
+ newRow(TABLE_ATTRIBUTE, expr2, null, UNION_PART2));
+ setFlag(query, 3);
+
+ assertEquals(multiline("Select * from Table1",
+ "UNION Select * from Table2;"),
+ query.toSQLString());
+
+ setFlag(query, 1);
+
+ assertEquals(multiline("Select * from Table1",
+ "UNION ALL Select * from Table2;"),
+ query.toSQLString());
+
+ query.getRows().add(newRow(ORDERBY_ATTRIBUTE, "Table1.id",
+ null, null));
+
+ assertEquals(multiline("Select * from Table1",
+ "UNION ALL Select * from Table2",
+ "ORDER BY Table1.id;"),
+ query.toSQLString());
+
+ }
+
+ public void testPassthroughQuery() throws Exception
+ {
+ String expr = "Select * from Table1";
+ String constr = "ODBC;";
+
+ PassthroughQuery query = (PassthroughQuery)newQuery(
+ Query.Type.PASSTHROUGH, expr, constr);
+
+ assertEquals(expr, query.toSQLString());
+ assertEquals(constr, query.getConnectionString());
+ }
+
+ public void testDataDefinitionQuery() throws Exception
+ {
+ String expr = "Drop table Table1";
+
+ DataDefinitionQuery query = (DataDefinitionQuery)newQuery(
+ Query.Type.DATA_DEFINITION, expr, null);
+
+ assertEquals(expr, query.toSQLString());
+ }
+
+ public void testUpdateQuery() throws Exception
+ {
+ UpdateQuery query = (UpdateQuery)newQuery(
+ Query.Type.UPDATE,
+ newRow(TABLE_ATTRIBUTE, null, "Table1", null),
+ newRow(COLUMN_ATTRIBUTE, "\"some string\"", null, "Table1.id"),
+ newRow(COLUMN_ATTRIBUTE, "42", null, "Table1.col1"));
+
+ assertEquals(
+ multiline("UPDATE Table1",
+ "SET Table1.id = \"some string\", Table1.col1 = 42;"),
+ query.toSQLString());
+
+ query.getRows().add(newRow(WHERE_ATTRIBUTE, "(Table1.col2 < 13)",
+ null, null));
+
+ assertEquals(
+ multiline("UPDATE Table1",
+ "SET Table1.id = \"some string\", Table1.col1 = 42",
+ "WHERE (Table1.col2 < 13);"),
+ query.toSQLString());
+ }
+
+ private static Query newQuery(Query.Type type, Row... rows)
+ {
+ return newQuery(type, null, null, rows);
+ }
+
+ private static Query newQuery(Query.Type type, String typeExpr,
+ String typeName1, Row... rows)
+ {
+ List<Row> rowList = new ArrayList<Row>();
+ rowList.add(newRow(TYPE_ATTRIBUTE, typeExpr, type.getValue(),
+ null, typeName1, null));
+ rowList.addAll(Arrays.asList(rows));
+ return Query.create(type.getObjectFlag(), "TestQuery", rowList, 13);
+ }
+
+ private static Row newRow(Byte attr, String expr, String name1, String name2)
+ {
+ return newRow(attr, expr, null, null, name1, name2);
+ }
+
+ private static Row newRow(Byte attr, String expr, Number flagNum,
+ String name1, String name2)
+ {
+ return newRow(attr, expr, flagNum, null, name1, name2);
+ }
+
+ private static Row newRow(Byte attr, String expr, Number flagNum,
+ Number extraNum, String name1, String name2)
+ {
+ Short flag = ((flagNum != null) ? flagNum.shortValue() : null);
+ Integer extra = ((extraNum != null) ? extraNum.intValue() : null);
+ return new Row(attr, expr, flag, extra, name1, name2, null, null);
+ }
+
+ private static void setFlag(Query query, Number newFlagNum)
+ {
+ removeRows(query, FLAG_ATTRIBUTE);
+ query.getRows().add(
+ newRow(FLAG_ATTRIBUTE, null, newFlagNum, null, null, null));
+ }
+
+ private static void removeRows(Query query, Byte attr)
+ {
+ for(Iterator<Row> iter = query.getRows().iterator(); iter.hasNext(); ) {
+ if(attr.equals(iter.next().attribute)) {
+ iter.remove();
+ }
+ }
+ }
+
+ private static String multiline(String... strs)
+ {
+ return StringUtils.join(strs, LINE_SEPARATOR);
+ }
+
+}