http://git-wip-us.apache.org/repos/asf/cayenne/blob/f6b2dac9/cayenne-server/src/main/java/org/apache/cayenne/dba/firebird/FirebirdSQLTreeProcessor.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/firebird/FirebirdSQLTreeProcessor.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/firebird/FirebirdSQLTreeProcessor.java new file mode 100644 index 0000000..e97fd2e --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/firebird/FirebirdSQLTreeProcessor.java @@ -0,0 +1,189 @@ +/***************************************************************** + * 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.cayenne.dba.firebird; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.cayenne.access.sqlbuilder.ExpressionNodeBuilder; +import org.apache.cayenne.access.sqlbuilder.QuotingAppendable; +import org.apache.cayenne.access.sqlbuilder.sqltree.FunctionNode; +import org.apache.cayenne.access.sqlbuilder.sqltree.InNode; +import org.apache.cayenne.access.sqlbuilder.sqltree.LimitOffsetNode; +import org.apache.cayenne.access.sqlbuilder.sqltree.Node; +import org.apache.cayenne.access.sqlbuilder.sqltree.NodeType; +import org.apache.cayenne.access.sqlbuilder.sqltree.OpExpressionNode; +import org.apache.cayenne.access.sqlbuilder.sqltree.TextNode; +import org.apache.cayenne.access.sqlbuilder.sqltree.ValueNode; +import org.apache.cayenne.access.translator.select.BaseSQLTreeProcessor; +import org.apache.cayenne.dba.firebird.sqltree.FirebirdLimitNode; +import org.apache.cayenne.dba.firebird.sqltree.FirebirdSubstringFunctionNode; +import org.apache.cayenne.util.ArrayUtil; + +import static org.apache.cayenne.access.sqlbuilder.SQLBuilder.exp; +import static org.apache.cayenne.access.sqlbuilder.SQLBuilder.node; + +/** + * @since 4.2 + */ +public class FirebirdSQLTreeProcessor extends BaseSQLTreeProcessor { + + private static final int FIREBIRD_IN_BATCH_SIZE = 1500; + + @Override + protected void onValueNode(Node parent, ValueNode child, int index) { + replaceChild(parent, index, new ValueNode(child.getValue(), child.isArray(), child.getAttribute()) { + @Override + protected void appendStringValue(QuotingAppendable buffer, CharSequence value) { + buffer.append("CAST("); + super.appendStringValue(buffer, value); + buffer.append(" AS VARCHAR(").append(value.length()).append("))"); + } + }); + } + + @Override + protected void onLimitOffsetNode(Node parent, LimitOffsetNode child, int index) { + if(child.getLimit() == 0 && child.getOffset() == 0) { + return; + } + int from = child.getOffset() + 1; + int to = child.getLimit() == 0 ? Integer.MAX_VALUE : from + child.getLimit(); + replaceChild(parent, index, new FirebirdLimitNode(from, to)); + } + + @Override + protected void onInNode(Node parent, InNode child, int index) { + Node arg = child.getChild(0); + Node childNode = child.getChild(1); + if(childNode.getType() != NodeType.VALUE) { + return; + } + + ValueNode valueNode = (ValueNode)childNode; + Object value = valueNode.getValue(); + if(!value.getClass().isArray()) { + return; + } + + List<Node> newChildren = new ArrayList<>(); + + // need to slice for batches of 1500 values + if(value instanceof Object[]) { + for(Object[] slice : ArrayUtil.sliceArray((Object[])value, FIREBIRD_IN_BATCH_SIZE)) { + newChildren.add(newSliceNode(child, arg, valueNode, slice)); + } + } else if(value instanceof int[]) { + for(int[] slice : ArrayUtil.sliceArray((int[])value, FIREBIRD_IN_BATCH_SIZE)) { + newChildren.add(newSliceNode(child, arg, valueNode, slice)); + } + } else if(value instanceof long[]) { + for(long[] slice : ArrayUtil.sliceArray((long[])value, FIREBIRD_IN_BATCH_SIZE)) { + newChildren.add(newSliceNode(child, arg, valueNode, slice)); + } + } else if(value instanceof float[]) { + for(float[] slice : ArrayUtil.sliceArray((float[])value, FIREBIRD_IN_BATCH_SIZE)) { + newChildren.add(newSliceNode(child, arg, valueNode, slice)); + } + } else if(value instanceof double[]) { + for(double[] slice : ArrayUtil.sliceArray((double[])value, FIREBIRD_IN_BATCH_SIZE)) { + newChildren.add(newSliceNode(child, arg, valueNode, slice)); + } + } else if(value instanceof short[]) { + for(short[] slice : ArrayUtil.sliceArray((short[])value, FIREBIRD_IN_BATCH_SIZE)) { + newChildren.add(newSliceNode(child, arg, valueNode, slice)); + } + } else if(value instanceof char[]) { + for(char[] slice : ArrayUtil.sliceArray((char[])value, FIREBIRD_IN_BATCH_SIZE)) { + newChildren.add(newSliceNode(child, arg, valueNode, slice)); + } + } else if(value instanceof boolean[]) { + for(boolean[] slice : ArrayUtil.sliceArray((boolean[])value, FIREBIRD_IN_BATCH_SIZE)) { + newChildren.add(newSliceNode(child, arg, valueNode, slice)); + } + } else if(value instanceof byte[]) { + for(byte[] slice : ArrayUtil.sliceArray((byte[])value, FIREBIRD_IN_BATCH_SIZE)) { + newChildren.add(newSliceNode(child, arg, valueNode, slice)); + } + } + + ExpressionNodeBuilder exp = exp(node(newChildren.get(0))); + for(int i=1; i<newChildren.size(); i++) { + exp = exp.or(node(newChildren.get(i))); + } + parent.replaceChild(index, exp.build()); + } + + private InNode newSliceNode(InNode child, Node arg, ValueNode valueNode, Object slice) { + InNode nextNode = new InNode(child.isNot()); + nextNode.addChild(arg.deepCopy()); + nextNode.addChild(new ValueNode(slice, valueNode.isArray(), valueNode.getAttribute())); + return nextNode; + } + + @Override + protected void onFunctionNode(Node parent, FunctionNode child, int index) { + switch (child.getFunctionName()) { + case "LENGTH": + replaceChild(parent, index, new FunctionNode("CHAR_LENGTH", child.getAlias())); + break; + case "LOCATE": + replaceChild(parent, index, new FunctionNode("POSITION", child.getAlias())); + break; + case "CONCAT": + replaceChild(parent, index, new OpExpressionNode("||")); + break; + + case "SUBSTRING": + replaceChild(parent, index, new FirebirdSubstringFunctionNode(child.getAlias())); + break; + + case "YEAR": + case "MONTH": + case "DAY": + case "DAY_OF_MONTH": + case "DAY_OF_WEEK": + case "DAY_OF_YEAR": + case "WEEK": + case "HOUR": + case "MINUTE": + case "SECOND": + Node functionReplacement = new FunctionNode("EXTRACT", child.getAlias(), true) { + @Override + public void appendChildrenSeparator(QuotingAppendable buffer, int childIdx) { + buffer.append(' '); + } + }; + + String partName = child.getFunctionName(); + if("DAY_OF_MONTH".equals(partName)) { + partName = "DAY"; + } else if("DAY_OF_WEEK".equals(partName)) { + partName = "WEEKDAY"; + } else if("DAY_OF_YEAR".equals(partName)) { + partName = "YEARDAY"; + } + functionReplacement.addChild(new TextNode(partName + " FROM ")); + replaceChild(parent, index, functionReplacement); + break; + } + } + +}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/f6b2dac9/cayenne-server/src/main/java/org/apache/cayenne/dba/firebird/FirebirdSelectAction.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/firebird/FirebirdSelectAction.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/firebird/FirebirdSelectAction.java new file mode 100644 index 0000000..184a909 --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/firebird/FirebirdSelectAction.java @@ -0,0 +1,40 @@ +/***************************************************************** + * 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.cayenne.dba.firebird; + +import org.apache.cayenne.access.DataNode; +import org.apache.cayenne.access.jdbc.SelectAction; +import org.apache.cayenne.query.SQLAction; +import org.apache.cayenne.query.SelectQuery; + +/** + * @since 4.1 + */ +public class FirebirdSelectAction extends SelectAction { + + public FirebirdSelectAction(SelectQuery<?> query, DataNode dataNode) { + super(query, dataNode); + } + + @Override + protected int getInMemoryOffset(int queryOffset) { + return 0; + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/f6b2dac9/cayenne-server/src/main/java/org/apache/cayenne/dba/firebird/sqltree/FirebirdLimitNode.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/firebird/sqltree/FirebirdLimitNode.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/firebird/sqltree/FirebirdLimitNode.java new file mode 100644 index 0000000..9572e79 --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/firebird/sqltree/FirebirdLimitNode.java @@ -0,0 +1,50 @@ +/***************************************************************** + * 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.cayenne.dba.firebird.sqltree; + +import org.apache.cayenne.access.sqlbuilder.QuotingAppendable; +import org.apache.cayenne.access.sqlbuilder.sqltree.Node; + +/** + * @since 4.2 + */ +public class FirebirdLimitNode extends Node { + private final int from; + private final int to; + + public FirebirdLimitNode(int from, int to) { + this.from = from; + this.to = to; + } + + @Override + public QuotingAppendable append(QuotingAppendable buffer) { + buffer.append(" ROWS "); + if(from > 0) { + buffer.append(from).append(" TO "); + } + return buffer.append(to); + } + + @Override + public Node copy() { + return new FirebirdLimitNode(from, to); + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/f6b2dac9/cayenne-server/src/main/java/org/apache/cayenne/dba/firebird/sqltree/FirebirdSubstringFunctionNode.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/firebird/sqltree/FirebirdSubstringFunctionNode.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/firebird/sqltree/FirebirdSubstringFunctionNode.java new file mode 100644 index 0000000..f7fe3e1 --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/firebird/sqltree/FirebirdSubstringFunctionNode.java @@ -0,0 +1,65 @@ +/***************************************************************** + * 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.cayenne.dba.firebird.sqltree; + +import org.apache.cayenne.access.sqlbuilder.QuotingAppendable; +import org.apache.cayenne.access.sqlbuilder.sqltree.FunctionNode; +import org.apache.cayenne.access.sqlbuilder.sqltree.Node; + +/** + * SUBSTRING function for Firebird + * + * It has following format: + * + * SUBSTRING (string FROM CAST(? AS INTEGER) FOR CAST(? AS INTEGER)) + * + * @since 4.1 + */ +public class FirebirdSubstringFunctionNode extends FunctionNode { + public FirebirdSubstringFunctionNode(String alias) { + super("SUBSTRING", alias); + } + + @Override + public void appendChildrenSeparator(QuotingAppendable buffer, int childIdx) { + if(skipContent()) { + return; + } + if(childIdx == 0) { + buffer.append(" FROM CAST("); + } else if(childIdx == 1) { + buffer.append(" AS INTEGER) FOR CAST("); + } + } + + @Override + public void appendChildrenEnd(QuotingAppendable buffer) { + if(skipContent()) { + return; + } + buffer.append(" AS INTEGER)"); + super.appendChildrenEnd(buffer); + } + + @Override + public Node copy() { + return new FirebirdSubstringFunctionNode(getAlias()); + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/f6b2dac9/cayenne-server/src/main/java/org/apache/cayenne/dba/frontbase/FrontBaseAdapter.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/frontbase/FrontBaseAdapter.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/frontbase/FrontBaseAdapter.java index 69b9876..76d1db6 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/dba/frontbase/FrontBaseAdapter.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/frontbase/FrontBaseAdapter.java @@ -20,9 +20,7 @@ package org.apache.cayenne.dba.frontbase; import org.apache.cayenne.CayenneRuntimeException; -import org.apache.cayenne.access.translator.select.QualifierTranslator; -import org.apache.cayenne.access.translator.select.QueryAssembler; -import org.apache.cayenne.access.translator.select.SelectTranslator; +import org.apache.cayenne.access.sqlbuilder.sqltree.Node; import org.apache.cayenne.access.types.ExtendedType; import org.apache.cayenne.access.types.ExtendedTypeFactory; import org.apache.cayenne.access.types.ExtendedTypeMap; @@ -36,8 +34,6 @@ import org.apache.cayenne.dba.TypesMapping; import org.apache.cayenne.di.Inject; import org.apache.cayenne.map.DbAttribute; import org.apache.cayenne.map.DbEntity; -import org.apache.cayenne.map.EntityResolver; -import org.apache.cayenne.query.SelectQuery; import org.apache.cayenne.resource.ResourceLocator; import java.sql.Types; @@ -45,6 +41,7 @@ import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; +import java.util.function.Function; /** * DbAdapter implementation for <a href="http://www.frontbase.com/">FrontBase @@ -79,20 +76,12 @@ public class FrontBaseAdapter extends JdbcAdapter { setSupportsBatchUpdates(true); } - /** - * @since 4.0 - */ - @Override - public SelectTranslator getSelectTranslator(SelectQuery<?> query, EntityResolver entityResolver) { - return new FrontBaseSelectTranslator(query, this, entityResolver); - } - - /** - * @since 4.0 - */ + /** + * @since 4.2 + */ @Override - public QualifierTranslator getQualifierTranslator(QueryAssembler queryAssembler) { - return new FrontBaseQualifierTranslator(queryAssembler); + public Function<Node, Node> getSqlTreeProcessor() { + return new FrontBaseSQLTreeProcessor(); } @Override http://git-wip-us.apache.org/repos/asf/cayenne/blob/f6b2dac9/cayenne-server/src/main/java/org/apache/cayenne/dba/frontbase/FrontBaseQualifierTranslator.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/frontbase/FrontBaseQualifierTranslator.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/frontbase/FrontBaseQualifierTranslator.java deleted file mode 100644 index fa97c6d..0000000 --- a/cayenne-server/src/main/java/org/apache/cayenne/dba/frontbase/FrontBaseQualifierTranslator.java +++ /dev/null @@ -1,134 +0,0 @@ -/***************************************************************** - * 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.cayenne.dba.frontbase; - -import org.apache.cayenne.CayenneRuntimeException; -import org.apache.cayenne.access.translator.select.QualifierTranslator; -import org.apache.cayenne.access.translator.select.QueryAssembler; -import org.apache.cayenne.exp.Expression; -import org.apache.cayenne.exp.parser.ASTExtract; -import org.apache.cayenne.exp.parser.ASTFunctionCall; - -/** - * @since 4.0 - */ -public class FrontBaseQualifierTranslator extends QualifierTranslator { - - private int substringArg = 0; - - public FrontBaseQualifierTranslator(QueryAssembler queryAssembler) { - super(queryAssembler); - } - - @Override - protected void appendFunction(ASTFunctionCall functionExpression) { - switch (functionExpression.getFunctionName()) { - case "CONCAT": - // noop - break; - case "LOCATE": - out.append("POSITION"); - break; - case "LENGTH": - out.append("CHAR_LENGTH"); - break; - case "SUBSTRING": - substringArg = 0; - default: - super.appendFunction(functionExpression); - } - } - - @Override - protected void appendFunctionArgDivider(ASTFunctionCall functionExpression) { - switch (functionExpression.getFunctionName()) { - case "CONCAT": - out.append(" || "); - break; - case "LOCATE": - out.append(" IN "); - break; - case "SUBSTRING": - // SUBSTRING (str FROM offset FOR length) - switch (substringArg++) { - case 0: - out.append(" FROM "); - break; - case 1: - out.append(" FOR "); - break; - } - break; - default: - super.appendFunctionArgDivider(functionExpression); - } - } - - @Override - protected void clearLastFunctionArgDivider(ASTFunctionCall functionExpression) { - switch (functionExpression.getFunctionName()) { - case "CONCAT": - out.delete(out.length() - " || ".length(), out.length()); - break; - case "LOCATE": - out.delete(out.length() - " IN ".length(), out.length()); - break; - case "SUBSTRING": - // no offset arg - if(substringArg == 2) { - out.delete(out.length() - " FOR ".length(), out.length()); - } - break; - default: - super.clearLastFunctionArgDivider(functionExpression); - } - if(functionExpression instanceof ASTExtract) { - out.append(")"); - } - } - - @Override - protected boolean parenthesisNeeded(Expression node, Expression parentNode) { - if (node.getType() == Expression.FUNCTION_CALL) { - if (node instanceof ASTExtract) { - return false; - } - } - - return super.parenthesisNeeded(node, parentNode); - } - - @Override - protected void appendExtractFunction(ASTExtract functionExpression) { - out.append("EXTRACT("); - switch (functionExpression.getPart()) { - case DAY_OF_WEEK: - case DAY_OF_YEAR: - case WEEK: - throw new CayenneRuntimeException("Function %s() is unsupported in FrontBase.", functionExpression.getPartCamelCaseName()); - case DAY_OF_MONTH: - out.append("DAY"); - break; - default: - out.append(functionExpression.getPart().name()); - } - out.append(" FROM "); - } -} http://git-wip-us.apache.org/repos/asf/cayenne/blob/f6b2dac9/cayenne-server/src/main/java/org/apache/cayenne/dba/frontbase/FrontBaseSQLTreeProcessor.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/frontbase/FrontBaseSQLTreeProcessor.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/frontbase/FrontBaseSQLTreeProcessor.java new file mode 100644 index 0000000..4fce3d7 --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/frontbase/FrontBaseSQLTreeProcessor.java @@ -0,0 +1,104 @@ +/***************************************************************** + * 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.cayenne.dba.frontbase; + +import org.apache.cayenne.CayenneRuntimeException; +import org.apache.cayenne.access.sqlbuilder.QuotingAppendable; +import org.apache.cayenne.access.sqlbuilder.sqltree.FunctionNode; +import org.apache.cayenne.access.sqlbuilder.sqltree.Node; +import org.apache.cayenne.access.sqlbuilder.sqltree.OpExpressionNode; +import org.apache.cayenne.access.sqlbuilder.sqltree.TextNode; +import org.apache.cayenne.access.translator.select.BaseSQLTreeProcessor; + +/** + * @since 4.2 + */ +public class FrontBaseSQLTreeProcessor extends BaseSQLTreeProcessor { + + @Override + protected void onFunctionNode(Node parent, FunctionNode child, int index) { + switch (child.getFunctionName()) { + case "CONCAT": + replaceChild(parent, index, new OpExpressionNode("||")); + break; + case "LOCATE": + // POSITION (substr IN str) + replaceChild(parent, index, new FunctionNode("POSITION", child.getAlias()) { + @Override + public void appendChildrenSeparator(QuotingAppendable buffer, int childIdx) { + buffer.append(" IN "); + } + }); + break; + case "LENGTH": + replaceChild(parent, index, new FunctionNode("CHAR_LENGTH", child.getAlias())); + break; + case "SUBSTRING": + // SUBSTRING (str FROM offset FOR length) + replaceChild(parent, index, new FunctionNode("SUBSTRING", child.getAlias()){ + @Override + public void appendChildrenSeparator(QuotingAppendable buffer, int childIdx) { + if(childIdx == 0) { + buffer.append(" FROM "); + } else if(childIdx == 1) { + buffer.append(" FOR "); + } + } + }); + break; + case "YEAR": + case "MONTH": + case "DAY": + case "DAY_OF_MONTH": + case "HOUR": + case "MINUTE": + case "SECOND": + Node functionReplacement = new ExtractFunctionNode(child.getAlias()); + String functionName = child.getFunctionName(); + if("DAY_OF_MONTH".equals(functionName)) { + functionName = "DAY"; + } + functionReplacement.addChild(new TextNode(functionName)); + replaceChild(parent, index, functionReplacement); + break; + + case "DAY_OF_WEEK": + case "DAY_OF_YEAR": + case "WEEK": + throw new CayenneRuntimeException("Function %s() is unsupported in FrontBase.", child.getFunctionName()); + } + } + + private static class ExtractFunctionNode extends FunctionNode { + public ExtractFunctionNode(String alias) { + super("EXTRACT", alias, true); + } + + @Override + public void appendChildrenSeparator(QuotingAppendable buffer, int childIdx) { + buffer.append(" FROM "); + } + + @Override + public Node copy() { + return new ExtractFunctionNode(getAlias()); + } + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/f6b2dac9/cayenne-server/src/main/java/org/apache/cayenne/dba/frontbase/FrontBaseSelectTranslator.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/frontbase/FrontBaseSelectTranslator.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/frontbase/FrontBaseSelectTranslator.java deleted file mode 100644 index 1e71f5f..0000000 --- a/cayenne-server/src/main/java/org/apache/cayenne/dba/frontbase/FrontBaseSelectTranslator.java +++ /dev/null @@ -1,52 +0,0 @@ -/***************************************************************** - * 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.cayenne.dba.frontbase; - -import org.apache.cayenne.access.translator.select.DefaultSelectTranslator; -import org.apache.cayenne.dba.DbAdapter; -import org.apache.cayenne.map.EntityResolver; -import org.apache.cayenne.query.Query; - -/** - * @since 1.2 - */ -class FrontBaseSelectTranslator extends DefaultSelectTranslator { - - static final String SELECT_PREFIX = "SELECT"; - - /** - * @since 4.0 - */ - public FrontBaseSelectTranslator(Query query, DbAdapter adapter, EntityResolver entityResolver) { - super(query, adapter, entityResolver); - } - - @Override - protected void appendLimitAndOffsetClauses(StringBuilder buffer) { - - int limit = queryMetadata.getFetchLimit(); - if (limit > 0 && buffer.length() > SELECT_PREFIX.length()) { - - if (SELECT_PREFIX.equals(buffer.substring(0, SELECT_PREFIX.length()))) { - buffer.insert(SELECT_PREFIX.length(), " TOP " + limit); - } - } - } -} http://git-wip-us.apache.org/repos/asf/cayenne/blob/f6b2dac9/cayenne-server/src/main/java/org/apache/cayenne/dba/h2/H2ActionBuilder.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/h2/H2ActionBuilder.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/h2/H2ActionBuilder.java new file mode 100644 index 0000000..2cf2a10 --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/h2/H2ActionBuilder.java @@ -0,0 +1,39 @@ +/***************************************************************** + * 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.cayenne.dba.h2; + +import org.apache.cayenne.access.DataNode; +import org.apache.cayenne.dba.JdbcActionBuilder; +import org.apache.cayenne.query.SQLAction; +import org.apache.cayenne.query.SelectQuery; + +/** + * @since 4.1 + */ +public class H2ActionBuilder extends JdbcActionBuilder { + public H2ActionBuilder(DataNode node) { + super(node); + } + + @Override + public <T> SQLAction objectSelectAction(SelectQuery<T> query) { + return new H2SelectAction(query, dataNode); + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/f6b2dac9/cayenne-server/src/main/java/org/apache/cayenne/dba/h2/H2Adapter.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/h2/H2Adapter.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/h2/H2Adapter.java index 6b47636..39cc43c 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/dba/h2/H2Adapter.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/h2/H2Adapter.java @@ -19,6 +19,8 @@ package org.apache.cayenne.dba.h2; +import org.apache.cayenne.access.DataNode; +import org.apache.cayenne.access.sqlbuilder.sqltree.Node; import org.apache.cayenne.access.types.ExtendedType; import org.apache.cayenne.access.types.ExtendedTypeFactory; import org.apache.cayenne.access.types.ValueObjectTypeRegistry; @@ -28,9 +30,12 @@ import org.apache.cayenne.dba.JdbcAdapter; import org.apache.cayenne.dba.PkGenerator; import org.apache.cayenne.di.Inject; import org.apache.cayenne.map.DbAttribute; +import org.apache.cayenne.query.Query; +import org.apache.cayenne.query.SQLAction; import org.apache.cayenne.resource.ResourceLocator; import java.util.List; +import java.util.function.Function; /** * DbAdapter implementation for <a href="http://www.h2database.com/">H2 @@ -66,6 +71,19 @@ public class H2Adapter extends JdbcAdapter { } } + /** + * @since 4.2 + */ + @Override + public Function<Node, Node> getSqlTreeProcessor() { + return new H2SQLTreeProcessor(); + } + + @Override + public SQLAction getAction(Query query, DataNode node) { + return query.createSQLAction(new H2ActionBuilder(node)); + } + @Override protected PkGenerator createPkGenerator() { return new H2PkGenerator(this); http://git-wip-us.apache.org/repos/asf/cayenne/blob/f6b2dac9/cayenne-server/src/main/java/org/apache/cayenne/dba/h2/H2SQLTreeProcessor.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/h2/H2SQLTreeProcessor.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/h2/H2SQLTreeProcessor.java new file mode 100644 index 0000000..cd797f5 --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/h2/H2SQLTreeProcessor.java @@ -0,0 +1,37 @@ +/***************************************************************** + * 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.cayenne.dba.h2; + +import org.apache.cayenne.access.sqlbuilder.sqltree.LimitOffsetNode; +import org.apache.cayenne.access.sqlbuilder.sqltree.Node; +import org.apache.cayenne.access.sqlbuilder.sqltree.OffsetFetchNextNode; +import org.apache.cayenne.access.translator.select.BaseSQLTreeProcessor; + +/** + * @since 4.2 + */ +public class H2SQLTreeProcessor extends BaseSQLTreeProcessor { + + @Override + protected void onLimitOffsetNode(Node parent, LimitOffsetNode child, int index) { + replaceChild(parent, index, new OffsetFetchNextNode(child), false); + } + +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/f6b2dac9/cayenne-server/src/main/java/org/apache/cayenne/dba/h2/H2SelectAction.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/h2/H2SelectAction.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/h2/H2SelectAction.java new file mode 100644 index 0000000..df7380d --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/h2/H2SelectAction.java @@ -0,0 +1,39 @@ +/***************************************************************** + * 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.cayenne.dba.h2; + +import org.apache.cayenne.access.DataNode; +import org.apache.cayenne.access.jdbc.SelectAction; +import org.apache.cayenne.query.SelectQuery; + +/** + * @since 4.1 + */ +public class H2SelectAction extends SelectAction { + + public H2SelectAction(SelectQuery<?> query, DataNode dataNode) { + super(query, dataNode); + } + + @Override + protected int getInMemoryOffset(int queryOffset) { + return 0; + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/f6b2dac9/cayenne-server/src/main/java/org/apache/cayenne/dba/hsqldb/HSQLDBAdapter.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/hsqldb/HSQLDBAdapter.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/hsqldb/HSQLDBAdapter.java index 64c59b3..99f4ae0 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/dba/hsqldb/HSQLDBAdapter.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/hsqldb/HSQLDBAdapter.java @@ -21,12 +21,9 @@ package org.apache.cayenne.dba.hsqldb; import org.apache.cayenne.CayenneRuntimeException; import org.apache.cayenne.access.DataNode; -import org.apache.cayenne.access.translator.ParameterBinding; +import org.apache.cayenne.access.sqlbuilder.sqltree.Node; import org.apache.cayenne.access.translator.ejbql.EJBQLTranslatorFactory; import org.apache.cayenne.access.translator.ejbql.JdbcEJBQLTranslatorFactory; -import org.apache.cayenne.access.translator.select.QualifierTranslator; -import org.apache.cayenne.access.translator.select.QueryAssembler; -import org.apache.cayenne.access.translator.select.SelectTranslator; import org.apache.cayenne.access.types.CharType; import org.apache.cayenne.access.types.ExtendedType; import org.apache.cayenne.access.types.ExtendedTypeFactory; @@ -40,18 +37,15 @@ import org.apache.cayenne.map.DbAttribute; import org.apache.cayenne.map.DbEntity; import org.apache.cayenne.map.DbJoin; import org.apache.cayenne.map.DbRelationship; -import org.apache.cayenne.map.EntityResolver; import org.apache.cayenne.query.Query; import org.apache.cayenne.query.SQLAction; -import org.apache.cayenne.query.SelectQuery; import org.apache.cayenne.resource.ResourceLocator; -import java.sql.PreparedStatement; -import java.sql.SQLException; import java.sql.Types; import java.util.Collection; import java.util.Iterator; import java.util.List; +import java.util.function.Function; /** * DbAdapter implementation for the <a href="http://hsqldb.sourceforge.net/"> @@ -91,22 +85,11 @@ public class HSQLDBAdapter extends JdbcAdapter { } /** - * @since 4.0 - */ - @Override - public SelectTranslator getSelectTranslator(SelectQuery<?> query, EntityResolver entityResolver) { - return new HSQLSelectTranslator(query, this, entityResolver); - } - - /** - * Returns a trimming translator. - * @since 4.0 + * @since 4.2 */ @Override - public QualifierTranslator getQualifierTranslator(QueryAssembler queryAssembler) { - QualifierTranslator translator = new HSQLQualifierTranslator(queryAssembler); - translator.setCaseInsensitive(caseInsensitiveCollations); - return translator; + public Function<Node, Node> getSqlTreeProcessor() { + return new HSQLTreeProcessor(); } /** http://git-wip-us.apache.org/repos/asf/cayenne/blob/f6b2dac9/cayenne-server/src/main/java/org/apache/cayenne/dba/hsqldb/HSQLQualifierTranslator.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/hsqldb/HSQLQualifierTranslator.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/hsqldb/HSQLQualifierTranslator.java deleted file mode 100644 index fce980c..0000000 --- a/cayenne-server/src/main/java/org/apache/cayenne/dba/hsqldb/HSQLQualifierTranslator.java +++ /dev/null @@ -1,86 +0,0 @@ -/***************************************************************** - * 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.cayenne.dba.hsqldb; - -import java.io.IOException; - -import org.apache.cayenne.CayenneRuntimeException; -import org.apache.cayenne.access.translator.select.QueryAssembler; -import org.apache.cayenne.access.translator.select.TrimmingQualifierTranslator; -import org.apache.cayenne.exp.parser.ASTExtract; -import org.apache.cayenne.exp.parser.ASTFunctionCall; -import org.apache.cayenne.exp.parser.PatternMatchNode; - -/** - * @since 4.0 - */ -public class HSQLQualifierTranslator extends TrimmingQualifierTranslator { - - public HSQLQualifierTranslator(QueryAssembler queryAssembler) { - super(queryAssembler, HSQLDBAdapter.TRIM_FUNCTION); - } - - @Override - protected void appendLikeEscapeCharacter(PatternMatchNode patternMatchNode) - throws IOException { - - char escapeChar = patternMatchNode.getEscapeChar(); - - if ('?' == escapeChar) { - throw new CayenneRuntimeException("the escape character of '?' is illegal for LIKE clauses."); - } - - if (0 != escapeChar) { - // this is a difference with super implementation - HSQL driver seems does not - // support JDBC escape syntax, so creating an explicit SQL escape: - out.append(" ESCAPE '"); - out.append(escapeChar); - out.append("'"); - } - } - - @Override - protected void appendFunction(ASTFunctionCall functionExpression) { - // from documentation: - // CURRENT_TIME returns a value of TIME WITH TIME ZONE type. - // LOCALTIME returns a value of TIME type. - // CURTIME() is a synonym for LOCALTIME. - // use LOCALTIME to better align with other DBs - if("CURRENT_TIME".equals(functionExpression.getFunctionName())) { - out.append("LOCALTIME"); - } else { - super.appendFunction(functionExpression); - } - } - - @Override - protected void appendExtractFunction(ASTExtract functionExpression) { - switch (functionExpression.getPart()) { - case DAY_OF_WEEK: - case DAY_OF_MONTH: - case DAY_OF_YEAR: - // hsqldb variants are without '_' - out.append(functionExpression.getPart().name().replace("_", "")); - break; - default: - appendFunction(functionExpression); - } - } -} http://git-wip-us.apache.org/repos/asf/cayenne/blob/f6b2dac9/cayenne-server/src/main/java/org/apache/cayenne/dba/hsqldb/HSQLSelectTranslator.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/hsqldb/HSQLSelectTranslator.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/hsqldb/HSQLSelectTranslator.java deleted file mode 100644 index ce3bb58..0000000 --- a/cayenne-server/src/main/java/org/apache/cayenne/dba/hsqldb/HSQLSelectTranslator.java +++ /dev/null @@ -1,57 +0,0 @@ -/***************************************************************** - * 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.cayenne.dba.hsqldb; - -import org.apache.cayenne.access.translator.select.DefaultSelectTranslator; -import org.apache.cayenne.dba.DbAdapter; -import org.apache.cayenne.map.EntityResolver; -import org.apache.cayenne.query.Query; - -/** - * @since 1.2 - */ -class HSQLSelectTranslator extends DefaultSelectTranslator { - - /** - * @since 4.0 - */ - public HSQLSelectTranslator(Query query, DbAdapter adapter, EntityResolver entityResolver) { - super(query, adapter, entityResolver); - } - - @Override - protected void appendLimitAndOffsetClauses(StringBuilder buffer) { - int offset = queryMetadata.getFetchOffset(); - int limit = queryMetadata.getFetchLimit(); - - if (offset > 0 || limit > 0) { - buffer.append(" LIMIT "); - - // both OFFSET and LIMIT must be present, so come up with defaults - // if one of - // them is not set by the user - if (limit == 0) { - limit = Integer.MAX_VALUE; - } - - buffer.append(limit).append(" OFFSET ").append(offset); - } - } -} http://git-wip-us.apache.org/repos/asf/cayenne/blob/f6b2dac9/cayenne-server/src/main/java/org/apache/cayenne/dba/hsqldb/HSQLTreeProcessor.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/hsqldb/HSQLTreeProcessor.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/hsqldb/HSQLTreeProcessor.java new file mode 100644 index 0000000..152f3ca --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/hsqldb/HSQLTreeProcessor.java @@ -0,0 +1,70 @@ +/***************************************************************** + * 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.cayenne.dba.hsqldb; + +import org.apache.cayenne.access.sqlbuilder.sqltree.ColumnNode; +import org.apache.cayenne.access.sqlbuilder.sqltree.FunctionNode; +import org.apache.cayenne.access.sqlbuilder.sqltree.Node; +import org.apache.cayenne.access.sqlbuilder.sqltree.OpExpressionNode; +import org.apache.cayenne.access.translator.select.BaseSQLTreeProcessor; +import org.apache.cayenne.access.sqlbuilder.sqltree.TrimmingColumnNode; + +/** + * @since 4.2 + */ +public class HSQLTreeProcessor extends BaseSQLTreeProcessor { + + @Override + protected void onColumnNode(Node parent, ColumnNode child, int index) { + replaceChild(parent, index, new TrimmingColumnNode(child)); + } + + @Override + protected void onFunctionNode(Node parent, FunctionNode child, int index) { + Node replacement = getReplacementForFunction(child); + if(replacement != null) { + replaceChild(parent, index, replacement); + } + } + + private Node getReplacementForFunction(FunctionNode child) { + switch (child.getFunctionName()) { + case "DAY_OF_MONTH": + case "DAY_OF_WEEK": + case "DAY_OF_YEAR": + // hsqldb variants are without '_' + return new FunctionNode(child.getFunctionName().replace("_", ""), child.getAlias(), true); + + case "CURRENT_DATE": + case "CURRENT_TIMESTAMP": + return new FunctionNode(child.getFunctionName(), child.getAlias(), false); + case "CURRENT_TIME": + // from documentation: + // CURRENT_TIME returns a value of TIME WITH TIME ZONE type. + // LOCALTIME returns a value of TIME type. + // CURTIME() is a synonym for LOCALTIME. + // use LOCALTIME to better align with other DBs + return new FunctionNode("LOCALTIME", child.getAlias(), false); + case "CONCAT": + return new OpExpressionNode("||"); + } + return null; + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/f6b2dac9/cayenne-server/src/main/java/org/apache/cayenne/dba/ingres/IngresAdapter.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/ingres/IngresAdapter.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/ingres/IngresAdapter.java index 60a39b6..08c156d 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/dba/ingres/IngresAdapter.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/ingres/IngresAdapter.java @@ -21,11 +21,8 @@ package org.apache.cayenne.dba.ingres; import org.apache.cayenne.CayenneRuntimeException; import org.apache.cayenne.access.DataNode; +import org.apache.cayenne.access.sqlbuilder.sqltree.Node; import org.apache.cayenne.access.translator.ParameterBinding; -import org.apache.cayenne.access.translator.select.QualifierTranslator; -import org.apache.cayenne.access.translator.select.QueryAssembler; -import org.apache.cayenne.access.translator.select.SelectTranslator; -import org.apache.cayenne.access.translator.select.TrimmingQualifierTranslator; import org.apache.cayenne.access.types.ExtendedType; import org.apache.cayenne.access.types.ExtendedTypeFactory; import org.apache.cayenne.access.types.ExtendedTypeMap; @@ -37,16 +34,15 @@ import org.apache.cayenne.dba.PkGenerator; import org.apache.cayenne.dba.TypesMapping; import org.apache.cayenne.di.Inject; import org.apache.cayenne.map.DbAttribute; -import org.apache.cayenne.map.EntityResolver; import org.apache.cayenne.query.Query; import org.apache.cayenne.query.SQLAction; -import org.apache.cayenne.query.SelectQuery; import org.apache.cayenne.resource.ResourceLocator; import java.sql.PreparedStatement; import java.sql.SQLException; import java.sql.Types; import java.util.List; +import java.util.function.Function; /** * DbAdapter implementation for <a @@ -75,17 +71,12 @@ public class IngresAdapter extends JdbcAdapter { setSupportsGeneratedKeys(true); } - /** - * @since 4.0 - */ - @Override - public SelectTranslator getSelectTranslator(SelectQuery<?> query, EntityResolver entityResolver) { - return new IngresSelectTranslator(query, this, entityResolver); - } - + /** + * @since 4.2 + */ @Override - public QualifierTranslator getQualifierTranslator(QueryAssembler queryAssembler) { - return new IngresQualifierTranslator(queryAssembler); + public Function<Node, Node> getSqlTreeProcessor() { + return new IngressSQLTreeProcessor(); } @Override http://git-wip-us.apache.org/repos/asf/cayenne/blob/f6b2dac9/cayenne-server/src/main/java/org/apache/cayenne/dba/ingres/IngresQualifierTranslator.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/ingres/IngresQualifierTranslator.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/ingres/IngresQualifierTranslator.java deleted file mode 100644 index 8334ff4..0000000 --- a/cayenne-server/src/main/java/org/apache/cayenne/dba/ingres/IngresQualifierTranslator.java +++ /dev/null @@ -1,122 +0,0 @@ -/***************************************************************** - * 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.cayenne.dba.ingres; - -import java.io.IOException; - -import org.apache.cayenne.access.translator.select.QueryAssembler; -import org.apache.cayenne.access.translator.select.TrimmingQualifierTranslator; -import org.apache.cayenne.exp.Expression; -import org.apache.cayenne.exp.parser.ASTExtract; -import org.apache.cayenne.exp.parser.ASTFunctionCall; -import org.apache.cayenne.exp.parser.Node; - -/** - * @since 4.0 - */ -class IngresQualifierTranslator extends TrimmingQualifierTranslator { - - IngresQualifierTranslator(QueryAssembler queryAssembler) { - super(queryAssembler, IngresAdapter.TRIM_FUNCTION); - } - - @Override - public void endNode(Expression node, Expression parentNode) { - super.endNode(node, parentNode); - if(node.getType() == Expression.FUNCTION_CALL) { - if("LOCATE".equals(((ASTFunctionCall)node).getFunctionName())) { - // order of args in ingres version of LOCATE is different, so swap them back - swapNodeChildren((ASTFunctionCall)node, 0, 1); - } - } - } - - @Override - protected void appendFunction(ASTFunctionCall functionExpression) { - if("CONCAT".equals(functionExpression.getFunctionName())) { - // noop - } else if("LOCATE".equals(functionExpression.getFunctionName())) { - // order of args in ingres version of LOCATE is different - // LOCATE(substr, str) -> LOCATE(str, substr) - out.append("LOCATE"); - swapNodeChildren(functionExpression, 0, 1); - } else if("TRIM".equals(functionExpression.getFunctionName())) { - // simple TRIM removes only trailing spaces - out.append("LTRIM(RTRIM"); - } else { - super.appendFunction(functionExpression); - } - } - - @Override - protected void appendFunctionArgDivider(ASTFunctionCall functionExpression) { - if("CONCAT".equals(functionExpression.getFunctionName())) { - out.append(" + "); - } else { - super.appendFunctionArgDivider(functionExpression); - } - } - - @Override - protected void appendFunctionArg(Object value, ASTFunctionCall functionExpression) throws IOException { - if("SUBSTRING".equals(functionExpression.getFunctionName())) { - out.append("CAST("); - super.appendFunctionArg(value, functionExpression); - clearLastFunctionArgDivider(functionExpression); - out.append(" AS INTEGER)"); - appendFunctionArgDivider(functionExpression); - } else { - super.appendFunctionArg(value, functionExpression); - } - } - - @Override - protected void clearLastFunctionArgDivider(ASTFunctionCall functionExpression) { - if("CONCAT".equals(functionExpression.getFunctionName())) { - out.delete(out.length() - " + ".length(), out.length()); - } else { - super.clearLastFunctionArgDivider(functionExpression); - if("TRIM".equals(functionExpression.getFunctionName())) { - out.append(")"); - } - } - } - - @Override - protected void appendExtractFunction(ASTExtract functionExpression) { - switch (functionExpression.getPart()) { - case DAY_OF_WEEK: - case DAY_OF_MONTH: - case DAY_OF_YEAR: - // ingres variants are without '_' - out.append(functionExpression.getPart().name().replace("_", "")); - break; - default: - appendFunction(functionExpression); - } - } - - private void swapNodeChildren(Node node, int i, int j) { - Node ni = node.jjtGetChild(i); - Node nj = node.jjtGetChild(j); - node.jjtAddChild(ni, j); - node.jjtAddChild(nj, i); - } -} http://git-wip-us.apache.org/repos/asf/cayenne/blob/f6b2dac9/cayenne-server/src/main/java/org/apache/cayenne/dba/ingres/IngresSelectTranslator.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/ingres/IngresSelectTranslator.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/ingres/IngresSelectTranslator.java deleted file mode 100644 index f466d5f..0000000 --- a/cayenne-server/src/main/java/org/apache/cayenne/dba/ingres/IngresSelectTranslator.java +++ /dev/null @@ -1,49 +0,0 @@ -/***************************************************************** - * 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.cayenne.dba.ingres; - -import org.apache.cayenne.access.translator.select.DefaultSelectTranslator; -import org.apache.cayenne.dba.DbAdapter; -import org.apache.cayenne.map.EntityResolver; -import org.apache.cayenne.query.Query; - -public class IngresSelectTranslator extends DefaultSelectTranslator { - - /** - * @since 4.0 - */ - public IngresSelectTranslator(Query query, DbAdapter adapter, EntityResolver entityResolver) { - super(query, adapter, entityResolver); - } - - @Override - protected void appendLimitAndOffsetClauses(StringBuilder buffer) { - // limit results - int offset = queryMetadata.getFetchOffset(); - int limit = queryMetadata.getFetchLimit(); - - if (offset > 0) { - buffer.append(" OFFSET ").append(offset); - } - - if (limit > 0) { - buffer.append(" FETCH NEXT ").append(limit).append(" ROWS ONLY "); - } - } -} http://git-wip-us.apache.org/repos/asf/cayenne/blob/f6b2dac9/cayenne-server/src/main/java/org/apache/cayenne/dba/ingres/IngressSQLTreeProcessor.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/ingres/IngressSQLTreeProcessor.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/ingres/IngressSQLTreeProcessor.java new file mode 100644 index 0000000..02a21fd --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/ingres/IngressSQLTreeProcessor.java @@ -0,0 +1,108 @@ +/***************************************************************** + * 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.cayenne.dba.ingres; + +import org.apache.cayenne.access.sqlbuilder.QuotingAppendable; +import org.apache.cayenne.access.sqlbuilder.sqltree.ColumnNode; +import org.apache.cayenne.access.sqlbuilder.sqltree.FunctionNode; +import org.apache.cayenne.access.sqlbuilder.sqltree.LimitOffsetNode; +import org.apache.cayenne.access.sqlbuilder.sqltree.Node; +import org.apache.cayenne.access.sqlbuilder.sqltree.OffsetFetchNextNode; +import org.apache.cayenne.access.sqlbuilder.sqltree.OpExpressionNode; +import org.apache.cayenne.access.sqlbuilder.sqltree.TrimmingColumnNode; +import org.apache.cayenne.access.translator.select.BaseSQLTreeProcessor; + +/** + * @since 4.2 + */ +public class IngressSQLTreeProcessor extends BaseSQLTreeProcessor { + + @Override + protected void onColumnNode(Node parent, ColumnNode child, int index) { + replaceChild(parent, index, new TrimmingColumnNode(child)); + } + + @Override + protected void onLimitOffsetNode(Node parent, LimitOffsetNode child, int index) { + replaceChild(parent, index, new OffsetFetchNextNode(child) { + @Override + public QuotingAppendable append(QuotingAppendable buffer) { + // OFFSET X FETCH NEXT Y ROWS ONLY + if(offset > 0) { + buffer.append("OFFSET ").append(offset); + } + if(limit > 0) { + buffer.append("FETCH NEXT ").append(limit).append(" ROWS ONLY"); + } + return buffer; + } + }); + } + + @Override + protected void onFunctionNode(Node parent, FunctionNode child, int index) { + switch (child.getFunctionName()) { + case "CONCAT": + replaceChild(parent, index, new OpExpressionNode("+")); + return; + case "LOCATE": + Node child0 = child.getChild(0); + child.replaceChild(0, child.getChild(1)); + child.replaceChild(1, child0); + return; + case "SUBSTRING": + Node replacement = new FunctionNode("SUBSTRING", child.getAlias(), true) { + @Override + public void appendChildrenSeparator(QuotingAppendable buffer, int childIdx) { + // 0, CAST(1 AS INTEGER), CAST(2 AS INTEGER) + if(childIdx == 1 || childIdx == 2) { + buffer.append(" AS INTEGER)"); + } + if(childIdx == 0 || childIdx == 1) { + buffer.append(", CAST("); + } + } + + @Override + public void appendChildrenEnd(QuotingAppendable buffer) { + buffer.append(" AS INTEGER)"); + super.appendChildrenEnd(buffer); + } + }; + replaceChild(parent, index, replacement); + return; + case "TRIM": + replaceChild(parent, index, new FunctionNode("RTRIM(LTRIM", child.getAlias(), true) { + @Override + public void appendChildrenEnd(QuotingAppendable buffer) { + buffer.append(')'); + super.appendChildrenEnd(buffer); + } + }); + return; + case "DAY_OF_WEEK": + case "DAY_OF_MONTH": + case "DAY_OF_YEAR": + // ingres variants are without '_' + replaceChild(parent, index, new FunctionNode(child.getFunctionName().replace("_", ""), child.getAlias(), true)); + return; + } + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/f6b2dac9/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/MySQLAdapter.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/MySQLAdapter.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/MySQLAdapter.java index b50fbc0..5230990 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/MySQLAdapter.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/MySQLAdapter.java @@ -21,12 +21,10 @@ package org.apache.cayenne.dba.mysql; import org.apache.cayenne.CayenneRuntimeException; import org.apache.cayenne.access.DataNode; +import org.apache.cayenne.access.sqlbuilder.sqltree.Node; import org.apache.cayenne.access.translator.ParameterBinding; import org.apache.cayenne.access.translator.ejbql.EJBQLTranslatorFactory; import org.apache.cayenne.access.translator.ejbql.JdbcEJBQLTranslatorFactory; -import org.apache.cayenne.access.translator.select.QualifierTranslator; -import org.apache.cayenne.access.translator.select.QueryAssembler; -import org.apache.cayenne.access.translator.select.SelectTranslator; import org.apache.cayenne.access.types.ByteArrayType; import org.apache.cayenne.access.types.CharType; import org.apache.cayenne.access.types.ExtendedType; @@ -43,10 +41,8 @@ import org.apache.cayenne.dba.TypesMapping; import org.apache.cayenne.di.Inject; import org.apache.cayenne.map.DbAttribute; import org.apache.cayenne.map.DbEntity; -import org.apache.cayenne.map.EntityResolver; import org.apache.cayenne.query.Query; import org.apache.cayenne.query.SQLAction; -import org.apache.cayenne.query.SelectQuery; import org.apache.cayenne.resource.ResourceLocator; import java.sql.PreparedStatement; @@ -59,6 +55,7 @@ import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; +import java.util.function.Function; /** * DbAdapter implementation for <a href="http://www.mysql.com">MySQL RDBMS</a>. @@ -109,16 +106,12 @@ public class MySQLAdapter extends JdbcAdapter { return new DefaultQuotingStrategy("`", "`"); } + /** + * @since 4.2 + */ @Override - public SelectTranslator getSelectTranslator(SelectQuery<?> query, EntityResolver entityResolver) { - return new MySQLSelectTranslator(query, this, entityResolver); - } - - @Override - public QualifierTranslator getQualifierTranslator(QueryAssembler queryAssembler) { - QualifierTranslator translator = new MySQLQualifierTranslator(queryAssembler); - translator.setCaseInsensitive(caseInsensitiveCollations); - return translator; + public Function<Node, Node> getSqlTreeProcessor() { + return MySQLTreeProcessor.getInstance(); } /** http://git-wip-us.apache.org/repos/asf/cayenne/blob/f6b2dac9/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/MySQLQualifierTranslator.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/MySQLQualifierTranslator.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/MySQLQualifierTranslator.java deleted file mode 100644 index 2b93c22..0000000 --- a/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/MySQLQualifierTranslator.java +++ /dev/null @@ -1,105 +0,0 @@ -/***************************************************************** - * 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.cayenne.dba.mysql; - -import java.io.IOException; - -import org.apache.cayenne.CayenneRuntimeException; -import org.apache.cayenne.access.translator.select.QualifierTranslator; -import org.apache.cayenne.access.translator.select.QueryAssembler; -import org.apache.cayenne.exp.Expression; -import org.apache.cayenne.exp.parser.ASTExtract; -import org.apache.cayenne.exp.parser.PatternMatchNode; - -class MySQLQualifierTranslator extends QualifierTranslator { - - public MySQLQualifierTranslator(QueryAssembler queryAssembler) { - super(queryAssembler); - } - - @Override - protected void appendLikeEscapeCharacter(PatternMatchNode patternMatchNode) - throws IOException { - - char escapeChar = patternMatchNode.getEscapeChar(); - - if ('?' == escapeChar) { - throw new CayenneRuntimeException("the escape character of '?' is illegal for LIKE clauses."); - } - - if (0 != escapeChar) { - // this is a difference with super implementation - MySQL driver does not - // support JDBC escape syntax, so creating an explicit SQL escape: - out.append(" ESCAPE '"); - out.append(escapeChar); - out.append("'"); - } - } - - @Override - public void finishedChild(Expression node, int childIndex, boolean hasMoreChildren) { - - if (!caseInsensitive) { - super.finishedChild(node, childIndex, hasMoreChildren); - } - else { - - if (!hasMoreChildren) { - return; - } - - // if we have something except LIKE or NOT LIKE then no need in specific handling - if (node.getType() != Expression.LIKE - && node.getType() != Expression.NOT_LIKE) { - super.finishedChild(node, childIndex, hasMoreChildren); - return; - } - - try { - Appendable out = (matchingObject) ? new StringBuilder() : this.out; - - switch (node.getType()) { - case Expression.LIKE: - out.append(" LIKE BINARY "); - break; - case Expression.NOT_LIKE: - out.append(" NOT LIKE BINARY "); - break; - } - } - catch (IOException ioex) { - throw new CayenneRuntimeException("Error appending content", ioex); - } - } - } - - @Override - protected void appendExtractFunction(ASTExtract functionExpression) { - switch (functionExpression.getPart()) { - case DAY_OF_WEEK: - case DAY_OF_MONTH: - case DAY_OF_YEAR: - // mysql variants are without '_' - out.append(functionExpression.getPart().name().replace("_", "")); - break; - default: - appendFunction(functionExpression); - } - } -} http://git-wip-us.apache.org/repos/asf/cayenne/blob/f6b2dac9/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/MySQLSelectTranslator.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/MySQLSelectTranslator.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/MySQLSelectTranslator.java deleted file mode 100644 index c9f0809..0000000 --- a/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/MySQLSelectTranslator.java +++ /dev/null @@ -1,57 +0,0 @@ -/***************************************************************** - * 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.cayenne.dba.mysql; - -import org.apache.cayenne.access.translator.select.DefaultSelectTranslator; -import org.apache.cayenne.dba.DbAdapter; -import org.apache.cayenne.map.EntityResolver; -import org.apache.cayenne.query.Query; - -/** - * @since 1.2 - */ -class MySQLSelectTranslator extends DefaultSelectTranslator { - - /** - * @since 4.0 - */ - public MySQLSelectTranslator(Query query, DbAdapter adapter, EntityResolver entityResolver) { - super(query, adapter, entityResolver); - } - - @Override - protected void appendLimitAndOffsetClauses(StringBuilder buffer) { - int offset = queryMetadata.getFetchOffset(); - int limit = queryMetadata.getFetchLimit(); - - if (offset > 0 || limit > 0) { - buffer.append(" LIMIT "); - - // both OFFSET and LIMIT must be present, so come up with defaults - // if one of - // them is not set by the user - if (limit == 0) { - limit = Integer.MAX_VALUE; - } - - buffer.append(limit).append(" OFFSET ").append(offset); - } - } -} http://git-wip-us.apache.org/repos/asf/cayenne/blob/f6b2dac9/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/MySQLTreeProcessor.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/MySQLTreeProcessor.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/MySQLTreeProcessor.java new file mode 100644 index 0000000..d816112 --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/MySQLTreeProcessor.java @@ -0,0 +1,68 @@ +/***************************************************************** + * 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.cayenne.dba.mysql; + +import org.apache.cayenne.access.sqlbuilder.sqltree.FunctionNode; +import org.apache.cayenne.access.sqlbuilder.sqltree.LikeNode; +import org.apache.cayenne.access.sqlbuilder.sqltree.LimitOffsetNode; +import org.apache.cayenne.access.sqlbuilder.sqltree.Node; +import org.apache.cayenne.access.translator.select.BaseSQLTreeProcessor; +import org.apache.cayenne.dba.mysql.sqltree.MysqlLikeNode; +import org.apache.cayenne.dba.mysql.sqltree.MysqlLimitOffsetNode; + +/** + * @since 4.2 + */ +public class MySQLTreeProcessor extends BaseSQLTreeProcessor { + + private static final MySQLTreeProcessor INSTANCE = new MySQLTreeProcessor(); + + public static MySQLTreeProcessor getInstance() { + return INSTANCE; + } + + private MySQLTreeProcessor() { + } + + @Override + protected void onLikeNode(Node parent, LikeNode child, int index) { + if(!child.isIgnoreCase()) { + replaceChild(parent, index, new MysqlLikeNode(child.isNot(), child.getEscape())); + } + } + + @Override + protected void onLimitOffsetNode(Node parent, LimitOffsetNode child, int index) { + Node replacement = new MysqlLimitOffsetNode(child.getLimit(), child.getOffset()); + replaceChild(parent, index, replacement, false); + } + + @Override + protected void onFunctionNode(Node parent, FunctionNode child, int index) { + String functionName = child.getFunctionName(); + if("DAY_OF_MONTH".equals(functionName) + || "DAY_OF_WEEK".equals(functionName) + || "DAY_OF_YEAR".equals(functionName)) { + FunctionNode replacement = new FunctionNode(functionName.replace("_", ""), child.getAlias(), true); + replaceChild(parent, index, replacement); + } + } + +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/f6b2dac9/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/sqltree/MysqlLikeNode.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/sqltree/MysqlLikeNode.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/sqltree/MysqlLikeNode.java new file mode 100644 index 0000000..5f25f14 --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/sqltree/MysqlLikeNode.java @@ -0,0 +1,46 @@ +/***************************************************************** + * 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.cayenne.dba.mysql.sqltree; + +import org.apache.cayenne.access.sqlbuilder.QuotingAppendable; +import org.apache.cayenne.access.sqlbuilder.sqltree.LikeNode; +import org.apache.cayenne.access.sqlbuilder.sqltree.Node; + +/** + * @since 4.2 + */ +public class MysqlLikeNode extends LikeNode { + public MysqlLikeNode(boolean isNot, char escape) { + super(false, isNot, escape); + } + + @Override + public void appendChildrenSeparator(QuotingAppendable buffer, int childIdx) { + if (not) { + buffer.append(" NOT"); + } + buffer.append(" LIKE BINARY "); + } + + @Override + public Node copy() { + return new MysqlLikeNode(isNot(), getEscape()); + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/f6b2dac9/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/sqltree/MysqlLimitOffsetNode.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/sqltree/MysqlLimitOffsetNode.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/sqltree/MysqlLimitOffsetNode.java new file mode 100644 index 0000000..9bc0105 --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/sqltree/MysqlLimitOffsetNode.java @@ -0,0 +1,40 @@ +/***************************************************************** + * 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.cayenne.dba.mysql.sqltree; + +import org.apache.cayenne.access.sqlbuilder.sqltree.LimitOffsetNode; +import org.apache.cayenne.access.sqlbuilder.sqltree.Node; + +/** + * @since 4.2 + */ +public class MysqlLimitOffsetNode extends LimitOffsetNode { + + public MysqlLimitOffsetNode(int limit, int offset) { + // Per MySQL documentation: "To retrieve all rows from a certain offset up to the end of the result set, + // you can use some large number for the second parameter." + super(limit == 0 && offset > 0 ? Integer.MAX_VALUE : limit, offset); + } + + @Override + public Node copy() { + return new MysqlLimitOffsetNode(limit, offset); + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/f6b2dac9/cayenne-server/src/main/java/org/apache/cayenne/dba/openbase/OpenBaseAdapter.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/openbase/OpenBaseAdapter.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/openbase/OpenBaseAdapter.java index 1a30779..c245942 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/dba/openbase/OpenBaseAdapter.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/openbase/OpenBaseAdapter.java @@ -25,11 +25,10 @@ import java.sql.ResultSet; import java.sql.Types; import java.util.Iterator; import java.util.List; +import java.util.function.Function; import org.apache.cayenne.CayenneRuntimeException; -import org.apache.cayenne.access.translator.select.QualifierTranslator; -import org.apache.cayenne.access.translator.select.QueryAssembler; -import org.apache.cayenne.access.translator.select.SelectTranslator; +import org.apache.cayenne.access.sqlbuilder.sqltree.Node; import org.apache.cayenne.access.types.ByteType; import org.apache.cayenne.access.types.CharType; import org.apache.cayenne.access.types.ExtendedType; @@ -46,8 +45,6 @@ import org.apache.cayenne.map.DbAttribute; import org.apache.cayenne.map.DbEntity; import org.apache.cayenne.map.DbJoin; import org.apache.cayenne.map.DbRelationship; -import org.apache.cayenne.map.EntityResolver; -import org.apache.cayenne.query.SelectQuery; import org.apache.cayenne.resource.ResourceLocator; /** @@ -78,11 +75,11 @@ public class OpenBaseAdapter extends JdbcAdapter { } /** - * @since 4.0 + * @since 4.2 */ @Override - public SelectTranslator getSelectTranslator(SelectQuery<?> query, EntityResolver entityResolver) { - return new OpenBaseSelectTranslator(query, this, entityResolver); + public Function<Node, Node> getSqlTreeProcessor() { + return new OpenBaseSQLTreeProcessor(); } @Override @@ -126,14 +123,6 @@ public class OpenBaseAdapter extends JdbcAdapter { } /** - * Returns OpenBase-specific translator for queries. - */ - @Override - public QualifierTranslator getQualifierTranslator(QueryAssembler queryAssembler) { - return new OpenBaseQualifierTranslator(queryAssembler); - } - - /** * Creates and returns a primary key generator. Overrides superclass * implementation to return an instance of OpenBasePkGenerator that uses * built-in multi-server primary key generation.