From 096aa3eea8cb2736891537975ae000bee8d79e1e Mon Sep 17 00:00:00 2001 From: Will Dazey Date: Tue, 31 May 2022 11:17:37 -0500 Subject: [PATCH] Improve EclipseLink query parameter binding behavior Signed-off-by: Will Dazey --- .../config/PersistenceUnitProperties.java | 33 +- .../persistence/expressions/Expression.java | 39 +- .../expressions/ExpressionMath.java | 67 +- .../expressions/ExpressionOperator.java | 378 ++++-- .../expressions/ListExpressionOperator.java | 68 +- .../persistence/history/AsOfClause.java | 5 +- .../persistence/history/AsOfSCNClause.java | 5 +- .../internal/databaseaccess/DatabaseCall.java | 486 +++---- .../databaseaccess/DatabasePlatform.java | 64 +- .../databaseaccess/DatasourceCall.java | 834 ++++++++++-- .../databaseaccess/DatasourcePlatform.java | 50 +- .../databaseaccess/QueryStringCall.java | 15 +- .../ArgumentListFunctionExpression.java | 19 +- .../expressions/CollectionExpression.java | 5 +- .../expressions/CompoundExpression.java | 15 +- .../expressions/ConstantExpression.java | 43 +- .../expressions/ExpressionSQLPrinter.java | 23 +- .../expressions/FunctionExpression.java | 21 +- .../expressions/ParameterExpression.java | 53 +- .../expressions/RelationExpression.java | 15 +- .../expressions/SQLDeleteAllStatement.java | 5 +- .../SQLModifyAllStatementForTempTable.java | 4 +- .../expressions/SQLSelectStatement.java | 20 + .../expressions/SQLUpdateAllStatement.java | 5 +- ...teAllStatementForOracleAnonymousBlock.java | 4 +- .../expressions/SubSelectExpression.java | 4 +- .../internal/helper/ComplexDatabaseType.java | 12 +- .../internal/helper/DatabaseType.java | 18 +- .../persistence/internal/helper/Helper.java | 19 +- .../ObjectPersistenceRuntimeXMLProject.java | 49 +- ...ctPersistenceRuntimeXMLProject_11_1_1.java | 54 +- .../platform/database/DB2Platform.java | 1162 ++++++++++++++++- .../platform/database/DB2ZPlatform.java | 496 ++++++- .../platform/database/DerbyPlatform.java | 381 +++++- .../platform/database/FirebirdPlatform.java | 8 +- .../platform/database/H2Platform.java | 8 +- .../platform/database/HANAPlatform.java | 17 +- .../platform/database/HSQLPlatform.java | 8 +- .../platform/database/Informix11Platform.java | 28 +- .../platform/database/MaxDBPlatform.java | 16 +- .../platform/database/OraclePlatform.java | 185 ++- .../platform/database/PostgreSQLPlatform.java | 7 +- .../platform/database/SQLServerPlatform.java | 255 +++- .../platform/database/SybasePlatform.java | 317 +++-- .../platform/database/SymfowarePlatform.java | 10 +- .../platform/database/jdbc/JDBCTypes.java | 11 +- .../oracle/plsql/OraclePLSQLTypes.java | 16 +- .../oracle/plsql/PLSQLStoredFunctionCall.java | 11 +- .../plsql/PLSQLStoredProcedureCall.java | 101 +- .../database/oracle/plsql/PLSQLargument.java | 47 +- .../database/oracle/plsql/PLSQLrecord.java | 19 +- .../persistence/queries/DatabaseQuery.java | 4 +- .../eclipse/persistence/queries/SQLCall.java | 37 +- .../queries/StoredFunctionCall.java | 5 +- .../internal/jpa/EntityManagerSetupImpl.java | 5 + .../persistence/internal/jpa/QueryImpl.java | 18 +- .../jpa/StoredProcedureQueryImpl.java | 13 +- .../queries/PLSQLParameterMetadata.java | 6 +- .../jpa/querydef/CriteriaBuilderImpl.java | 11 +- .../mappingsmodel/query/MWProcedure.java | 19 +- .../dbws/XmlEntityMappingsGenerator.java | 85 +- 61 files changed, 4537 insertions(+), 1201 deletions(-) diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/config/PersistenceUnitProperties.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/config/PersistenceUnitProperties.java index ba62db2672d..faa39457405 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/config/PersistenceUnitProperties.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/config/PersistenceUnitProperties.java @@ -1016,19 +1016,40 @@ public class PersistenceUnitProperties { public static final String PARTITIONING_CALLBACK = "eclipselink.partitioning.callback"; /** - * Property "eclipselink.jdbc.bind-parameters" configures whether parameter binding will be used in the - * creation of JDBC prepared statements. Usage of parameter binding is - * generally a performance optimization allowing for SQL and prepared - * statement caching as well as usage of batch writing. + * Property "eclipselink.jdbc.bind-parameters" configures whether parameter binding + * should be used in the creation of JDBC prepared statements. + *

+ * Usage of parameter binding is generally a performance optimization; + * allowing for SQL and prepared statement caching, as well as usage of batch writing. *

* Allowed Values: *

*/ public static final String JDBC_BIND_PARAMETERS = "eclipselink.jdbc.bind-parameters"; + /** + * Property "eclipselink.jdbc.allow-partial-bind-parameters" configures whether + * partial parameter binding should be allowed in the creation of JDBC prepared statements. + *

+ * EclipseLink determines binding behavior based on the database platform's support for binding. + * If the database platform doesn't support binding for a specific expression, EclipseLink disables + * all binding for the whole query. Setting this property to 'true' will allow EclipseLink to bind + * per expression, instead of per query. + *

+ * Usage of parameter binding is generally a performance optimization; + * allowing for SQL and prepared statement caching, as well as usage of batch writing. + *

+ * Allowed Values: + *

+ */ + public static final String JDBC_ALLOW_PARTIAL_PARAMETERS = "eclipselink.jdbc.allow-partial-bind-parameters"; + /** * Property "eclipselink.jdbc.force-bind-parameters" enables parameter binding * in the creation of JDBC prepared statements. Some database platforms disable parameter binding diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/expressions/Expression.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/expressions/Expression.java index 6a6da0fae94..93dfa97c23f 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/expressions/Expression.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/expressions/Expression.java @@ -1,6 +1,6 @@ /* - * Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2021 IBM Corporation. All rights reserved. + * Copyright (c) 1998, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2022 IBM Corporation. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -750,10 +750,8 @@ public Expression caseStatement(Map caseItems, Object defaultItem) { * @see ArgumentListFunctionExpression */ public ArgumentListFunctionExpression caseStatement() { - - ListExpressionOperator caseOperator = (ListExpressionOperator)getOperator(ExpressionOperator.Case); - ListExpressionOperator clonedCaseOperator = new ListExpressionOperator(); - caseOperator.copyTo(clonedCaseOperator); + ExpressionOperator caseOperator = getOperator(ExpressionOperator.Case); + ExpressionOperator clonedCaseOperator = caseOperator.clone(); ArgumentListFunctionExpression expression = new ArgumentListFunctionExpression(); expression.setBaseExpression(this); @@ -822,9 +820,8 @@ public Expression caseConditionStatement(Map caseConditions, * @see ArgumentListFunctionExpression */ public ArgumentListFunctionExpression caseConditionStatement() { - ListExpressionOperator caseOperator = (ListExpressionOperator)getOperator(ExpressionOperator.CaseCondition); - ListExpressionOperator clonedCaseOperator = new ListExpressionOperator(); - caseOperator.copyTo(clonedCaseOperator); + ExpressionOperator caseOperator = getOperator(ExpressionOperator.CaseCondition); + ExpressionOperator clonedCaseOperator = caseOperator.clone(); ArgumentListFunctionExpression expression = new ArgumentListFunctionExpression(); expression.setBaseExpression(this); @@ -885,9 +882,8 @@ public ArgumentListFunctionExpression coalesce(Collection expressions) { } public ArgumentListFunctionExpression coalesce() { - ListExpressionOperator coalesceOperator = (ListExpressionOperator)getOperator(ExpressionOperator.Coalesce); - ListExpressionOperator clonedCoalesceOperator = new ListExpressionOperator(); - coalesceOperator.copyTo(clonedCoalesceOperator); + ExpressionOperator coalesceOperator = getOperator(ExpressionOperator.Coalesce); + ExpressionOperator clonedCoalesceOperator = coalesceOperator.clone(); ArgumentListFunctionExpression expression = new ArgumentListFunctionExpression(); expression.setBaseExpression(this); @@ -2003,14 +1999,27 @@ public ExpressionOperator getOperator() { * INTERNAL: * Create a new expression tree with the named operator. Part of the implementation of user-level "get" */ - public ExpressionOperator getOperator(int selector) { + public static ExpressionOperator getOperator(int selector) { + /* + * Get an operator based on a user defined function, if it exists. + */ ExpressionOperator result = ExpressionOperator.getOperator(Integer.valueOf(selector)); if (result != null) { return result; } - // Make a temporary operator which we expect the platform - // to supply later. + /* + * Create an operator based on known selectors. + * This is actually a temporary object which we expect Platforms to supply later. + * @see org.eclipse.persistence.internal.expressions.CompoundExpression#initializePlatformOperator(DatabasePlatform platform) + * @see org.eclipse.persistence.internal.expressions.FunctionExpression#initializePlatformOperator(DatabasePlatform platform) + */ + result = ExpressionOperator.getInternalOperator(Integer.valueOf(selector)); + if (result != null) { + return result; + } + + // Create a default Function ExpressionOperator result = new ExpressionOperator(); result.setSelector(selector); result.setNodeClass(ClassConstants.FunctionExpression_Class); diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/expressions/ExpressionMath.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/expressions/ExpressionMath.java index 3958ca49b05..cf57cca53d0 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/expressions/ExpressionMath.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/expressions/ExpressionMath.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 1998, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022 IBM Corporation. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -37,7 +38,7 @@ public class ExpressionMath { * */ public static Expression abs(Expression expression) { - ExpressionOperator anOperator = expression.getOperator(ExpressionOperator.Abs); + ExpressionOperator anOperator = Expression.getOperator(ExpressionOperator.Abs); return anOperator.expressionFor(expression); } @@ -46,7 +47,7 @@ public static Expression abs(Expression expression) { * Return a new expression that applies the function to the given expression. */ public static Expression acos(Expression expression) { - ExpressionOperator anOperator = expression.getOperator(ExpressionOperator.Acos); + ExpressionOperator anOperator = Expression.getOperator(ExpressionOperator.Acos); return anOperator.expressionFor(expression); } @@ -63,7 +64,7 @@ public static Expression add(Expression left, int right) { * Return a new expression that applies the function to the given expression. */ public static Expression add(Expression right, Object left) { - ExpressionOperator anOperator = right.getOperator(ExpressionOperator.Add); + ExpressionOperator anOperator = Expression.getOperator(ExpressionOperator.Add); return anOperator.expressionFor(right, left); } @@ -72,7 +73,7 @@ public static Expression add(Expression right, Object left) { * Return a new expression that applies the function to the given expression. */ public static Expression asin(Expression expression) { - ExpressionOperator anOperator = expression.getOperator(ExpressionOperator.Asin); + ExpressionOperator anOperator = Expression.getOperator(ExpressionOperator.Asin); return anOperator.expressionFor(expression); } @@ -98,7 +99,7 @@ public static Expression atan2(Expression expression, int value) { * Return a new expression that applies the function to the given expression. */ public static Expression atan2(Expression expression, Object value) { - ExpressionOperator anOperator = expression.getOperator(ExpressionOperator.Atan2); + ExpressionOperator anOperator = Expression.getOperator(ExpressionOperator.Atan2); return anOperator.expressionFor(expression, value); } @@ -107,7 +108,7 @@ public static Expression atan2(Expression expression, Object value) { * Return a new expression that applies the function to the given expression. */ public static Expression atan2(Expression expression1, Expression expression2) { - ExpressionOperator anOperator = expression1.getOperator(ExpressionOperator.Atan2); + ExpressionOperator anOperator = Expression.getOperator(ExpressionOperator.Atan2); return anOperator.expressionFor(expression1, expression2); } @@ -116,7 +117,7 @@ public static Expression atan2(Expression expression1, Expression expression2) { * Return a new expression that applies the function to the given expression. */ public static Expression ceil(Expression expression) { - ExpressionOperator anOperator = expression.getOperator(ExpressionOperator.Ceil); + ExpressionOperator anOperator = Expression.getOperator(ExpressionOperator.Ceil); return anOperator.expressionFor(expression); } @@ -125,7 +126,7 @@ public static Expression ceil(Expression expression) { * Return a new expression that applies the function to the given expression. */ public static Expression chr(Expression expression) { - ExpressionOperator anOperator = expression.getOperator(ExpressionOperator.Chr); + ExpressionOperator anOperator = Expression.getOperator(ExpressionOperator.Chr); return anOperator.expressionFor(expression); } @@ -134,7 +135,7 @@ public static Expression chr(Expression expression) { * Return a new expression that applies the function to the given expression. */ public static Expression cos(Expression expression) { - ExpressionOperator anOperator = expression.getOperator(ExpressionOperator.Cos); + ExpressionOperator anOperator = Expression.getOperator(ExpressionOperator.Cos); return anOperator.expressionFor(expression); } @@ -144,7 +145,7 @@ public static Expression cos(Expression expression) { */ public static Expression cosh(Expression expression) { - ExpressionOperator anOperator = expression.getOperator(ExpressionOperator.Cosh); + ExpressionOperator anOperator = Expression.getOperator(ExpressionOperator.Cosh); return anOperator.expressionFor(expression); } @@ -153,7 +154,7 @@ public static Expression cosh(Expression expression) { * Return a new expression that applies the function to the given expression. */ public static Expression cot(Expression expression) { - ExpressionOperator anOperator = expression.getOperator(ExpressionOperator.Cot); + ExpressionOperator anOperator = Expression.getOperator(ExpressionOperator.Cot); return anOperator.expressionFor(expression); } @@ -170,7 +171,7 @@ public static Expression divide(Expression left, int right) { * Return a new expression that applies the function to the given expression. */ public static Expression divide(Expression left, Object right) { - ExpressionOperator anOperator = left.getOperator(ExpressionOperator.Divide); + ExpressionOperator anOperator = Expression.getOperator(ExpressionOperator.Divide); return anOperator.expressionFor(left, right); } @@ -179,7 +180,7 @@ public static Expression divide(Expression left, Object right) { * Return a new expression that applies the function to the given expression. */ public static Expression exp(Expression expression) { - ExpressionOperator anOperator = expression.getOperator(ExpressionOperator.Exp); + ExpressionOperator anOperator = Expression.getOperator(ExpressionOperator.Exp); return anOperator.expressionFor(expression); } @@ -188,7 +189,7 @@ public static Expression exp(Expression expression) { * Return a new expression that applies the function to the given expression. */ public static Expression floor(Expression expression) { - ExpressionOperator anOperator = expression.getOperator(ExpressionOperator.Floor); + ExpressionOperator anOperator = Expression.getOperator(ExpressionOperator.Floor); return anOperator.expressionFor(expression); } @@ -197,7 +198,7 @@ public static Expression floor(Expression expression) { * Return the operator. */ public static ExpressionOperator getOperator(int selector) { - ExpressionOperator result = ExpressionOperator.getOperator(Integer.valueOf(selector)); + ExpressionOperator result = Expression.getOperator(Integer.valueOf(selector)); if (result != null) { return result; } @@ -215,7 +216,7 @@ public static ExpressionOperator getOperator(int selector) { * Return a new expression that applies the function to the given expression. */ public static Expression ln(Expression expression) { - ExpressionOperator anOperator = expression.getOperator(ExpressionOperator.Ln); + ExpressionOperator anOperator = Expression.getOperator(ExpressionOperator.Ln); return anOperator.expressionFor(expression); } @@ -224,7 +225,7 @@ public static Expression ln(Expression expression) { * Return a new expression that applies the function to the given expression. */ public static Expression log(Expression expression) { - ExpressionOperator anOperator = expression.getOperator(ExpressionOperator.Log); + ExpressionOperator anOperator = Expression.getOperator(ExpressionOperator.Log); return anOperator.expressionFor(expression); } @@ -241,7 +242,7 @@ public static Expression max(Expression left, int right) { * Return a new expression that applies the function to the given expression. */ public static Expression max(Expression left, Object right) { - ExpressionOperator anOperator = left.getOperator(ExpressionOperator.Greatest); + ExpressionOperator anOperator = Expression.getOperator(ExpressionOperator.Greatest); return anOperator.expressionFor(left, right); } @@ -258,7 +259,7 @@ public static Expression min(Expression left, int right) { * Return a new expression that applies the function to the given expression. */ public static Expression min(Expression left, Object right) { - ExpressionOperator anOperator = left.getOperator(ExpressionOperator.Least); + ExpressionOperator anOperator = Expression.getOperator(ExpressionOperator.Least); return anOperator.expressionFor(left, right); } @@ -275,7 +276,7 @@ public static Expression mod(Expression expression, int base) { * Return a new expression that applies the function to the given expression. */ public static Expression mod(Expression expression, Object base) { - ExpressionOperator anOperator = expression.getOperator(ExpressionOperator.Mod); + ExpressionOperator anOperator = Expression.getOperator(ExpressionOperator.Mod); return anOperator.expressionFor(expression, base); } @@ -292,7 +293,7 @@ public static Expression multiply(Expression left, int right) { * Return a new expression that applies the function to the given expression. */ public static Expression multiply(Expression left, Object right) { - ExpressionOperator anOperator = left.getOperator(ExpressionOperator.Multiply); + ExpressionOperator anOperator = Expression.getOperator(ExpressionOperator.Multiply); return anOperator.expressionFor(left, right); } @@ -301,7 +302,7 @@ public static Expression multiply(Expression left, Object right) { * Return a new expression that applies the function to the given expression. */ public static Expression negate(Expression expression) { - ExpressionOperator anOperator = expression.getOperator(ExpressionOperator.Negate); + ExpressionOperator anOperator = Expression.getOperator(ExpressionOperator.Negate); return anOperator.expressionFor(expression); } @@ -318,7 +319,7 @@ public static Expression power(Expression expression, int raised) { * Return a new expression that applies the function to the given expression. */ public static Expression power(Expression expression, Object raised) { - ExpressionOperator anOperator = expression.getOperator(ExpressionOperator.Power); + ExpressionOperator anOperator = Expression.getOperator(ExpressionOperator.Power); return anOperator.expressionFor(expression, raised); } @@ -335,7 +336,7 @@ public static Expression round(Expression expression, int decimalPlaces) { * Return a new expression that applies the function to the given expression. */ public static Expression round(Expression expression, Object decimalPlaces) { - ExpressionOperator anOperator = expression.getOperator(ExpressionOperator.Round); + ExpressionOperator anOperator = Expression.getOperator(ExpressionOperator.Round); return anOperator.expressionFor(expression, decimalPlaces); } @@ -344,7 +345,7 @@ public static Expression round(Expression expression, Object decimalPlaces) { * Return a new expression that applies the function to the given expression. */ public static Expression sign(Expression expression) { - ExpressionOperator anOperator = expression.getOperator(ExpressionOperator.Sign); + ExpressionOperator anOperator = Expression.getOperator(ExpressionOperator.Sign); return anOperator.expressionFor(expression); } @@ -353,7 +354,7 @@ public static Expression sign(Expression expression) { * Return a new expression that applies the function to the given expression. */ public static Expression sin(Expression expression) { - ExpressionOperator anOperator = expression.getOperator(ExpressionOperator.Sin); + ExpressionOperator anOperator = Expression.getOperator(ExpressionOperator.Sin); return anOperator.expressionFor(expression); } @@ -362,7 +363,7 @@ public static Expression sin(Expression expression) { * Return a new expression that applies the function to the given expression. */ public static Expression sinh(Expression expression) { - ExpressionOperator anOperator = expression.getOperator(ExpressionOperator.Sinh); + ExpressionOperator anOperator = Expression.getOperator(ExpressionOperator.Sinh); return anOperator.expressionFor(expression); } @@ -371,7 +372,7 @@ public static Expression sinh(Expression expression) { * Return a new expression that applies the function to the given expression. */ public static Expression sqrt(Expression expression) { - ExpressionOperator anOperator = expression.getOperator(ExpressionOperator.Sqrt); + ExpressionOperator anOperator = Expression.getOperator(ExpressionOperator.Sqrt); return anOperator.expressionFor(expression); } @@ -388,7 +389,7 @@ public static Expression subtract(Expression left, int right) { * Return a new expression that applies the function to the given expression. */ public static Expression subtract(Expression left, Object right) { - ExpressionOperator anOperator = left.getOperator(ExpressionOperator.Subtract); + ExpressionOperator anOperator = Expression.getOperator(ExpressionOperator.Subtract); return anOperator.expressionFor(left, right); } @@ -397,7 +398,7 @@ public static Expression subtract(Expression left, Object right) { * Return a new expression that applies the function to the given expression. */ public static Expression tan(Expression expression) { - ExpressionOperator anOperator = expression.getOperator(ExpressionOperator.Tan); + ExpressionOperator anOperator = Expression.getOperator(ExpressionOperator.Tan); return anOperator.expressionFor(expression); } @@ -406,7 +407,7 @@ public static Expression tan(Expression expression) { * Return a new expression that applies the function to the given expression. */ public static Expression tanh(Expression expression) { - ExpressionOperator anOperator = expression.getOperator(ExpressionOperator.Tanh); + ExpressionOperator anOperator = Expression.getOperator(ExpressionOperator.Tanh); return anOperator.expressionFor(expression); } @@ -423,7 +424,7 @@ public static Expression trunc(Expression expression, int decimalPlaces) { * Return a new expression that applies the function to the given expression. */ public static Expression trunc(Expression expression, Object decimalPlaces) { - ExpressionOperator anOperator = expression.getOperator(ExpressionOperator.Trunc); + ExpressionOperator anOperator = Expression.getOperator(ExpressionOperator.Trunc); return anOperator.expressionFor(expression, decimalPlaces); } } diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/expressions/ExpressionOperator.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/expressions/ExpressionOperator.java index db7da5a082e..ea6bb51beca 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/expressions/ExpressionOperator.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/expressions/ExpressionOperator.java @@ -1,6 +1,6 @@ /* - * Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2018, 2021 IBM Corporation. All rights reserved. + * Copyright (c) 1998, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2022 IBM Corporation. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -42,18 +42,26 @@ public class ExpressionOperator implements Serializable { static final long serialVersionUID = -7066100204792043980L; protected int selector; protected String name; - protected String[] databaseStrings; + + // ListExpressionOperator uses its own start/separator/terminator strings + private String[] databaseStrings; + protected boolean isPrefix = false; protected boolean isRepeating = false; protected Class nodeClass; protected int type; + /** Contains user defined operators */ protected int[] argumentIndices = null; protected static Map allOperators = initializeOperators(); + /** Contains internal defined operators meant as placeholders for platform operators */ + protected static Map allInternalOperators = initializeInternalOperators(); protected static final Map platformOperatorSelectors = initializePlatformOperatorSelectors(); protected static final Map platformOperatorNames = initializePlatformOperatorNames(); protected String[] javaStrings; - /** Allow operator to disable binding. */ - protected boolean isBindingSupported = true; + + /** Allow operator to disable/enable binding for the whole expression. + * Set to 'null' to enable `isArgumentBindingSupported` finer detail. */ + protected Boolean isBindingSupported = true; /** Operator types */ public static final int LogicalOperator = 1; @@ -276,7 +284,7 @@ public ExpressionOperator(int selector, Vector newDatabaseStrings) { * PUBLIC: * Return if binding is compatible with this operator. */ - public boolean isBindingSupported() { + public Boolean isBindingSupported() { return isBindingSupported; } @@ -285,7 +293,8 @@ public boolean isBindingSupported() { * Set if binding is compatible with this operator. * Some databases do not allow binding, or require casting with certain operators. */ - public void setIsBindingSupported(boolean isBindingSupported) { + @Deprecated + public void setIsBindingSupported(Boolean isBindingSupported) { this.isBindingSupported = isBindingSupported; } @@ -302,7 +311,7 @@ public boolean equals(Object object) { } ExpressionOperator operator = (ExpressionOperator) object; if (getSelector() == 0) { - return Arrays.equals(getDatabaseStrings(), operator.getDatabaseStrings()); + return Arrays.equals(getDatabaseStrings(0), operator.getDatabaseStrings(0)); } else { return getSelector() == operator.getSelector(); } @@ -332,6 +341,14 @@ public static ExpressionOperator acos() { return simpleFunction(Acos, "ACOS"); } + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator add() { + return ExpressionOperator.simpleMath(ExpressionOperator.Add, "+"); + } + /** * INTERNAL: * Build operator. @@ -357,12 +374,19 @@ public static ExpressionOperator addMonths() { /** * ADVANCED: - * Add an operator to the global list of operators. + * Add an operator to the user defined list of operators. */ public static void addOperator(ExpressionOperator exOperator) { allOperators.put(Integer.valueOf(exOperator.getSelector()), exOperator); } + /** + * INTERNAL: + */ + private static void addOperator(Map map, ExpressionOperator exOperator) { + map.put(Integer.valueOf(exOperator.getSelector()), exOperator); + } + /** * ADVANCED: * Define a name for a user defined operator. @@ -571,6 +595,25 @@ public static ExpressionOperator between() { return result; } + /** + * INTERNAL: + * Create the NOT BETWEEN Operator + */ + public static ExpressionOperator notBetween() { + ExpressionOperator result = new ExpressionOperator(); + result.setSelector(NotBetween); + result.setType(ComparisonOperator); + Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(); + v.add("("); + v.add(" NOT BETWEEN "); + v.add(" AND "); + v.add(")"); + result.printsAs(v); + result.bePrefix(); + result.setNodeClass(ClassConstants.FunctionExpression_Class); + return result; + } + /** * INTERNAL: * Build operator. @@ -739,7 +782,18 @@ public boolean conformLike(Object left, Object right) { return true; } - public void copyTo(ExpressionOperator operator){ + @Override + public ExpressionOperator clone() { + ExpressionOperator clone = new ExpressionOperator(); + this.copyTo(clone); + return clone; + } + + public void copyTo(ExpressionOperator operator) { + if(operator == null) + return; + + operator.selector = selector; operator.isPrefix = isPrefix; operator.isRepeating = isRepeating; @@ -748,7 +802,7 @@ public void copyTo(ExpressionOperator operator){ operator.databaseStrings = databaseStrings == null ? null : Helper.copyStringArray(databaseStrings); operator.argumentIndices = argumentIndices == null ? null : Helper.copyIntArray(argumentIndices); operator.javaStrings = javaStrings == null ? null : Helper.copyStringArray(javaStrings); - operator.isBindingSupported = isBindingSupported; + operator.isBindingSupported = isBindingSupported == null ? null : new Boolean(isBindingSupported); } /** @@ -803,6 +857,7 @@ public static ExpressionOperator dateName() { * INTERNAL: * Oracle equivalent to DATENAME is TO_CHAR. */ + @Deprecated public static ExpressionOperator oracleDateName() { ExpressionOperator exOperator = new ExpressionOperator(); exOperator.setType(FunctionOperator); @@ -900,6 +955,14 @@ public static ExpressionOperator distinct() { return simpleFunction(Distinct, "DISTINCT", "distinct"); } + /** + * INTERNAL: + * Create the DISTINCT operator. + */ + public static ExpressionOperator divide() { + return ExpressionOperator.simpleMath(ExpressionOperator.Divide, "/"); + } + /** * INTERNAL: * Compare the values in memory. @@ -1033,6 +1096,10 @@ else if ((this.selector == Regexp) && (right instanceof Vector) && (((Vector)rig throw QueryException.cannotConformExpression(); } + public static ExpressionOperator equal() { + return ExpressionOperator.simpleRelation(ExpressionOperator.Equal, "=", "equal"); + } + /** * INTERNAL: * Initialize the outer join operator @@ -1054,8 +1121,8 @@ public static ExpressionOperator exists() { exOperator.setType(FunctionOperator); exOperator.setSelector(Exists); Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(2); - v.add("EXISTS" + " "); - v.add(" "); + v.add("EXISTS "); + v.add(""); exOperator.printsAs(v); exOperator.bePrefix(); exOperator.setNodeClass(ClassConstants.FunctionExpression_Class); @@ -1212,6 +1279,13 @@ public static Map getAllOperators() { return allOperators; } + /** + * INTERNAL: + */ + public static Map getAllInternalOperators() { + return allInternalOperators; + } + public static Map getPlatformOperatorSelectors() { return platformOperatorSelectors; } @@ -1219,10 +1293,18 @@ public static Map getPlatformOperatorSelectors() { /** * INTERNAL: */ + @Deprecated public String[] getDatabaseStrings() { return databaseStrings; } + /** + * INTERNAL: + */ + public String[] getDatabaseStrings(int arguments) { + return databaseStrings; + } + /** * INTERNAL: */ @@ -1240,11 +1322,21 @@ public Class getNodeClass() { /** * INTERNAL: * Lookup the operator with the given id. + *

+ * This will only check user defined operators. For operators defined internally, see {@link ExpressionOperator#getInternalOperator()} */ public static ExpressionOperator getOperator(Integer selector) { return getAllOperators().get(selector); } + /** + * INTERNAL: + * Lookup the internal operator with the given id. + */ + public static ExpressionOperator getInternalOperator(Integer selector) { + return getAllInternalOperators().get(selector); + } + /** * INTERNAL: * Return the selector id. @@ -1278,6 +1370,22 @@ public int getType() { return this.type; } + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator greaterThan() { + return ExpressionOperator.simpleRelation(ExpressionOperator.GreaterThan, ">", "greaterThan"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator greaterThanEqual() { + return ExpressionOperator.simpleRelation(ExpressionOperator.GreaterThanEqual, ">=", "greaterThanEqual"); + } + /** * INTERNAL: * Build operator. @@ -1345,40 +1453,76 @@ protected static void initializeAggregateFunctionOperators() { addOperator(average()); addOperator(minimum()); addOperator(maximum()); - addOperator(distinct()); + } + + /** + * INTERNAL: + */ + protected static void initializeComparisonOperators() { + // Comparison Operators + addOperator(between()); + addOperator(notBetween()); + addOperator(isNull()); + addOperator(notNull()); } /** * INTERNAL: */ protected static void initializeFunctionOperators() { + // Function Operators + addOperator(like()); + addOperator(likeEscape()); + addOperator(notLike()); + addOperator(notLikeEscape()); + addOperator(exists()); + addOperator(notExists()); addOperator(notOperator()); - addOperator(ascending()); - addOperator(descending()); addOperator(as()); - addOperator(nullsFirst()); - addOperator(nullsLast()); addOperator(any()); addOperator(some()); addOperator(all()); - addOperator(in()); addOperator(inSubQuery()); - addOperator(notIn()); addOperator(notInSubQuery()); addOperator(coalesce()); addOperator(caseStatement()); addOperator(caseConditionStatement()); + addOperator(distinct()); } /** * INTERNAL: */ protected static void initializeLogicalOperators() { + // Logical Operators addOperator(and()); addOperator(or()); - addOperator(isNull()); - addOperator(notNull()); + } + /** + * INTERNAL: + */ + protected static void initializeOrderOperators() { + // Order Operators + addOperator(ascending()); + addOperator(descending()); + addOperator(nullsFirst()); + addOperator(nullsLast()); + } + + /** + * INTERNAL: + */ + protected static void initializeRelationOperators() { + // Relation Operators + addOperator(equal()); + addOperator(notEqual()); + addOperator(lessThan()); + addOperator(lessThanEqual()); + addOperator(greaterThan()); + addOperator(greaterThanEqual()); + addOperator(in()); + addOperator(notIn()); } /** @@ -1386,13 +1530,70 @@ protected static void initializeLogicalOperators() { */ public static Map initializeOperators() { resetOperators(); - initializeFunctionOperators(); - initializeRelationOperators(); - initializeLogicalOperators(); - initializeAggregateFunctionOperators(); return allOperators; } + /** + * INTERNAL: + */ + private static Map initializeInternalOperators() { + Map allTempOperators = new HashMap(); + + // Aggregate Function Operators + addOperator(allTempOperators, count()); + addOperator(allTempOperators, sum()); + addOperator(allTempOperators, average()); + addOperator(allTempOperators, minimum()); + addOperator(allTempOperators, maximum()); + + // Comparison Operators + addOperator(allTempOperators, between()); + addOperator(allTempOperators, notBetween()); + addOperator(allTempOperators, isNull()); + addOperator(allTempOperators, notNull()); + + // Function Operators + addOperator(allTempOperators, like()); + addOperator(allTempOperators, likeEscape()); + addOperator(allTempOperators, notLike()); + addOperator(allTempOperators, notLikeEscape()); + addOperator(allTempOperators, exists()); + addOperator(allTempOperators, notExists()); + addOperator(allTempOperators, notOperator()); + addOperator(allTempOperators, as()); + addOperator(allTempOperators, any()); + addOperator(allTempOperators, some()); + addOperator(allTempOperators, all()); + addOperator(allTempOperators, inSubQuery()); + addOperator(allTempOperators, notInSubQuery()); + addOperator(allTempOperators, coalesce()); + addOperator(allTempOperators, caseStatement()); + addOperator(allTempOperators, caseConditionStatement()); + addOperator(allTempOperators, distinct()); + + // Logical Operators + addOperator(allTempOperators, and()); + addOperator(allTempOperators, or()); + + // Order Operators + addOperator(allTempOperators, ascending()); + addOperator(allTempOperators, descending()); + addOperator(allTempOperators, nullsFirst()); + addOperator(allTempOperators, nullsLast()); + + // Relation Operators + addOperator(allTempOperators, equal()); + addOperator(allTempOperators, notEqual()); + addOperator(allTempOperators, lessThan()); + addOperator(allTempOperators, lessThanEqual()); + addOperator(allTempOperators, greaterThan()); + addOperator(allTempOperators, greaterThanEqual()); + addOperator(allTempOperators, in()); + addOperator(allTempOperators, notIn()); + + return allTempOperators; + } + /** * INTERNAL: * Initialize a mapping to the platform operator names for usage with exceptions. @@ -1614,27 +1815,6 @@ public static Map initializePlatformOperatorSelectors() { return platformOperatorNames; } - /** - * INTERNAL: - */ - protected static void initializeRelationOperators() { - addOperator(simpleRelation(Equal, "=", "equal")); - addOperator(simpleRelation(NotEqual, "<>", "notEqual")); - addOperator(simpleRelation(LessThan, "<", "lessThan")); - addOperator(simpleRelation(LessThanEqual, "<=", "lessThanEqual")); - addOperator(simpleRelation(GreaterThan, ">", "greaterThan")); - addOperator(simpleRelation(GreaterThanEqual, ">=", "greaterThanEqual")); - - addOperator(like()); - addOperator(likeEscape()); - addOperator(notLike()); - addOperator(notLikeEscape()); - addOperator(between()); - - addOperator(exists()); - addOperator(notExists()); - } - /** * INTERNAL: * Build operator. @@ -1763,6 +1943,14 @@ public static ExpressionOperator length() { return simpleFunction(Length, "LENGTH"); } + public static ExpressionOperator lessThan() { + return ExpressionOperator.simpleRelation(ExpressionOperator.LessThan, "<", "lessThan"); + } + + public static ExpressionOperator lessThanEqual() { + return ExpressionOperator.simpleRelation(ExpressionOperator.LessThanEqual, "<=", "lessThanEqual"); + } + /** * INTERNAL: * Create the LIKE operator. @@ -1928,6 +2116,14 @@ public static ExpressionOperator monthsBetween() { return simpleTwoArgumentFunction(MonthsBetween, "MONTHS_BETWEEN"); } + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator multiply() { + return ExpressionOperator.simpleMath(ExpressionOperator.Multiply, "*"); + } + /** * INTERNAL: * Create a new expression. Optimized for the single argument case. @@ -2038,6 +2234,10 @@ public static ExpressionOperator nextDay() { return simpleTwoArgumentFunction(NextDay, "NEXT_DAY"); } + public static ExpressionOperator notEqual() { + return ExpressionOperator.simpleRelation(ExpressionOperator.NotEqual, "<>", "notEqual"); + } + /** * INTERNAL: * Create the NOT EXISTS operator. @@ -2047,8 +2247,8 @@ public static ExpressionOperator notExists() { exOperator.setType(FunctionOperator); exOperator.setSelector(NotExists); Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(2); - v.add("NOT EXISTS" + " "); - v.add(" "); + v.add("NOT EXISTS "); + v.add(""); exOperator.printsAs(v); exOperator.bePrefix(); exOperator.setNodeClass(ClassConstants.FunctionExpression_Class); @@ -2165,32 +2365,32 @@ public static ExpressionOperator power() { /** * INTERNAL: Print the collection onto the SQL stream. */ - public void printCollection(Vector items, ExpressionSQLPrinter printer) { - // Certain functions don't allow binding on some platforms. - if (printer.getPlatform().isDynamicSQLRequiredForFunctions() && !isBindingSupported()) { + public void printCollection(List items, ExpressionSQLPrinter printer) { + /* + * If this ExpressionOperator does not support binding, and the platform allows, + * then disable binding for the whole query + */ + if (printer.getPlatform().isDynamicSQLRequiredForFunctions() && Boolean.FALSE.equals(isBindingSupported())) { printer.getCall().setUsesBinding(false); } + int dbStringIndex = 0; - try { - if (isPrefix()) { - printer.getWriter().write(getDatabaseStrings()[0]); - dbStringIndex = 1; - } else { - dbStringIndex = 0; - } - } catch (IOException e) { - e.printStackTrace(); + if (isPrefix()) { + printer.printString(getDatabaseStrings()[0]); + dbStringIndex = 1; } - if (argumentIndices == null) { - argumentIndices = new int[items.size()]; - for (int i = 0; i < argumentIndices.length; i++){ - argumentIndices[i] = i; + if (this.argumentIndices == null) { + this.argumentIndices = new int[items.size()]; + for (int i = 0; i < this.argumentIndices.length; i++){ + this.argumentIndices[i] = i; } } - for (final int index : argumentIndices) { - Expression item = (Expression)items.elementAt(index); + String[] dbStrings = getDatabaseStrings(items.size()); + for (int i = 0; i < this.argumentIndices.length; i++) { + final int index = this.argumentIndices[i]; + Expression item = items.get(index); if ((this.selector == Ref) || ((this.selector == Deref) && (item.isObjectExpression()))) { DatabaseTable alias = ((ObjectExpression)item).aliasForTable(((ObjectExpression)item).getDescriptor().getTables().firstElement()); printer.printString(alias.getNameDelimited(printer.getPlatform())); @@ -2199,8 +2399,8 @@ public void printCollection(Vector items, ExpressionSQLPrinter printer) { } else { item.printSQL(printer); } - if (dbStringIndex < getDatabaseStrings().length) { - printer.printString(getDatabaseStrings()[dbStringIndex++]); + if (dbStringIndex < dbStrings.length) { + printer.printString(dbStrings[dbStringIndex++]); } } } @@ -2208,11 +2408,11 @@ public void printCollection(Vector items, ExpressionSQLPrinter printer) { /** * INTERNAL: Print the collection onto the SQL stream. */ - public void printJavaCollection(Vector items, ExpressionJavaPrinter printer) { + public void printJavaCollection(Vector items, ExpressionJavaPrinter printer) { int javaStringIndex = 0; for (int i = 0; i < items.size(); i++) { - Expression item = (Expression)items.elementAt(i); + Expression item = items.elementAt(i); item.printJava(printer); if (javaStringIndex < getJavaStrings().length) { printer.printString(getJavaStrings()[javaStringIndex++]); @@ -2225,16 +2425,18 @@ public void printJavaCollection(Vector items, ExpressionJavaPrinter printer) { * For performance, special case printing two children, since it's by far the most common */ public void printDuo(Expression first, Expression second, ExpressionSQLPrinter printer) { - // Certain functions don't allow binding on some platforms. - if (printer.getPlatform().isDynamicSQLRequiredForFunctions() && !isBindingSupported()) { + /* + * If this ExpressionOperator does not support binding, and the platform allows, + * then disable binding for the whole query + */ + if (printer.getPlatform().isDynamicSQLRequiredForFunctions() && Boolean.FALSE.equals(isBindingSupported())) { printer.getCall().setUsesBinding(false); } - int dbStringIndex; + + int dbStringIndex = 0; if (isPrefix()) { printer.printString(getDatabaseStrings()[0]); dbStringIndex = 1; - } else { - dbStringIndex = 0; } first.printSQL(printer); @@ -2549,11 +2751,10 @@ public static ExpressionOperator simpleLogical(int selector, String databaseName /** * INTERNAL: - * Create an operator for a simple math operatin, i.e. +, -, *, / + * Create an operator for a simple math operation, i.e. +, -, *, / */ public static ExpressionOperator simpleMath(int selector, String databaseName) { ExpressionOperator exOperator = new ExpressionOperator(); - exOperator.setIsBindingSupported(false); exOperator.setType(FunctionOperator); exOperator.setSelector(selector); Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(3); @@ -2563,6 +2764,7 @@ public static ExpressionOperator simpleMath(int selector, String databaseName) { exOperator.printsAs(v); exOperator.bePrefix(); exOperator.setNodeClass(ClassConstants.FunctionExpression_Class); + exOperator.setIsBindingSupported(false); return exOperator; } @@ -2727,8 +2929,11 @@ public static ExpressionOperator substringSingleArg() { return simpleTwoArgumentFunction(SubstringSingleArg, "SUBSTR"); } + public static ExpressionOperator subtract() { + return ExpressionOperator.simpleMath(ExpressionOperator.Subtract, "-"); + } + /** - * INTERNAL: * Create the SUM operator. */ public static ExpressionOperator sum() { @@ -2739,6 +2944,7 @@ public static ExpressionOperator sum() { * INTERNAL: * Function, to add months to a date. */ + @Deprecated public static ExpressionOperator sybaseAddMonthsOperator() { ExpressionOperator exOperator = new ExpressionOperator(); exOperator.setType(FunctionOperator); @@ -2760,6 +2966,7 @@ public static ExpressionOperator sybaseAddMonthsOperator() { * INTERNAL: * Build operator. */ + @Deprecated public static ExpressionOperator sybaseAtan2Operator() { return ExpressionOperator.simpleTwoArgumentFunction(Atan2, "ATN2"); } @@ -2768,6 +2975,7 @@ public static ExpressionOperator sybaseAtan2Operator() { * INTERNAL: * Build instring operator */ + @Deprecated public static ExpressionOperator sybaseInStringOperator() { ExpressionOperator exOperator = new ExpressionOperator(); exOperator.setType(FunctionOperator); @@ -2789,6 +2997,7 @@ public static ExpressionOperator sybaseInStringOperator() { * INTERNAL: * Build Sybase equivalent to TO_NUMBER. */ + @Deprecated public static ExpressionOperator sybaseToNumberOperator() { ExpressionOperator exOperator = new ExpressionOperator(); exOperator.setType(FunctionOperator); @@ -2806,6 +3015,7 @@ public static ExpressionOperator sybaseToNumberOperator() { * INTERNAL: * Build Sybase equivalent to TO_CHAR. */ + @Deprecated public static ExpressionOperator sybaseToDateToStringOperator() { ExpressionOperator exOperator = new ExpressionOperator(); exOperator.setType(FunctionOperator); @@ -2823,6 +3033,7 @@ public static ExpressionOperator sybaseToDateToStringOperator() { * INTERNAL: * Build Sybase equivalent to TO_DATE. */ + @Deprecated public static ExpressionOperator sybaseToDateOperator() { ExpressionOperator exOperator = new ExpressionOperator(); exOperator.setType(FunctionOperator); @@ -2840,6 +3051,7 @@ public static ExpressionOperator sybaseToDateOperator() { * INTERNAL: * Build Sybase equivalent to TO_CHAR. */ + @Deprecated public static ExpressionOperator sybaseToCharOperator() { ExpressionOperator exOperator = new ExpressionOperator(); exOperator.setType(FunctionOperator); @@ -2857,6 +3069,7 @@ public static ExpressionOperator sybaseToCharOperator() { * INTERNAL: * Build Sybase equivalent to TO_CHAR. */ + @Deprecated public static ExpressionOperator sybaseToCharWithFormatOperator() { ExpressionOperator exOperator = new ExpressionOperator(); exOperator.setType(FunctionOperator); @@ -2875,6 +3088,7 @@ public static ExpressionOperator sybaseToCharWithFormatOperator() { * INTERNAL: * Build the Sybase equivalent to Locate */ + @Deprecated public static ExpressionOperator sybaseLocateOperator() { ExpressionOperator result = simpleTwoArgumentFunction(ExpressionOperator.Locate, "CHARINDEX"); int[] argumentIndices = new int[2]; @@ -2889,6 +3103,7 @@ public static ExpressionOperator sybaseLocateOperator() { * Build the Sybase equivalent to Locate with a start index. * Sybase does not define this, so this gets a little complex... */ + @Deprecated public static ExpressionOperator sybaseLocate2Operator() { ExpressionOperator result = new ExpressionOperator(); result.setSelector(ExpressionOperator.Locate2); @@ -2999,11 +3214,12 @@ public static ExpressionOperator toNumber() { * Print a debug representation of this operator. */ public String toString() { - if ((getDatabaseStrings() == null) || (getDatabaseStrings().length == 0)) { + String[] dbStrings = getDatabaseStrings(); + if ((dbStrings == null) || (dbStrings.length == 0)) { //CR#... Print a useful name for the missing platform operator. return "platform operator - " + getPlatformOperatorName(this.selector); } else { - return "operator " + Arrays.asList(getDatabaseStrings()); + return "operator " + Arrays.asList(dbStrings); } } diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/expressions/ListExpressionOperator.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/expressions/ListExpressionOperator.java index 2791f4b6487..aeb0bef0ab8 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/expressions/ListExpressionOperator.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/expressions/ListExpressionOperator.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 1998, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022 IBM Corporation. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -39,17 +40,27 @@ public class ListExpressionOperator extends ExpressionOperator { protected String[] startStrings = null; protected String[] separators = null; protected String[] terminationStrings = null; + @Deprecated protected int numberOfItems = 0; + protected boolean changed = false; protected boolean isComplete = false; + @Override + public ExpressionOperator clone(){ + ListExpressionOperator clone = new ListExpressionOperator(); + this.copyTo(clone); + return clone; + } + public void copyTo(ExpressionOperator operator){ super.copyTo(operator); + if(operator == null) + return; + if (operator instanceof ListExpressionOperator){ ((ListExpressionOperator)operator).startStrings = Helper.copyStringArray(startStrings); ((ListExpressionOperator)operator).separators = Helper.copyStringArray(separators); ((ListExpressionOperator)operator).terminationStrings = Helper.copyStringArray(terminationStrings); - // don't copy numberOfItems since this copy method is used to duplicate an operator that - // may have a different number of items } } @@ -58,33 +69,59 @@ public void copyTo(ExpressionOperator operator){ * Recalculate the database strings each time this is called in * case one has been added. */ + @Deprecated @Override public String[] getDatabaseStrings() { - databaseStrings = new String[numberOfItems + 1]; + return getDatabaseStrings(0); + } + + /** + * Returns an array of Strings that expects a query argument between each String in the array to form the Expression. + * The array is built from the defined startStrings, separators, and terminationStrings. + * Start strings and termination strings take precedence over separator strings. + * + * The first defined start string will be added to the array. + * All subsequent start strings are optional, meaning they will only be added to the array if there are argument spaces available. + * + * The defined set of separator strings will be repeated, as a complete set, as long as there are argument spaces available. + * + * The last defined termination string will be added to the array. + * All antecedent termination strings are optional, meaning they will only be added to the array if there are argument spaces available. + */ + @Override + public String[] getDatabaseStrings(int arguments) { int i = 0; - while (i < startStrings.length){ - databaseStrings[i] = startStrings[i]; + String[] databaseStrings = new String[(arguments == 0) ? 2 : arguments + 1]; + + int start = (arguments < (startStrings.length)) ? databaseStrings.length - 1 : startStrings.length; + for (int j = 0; j < start; j++) { + databaseStrings[i] = startStrings[j]; i++; } - while (i < numberOfItems - (terminationStrings.length - 1)){ - for (int j=0;j outputCursors; - public DatabaseCall() { super.shouldProcessTokenInQuotes = false; - this.usesBinding = null; this.shouldCacheStatement = null; this.isFieldMatchingRequired = false; this.queryTimeout = 0; @@ -220,56 +214,14 @@ public void setHasMultipleResultSets(boolean hasMultipleResultSets) { this.hasMultipleResultSets = hasMultipleResultSets; } - /** - * INTERNAL: - */ - public void appendIn(Object inObject) { - getParameters().add(inObject); - getParameterTypes().add(IN); - } - - /** - * INTERNAL: - */ - public void appendInOut(DatabaseField inoutField) { - Object[] inOut = { inoutField, inoutField }; - getParameters().add(inOut); - getParameterTypes().add(INOUT); - } - - /** - * INTERNAL: - */ - public void appendInOut(Object inValueOrField, DatabaseField outField) { - Object[] inOut = { inValueOrField, outField }; - getParameters().add(inOut); - getParameterTypes().add(INOUT); - } - - /** - * INTERNAL: - */ - public void appendOut(DatabaseField outField) { - getParameters().add(outField); - getParameterTypes().add(OUT); - } - - /** - * INTERNAL: - */ - public void appendOutCursor(DatabaseField outField) { - getParameters().add(outField); - getParameterTypes().add(OUT_CURSOR); - getOutputCursors().add(outField); - } - /** * Add the parameter. - * If using binding bind the parameter otherwise let the platform print it. + *

+ * If binding is enabled, then bind the parameter; otherwise let the platform print it. * The platform may also decide to bind the value. */ - public void appendParameter(Writer writer, Object parameter, AbstractSession session) { - if (Boolean.TRUE.equals(usesBinding)) { + public void appendParameter(Writer writer, Object parameter, boolean shouldBind, AbstractSession session) { + if (Boolean.TRUE.equals(shouldBind)) { bindParameter(writer, parameter); } else { session.getPlatform().appendParameter(this, writer, parameter); @@ -277,7 +229,7 @@ public void appendParameter(Writer writer, Object parameter, AbstractSession ses } /** - * Bind the parameter. Binding is determined by the call and second the platform. + * Bind the parameter. Binding is determined by the parameter and second the platform. */ public void bindParameter(Writer writer, Object parameter) { if (parameter instanceof Collection) { @@ -508,32 +460,20 @@ public int getMaxRows() { * Returns the fields to be used in output row. */ public Vector getOutputRowFields() { - Vector fields = new Vector(); + Vector fields = new Vector(); int size = getParameters().size(); for (int i = 0; i < size; i++) { - Integer parameterType = this.parameterTypes.get(i); Object parameter = this.parameters.get(i); - if (parameterType == OUT) { + ParameterType parameterType = this.parameterTypes.get(i); + if (parameterType == ParameterType.OUT) { fields.add(parameter); - } else if (parameterType == INOUT) { + } else if (parameterType == ParameterType.INOUT) { fields.add(((Object[])parameter)[1]); } } return fields; } - /** - * INTERNAL: - * Return the output cursors for this stored procedure call. - */ - public List getOutputCursors() { - if (outputCursors == null) { - outputCursors = new ArrayList(); - } - - return outputCursors; - } - /** * INTERNAL: * Return the query string (SQL) of the call. @@ -610,13 +550,6 @@ public boolean hasOptimisticLock() { return hasOptimisticLock; } - /** - * Return true if there are output cursors on this call. - */ - public boolean hasOutputCursors() { - return outputCursors != null && ! outputCursors.isEmpty(); - } - /** * Callable statement is required if there is an output parameter. */ @@ -726,15 +659,15 @@ protected void prepareInternalParameters(AbstractSession session) { boolean hasFoundOutCursor = false; int size = this.parameters.size(); for (int index = 0; index < size; index++) { - Integer parameterType = this.parameterTypes.get(index); - if (parameterType == DatasourceCall.OUT_CURSOR) { + ParameterType parameterType = this.parameterTypes.get(index); + if (parameterType == ParameterType.OUT_CURSOR) { if (hasFoundOutCursor) { // one cursor has been already found throw ValidationException.multipleCursorsNotSupported(toString()); } else { hasFoundOutCursor = true; } - } else if (parameterType == DatasourceCall.OUT) { + } else if (parameterType == ParameterType.OUT) { if (nFirstOutParameterIndex == -1) { nFirstOutParameterIndex = index; } @@ -744,61 +677,69 @@ protected void prepareInternalParameters(AbstractSession session) { } } if (!hasFoundOutCursor && (nFirstOutParameterIndex >= 0)) { - this.parameterTypes.set(nFirstOutParameterIndex, DatasourceCall.OUT_CURSOR); + this.parameterTypes.set(nFirstOutParameterIndex, ParameterType.OUT_CURSOR); } } int size = getParameters().size(); for (int i = 0; i < size; i++) { Object parameter = this.parameters.get(i); - Integer parameterType = this.parameterTypes.get(i); - if (parameterType == MODIFY) { - // in case the field's type is not set, the parameter type is set to CUSTOM_MODIFY. - DatabaseField field = (DatabaseField)parameter; - if ((field.getType() == null) || session.getPlatform().shouldUseCustomModifyForCall(field)) { - this.parameterTypes.set(i, CUSTOM_MODIFY); - } - } else if (parameterType == INOUT) { - // In case there is a type in outField, outParameter is created. - // During translate call, either outParameter or outField is used for - // creating inOut parameter. - setShouldBuildOutputRow(true); - setIsCallableStatementRequired(true); - DatabaseField outField = (DatabaseField)((Object[])parameter)[1]; - if (outField.getType() == null) { - DatabaseField typeOutField = getFieldWithTypeFromDescriptor(outField); - if (typeOutField != null) { - outField = typeOutField.clone(); + ParameterType parameterType = this.parameterTypes.get(i); + + switch(parameterType) { + case MODIFY: + // in case the field's type is not set, the parameter type is set to CUSTOM_MODIFY. + DatabaseField field = (DatabaseField)parameter; + if ((field.getType() == null) || session.getPlatform().shouldUseCustomModifyForCall(field)) { + this.parameterTypes.set(i, ParameterType.CUSTOM_MODIFY); } - } - if (outField.getType() != null) { - // outParameter contains all the info for registerOutputParameter call. - OutputParameterForCallableStatement outParameter = new OutputParameterForCallableStatement(outField, session); - ((Object[])parameter)[1] = outParameter; - } - } else if ((parameterType == OUT) || (parameterType == OUT_CURSOR)) { - boolean isCursor = parameterType == OUT_CURSOR; - if (!isCursor) { + break; + case INOUT: + // In case there is a type in outField, outParameter is created. + // During translate call, either outParameter or outField is used for + // creating inOut parameter. setShouldBuildOutputRow(true); - } - setIsCallableStatementRequired(true); - DatabaseField outField = (DatabaseField)parameter; - if (outField.getType() == null) { - DatabaseField typeOutField = getFieldWithTypeFromDescriptor(outField); - if (typeOutField != null) { - outField = typeOutField.clone(); + setIsCallableStatementRequired(true); + DatabaseField outField = (DatabaseField)((Object[])parameter)[1]; + if (outField.getType() == null) { + DatabaseField typeOutField = getFieldWithTypeFromDescriptor(outField); + if (typeOutField != null) { + outField = typeOutField.clone(); + } + } + if (outField.getType() != null) { + // outParameter contains all the info for registerOutputParameter call. + OutputParameterForCallableStatement outParameter = new OutputParameterForCallableStatement(outField, session); + ((Object[])parameter)[1] = outParameter; + } + break; + case OUT: + case OUT_CURSOR: + boolean isCursor = parameterType == ParameterType.OUT_CURSOR; + if (!isCursor) { + setShouldBuildOutputRow(true); + } + setIsCallableStatementRequired(true); + outField = (DatabaseField)parameter; + if (outField.getType() == null) { + DatabaseField typeOutField = getFieldWithTypeFromDescriptor(outField); + if (typeOutField != null) { + outField = typeOutField.clone(); + } } - } - // outParameter contains all the info for registerOutputParameter call. - OutputParameterForCallableStatement outParameter = new OutputParameterForCallableStatement(outField, session, isCursor); - this.parameters.set(i, outParameter); - this.parameterTypes.set(i, parameterType); + // outParameter contains all the info for registerOutputParameter call. + OutputParameterForCallableStatement outParameter = new OutputParameterForCallableStatement(outField, session, isCursor); + this.parameters.set(i, outParameter); + this.parameterTypes.set(i, parameterType); + break; } } + if (this.returnsResultSet == null) { setReturnsResultSet(!isCallableStatementRequired()); } + // if there is nothing returned and we are not using optimistic locking then batch //if it is a StoredProcedure with in/out or out parameters then do not batch //logic may be weird but we must not batch if we are not using JDBC batchwriting and we have parameters @@ -844,7 +785,7 @@ public Statement prepareStatement(DatabaseAccessor accessor, AbstractRecord tran if (this.parameters == null) { return statement; } - List parameters = getParameters(); + List parameters = getParameters(); int size = parameters.size(); for (int index = 0; index < size; index++) { session.getPlatform().setParameterValueInDatabaseCall(parameters.get(index), (PreparedStatement)statement, index+1, session); @@ -1053,13 +994,6 @@ public void setStatement(Statement statement) { this.statement = statement; } - /** - * The call may specify that its parameters should be bound. - */ - public void setUsesBinding(boolean usesBinding) { - this.usesBinding = Boolean.valueOf(usesBinding); - } - /** * Set whether the call has to build output row */ @@ -1136,233 +1070,121 @@ public void translate(AbstractRecord translationRow, AbstractRecord modifyRow, A if (!isPrepared()) { throw ValidationException.cannotTranslateUnpreparedCall(toString()); } - if (usesBinding(session) && (this.parameters != null)) { + + if(session.getPlatform().shouldBindPartialParameters() && (this.parameters != null)) { + translateQueryStringAndBindParameters(translationRow, modifyRow, session); + } else if (usesBinding(session) && (this.parameters != null)) { boolean hasParameterizedIN = false; - List parameters = getParameters(); - List parameterTypes = getParameterTypes(); + List parameters = getParameters(); int size = parameters.size(); - List parametersValues = new ArrayList(size); + List translatedParametersValues = new ArrayList(size); + for (int index = 0; index < size; index++) { Object parameter = parameters.get(index); - Object parameterType = parameterTypes.get(index); - if (parameterType == MODIFY) { - DatabaseField field = (DatabaseField)parameter; - Object value = modifyRow.get(field); - // If the value is null, the field is passed as the value so the type can be obtained from the field. - if (value == null) { - // The field from the modify row is used, as the calls field may not have the type, - // but if the field is missing the calls field may also have the type. - value = modifyRow.getField(field); - if (value == null) { - value = field; - } - } - parametersValues.add(value); - } else if (parameterType == CUSTOM_MODIFY) { - DatabaseField field = (DatabaseField)parameter; - Object value = modifyRow.get(field); - value = session.getPlatform().getCustomModifyValueForCall(this, value, field, true); - //Bug#8200836 needs use unwrapped connection - if ((value!=null) && (value instanceof BindCallCustomParameter) && (((BindCallCustomParameter)value).shouldUseUnwrappedConnection())){ - this.isNativeConnectionRequired=true; - } + ParameterType parameterType = parameterTypes.get(index); - // If the value is null, the field is passed as the value so the type can be obtained from the field. - if (value == null) { - // The field from the modify row is used, as the calls field may not have the type, - // but if the field is missing the calls field may also have the type. - value = modifyRow.getField(field); - if (value == null) { - value = field; - } - } - parametersValues.add(value); - } else if (parameterType == TRANSLATION) { - Object value = null; - DatabaseField field = null; - if (parameter instanceof ParameterExpression) { - field = ((ParameterExpression)parameter).getField(); - value = ((ParameterExpression)parameter).getValue(translationRow, query, session); - } else { + DatabaseField field = null; + Object translatedValue = null; + switch(parameterType) { + case MODIFY: field = (DatabaseField)parameter; - value = translationRow.get(field); - if (value == null) {// Backward compatibility double check. - value = modifyRow.get(field); - } - } - if (value instanceof Collection) { - // Must re-translate IN parameters. - hasParameterizedIN = true; - } - // If the value is null, the field is passed as the value so the type can be obtained from the field. - if ((value == null) && (field != null)) { - if (!this.query.hasNullableArguments() || !this.query.getNullableArguments().contains(field)) { - value = translationRow.getField(field); - // The field from the row is used, as the calls field may not have the type, + translatedValue = modifyRow.get(field); + // If the value is null, the field is passed as the value so the type can be obtained from the field. + if (translatedValue == null) { + // The field from the modify row is used, as the calls field may not have the type, // but if the field is missing the calls field may also have the type. - if (value == null) { - value = field; + translatedValue = modifyRow.getField(field); + if (translatedValue == null) { + translatedValue = field; } - parametersValues.add(value); } - } else { - parametersValues.add(value); - } - } else if (parameterType == LITERAL) { - parametersValues.add(parameter); - } else if (parameterType == IN) { - Object value = getValueForInParameter(parameter, translationRow, modifyRow, session, true); - // Returning this means the parameter was optional and should not be included. - if (value != this) { - parametersValues.add(value); - } - } else if (parameterType == INOUT) { - Object value = getValueForInOutParameter(parameter, translationRow, modifyRow, session); - parametersValues.add(value); - } else if (parameterType == OUT || parameterType == OUT_CURSOR) { - if (parameter != null) { - ((OutputParameterForCallableStatement) parameter).getOutputField().setIndex(index); - } - parametersValues.add(parameter); - } - } - setParameters(parametersValues); - // If an IN parameter was found must translate SQL. - if (hasParameterizedIN) { - translateQueryStringForParameterizedIN(translationRow, modifyRow, session); - } - return; - } - - translateQueryString(translationRow, modifyRow, session); - } + translatedParametersValues.add(translatedValue); + break; + case CUSTOM_MODIFY: + field = (DatabaseField)parameter; + translatedValue = modifyRow.get(field); + translatedValue = session.getPlatform().getCustomModifyValueForCall(this, translatedValue, field, true); + //Bug#8200836 needs use unwrapped connection + if ((translatedValue != null) && (translatedValue instanceof BindCallCustomParameter) + && (((BindCallCustomParameter)translatedValue).shouldUseUnwrappedConnection())) { + this.isNativeConnectionRequired = true; + } - /** - * INTERNAL: - * Translate only IN() parameter values (List parameters). - */ - public void translateQueryStringForParameterizedIN(AbstractRecord translationRow, AbstractRecord modifyRow, AbstractSession session) { - int lastIndex = 0; - int parameterIndex = 0; - String queryString = getQueryString(); - Writer writer = new CharArrayWriter(queryString.length() + 50); - try { - // PERF: This method is heavily optimized do not touch anything unless you know "very well" what your doing. - List parameters = getParameters(); - List parametersValues = new ArrayList(parameters.size()); - while (lastIndex != -1) { - int tokenIndex = queryString.indexOf(argumentMarker(), lastIndex); - String token; - if (tokenIndex == -1) { - token = queryString.substring(lastIndex, queryString.length()); - lastIndex = -1; - } else { - token = queryString.substring(lastIndex, tokenIndex); - } - writer.write(token); - if (tokenIndex != -1) { - // Process next parameter. - Object parameter = parameters.get(parameterIndex); - // Parameter expressions are used for nesting and correct mapping conversion of the value. - if (parameter instanceof Collection) { - Collection values = (Collection)parameter; - writer.write("("); - if ((values.size() > 0) && (values.iterator().next() instanceof List)) { - // Support nested lists. - int size = values.size(); - Iterator valuesIterator = values.iterator(); - for (int index = 0; index < size; index++) { - List nestedValues = (List)valuesIterator.next(); - parametersValues.addAll(nestedValues); - int nestedSize = nestedValues.size(); - writer.write("("); - for (int nestedIndex = 0; nestedIndex < nestedSize; nestedIndex++) { - writer.write("?"); - if ((nestedIndex + 1) < nestedSize) { - writer.write(","); - } - } - writer.write(")"); - if ((index + 1) < size) { - writer.write(","); - } + // If the value is null, the field is passed as the value so the type can be obtained from the field. + if (translatedValue == null) { + // The field from the modify row is used, as the calls field may not have the type, + // but if the field is missing the calls field may also have the type. + translatedValue = modifyRow.getField(field); + if (translatedValue == null) { + translatedValue = field; } + } + translatedParametersValues.add(translatedValue); + break; + case TRANSLATION: + if (parameter instanceof ParameterExpression) { + field = ((ParameterExpression)parameter).getField(); + translatedValue = ((ParameterExpression)parameter).getValue(translationRow, query, session); } else { - parametersValues.addAll(values); - int size = values.size(); - - int limit = ((DatasourcePlatform)session.getDatasourcePlatform()).getINClauseLimit(); - //The database platform has a limit for the IN clause so we need to reformat the clause - if(limit > 0) { - boolean not = token.endsWith(" NOT IN "); - String subToken = token.substring(0, token.length() - (not ? " NOT IN " : " IN ").length()); - int spaceIndex = subToken.lastIndexOf(' '); - int braceIndex = subToken.lastIndexOf('('); - String fieldName = subToken.substring((spaceIndex > braceIndex ? spaceIndex : braceIndex) + 1); - String inToken = not ? ") AND " + fieldName + " NOT IN (" : ") OR " + fieldName + " IN ("; - - for (int index = 0; index < size; index++) { - writer.write("?"); - if ((index + 1) < size) { - if (index > 0 && (index + 1) % limit == 0) { - writer.write(inToken); - } else { - writer.write(","); - } - } - } - } else { - for (int index = 0; index < size; index++) { - writer.write("?"); - if ((index + 1) < size) { - writer.write(","); - } + field = (DatabaseField)parameter; + translatedValue = translationRow.get(field); + if (translatedValue == null) {// Backward compatibility double check. + translatedValue = modifyRow.get(field); + } + } + if (translatedValue instanceof Collection) { + // Must re-translate IN parameters. + hasParameterizedIN = true; + } + // If the value is null, the field is passed as the value so the type can be obtained from the field. + if ((translatedValue == null) && (field != null)) { + if (!this.query.hasNullableArguments() || !this.query.getNullableArguments().contains(field)) { + translatedValue = translationRow.getField(field); + // The field from the row is used, as the calls field may not have the type, + // but if the field is missing the calls field may also have the type. + if (translatedValue == null) { + translatedValue = field; } + translatedParametersValues.add(translatedValue); } + } else { + translatedParametersValues.add(translatedValue); } - writer.write(")"); - } else { - parametersValues.add(parameter); - writer.write("?"); - } - lastIndex = tokenIndex + 1; - parameterIndex++; + break; + case LITERAL: + translatedParametersValues.add(parameter); + break; + case IN: + translatedValue = getValueForInParameter(parameter, translationRow, modifyRow, session, true); + // Returning this means the parameter was optional and should not be included. + if (translatedValue != this) { + translatedParametersValues.add(translatedValue); + } + break; + case INOUT: + translatedValue = getValueForInOutParameter(parameter, translationRow, modifyRow, session); + translatedParametersValues.add(translatedValue); + break; + case OUT: + case OUT_CURSOR: + if (parameter != null) { + ((OutputParameterForCallableStatement) parameter).getOutputField().setIndex(index); + } + translatedParametersValues.add(parameter); + break; } } - setParameters(parametersValues); - setQueryString(writer.toString()); - - } catch (IOException exception) { - throw ValidationException.fileError(exception); - } - } - - /** - * The call may specify that its parameters should be bound. - */ - public boolean usesBinding(AbstractSession session) { - return usesBinding(session.getPlatform()); - } - /** - * The call may specify that its parameters should be bound. - */ - public boolean usesBinding(DatabasePlatform databasePlatform) { - if (this.usesBinding == null) { - return databasePlatform.shouldBindAllParameters(); + setParameters(translatedParametersValues); + // If an IN parameter was found must translate SQL. + if (hasParameterizedIN) { + translateQueryStringForParameterizedIN(translationRow, modifyRow, session); + } } else { - return this.usesBinding.booleanValue(); + translateQueryString(translationRow, modifyRow, session); } } - /** - * INTERNAL - * Indicates whether usesBinding has been set. - */ - public boolean isUsesBindingSet() { - return this.usesBinding != null; - } - /** * INTERNAL: * Return if the locator is required for the LOB (BLOB and CLOB) writing. diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/databaseaccess/DatabasePlatform.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/databaseaccess/DatabasePlatform.java index 1afc2550839..f673c145530 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/databaseaccess/DatabasePlatform.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/databaseaccess/DatabasePlatform.java @@ -68,6 +68,7 @@ import org.eclipse.persistence.exceptions.ValidationException; import org.eclipse.persistence.expressions.Expression; import org.eclipse.persistence.expressions.ExpressionBuilder; +import org.eclipse.persistence.internal.databaseaccess.DatasourceCall.ParameterType; import org.eclipse.persistence.internal.expressions.ExpressionSQLPrinter; import org.eclipse.persistence.internal.expressions.ParameterExpression; import org.eclipse.persistence.internal.expressions.SQLSelectStatement; @@ -136,11 +137,14 @@ public class DatabasePlatform extends DatasourcePlatform { protected boolean usesBatchWriting; /** Bind all arguments to any SQL statement. */ - protected boolean shouldBindAllParameters; + protected Boolean shouldBindAllParameters; /** Bind all arguments to any SQL statement. */ protected boolean shouldForceBindAllParameters; + /** Bind some arguments to any SQL statement. */ + protected boolean shouldBindPartialParameters; + /** Cache all prepared statements, this requires full parameter binding as well. */ protected boolean shouldCacheAllStatements; @@ -286,7 +290,7 @@ public DatabasePlatform() { this.usesStringBinding = false; this.stringBindingSize = 255; this.shouldTrimStrings = true; - this.shouldBindAllParameters = true; + this.shouldBindAllParameters = null; this.shouldForceBindAllParameters = false; this.shouldCacheAllStatements = false; this.shouldOptimizeDataConversion = true; @@ -468,13 +472,13 @@ protected void appendNumber(Number number, Writer writer) throws IOException { * In case shouldBindLiterals is true, instead of null value a DatabaseField * value may be passed (so that it's type could be used for binding null). */ - public void appendLiteralToCall(Call call, Writer writer, Object literal) { - if(shouldBindLiterals()) { + public void appendLiteralToCall(Call call, Writer writer, Object literal, Boolean canBind) { + if(!Boolean.FALSE.equals(canBind) && shouldBindLiterals()) { appendLiteralToCallWithBinding(call, writer, literal); } else { int nParametersToAdd = appendParameterInternal(call, writer, literal); for (int i = 0; i < nParametersToAdd; i++) { - ((DatabaseCall)call).getParameterTypes().add(DatabaseCall.LITERAL); + ((DatabaseCall)call).getParameterTypes().add(ParameterType.LITERAL); } } } @@ -836,7 +840,7 @@ public String buildProcedureCallString(StoredProcedureCall call, AbstractSession for (int index = indexFirst; index < size; index++) { String name = call.getProcedureArgumentNames().get(index); Object parameter = call.getParameters().get(index); - Integer parameterType = call.getParameterTypes().get(index); + ParameterType parameterType = call.getParameterTypes().get(index); // If the argument is optional and null, ignore it. if (!call.hasOptionalArguments() || !call.getOptionalArguments().contains(parameter) || (row.get(parameter) != null)) { @@ -994,8 +998,9 @@ public void copyInto(Platform platform) { databasePlatform.setUsesNativeSQL(usesNativeSQL()); databasePlatform.setUsesByteArrayBinding(usesByteArrayBinding()); databasePlatform.setUsesStringBinding(usesStringBinding()); - databasePlatform.setShouldBindAllParameters(shouldBindAllParameters()); - databasePlatform.setShouldForceBindAllParameters(shouldForceBindAllParameters()); + databasePlatform.shouldBindAllParameters = this.shouldBindAllParameters; + databasePlatform.shouldForceBindAllParameters = this.shouldForceBindAllParameters; + databasePlatform.shouldBindPartialParameters = this.shouldBindPartialParameters; databasePlatform.setShouldCacheAllStatements(shouldCacheAllStatements()); databasePlatform.setStatementCacheSize(getStatementCacheSize()); databasePlatform.setTransactionIsolation(getTransactionIsolation()); @@ -1508,7 +1513,18 @@ public String getProcedureArgumentString() { /** * Obtain the platform specific argument string */ + @Deprecated public String getProcedureArgument(String name, Object parameter, Integer parameterType, StoredProcedureCall call, AbstractSession session) { + if (name != null && shouldPrintStoredProcedureArgumentNameInCall()) { + return getProcedureArgumentString() + name + " = " + "?"; + } + return getProcedureArgument(name, parameter, ParameterType.valueOf(parameterType), call, session); + } + + /** + * Obtain the platform specific argument string + */ + public String getProcedureArgument(String name, Object parameter, ParameterType parameterType, StoredProcedureCall call, AbstractSession session) { if (name != null && shouldPrintStoredProcedureArgumentNameInCall()) { return getProcedureArgumentString() + name + " = " + "?"; } @@ -2021,6 +2037,13 @@ public void setShouldForceBindAllParameters(boolean shouldForceBindAllParameters this.shouldForceBindAllParameters = shouldForceBindAllParameters; } + /** + * Used to enable parameter binding and override the platform default + */ + public void setShouldBindPartialParameters(boolean shouldBindPartialParameters) { + this.shouldBindPartialParameters = shouldBindPartialParameters; + } + /** * Can be used if the app expects upper case but the database is not return consistent case, i.e. different databases. */ @@ -2184,9 +2207,25 @@ public void setUsesStringBinding(boolean aBool) { /** * Bind all arguments to any SQL statement. + *

+ * {@link org.eclipse.persistence.config.PersistenceUnitProperties#JDBC_BIND_PARAMETERS} */ public boolean shouldBindAllParameters() { - return shouldBindAllParameters; + // Non-null value implies it has been overridden + if(this.shouldBindAllParameters != null) { + return this.shouldBindAllParameters; + } + // Default value + return true; + } + + /** + * Used to determine if the platform should perform partial parameter binding or not + *

+ * Off by default. Only platforms with the support added should enable this configuration. + */ + public boolean shouldBindPartialParameters() { + return false; } /** @@ -3493,11 +3532,18 @@ public void setShouldBindLiterals(boolean shouldBindLiterals) { * INTERNAL: * Some databases have issues with using parameters on certain functions and relations. * This allows statements to disable binding only in these cases. + *

+ * Alternatively, DatabasePlatforms can override specific ExpressionOperators and add them + * to the platform specific operators. See {@link DatasourcePlatform#initializePlatformOperators()} */ public boolean isDynamicSQLRequiredForFunctions() { return false; } + public boolean allowBindingForSelectClause() { + return true; + } + /** * INTERNAL: * Platforms that support java.sql.Ref may override this method. diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/databaseaccess/DatasourceCall.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/databaseaccess/DatasourceCall.java index 24f0ca506cb..0e54fae10d3 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/databaseaccess/DatasourceCall.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/databaseaccess/DatasourceCall.java @@ -1,6 +1,6 @@ /* - * Copyright (c) 1998, 2019 Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2019 IBM Corporation. All rights reserved. + * Copyright (c) 1998, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022 IBM Corporation. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -42,6 +42,8 @@ import java.io.ObjectInputStream; import java.io.Writer; import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; import java.util.List; /** @@ -56,19 +58,41 @@ public abstract class DatasourceCall implements Call { protected transient DatabaseQuery query; // The parameters (values) are ordered as they appear in the call. - protected List parameters; + protected List parameters; // The parameter types determine if the parameter is a modify, translation or literal type. - protected List parameterTypes; - public static final Integer LITERAL = Integer.valueOf(1); - public static final Integer MODIFY = Integer.valueOf(2); - public static final Integer TRANSLATION = Integer.valueOf(3); - public static final Integer CUSTOM_MODIFY = Integer.valueOf(4); - public static final Integer OUT = Integer.valueOf(5); - public static final Integer INOUT = Integer.valueOf(6); - public static final Integer IN = Integer.valueOf(7); - public static final Integer OUT_CURSOR = Integer.valueOf(8); - public static final Integer INLINE = Integer.valueOf(9); + + protected List parameterTypes; + + // The parameter binding determines if the specific parameter should be bound. + protected List parameterBindings; + + /** + * The call may specify that all of its parameters should/shouldn't be bound. + *

+ * Typically, this is set to false in the event that the DatabasePlatform marks the call + * as containing illegal binding behavior during JPQL parsing. + *

+ * Defaults to null to indicate no preference and allows database platforms to determine + */ + protected Boolean usesBinding; + + public enum ParameterType { + LITERAL(1), MODIFY(2), TRANSLATION(3), CUSTOM_MODIFY(4), OUT(5), + INOUT(6), IN(7), OUT_CURSOR(8), INLINE(9); + + public int val; + + ParameterType(int val) { + this.val = val; + } + + public static ParameterType valueOf(int value) { + for(ParameterType v : values()) + if(v.val == value) return v; + throw new IllegalArgumentException("Value (" + value + ") does not match a ParameterType"); + } + } // Store if the call has been prepared. protected boolean isPrepared; @@ -79,6 +103,11 @@ public abstract class DatasourceCall implements Call { //Eclipselink Bug 217745 indicates whether or not the token(#,?) needs to be processed if they are in the quotes. protected boolean shouldProcessTokenInQuotes; + /** + * Keep a list of the output cursors. + */ + protected List outputCursors; + // Type of call. protected int returnType; protected static final int NO_RETURN = 1; @@ -90,6 +119,7 @@ public abstract class DatasourceCall implements Call { public DatasourceCall() { this.isPrepared = false; this.shouldProcessTokenInQuotes = true; + this.usesBinding = null; } /** @@ -98,7 +128,7 @@ public DatasourceCall() { */ public List getParameters() { if (parameters == null) { - parameters = new ArrayList(); + parameters = new ArrayList(); } return parameters; } @@ -106,27 +136,44 @@ public List getParameters() { /** * The parameter types determine if the parameter is a modify, translation or literal type. */ - public List getParameterTypes() { + public List getParameterTypes() { if (parameterTypes == null) { - parameterTypes = new ArrayList(); + parameterTypes = new ArrayList(); } return parameterTypes; } + /** + * The parameter binding determines if the specific parameter should be bound. + */ + public List getParameterBindings() { + if (parameterBindings == null) { + parameterBindings = new ArrayList(); + } + return parameterBindings; + } + /** * The parameters are the values in order of occurrence in the SQL statement. */ - public void setParameters(List parameters) { + public void setParameters(List parameters) { this.parameters = parameters; } /** * The parameter types determine if the parameter is a modify, translation or literal type. */ - public void setParameterTypes(List parameterTypes) { + public void setParameterTypes(List parameterTypes) { this.parameterTypes = parameterTypes; } + /** + * The parameter binding determines if the specific parameter should be bound. + */ + public void setParameterBindings(List parameterBindings) { + this.parameterBindings = parameterBindings; + } + /** * The parameters are the values in order of occurrence in call. * This is lazy initialized to conserve space on calls that have no parameters. @@ -135,6 +182,25 @@ public boolean hasParameters() { return (parameters != null) && (!getParameters().isEmpty()); } + /** + * INTERNAL: + * Return the output cursors for this stored procedure call. + */ + public List getOutputCursors() { + if (outputCursors == null) { + outputCursors = new ArrayList(); + } + + return outputCursors; + } + + /** + * Return true if there are output cursors on this call. + */ + public boolean hasOutputCursors() { + return outputCursors != null && ! outputCursors.isEmpty(); + } + /** * The return type is one of, NoReturn, ReturnOneRow or ReturnManyRows. */ @@ -142,8 +208,8 @@ public boolean areManyRowsReturned() { return this.returnType == RETURN_MANY_ROWS; } - public static boolean isOutputParameterType(Integer parameterType) { - return (parameterType == OUT) || (parameterType == INOUT) || (parameterType == OUT_CURSOR); + public static boolean isOutputParameterType(ParameterType parameterType) { + return (parameterType == ParameterType.OUT) || (parameterType == ParameterType.INOUT) || (parameterType == ParameterType.OUT_CURSOR); } /** @@ -160,6 +226,53 @@ public void setIsPrepared(boolean isPrepared) { this.isPrepared = isPrepared; } + /** + * Set that this call should or shouldn't bind all parameters + */ + public void setUsesBinding(boolean usesBinding) { + this.usesBinding = Boolean.valueOf(usesBinding); + } + + /** + * Convenience method + * @see {@link #usesBinding(DatabasePlatform databasePlatform)} + */ + public boolean usesBinding(AbstractSession session) { + return usesBinding(session.getPlatform()); + } + + /** + * Determines if this call should bind all parameters. + *

+ * Defaults behavior to the databasePlatform if this call does not have a preference; if + * {@link org.eclipse.persistence.internal.databaseaccess.DatasourceCall#usesBinding} is not set + *

+ * @see org.eclipse.persistence.internal.databaseaccess.DatabasePlatform#shouldBindAllParameters() + */ + public boolean usesBinding(DatabasePlatform databasePlatform) { + if (this.usesBinding == null) { + return databasePlatform.shouldBindAllParameters(); + } else { + return this.usesBinding.booleanValue(); + } + } + + /** + * INTERNAL + * Indicates whether usesBinding has been set. + */ + public Boolean usesBinding() { + return this.usesBinding; + } + + /** + * INTERNAL + * Indicates whether usesBinding has been set. + */ + public boolean isUsesBindingSet() { + return this.usesBinding != null; + } + /** * Return the appropriate mechanism, * with the call added as necessary. @@ -569,8 +682,7 @@ public void appendLiteral(Writer writer, Object literal) { } catch (IOException exception) { throw ValidationException.fileError(exception); } - getParameters().add(literal); - getParameterTypes().add(LITERAL); + appendLiteral(literal); } /** @@ -583,8 +695,7 @@ public void appendTranslation(Writer writer, DatabaseField modifyField) { } catch (IOException exception) { throw ValidationException.fileError(exception); } - getParameters().add(modifyField); - getParameterTypes().add(TRANSLATION); + appendTranslation(modifyField); } /** @@ -597,8 +708,7 @@ public void appendModify(Writer writer, DatabaseField modifyField) { } catch (IOException exception) { throw ValidationException.fileError(exception); } - getParameters().add(modifyField); - getParameterTypes().add(MODIFY); + appendModify(modifyField); } /** @@ -611,8 +721,7 @@ public void appendIn(Writer writer, DatabaseField field) { } catch (IOException exception) { throw ValidationException.fileError(exception); } - getParameters().add(field); - getParameterTypes().add(IN); + appendIn(field); } /** @@ -625,9 +734,7 @@ public void appendInOut(Writer writer, DatabaseField inoutField) { } catch (IOException exception) { throw ValidationException.fileError(exception); } - Object[] inOut = { inoutField, inoutField }; - getParameters().add(inOut); - getParameterTypes().add(INOUT); + appendInOut(inoutField); } /** @@ -640,8 +747,147 @@ public void appendOut(Writer writer, DatabaseField outField) { } catch (IOException exception) { throw ValidationException.fileError(exception); } + appendOut(outField); + } + + /** + * INTERNAL: + */ + public void appendLiteral(Object literal) { + getParameters().add(literal); + getParameterTypes().add(ParameterType.LITERAL); + getParameterBindings().add(true); + } + + /** + * INTERNAL: + */ + public void appendLiteral(Object literal, Boolean shouldBind) { + getParameters().add(literal); + getParameterTypes().add(ParameterType.LITERAL); + getParameterBindings().add(shouldBind); + } + + /** + * INTERNAL: + */ + public void appendTranslation(DatabaseField modifyField) { + getParameters().add(modifyField); + getParameterTypes().add(ParameterType.TRANSLATION); + getParameterBindings().add(true); + } + + /** + * INTERNAL: + */ + public void appendTranslation(DatabaseField modifyField, Boolean shouldBind) { + getParameters().add(modifyField); + getParameterTypes().add(ParameterType.TRANSLATION); + getParameterBindings().add(shouldBind); + } + + /** + * INTERNAL: + */ + public void appendModify(DatabaseField modifyField) { + getParameters().add(modifyField); + getParameterTypes().add(ParameterType.MODIFY); + getParameterBindings().add(true); + } + + /** + * INTERNAL: + */ + public void appendModify(DatabaseField modifyField, Boolean shouldBind) { + getParameters().add(modifyField); + getParameterTypes().add(ParameterType.MODIFY); + getParameterBindings().add(shouldBind); + } + + /** + * INTERNAL: + */ + public void appendIn(Object inObject) { + getParameters().add(inObject); + getParameterTypes().add(ParameterType.IN); + getParameterBindings().add(true); + } + + /** + * INTERNAL: + */ + public void appendIn(Object inObject, Boolean shouldBind) { + getParameters().add(inObject); + getParameterTypes().add(ParameterType.IN); + getParameterBindings().add(shouldBind); + } + + /** + * INTERNAL: + */ + public void appendInOut(DatabaseField inoutField) { + Object[] inOut = { inoutField, inoutField }; + getParameters().add(inOut); + getParameterTypes().add(ParameterType.INOUT); + getParameterBindings().add(true); + } + + /** + * INTERNAL: + */ + public void appendInOut(DatabaseField inoutField, Boolean shouldBind) { + Object[] inOut = { inoutField, inoutField }; + getParameters().add(inOut); + getParameterTypes().add(ParameterType.INOUT); + getParameterBindings().add(shouldBind); + } + + /** + * INTERNAL: + */ + public void appendInOut(Object inValueOrField, DatabaseField outField) { + Object[] inOut = { inValueOrField, outField }; + getParameters().add(inOut); + getParameterTypes().add(ParameterType.INOUT); + getParameterBindings().add(true); + } + + /** + * INTERNAL: + */ + public void appendInOut(Object inValueOrField, DatabaseField outField, Boolean shouldBind) { + Object[] inOut = { inValueOrField, outField }; + getParameters().add(inOut); + getParameterTypes().add(ParameterType.INOUT); + getParameterBindings().add(shouldBind); + } + + /** + * INTERNAL: + */ + public void appendOut(DatabaseField outField) { + getParameters().add(outField); + getParameterTypes().add(ParameterType.OUT); + getParameterBindings().add(true); + } + + /** + * INTERNAL: + */ + public void appendOut(DatabaseField outField, Boolean shouldBind) { getParameters().add(outField); - getParameterTypes().add(OUT); + getParameterTypes().add(ParameterType.OUT); + getParameterBindings().add(shouldBind); + } + + /** + * INTERNAL: + */ + public void appendOutCursor(DatabaseField outField) { + getParameters().add(outField); + getParameterTypes().add(ParameterType.OUT_CURSOR); + getParameterBindings().add(true); + getOutputCursors().add(outField); } /** @@ -649,7 +895,17 @@ public void appendOut(Writer writer, DatabaseField outField) { * If using binding bind the parameter otherwise let the platform print it. * The platform may also decide to bind the value. */ - public void appendParameter(Writer writer, Object parameter, AbstractSession session) { + public void appendOutCursor(DatabaseField outField, Boolean shouldBind) { + getParameters().add(outField); + getParameterTypes().add(ParameterType.OUT_CURSOR); + getParameterBindings().add(shouldBind); + getOutputCursors().add(outField); + } + + /** + * Add the parameter using the DatasourcePlatform. + */ + public void appendParameter(Writer writer, Object parameter, boolean shouldBind, AbstractSession session) { session.getDatasourcePlatform().appendParameter(this, writer, parameter); } @@ -675,7 +931,7 @@ protected String whitespace() { * Allow the call to translate from the translation for predefined calls. */ public void translateQueryString(AbstractRecord translationRow, AbstractRecord modifyRow, AbstractSession session) { - //has a '?' + //has a '?' if ((this.parameters == null) || getParameters().isEmpty()) { //has no parameters return; @@ -691,9 +947,9 @@ public void translateQueryString(AbstractRecord translationRow, AbstractRecord m try { // PERF: This method is heavily optimized do not touch anything unless you know "very well" what your doing. // Must translate field parameters and may get new bound parameters for large data. - List parameterFields = getParameters(); - List parameterTypes = getParameterTypes(); - setParameters(new ArrayList(parameterFields.size())); + List parameterFields = getParameters(); + List parameterTypes = getParameterTypes(); + setParameters(new ArrayList(parameterFields.size())); while (lastIndex != -1) { int tokenIndex = queryString.indexOf(argumentMarker(), lastIndex); String token; @@ -733,61 +989,445 @@ public void translateQueryString(AbstractRecord translationRow, AbstractRecord m writer.write(token); if (tokenIndex != -1) { // Process next parameter. - Integer parameterType = parameterTypes.get(parameterIndex); + + DatabaseField field = null; + Object value = null; + ParameterType parameterType = parameterTypes.get(parameterIndex); Object parameter = parameterFields.get(parameterIndex); - if (parameterType == MODIFY) { - DatabaseField field = (DatabaseField)parameter; - Object value = modifyRow.get(field); - appendParameter(writer, value, session); - } else if (parameterType == CUSTOM_MODIFY) { - DatabaseField field = (DatabaseField)parameter; - Object value = modifyRow.get(field); - if (value != null) { - value = session.getDatasourcePlatform().getCustomModifyValueForCall(this, value, field, false); - //Bug#5200826 needs use unwrapped connection. - if ((value instanceof BindCallCustomParameter) && ((BindCallCustomParameter)value).shouldUseUnwrappedConnection()){ - this.isNativeConnectionRequired=true; + + switch(parameterType) { + case MODIFY: + field = (DatabaseField)parameter; + value = modifyRow.get(field); + appendParameter(writer, value, false, session); + break; + case CUSTOM_MODIFY: + field = (DatabaseField)parameter; + value = modifyRow.get(field); + if (value != null) { + value = session.getDatasourcePlatform().getCustomModifyValueForCall(this, value, field, false); + //Bug#5200826 needs use unwrapped connection. + if ((value instanceof BindCallCustomParameter) && ((BindCallCustomParameter)value).shouldUseUnwrappedConnection()){ + this.isNativeConnectionRequired=true; + } + } + appendParameter(writer, value, false, session); + break; + case TRANSLATION: + value = null; + // Parameter expressions are used for nesting and correct mapping conversion of the value. + if (parameter instanceof ParameterExpression) { + value = ((ParameterExpression)parameter).getValue(translationRow, getQuery(), session); + } else { + field = (DatabaseField)parameter; + value = translationRow.get(field); + // Must check for the modify row as well for custom SQL compatibility as only one # is required. + if ((value == null) && (modifyRow != null)) { + value = modifyRow.get(field); + } } + appendParameter(writer, value, false, session); + break; + case LITERAL: + if (parameter instanceof DatabaseField) { + parameter = null; + } + appendParameter(writer, parameter, false, session); + break; + case IN: + value = getValueForInParameter(parameter, translationRow, modifyRow, session, false); + appendParameter(writer, value, false, session); + break; + case INOUT: + value = getValueForInOutParameter(parameter, translationRow, modifyRow, session); + appendParameter(writer, value, false, session); + break; + case OUT: + case OUT_CURSOR: + if (parameter instanceof DatabaseField) { + parameter = null; + } + appendParameter(writer, parameter, false, session); + break; + } + lastIndex = tokenIndex + 1; + parameterIndex++; + } + } + + setQueryString(writer.toString()); + + } catch (IOException exception) { + throw ValidationException.fileError(exception); + } + } + + /** + * INTERNAL: + * Allow the call to translate from the translation for predefined calls. + */ + public void translateQueryStringAndBindParameters(AbstractRecord translationRow, AbstractRecord modifyRow, AbstractSession session) { + List parameters = getParameters(); + + // This call has no parameters + if ((parameters == null) || parameters.isEmpty()) { + return; + } + + String marker = "" + argumentMarker(); + StringBuilder queryString = new StringBuilder(getQueryString()); + // The string has no argument markers + if (queryString.indexOf(marker) == -1) { + return; + } + + int lastIndex = 0; + int tokenIndex = -1; + + boolean hasParameterizedIN = false; + int size = parameters.size(); + List translatedParametersValues = new ArrayList(size); + + Writer writer = new CharArrayWriter(queryString.length() + 50); + try { + // PERF: This method is heavily optimized do not touch anything unless you know "very well" what your doing. + // Must translate field parameters and may get new bound parameters for large data. + List parameterFields = getParameters(); + List parameterTypes = getParameterTypes(); + List canBindParameters = getParameterBindings(); + + // clear the parameters list + setParameters(new ArrayList(parameterFields.size())); + + for (int parameterIndex = 0; parameterIndex < size; parameterIndex++) { + tokenIndex = queryString.indexOf(marker, tokenIndex + 1); + if (!this.shouldProcessTokenInQuotes) { + + // Look for a parameter marker NOT inside quotes + do { + boolean hasPairedQuoteBeforeMark = true; + int quotePairIndex = tokenIndex; + + // First, check if current mark is inside quotes + do { + quotePairIndex = queryString.lastIndexOf(String.valueOf('\''), quotePairIndex - 1); + if (quotePairIndex != -1 && quotePairIndex > lastIndex) { + hasPairedQuoteBeforeMark = !hasPairedQuoteBeforeMark; + } else { + break; + } + } while (true); + + int endQuoteIndex = -1; + if (!hasPairedQuoteBeforeMark) { + // All the quotes in front of current mark are not paired, so we should be inside quotes + endQuoteIndex = queryString.indexOf(String.valueOf('\''), tokenIndex + 1); } - appendParameter(writer, value, session); - } else if (parameterType == TRANSLATION) { - Object value = null; - // Parameter expressions are used for nesting and correct mapping conversion of the value. - if (parameter instanceof ParameterExpression) { - value = ((ParameterExpression)parameter).getValue(translationRow, getQuery(), session); + + if (endQuoteIndex != -1) { + // there is a quote around the mark, so find the next mark and try again + tokenIndex = queryString.indexOf(marker, tokenIndex + 1); } else { - DatabaseField field = (DatabaseField)parameter; - value = translationRow.get(field); - // Must check for the modify row as well for custom SQL compatibility as only one # is required. - if ((value == null) && (modifyRow != null)) { - value = modifyRow.get(field); + // we aren't inside quotes, so we're done + break; + } + } while (true); + } + + DatabaseField field = null; + Object translatedValue = null; + Object parameterValue = parameterFields.get(parameterIndex); + ParameterType parameterType = parameterTypes.get(parameterIndex); + Boolean canBind = canBindParameters.get(parameterIndex); + + switch(parameterType) { + case MODIFY: + field = (DatabaseField) parameterValue; + translatedValue = modifyRow.get(field); + + // If the value is null, the field is passed as the value so the type can be obtained from the field. + if (translatedValue == null) { + // The field from the modify row is used, as the calls field may not have the type, + // but if the field is missing the calls field may also have the type. + translatedValue = modifyRow.getField(field); + if (translatedValue == null) { + translatedValue = field; } } - appendParameter(writer, value, session); - } else if (parameterType == LITERAL) { - if (parameter instanceof DatabaseField) { - parameter = null; + + // If the parameter doesn't allow binding, we have to append this translated + // parameter value into the query string + if(Boolean.FALSE.equals(canBind)) { + String token = queryString.substring(lastIndex, tokenIndex); + writer.write(token); + lastIndex = tokenIndex + 1; + appendParameter(writer, translatedValue, false, session); + } else { + translatedParametersValues.add(translatedValue); } - appendParameter(writer, parameter, session); - } else if (parameterType == IN) { - Object value = getValueForInParameter(parameter, translationRow, modifyRow, session, false); - appendParameter(writer, value, session); - } else if (parameterType == INOUT) { - Object value = getValueForInOutParameter(parameter, translationRow, modifyRow, session); - appendParameter(writer, value, session); - } else if (parameterType == INLINE) { - writer.write((String)parameter); - } else if (parameterType == OUT || parameterType == OUT_CURSOR) { - if (parameter instanceof DatabaseField) { - parameter = null; + + break; + case CUSTOM_MODIFY: + field = (DatabaseField) parameterValue; + translatedValue = modifyRow.get(field); + translatedValue = session.getPlatform().getCustomModifyValueForCall(this, translatedValue, field, true); + //Bug#8200836 needs use unwrapped connection + if ((translatedValue != null) && (translatedValue instanceof BindCallCustomParameter) && (((BindCallCustomParameter)translatedValue).shouldUseUnwrappedConnection())){ + this.isNativeConnectionRequired=true; + } + + // If the value is null, the field is passed as the value so the type can be obtained from the field. + if (translatedValue == null) { + // The field from the modify row is used, as the calls field may not have the type, + // but if the field is missing the calls field may also have the type. + translatedValue = modifyRow.getField(field); + if (translatedValue == null) { + translatedValue = field; + } } - appendParameter(writer, parameter, session); + + // If the parameter doesn't allow binding, we have to append this translated + // parameter value into the query string + if(Boolean.FALSE.equals(canBind)) { + String token = queryString.substring(lastIndex, tokenIndex); + writer.write(token); + lastIndex = tokenIndex + 1; + appendParameter(writer, translatedValue, false, session); + } else { + translatedParametersValues.add(translatedValue); + } + + break; + case TRANSLATION: + if (parameterValue instanceof ParameterExpression) { + field = ((ParameterExpression) parameterValue).getField(); + translatedValue = ((ParameterExpression) parameterValue).getValue(translationRow, query, session); + } else { + field = (DatabaseField)parameterValue; + translatedValue = translationRow.get(field); + if (translatedValue == null) {// Backward compatibility double check. + translatedValue = modifyRow.get(field); + } + } + + if (translatedValue instanceof Collection && !Boolean.FALSE.equals(canBind)) { + // Must re-translate IN parameters. + hasParameterizedIN = true; + } + + // If the value is null, the field is passed as the value so the type can be obtained from the field. + if ((translatedValue == null) && (field != null)) { + if (!this.query.hasNullableArguments() || !this.query.getNullableArguments().contains(field)) { + translatedValue = translationRow.getField(field); + // The field from the row is used, as the calls field may not have the type, + // but if the field is missing the calls field may also have the type. + if (translatedValue == null) { + translatedValue = field; + } + + // If the parameter doesn't allow binding, we have to append this translated + // parameter value into the query string + if(Boolean.FALSE.equals(canBind)) { + String token = queryString.substring(lastIndex, tokenIndex); + writer.write(token); + lastIndex = tokenIndex + 1; + appendParameter(writer, translatedValue, false, session); + } else { + translatedParametersValues.add(translatedValue); + } + } + } else { + // If the parameter doesn't allow binding, we have to append this translated + // parameter value into the query string + if(Boolean.FALSE.equals(canBind)) { + String token = queryString.substring(lastIndex, tokenIndex); + writer.write(token); + lastIndex = tokenIndex + 1; + appendParameter(writer, translatedValue, false, session); + } else { + translatedParametersValues.add(translatedValue); + } + } + break; + case LITERAL: + translatedValue = parameterValue; + + // If the parameter doesn't allow binding, we have to append this translated + // parameter value into the query string + if(Boolean.FALSE.equals(canBind)) { + String token = queryString.substring(lastIndex, tokenIndex); + writer.write(token); + lastIndex = tokenIndex + 1; + + if (parameterValue instanceof DatabaseField) { + translatedValue = null; + } + appendParameter(writer, translatedValue, false, session); + } else { + translatedParametersValues.add(translatedValue); + } + break; + case IN: + translatedValue = getValueForInParameter(parameterValue, translationRow, modifyRow, session, true); + // Returning this means the parameter was optional and should not be included. + if (translatedValue != this) { + // If the parameter doesn't allow binding, we have to append this translated + // parameter value into the query string + if(Boolean.FALSE.equals(canBind)) { + String token = queryString.substring(lastIndex, tokenIndex); + writer.write(token); + lastIndex = tokenIndex + 1; + appendParameter(writer, translatedValue, false, session); + } else { + translatedParametersValues.add(translatedValue); + } + } + break; + case INOUT: + translatedValue = getValueForInOutParameter(parameterValue, translationRow, modifyRow, session); + + // If the parameter doesn't allow binding, we have to append this translated + // parameter value into the query string + if(Boolean.FALSE.equals(canBind)) { + String token = queryString.substring(lastIndex, tokenIndex); + writer.write(token); + lastIndex = tokenIndex + 1; + appendParameter(writer, translatedValue, false, session); + } else { + translatedParametersValues.add(translatedValue); + } + break; + case OUT: + case OUT_CURSOR: + if (parameterValue != null && parameterValue instanceof OutputParameterForCallableStatement) { + ((OutputParameterForCallableStatement) parameterValue).getOutputField().setIndex(parameterIndex); + } + + // If the parameter doesn't allow binding, we have to append this translated + // parameter value into the query string + if(Boolean.FALSE.equals(canBind)) { + String token = queryString.substring(lastIndex, tokenIndex); + writer.write(token); + lastIndex = tokenIndex + 1; + appendParameter(writer, translatedValue, false, session); + } else { + translatedParametersValues.add(translatedValue); + } + break; + } + } + + if(writer.toString().length() > 0) { + String token = queryString.substring(lastIndex); + writer.write(token); + setQueryString(writer.toString()); + } + if(translatedParametersValues.size() > 0) { + setParameters(translatedParametersValues); + } + + // If an IN parameter was found must translate SQL. + if (hasParameterizedIN) { + translateQueryStringForParameterizedIN(translationRow, modifyRow, session); + } + } catch (IOException exception) { + throw ValidationException.fileError(exception); + } + } + + /** + * INTERNAL: + * Translate only IN() parameter values (List parameters). + */ + public void translateQueryStringForParameterizedIN(AbstractRecord translationRow, AbstractRecord modifyRow, AbstractSession session) { + int lastIndex = 0; + int parameterIndex = 0; + String queryString = getQueryString(); + Writer writer = new CharArrayWriter(queryString.length() + 50); + try { + // PERF: This method is heavily optimized do not touch anything unless you know "very well" what your doing. + List parameters = getParameters(); + List parametersValues = new ArrayList(parameters.size()); + while (lastIndex != -1) { + int tokenIndex = queryString.indexOf(argumentMarker(), lastIndex); + String token; + if (tokenIndex == -1) { + token = queryString.substring(lastIndex, queryString.length()); + lastIndex = -1; + } else { + token = queryString.substring(lastIndex, tokenIndex); + } + writer.write(token); + if (tokenIndex != -1) { + // Process next parameter. + Object parameter = parameters.get(parameterIndex); + // Parameter expressions are used for nesting and correct mapping conversion of the value. + if (parameter instanceof Collection) { + Collection values = (Collection)parameter; + writer.write("("); + if ((values.size() > 0) && (values.iterator().next() instanceof List)) { + // Support nested lists. + int size = values.size(); + Iterator valuesIterator = values.iterator(); + for (int index = 0; index < size; index++) { + List nestedValues = (List)valuesIterator.next(); + parametersValues.addAll(nestedValues); + int nestedSize = nestedValues.size(); + writer.write("("); + for (int nestedIndex = 0; nestedIndex < nestedSize; nestedIndex++) { + writer.write("?"); + if ((nestedIndex + 1) < nestedSize) { + writer.write(","); + } + } + writer.write(")"); + if ((index + 1) < size) { + writer.write(","); + } + } + } else { + parametersValues.addAll(values); + int size = values.size(); + + int limit = ((DatasourcePlatform)session.getDatasourcePlatform()).getINClauseLimit(); + //The database platform has a limit for the IN clause so we need to reformat the clause + if(limit > 0) { + boolean not = token.endsWith(" NOT IN "); + String subToken = token.substring(0, token.length() - (not ? " NOT IN " : " IN ").length()); + int spaceIndex = subToken.lastIndexOf(' '); + int braceIndex = subToken.lastIndexOf('('); + String fieldName = subToken.substring((spaceIndex > braceIndex ? spaceIndex : braceIndex) + 1); + String inToken = not ? ") AND " + fieldName + " NOT IN (" : ") OR " + fieldName + " IN ("; + + for (int index = 0; index < size; index++) { + writer.write("?"); + if ((index + 1) < size) { + if (index > 0 && (index + 1) % limit == 0) { + writer.write(inToken); + } else { + writer.write(","); + } + } + } + } else { + for (int index = 0; index < size; index++) { + writer.write("?"); + if ((index + 1) < size) { + writer.write(","); + } + } + } + } + writer.write(")"); + } else { + parametersValues.add(parameter); + writer.write("?"); } lastIndex = tokenIndex + 1; parameterIndex++; } } - + setParameters(parametersValues); setQueryString(writer.toString()); } catch (IOException exception) { @@ -947,24 +1587,24 @@ public boolean isNativeConnectionRequired() { private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); if (parameterTypes !=null) { - List newParameterTypes = new ArrayList(parameterTypes.size()); - for (Integer type: parameterTypes){ - if (LITERAL.equals(type)) { - newParameterTypes.add(LITERAL); - } else if (MODIFY.equals(type)) { - newParameterTypes.add(MODIFY); - } else if (TRANSLATION.equals(type)) { - newParameterTypes.add(TRANSLATION); - } else if (CUSTOM_MODIFY.equals(type)) { - newParameterTypes.add(CUSTOM_MODIFY); - } else if (OUT.equals(type)) { - newParameterTypes.add(OUT); - } else if (INOUT.equals(type)) { - newParameterTypes.add(INOUT); - } else if (IN.equals(type)) { - newParameterTypes.add(IN); - } else if (OUT_CURSOR.equals(type)) { - newParameterTypes.add(OUT_CURSOR); + List newParameterTypes = new ArrayList(parameterTypes.size()); + for (ParameterType type: parameterTypes){ + if (ParameterType.LITERAL.equals(type)) { + newParameterTypes.add(ParameterType.LITERAL); + } else if (ParameterType.MODIFY.equals(type)) { + newParameterTypes.add(ParameterType.MODIFY); + } else if (ParameterType.TRANSLATION.equals(type)) { + newParameterTypes.add(ParameterType.TRANSLATION); + } else if (ParameterType.CUSTOM_MODIFY.equals(type)) { + newParameterTypes.add(ParameterType.CUSTOM_MODIFY); + } else if (ParameterType.OUT.equals(type)) { + newParameterTypes.add(ParameterType.OUT); + } else if (ParameterType.INOUT.equals(type)) { + newParameterTypes.add(ParameterType.INOUT); + } else if (ParameterType.IN.equals(type)) { + newParameterTypes.add(ParameterType.IN); + } else if (ParameterType.OUT_CURSOR.equals(type)) { + newParameterTypes.add(ParameterType.OUT_CURSOR); } } parameterTypes = newParameterTypes; diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/databaseaccess/DatasourcePlatform.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/databaseaccess/DatasourcePlatform.java index f5206bab685..f9e84690970 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/databaseaccess/DatasourcePlatform.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/databaseaccess/DatasourcePlatform.java @@ -461,6 +461,31 @@ protected void initializePlatformOperators() { addOperator(ExpressionOperator.except()); addOperator(ExpressionOperator.exceptAll()); + addOperator(ExpressionOperator.count()); + addOperator(ExpressionOperator.sum()); + addOperator(ExpressionOperator.average()); + addOperator(ExpressionOperator.minimum()); + addOperator(ExpressionOperator.maximum()); + addOperator(ExpressionOperator.distinct()); + addOperator(ExpressionOperator.notOperator()); + addOperator(ExpressionOperator.ascending()); + addOperator(ExpressionOperator.descending()); + addOperator(ExpressionOperator.as()); + addOperator(ExpressionOperator.nullsFirst()); + addOperator(ExpressionOperator.nullsLast()); + addOperator(ExpressionOperator.any()); + addOperator(ExpressionOperator.some()); + addOperator(ExpressionOperator.all()); + addOperator(ExpressionOperator.in()); + addOperator(ExpressionOperator.inSubQuery()); + addOperator(ExpressionOperator.notIn()); + addOperator(ExpressionOperator.notInSubQuery()); + + addOperator(ExpressionOperator.and()); + addOperator(ExpressionOperator.or()); + addOperator(ExpressionOperator.isNull()); + addOperator(ExpressionOperator.notNull()); + // Date addOperator(ExpressionOperator.addMonths()); addOperator(ExpressionOperator.dateToString()); @@ -475,12 +500,29 @@ protected void initializePlatformOperators() { addOperator(ExpressionOperator.extract()); // Math - addOperator(ExpressionOperator.simpleMath(ExpressionOperator.Add, "+")); - addOperator(ExpressionOperator.simpleMath(ExpressionOperator.Subtract, "-")); - addOperator(ExpressionOperator.simpleMath(ExpressionOperator.Multiply, "*")); - addOperator(ExpressionOperator.simpleMath(ExpressionOperator.Divide, "/")); + addOperator(ExpressionOperator.add()); + addOperator(ExpressionOperator.subtract()); + addOperator(ExpressionOperator.multiply()); + addOperator(ExpressionOperator.divide()); addOperator(ExpressionOperator.negate()); + addOperator(ExpressionOperator.equal()); + addOperator(ExpressionOperator.notEqual()); + addOperator(ExpressionOperator.lessThan()); + addOperator(ExpressionOperator.lessThanEqual()); + addOperator(ExpressionOperator.greaterThan()); + addOperator(ExpressionOperator.greaterThanEqual()); + + addOperator(ExpressionOperator.like()); + addOperator(ExpressionOperator.likeEscape()); + addOperator(ExpressionOperator.notLike()); + addOperator(ExpressionOperator.notLikeEscape()); + addOperator(ExpressionOperator.between()); + addOperator(ExpressionOperator.notBetween()); + + addOperator(ExpressionOperator.exists()); + addOperator(ExpressionOperator.notExists()); + addOperator(ExpressionOperator.ceil()); addOperator(ExpressionOperator.cos()); addOperator(ExpressionOperator.cosh()); diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/databaseaccess/QueryStringCall.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/databaseaccess/QueryStringCall.java index cecfd6ca0b6..08d186f5112 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/databaseaccess/QueryStringCall.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/databaseaccess/QueryStringCall.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 1998, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022 IBM Corporation. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -17,6 +18,7 @@ import java.util.*; import java.io.*; import org.eclipse.persistence.queries.*; +import org.eclipse.persistence.internal.databaseaccess.DatasourceCall.ParameterType; import org.eclipse.persistence.internal.helper.*; import org.eclipse.persistence.internal.sessions.AbstractRecord; import org.eclipse.persistence.internal.sessions.AbstractSession; @@ -39,9 +41,14 @@ public interface QueryStringCall extends Call { public List getParameters(); /** - * The parameter types determine if the parameter is a modify, translation or litteral type. + * The parameter types determine if the parameter is a modify, translation or literal type. */ - public List getParameterTypes(); + public List getParameterTypes(); + + /** + * The parameter binding behavior + */ + public List getParameterBindings(); /** * The parameters are the values in order of occurance in call. @@ -99,7 +106,7 @@ public interface QueryStringCall extends Call { * If using binding bind the parameter otherwise let the platform print it. * The platform may also decide to bind the value. */ - public void appendParameter(Writer writer, Object parameter, AbstractSession session); + public void appendParameter(Writer writer, Object parameter, boolean shouldBind, AbstractSession session); /** * Allow the call to translate from the translation for predefined calls. diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/ArgumentListFunctionExpression.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/ArgumentListFunctionExpression.java index 92b80ab561a..1d43db5429d 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/ArgumentListFunctionExpression.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/ArgumentListFunctionExpression.java @@ -1,6 +1,6 @@ /* - * Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2021 IBM Corporation. All rights reserved. + * Copyright (c) 1998, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2022 IBM Corporation. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -58,7 +58,6 @@ public synchronized void addChild(Expression argument){ super.addChild(argument); } setBaseExpression(getChildren().firstElement()); - ((ListExpressionOperator)operator).incrementNumberOfItems(); } /** @@ -89,7 +88,6 @@ public synchronized void addRightMostChild(Expression argument){ public void setOperator(ExpressionOperator theOperator) { assert(theOperator instanceof ListExpressionOperator); super.setOperator(theOperator); - ((ListExpressionOperator)theOperator).setNumberOfItems(0); } /** @@ -97,10 +95,11 @@ public void setOperator(ExpressionOperator theOperator) { * Print SQL */ public void printSQL(ExpressionSQLPrinter printer) { - ListExpressionOperator platformOperator = (ListExpressionOperator)getPlatformOperator(printer.getPlatform()); - platformOperator.copyTo(operator); - ((ListExpressionOperator)operator).setIsComplete(true); - operator.printCollection(getChildren(), printer); + ListExpressionOperator realOperator; + realOperator = (ListExpressionOperator)getPlatformOperator(printer.getPlatform()); + operator.copyTo(realOperator); + ((ListExpressionOperator) realOperator).setIsComplete(true); + realOperator.printCollection(this.children, printer); } @Override @@ -127,9 +126,5 @@ protected void postCopyIn(Map alreadyDone) { */ public void initializePlatformOperator(DatabasePlatform platform) { super.initializePlatformOperator(platform); - ((ListExpressionOperator)platformOperator).setNumberOfItems(((ListExpressionOperator)operator).getNumberOfItems()); } - - } - diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/CollectionExpression.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/CollectionExpression.java index 18c02248cef..05f6304d7b7 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/CollectionExpression.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/CollectionExpression.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 1998, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022 IBM Corporation. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -40,7 +41,7 @@ public void printSQL(ExpressionSQLPrinter printer) { if(this.localBase != null) { value = this.localBase.getFieldValue(value, getSession()); } - printer.printList((Collection)value); + printer.printList((Collection)value, this.canBind); } /** diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/CompoundExpression.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/CompoundExpression.java index 6e08009b035..bea5de226ff 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/CompoundExpression.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/CompoundExpression.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 1998, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022 IBM Corporation. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -177,13 +178,15 @@ public Expression getSecondChild() { * INTERNAL: */ public void initializePlatformOperator(DatabasePlatform platform) { - if (this.operator.isComplete()) { - platformOperator = this.operator; - return; - } + // First, check that the platform operator doesn't override the operator behavior platformOperator = platform.getOperator(this.operator.getSelector()); if (platformOperator == null) { - throw QueryException.invalidOperator(this.operator.toString()); + // If the platform doesn't specifically override, fallback on the internal operator + // This operator should be either user-defined or one from ExpressionOperator.initializeInternalOperators. + platformOperator = this.operator; + if (platformOperator == null) { + throw QueryException.invalidOperator(this.operator); + } } } diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/ConstantExpression.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/ConstantExpression.java index a458258518d..463fa1e8322 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/ConstantExpression.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/ConstantExpression.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 1998, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022 IBM Corporation. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -29,6 +30,7 @@ public class ConstantExpression extends Expression { protected Object value; protected Expression localBase; + protected Boolean canBind = null; public ConstantExpression() { super(); @@ -101,6 +103,26 @@ public void setValue(Object value) { this.value = value; } + /** + * INTERNAL: + * true indicates this expression can bind parameters + * false indicates this expression cannot bind parameters + * Defaults to null to indicate no specific preference + */ + public Boolean canBind() { + return canBind; + } + + /** + * INTERNAL: + * Set to true if this expression can bind parameters + * Set to false if this expression cannot bind parameters + * Set to null to indicate no specific preference + */ + public void setCanBind(Boolean canBind) { + this.canBind = canBind; + } + public boolean isConstantExpression() { return true; } @@ -161,7 +183,7 @@ public void printSQL(ExpressionSQLPrinter printer) { if(value == null) { printer.printNull(this); } else { - printer.printPrimitive(value); + printer.printPrimitive(value, this.canBind); } } @@ -243,9 +265,26 @@ public void writeDescriptionOn(BufferedWriter writer) throws IOException { */ @Override public void writeFields(ExpressionSQLPrinter printer, Vector newFields, SQLSelectStatement statement) { + /* + * If the platform doesn't support binding for functions, then disable binding for the whole query + * + * DatabasePlatform classes should instead override DatasourcePlatform.initializePlatformOperators() + * @see ExpressionOperator.setIsBindingSupported(boolean isBindingSupported) + * In this way, platforms can define their own supported binding behaviors for individual functions + */ if (printer.getPlatform().isDynamicSQLRequiredForFunctions()) { printer.getCall().setUsesBinding(false); } + + /* + * Allow the platform to indicate if they support parameter expressions in the SELECT clause + * as a whole, regardless if individual functions allow binding. We make that decision here + * before we continue parsing into generic API calls + */ + if (!printer.getPlatform().allowBindingForSelectClause()) { + setCanBind(false); + } + //print ", " before each selected field except the first one if (printer.isFirstElementPrinted()) { printer.printString(", "); diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/ExpressionSQLPrinter.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/ExpressionSQLPrinter.java index 647b2729e25..e6a97064ea5 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/ExpressionSQLPrinter.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/ExpressionSQLPrinter.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 1998, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022 IBM Corporation. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -183,13 +184,13 @@ public void printParameter(DatabaseField field) { getCall().appendTranslation(getWriter(), field); } - public void printPrimitive(Object value) { + public void printPrimitive(Object value, Boolean canBind) { if (value instanceof Collection) { - printValuelist((Collection)value); + printValuelist((Collection)value, canBind); return; } - session.getPlatform().appendLiteralToCall(getCall(), getWriter(), value); + session.getPlatform().appendLiteralToCall(getCall(), getWriter(), value, canBind); } public void printNull(ConstantExpression nullValueExpression) { @@ -199,9 +200,9 @@ public void printNull(ConstantExpression nullValueExpression) { if(localBase != null && (localBase.isFieldExpression() || localBase.isQueryKeyExpression())) { field = ((DataExpression)localBase).getField(); } - session.getPlatform().appendLiteralToCall(getCall(), getWriter(), field); + session.getPlatform().appendLiteralToCall(getCall(), getWriter(), field, nullValueExpression.canBind()); } else { - session.getPlatform().appendLiteralToCall(getCall(), getWriter(), null); + session.getPlatform().appendLiteralToCall(getCall(), getWriter(), null, nullValueExpression.canBind()); } } @@ -214,7 +215,7 @@ public void printString(String value) { } } - public void printValuelist(Collection values) { + public void printValuelist(Collection values, Boolean canBind) { try { getWriter().write("("); if (values == null || values.isEmpty()) { @@ -225,11 +226,11 @@ public void printValuelist(Collection values) { Object value = valuesEnum.next(); // Support nested arrays for IN. if (value instanceof Collection) { - printValuelist((Collection) value); + printValuelist((Collection) value, canBind); } else if (value instanceof Expression) { ((Expression) value).printSQL(this); } else { - session.getPlatform().appendLiteralToCall(getCall(), getWriter(), value); + session.getPlatform().appendLiteralToCall(getCall(), getWriter(), value, canBind); } if (valuesEnum.hasNext()) { getWriter().write(", "); @@ -245,7 +246,7 @@ public void printValuelist(Collection values) { /* * Same as printValuelist, but allows for collections containing expressions recursively */ - public void printList(Collection values) { + public void printList(Collection values, Boolean canBind) { try { getWriter().write("("); if (values == null || values.isEmpty()) { @@ -257,7 +258,7 @@ public void printList(Collection values) { if (value instanceof Expression) { ((Expression) value).printSQL(this); } else { - session.getPlatform().appendLiteralToCall(getCall(), getWriter(), value); + session.getPlatform().appendLiteralToCall(getCall(), getWriter(), value, canBind); } if (valuesEnum.hasNext()) { getWriter().write(", "); diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/FunctionExpression.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/FunctionExpression.java index a672279c157..a882bf56716 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/FunctionExpression.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/FunctionExpression.java @@ -1,6 +1,6 @@ /* - * Copyright (c) 1998, 2019 Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2019 IBM Corporation. All rights reserved. + * Copyright (c) 1998, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022 IBM Corporation. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -347,13 +347,15 @@ public boolean hasResultType() { * INTERNAL: */ public void initializePlatformOperator(DatabasePlatform platform) { - if (this.operator.isComplete()) { - platformOperator = this.operator; - return; - } + // First, check that the platform operator doesn't override the operator behavior platformOperator = platform.getOperator(this.operator.getSelector()); if (platformOperator == null) { - throw QueryException.invalidOperator(this.operator.toString()); + // If the platform doesn't specifically override, fallback on the internal operator + // This operator should be either user-defined or one from ExpressionOperator.initializeInternalOperators. + platformOperator = this.operator; + if (platformOperator == null) { + throw QueryException.invalidOperator(this.operator); + } } } @@ -558,7 +560,10 @@ protected void postCopyIn(Map alreadyDone) { */ @Override public void printSQL(ExpressionSQLPrinter printer) { - // If all children are parameters, some databases don't allow binding. + /* + * If this ExpressionOperator does not support binding, and the platform allows, + * then disable binding for the whole query + */ if (printer.getPlatform().isDynamicSQLRequiredForFunctions() && !this.children.isEmpty()) { boolean allParams = true; for (Iterator iterator = this.children.iterator(); iterator.hasNext(); ) { diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/ParameterExpression.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/ParameterExpression.java index 5b6ad09ad48..e56cfef2830 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/ParameterExpression.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/ParameterExpression.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 1998, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022 IBM Corporation. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -41,6 +42,13 @@ public class ParameterExpression extends BaseExpression { protected boolean isProperty = false; + /** + * 'True' indicates this expression can bind parameters + * 'False' indicates this expression cannot bind parameters + * Defaults to 'null' to indicate specific no preference + */ + protected Boolean canBind = null; + /** The inferred type of the parameter. * Please note that the type might not be always initialized to correct value. * It might be null if not initialized correctly. @@ -323,6 +331,16 @@ public boolean isProperty() { return isProperty; } + /** + * INTERNAL: + * true indicates this expression can bind parameters + * false indicates this expression cannot bind parameters + * Defaults to null to indicate no specific preference + */ + public Boolean canBind() { + return canBind; + } + /** * INTERNAL: * Used for cloning. @@ -342,10 +360,10 @@ public void printSQL(ExpressionSQLPrinter printer) { if (printer.shouldPrintParameterValues()) { Object value = getValue(printer.getTranslationRow(), printer.getSession()); if (value instanceof Collection) { - printer.printValuelist((Collection)value); - }else{ + printer.printValuelist((Collection)value, this.canBind); + } else { if(getField() == null) { - printer.printPrimitive(value); + printer.printPrimitive(value, this.canBind); } else { printer.printParameter(this); } @@ -395,6 +413,16 @@ public void setIsProperty(boolean isProperty) { this.isProperty = isProperty; } + /** + * INTERNAL: + * Set to true if this expression can bind parameters + * Set to false if this expression cannot bind parameters + * Set to null to indicate no specific preference + */ + public void setCanBind(Boolean canBind) { + this.canBind = canBind; + } + /** * The opposite side of the relation, this is used for conversion of the parameter using the others mapping. */ @@ -490,9 +518,26 @@ public void writeDescriptionOn(BufferedWriter writer) throws IOException { */ @Override public void writeFields(ExpressionSQLPrinter printer, Vector newFields, SQLSelectStatement statement) { + /* + * If the platform doesn't support binding for functions, then disable binding for the whole query + * + * DatabasePlatform classes should instead override DatasourcePlatform.initializePlatformOperators() + * @see ExpressionOperator.setIsBindingSupported(boolean isBindingSupported) + * In this way, platforms can define their own supported binding behaviors for individual functions + */ if (printer.getPlatform().isDynamicSQLRequiredForFunctions()) { printer.getCall().setUsesBinding(false); } + + /* + * Allow the platform to indicate if they support parameter expressions in the SELECT clause + * as a whole, regardless if individual functions allow binding. We make that decision here + * before we continue parsing into generic API calls + */ + if (!printer.getPlatform().allowBindingForSelectClause()) { + setCanBind(false); + } + //print ", " before each selected field except the first one if (printer.isFirstElementPrinted()) { printer.printString(", "); diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/RelationExpression.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/RelationExpression.java index 661e4662b56..5daf0db2918 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/RelationExpression.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/RelationExpression.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 1998, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022 IBM Corporation. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -887,10 +888,16 @@ public boolean performSelector(boolean areValuesEqual) { * Print SQL */ public void printSQL(ExpressionSQLPrinter printer) { - // If both sides are parameters, some databases don't allow binding. + /* + * If the platform doesn't support binding for functions and both sides are parameters/constants, + * then disable binding for the whole query + * + * DatabasePlatform classes should instead override DatasourcePlatform.initializePlatformOperators() + * @see ExpressionOperator.setIsBindingSupported(boolean isBindingSupported) + * In this way, platforms can define their own supported binding behaviors for individual functions + */ if (printer.getPlatform().isDynamicSQLRequiredForFunctions() - && ((this.firstChild.isParameterExpression() || this.firstChild.isConstantExpression()) - && (this.secondChild.isParameterExpression() || this.secondChild.isConstantExpression()))) { + && (this.firstChild.isValueExpression() && this.secondChild.isValueExpression())) { printer.getCall().setUsesBinding(false); } if (isEqualNull(printer)) { diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/SQLDeleteAllStatement.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/SQLDeleteAllStatement.java index f726b67b545..252b6807f98 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/SQLDeleteAllStatement.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/SQLDeleteAllStatement.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 1998, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022 IBM Corporation. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -218,6 +219,7 @@ protected void writeSelect(Writer writer, SQLCall selectCall, String tableAliasI // add parameters call.getParameters().addAll(selectCall.getParameters()); call.getParameterTypes().addAll(selectCall.getParameterTypes()); + call.getParameterBindings().addAll(selectCall.getParameterBindings()); } protected boolean writeWhere(Writer writer, SQLCall selectCall, SQLCall call) throws IOException { @@ -236,6 +238,7 @@ protected boolean writeWhere(Writer writer, SQLCall selectCall, SQLCall call) th // add parameters call.getParameters().addAll(selectCall.getParameters()); call.getParameterTypes().addAll(selectCall.getParameterTypes()); + call.getParameterBindings().addAll(selectCall.getParameterBindings()); return true; } diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/SQLModifyAllStatementForTempTable.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/SQLModifyAllStatementForTempTable.java index 1d7c80ec167..b5f2c2ff02b 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/SQLModifyAllStatementForTempTable.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/SQLModifyAllStatementForTempTable.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 1998, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022 IBM Corporation. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -88,6 +89,7 @@ public DatabaseCall buildCall(AbstractSession session) { call.getParameters().addAll(selectCall.getParameters()); call.getParameterTypes().addAll(selectCall.getParameterTypes()); + call.getParameterBindings().addAll(selectCall.getParameterBindings()); String selectStr = selectCall.getSQLString(); writer.write(selectStr); diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/SQLSelectStatement.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/SQLSelectStatement.java index e62d587df72..8fc19516f0e 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/SQLSelectStatement.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/SQLSelectStatement.java @@ -764,6 +764,26 @@ public void appendOrderClauseToWriter(ExpressionSQLPrinter printer) throws IOExc for (Iterator expressionsEnum = getOrderByExpressions().iterator(); expressionsEnum.hasNext();) { Expression expression = expressionsEnum.next(); + /* + * Allow the platform to indicate if they support parameter expressions in the ORDER BY clause + * as a whole, regardless if individual functions allow binding. We make that decision here + * before we continue parsing into generic API calls + */ + if(!printer.getPlatform().supportsOrderByParameters()) { + if(printer.getPlatform().shouldBindPartialParameters()) { + if(expression.isParameterExpression()) { + ((ParameterExpression) expression).setCanBind(false); + } else if(expression.isConstantExpression() && printer.getPlatform().shouldBindLiterals()) { + ((ConstantExpression) expression).setCanBind(false); + } + } else if (printer.getPlatform().isDynamicSQLRequiredForFunctions()) { + if(expression.isParameterExpression() + || (expression.isConstantExpression() && printer.getPlatform().shouldBindLiterals())) { + printer.getCall().setUsesBinding(false); + } + } + } + expression.printSQL(printer); if (expressionsEnum.hasNext()) { diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/SQLUpdateAllStatement.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/SQLUpdateAllStatement.java index a58d28f6191..97c0c49cdd0 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/SQLUpdateAllStatement.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/SQLUpdateAllStatement.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 1998, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022 IBM Corporation. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -218,6 +219,7 @@ protected void writeSelect(Writer writer, SQLCall selectCall, String tableAliasI call.getParameters().addAll(selectCall.getParameters()); call.getParameterTypes().addAll(selectCall.getParameterTypes()); + call.getParameterBindings().addAll(selectCall.getParameterBindings()); } protected boolean writeWhere(Writer writer, SQLCall selectCall, SQLCall call) throws IOException { @@ -236,6 +238,7 @@ protected boolean writeWhere(Writer writer, SQLCall selectCall, SQLCall call) th // add parameters call.getParameters().addAll(selectCall.getParameters()); call.getParameterTypes().addAll(selectCall.getParameterTypes()); + call.getParameterBindings().addAll(selectCall.getParameterBindings()); return true; } diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/SQLUpdateAllStatementForOracleAnonymousBlock.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/SQLUpdateAllStatementForOracleAnonymousBlock.java index 5e06feb63c0..5262c1b6b51 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/SQLUpdateAllStatementForOracleAnonymousBlock.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/SQLUpdateAllStatementForOracleAnonymousBlock.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 1998, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022 IBM Corporation. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -116,6 +117,7 @@ public DatabaseCall buildCall(AbstractSession session) { call.getParameters().addAll(selectCall.getParameters()); call.getParameterTypes().addAll(selectCall.getParameterTypes()); + call.getParameterBindings().addAll(selectCall.getParameterBindings()); DatabaseField firstMainPrimaryKey = (DatabaseField)mainPrimaryKeys.firstElement(); writer.write(tab); diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/SubSelectExpression.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/SubSelectExpression.java index 8f88d3e87b6..428cd0397c9 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/SubSelectExpression.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/expressions/SubSelectExpression.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 1998, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022 IBM Corporation. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -249,6 +250,7 @@ protected void printCustomSQL(ExpressionSQLPrinter printer) { call.translateCustomQuery(); printer.getCall().getParameters().addAll(call.getParameters()); printer.getCall().getParameterTypes().addAll(call.getParameterTypes()); + printer.getCall().getParameterBindings().addAll(call.getParameterBindings()); printer.printString(call.getCallString()); } diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/helper/ComplexDatabaseType.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/helper/ComplexDatabaseType.java index dbb0f33be0d..2243c0ce229 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/helper/ComplexDatabaseType.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/helper/ComplexDatabaseType.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022 IBM Corporation. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -18,6 +19,7 @@ import java.util.List; import org.eclipse.persistence.exceptions.QueryException; +import org.eclipse.persistence.internal.databaseaccess.DatasourceCall.ParameterType; import org.eclipse.persistence.internal.sessions.AbstractRecord; import org.eclipse.persistence.platform.database.DatabasePlatform; import org.eclipse.persistence.platform.database.oracle.plsql.PLSQLStoredProcedureCall; @@ -229,8 +231,16 @@ public int computeOutIndex(PLSQLargument outArg, int newIndex, ListIterator outputRowFields, List outputRowValues); + @Deprecated public void logParameter(StringBuilder sb, Integer direction, PLSQLargument arg, AbstractRecord translationRow, DatabasePlatform platform); + public void logParameter(StringBuilder sb, ParameterType direction, PLSQLargument arg, + AbstractRecord translationRow, DatabasePlatform platform); + public enum DatabaseTypeHelper { databaseTypeHelper; @@ -210,14 +213,19 @@ public void buildOutputRow(PLSQLargument outArg, AbstractRecord outputRow, } public void logParameter(StringBuilder sb, Integer direction, PLSQLargument arg, - AbstractRecord translationRow, DatabasePlatform platform) { - if (direction == IN && arg.inIndex != MIN_VALUE) { + AbstractRecord translationRow, DatabasePlatform platform) { + logParameter(sb, ParameterType.valueOf(direction), arg, translationRow, platform); + } + + public void logParameter(StringBuilder sb, ParameterType direction, PLSQLargument arg, + AbstractRecord translationRow, DatabasePlatform platform) { + if (direction == ParameterType.IN && arg.inIndex != MIN_VALUE) { sb.append(":"); sb.append(arg.inIndex); sb.append(" => "); sb.append(platform.convertToDatabaseType(translationRow.get(arg.name))); } - if (direction == OUT && arg.outIndex != MIN_VALUE) { + if (direction == ParameterType.OUT && arg.outIndex != MIN_VALUE) { sb.append(arg.name); sb.append(" => :"); sb.append(arg.outIndex); diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/helper/Helper.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/helper/Helper.java index de626dadd02..b331dc7ba58 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/helper/Helper.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/helper/Helper.java @@ -1,6 +1,6 @@ /* - * Copyright (c) 1998, 2018 Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 1998, 2018 IBM Corporation. All rights reserved. + * Copyright (c) 1998, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022 IBM Corporation. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -831,6 +831,21 @@ public static int[] copyIntArray(int[] original){ return copy; } + /** + * Copy an array of boolean to a new array + * @param original + * @return + */ + public static boolean[] copyBooleanArray(boolean[] original){ + if (original == null){ + return null; + } + int length = original.length; + boolean[] copy = new boolean[length]; + System.arraycopy(original, 0, copy, 0, length); + return copy; + } + /** * Return a string containing the platform-appropriate * characters for carriage return. diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/sessions/factories/ObjectPersistenceRuntimeXMLProject.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/sessions/factories/ObjectPersistenceRuntimeXMLProject.java index d753b533502..7b39e74634b 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/sessions/factories/ObjectPersistenceRuntimeXMLProject.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/sessions/factories/ObjectPersistenceRuntimeXMLProject.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 1998, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022 IBM Corporation. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -1033,8 +1034,8 @@ protected ClassDescriptor buildLogicalExpressionDescriptor() { XMLDirectMapping operatorMapping = new XMLDirectMapping(); operatorMapping.setAttributeName("operator"); ObjectTypeConverter operatorConverter = new ObjectTypeConverter(); - operatorConverter.addConversionValue("and", ExpressionOperator.getOperator(Integer.valueOf(ExpressionOperator.And))); - operatorConverter.addConversionValue("or", ExpressionOperator.getOperator(Integer.valueOf(ExpressionOperator.Or))); + operatorConverter.addConversionValue("and", Expression.getOperator(Integer.valueOf(ExpressionOperator.And))); + operatorConverter.addConversionValue("or", Expression.getOperator(Integer.valueOf(ExpressionOperator.Or))); operatorMapping.setConverter(operatorConverter); operatorMapping.setXPath("@operator"); descriptor.addMapping(operatorMapping); @@ -1085,14 +1086,14 @@ public void postBuild(DescriptorEvent event) { XMLDirectMapping operatorMapping = new XMLDirectMapping(); operatorMapping.setAttributeName("operator"); ObjectTypeConverter operatorConverter = new ObjectTypeConverter(); - operatorConverter.addConversionValue("equal", ExpressionOperator.getOperator(Integer.valueOf(ExpressionOperator.Equal))); - operatorConverter.addConversionValue("notEqual", ExpressionOperator.getOperator(Integer.valueOf(ExpressionOperator.NotEqual))); - operatorConverter.addConversionValue("like", ExpressionOperator.getOperator(Integer.valueOf(ExpressionOperator.Like))); - operatorConverter.addConversionValue("notLike", ExpressionOperator.getOperator(Integer.valueOf(ExpressionOperator.NotLike))); - operatorConverter.addConversionValue("greaterThan", ExpressionOperator.getOperator(Integer.valueOf(ExpressionOperator.GreaterThan))); - operatorConverter.addConversionValue("greaterThanEqual", ExpressionOperator.getOperator(Integer.valueOf(ExpressionOperator.GreaterThanEqual))); - operatorConverter.addConversionValue("lessThan", ExpressionOperator.getOperator(Integer.valueOf(ExpressionOperator.LessThan))); - operatorConverter.addConversionValue("lessThanEqual", ExpressionOperator.getOperator(Integer.valueOf(ExpressionOperator.LessThanEqual))); + operatorConverter.addConversionValue("equal", Expression.getOperator(Integer.valueOf(ExpressionOperator.Equal))); + operatorConverter.addConversionValue("notEqual", Expression.getOperator(Integer.valueOf(ExpressionOperator.NotEqual))); + operatorConverter.addConversionValue("like", Expression.getOperator(Integer.valueOf(ExpressionOperator.Like))); + operatorConverter.addConversionValue("notLike", Expression.getOperator(Integer.valueOf(ExpressionOperator.NotLike))); + operatorConverter.addConversionValue("greaterThan", Expression.getOperator(Integer.valueOf(ExpressionOperator.GreaterThan))); + operatorConverter.addConversionValue("greaterThanEqual", Expression.getOperator(Integer.valueOf(ExpressionOperator.GreaterThanEqual))); + operatorConverter.addConversionValue("lessThan", Expression.getOperator(Integer.valueOf(ExpressionOperator.LessThan))); + operatorConverter.addConversionValue("lessThanEqual", Expression.getOperator(Integer.valueOf(ExpressionOperator.LessThanEqual))); operatorMapping.setConverter(operatorConverter); operatorMapping.setXPath("@operator"); descriptor.addMapping(operatorMapping); @@ -1253,26 +1254,26 @@ public void postBuild(DescriptorEvent event) { XMLDirectMapping operatorMapping = new XMLDirectMapping(); operatorMapping.setAttributeName("operator"); ExpressionOperatorConverter operatorConverter = new ExpressionOperatorConverter(); - operatorConverter.addConversionValue("like", ExpressionOperator.getOperator(Integer.valueOf(ExpressionOperator.Like))); - operatorConverter.addConversionValue("notLike", ExpressionOperator.getOperator(Integer.valueOf(ExpressionOperator.NotLike))); - operatorConverter.addConversionValue("not", ExpressionOperator.getOperator(Integer.valueOf(ExpressionOperator.Not))); - operatorConverter.addConversionValue("isNull", ExpressionOperator.getOperator(Integer.valueOf(ExpressionOperator.IsNull))); - operatorConverter.addConversionValue("notNull", ExpressionOperator.getOperator(Integer.valueOf(ExpressionOperator.NotNull))); - operatorConverter.addConversionValue("ascending", ExpressionOperator.getOperator(Integer.valueOf(ExpressionOperator.Ascending))); - operatorConverter.addConversionValue("descending", ExpressionOperator.getOperator(Integer.valueOf(ExpressionOperator.Descending))); + operatorConverter.addConversionValue("like", Expression.getOperator(Integer.valueOf(ExpressionOperator.Like))); + operatorConverter.addConversionValue("notLike", Expression.getOperator(Integer.valueOf(ExpressionOperator.NotLike))); + operatorConverter.addConversionValue("not", Expression.getOperator(Integer.valueOf(ExpressionOperator.Not))); + operatorConverter.addConversionValue("isNull", Expression.getOperator(Integer.valueOf(ExpressionOperator.IsNull))); + operatorConverter.addConversionValue("notNull", Expression.getOperator(Integer.valueOf(ExpressionOperator.NotNull))); + operatorConverter.addConversionValue("ascending", Expression.getOperator(Integer.valueOf(ExpressionOperator.Ascending))); + operatorConverter.addConversionValue("descending", Expression.getOperator(Integer.valueOf(ExpressionOperator.Descending))); // These are platform specific so not on operator. operatorConverter.addConversionValue("upper", new ExpressionOperator(ExpressionOperator.ToUpperCase, NonSynchronizedVector.newInstance(0))); operatorConverter.addConversionValue("lower", new ExpressionOperator(ExpressionOperator.ToLowerCase, NonSynchronizedVector.newInstance(0))); // Aggregate functions - operatorConverter.addConversionValue("count", ExpressionOperator.getOperator(Integer.valueOf(ExpressionOperator.Count))); - operatorConverter.addConversionValue("sum", ExpressionOperator.getOperator(Integer.valueOf(ExpressionOperator.Sum))); - operatorConverter.addConversionValue("average", ExpressionOperator.getOperator(Integer.valueOf(ExpressionOperator.Average))); - operatorConverter.addConversionValue("maximum", ExpressionOperator.getOperator(Integer.valueOf(ExpressionOperator.Maximum))); - operatorConverter.addConversionValue("minimum", ExpressionOperator.getOperator(Integer.valueOf(ExpressionOperator.Minimum))); + operatorConverter.addConversionValue("count", Expression.getOperator(Integer.valueOf(ExpressionOperator.Count))); + operatorConverter.addConversionValue("sum", Expression.getOperator(Integer.valueOf(ExpressionOperator.Sum))); + operatorConverter.addConversionValue("average", Expression.getOperator(Integer.valueOf(ExpressionOperator.Average))); + operatorConverter.addConversionValue("maximum", Expression.getOperator(Integer.valueOf(ExpressionOperator.Maximum))); + operatorConverter.addConversionValue("minimum", Expression.getOperator(Integer.valueOf(ExpressionOperator.Minimum))); // standardDeviation is platform specific. operatorConverter.addConversionValue("standardDeviation", new ExpressionOperator(ExpressionOperator.StandardDeviation, NonSynchronizedVector.newInstance(0))); operatorConverter.addConversionValue("variance", new ExpressionOperator(ExpressionOperator.Variance, NonSynchronizedVector.newInstance(0))); - operatorConverter.addConversionValue("distinct", ExpressionOperator.getOperator(Integer.valueOf(ExpressionOperator.Distinct))); + operatorConverter.addConversionValue("distinct", Expression.getOperator(Integer.valueOf(ExpressionOperator.Distinct))); operatorMapping.setConverter(operatorConverter); operatorMapping.setXPath("@function"); descriptor.addMapping(operatorMapping); diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/sessions/factories/ObjectPersistenceRuntimeXMLProject_11_1_1.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/sessions/factories/ObjectPersistenceRuntimeXMLProject_11_1_1.java index 128ac2a882c..bc2b5769da5 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/sessions/factories/ObjectPersistenceRuntimeXMLProject_11_1_1.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/sessions/factories/ObjectPersistenceRuntimeXMLProject_11_1_1.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 1998, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022 IBM Corporation. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -30,6 +31,7 @@ import org.eclipse.persistence.descriptors.ClassDescriptor; import org.eclipse.persistence.descriptors.RelationalDescriptor; import org.eclipse.persistence.exceptions.DescriptorException; +import org.eclipse.persistence.internal.databaseaccess.DatasourceCall.ParameterType; import org.eclipse.persistence.internal.descriptors.InstantiationPolicy; import org.eclipse.persistence.internal.helper.ComplexDatabaseType; import org.eclipse.persistence.internal.helper.DatabaseField; @@ -97,10 +99,6 @@ import org.eclipse.persistence.queries.ScrollableCursorPolicy; import org.eclipse.persistence.queries.StoredFunctionCall; import org.eclipse.persistence.queries.StoredProcedureCall; -import static org.eclipse.persistence.internal.databaseaccess.DatasourceCall.IN; -import static org.eclipse.persistence.internal.databaseaccess.DatasourceCall.INOUT; -import static org.eclipse.persistence.internal.databaseaccess.DatasourceCall.OUT; -import static org.eclipse.persistence.internal.databaseaccess.DatasourceCall.OUT_CURSOR; import static org.eclipse.persistence.internal.helper.DatabaseField.NULL_SQL_TYPE; import static org.eclipse.persistence.sessions.factories.XMLProjectReader.SCHEMA_DIR; import static org.eclipse.persistence.sessions.factories.XMLProjectReader.TOPLINK_11_SCHEMA; @@ -755,8 +753,8 @@ class StoredProcedureArgument { StoredProcedureArgument(DatabaseField dbfield) { this.setDatabaseField(dbfield); } - Integer getDirection() { - return IN; + ParameterType getDirection() { + return ParameterType.IN; } DatabaseField getDatabaseField() { DatabaseField dbfield = new DatabaseField(argumentFieldName == null ? "" : argumentFieldName); @@ -815,8 +813,8 @@ class StoredProcedureInOutArgument extends StoredProcedureArgument { StoredProcedureInOutArgument(DatabaseField dbfield) { super(dbfield); } - Integer getDirection() { - return INOUT; + ParameterType getDirection() { + return ParameterType.INOUT; } } @@ -827,8 +825,8 @@ class StoredProcedureOutArgument extends StoredProcedureArgument { StoredProcedureOutArgument(DatabaseField dbfield){ super(dbfield); } - Integer getDirection() { - return OUT; + ParameterType getDirection() { + return ParameterType.OUT; } } @@ -839,8 +837,8 @@ class StoredProcedureOutCursorArgument extends StoredProcedureOutArgument { StoredProcedureOutCursorArgument(DatabaseField dbfield){ super(dbfield); } - Integer getDirection() { - return OUT_CURSOR; + ParameterType getDirection() { + return ParameterType.OUT_CURSOR; } } @@ -988,22 +986,22 @@ class StoredProcedureArgumentsAccessor extends AttributeAccessor { @Override public Object getAttributeValueFromObject(Object anObject) throws DescriptorException { StoredProcedureCall spc = (StoredProcedureCall)anObject; - List parameterTypes = spc.getParameterTypes(); + List parameterTypes = spc.getParameterTypes(); List parameters = spc.getParameters(); List procedureArgumentNames = spc.getProcedureArgumentNames(); List storedProcedureArguments = new Vector(); for (int i = spc.getFirstParameterIndexForCallString(); i < parameterTypes.size(); i++) { StoredProcedureArgument spa = null; - Integer direction = (Integer)parameterTypes.get(i); + ParameterType direction = parameterTypes.get(i); Object argument = parameters.get(i); String argumentName = (String)procedureArgumentNames.get(i); - if (direction.equals(IN)) { + if (direction.equals(ParameterType.IN)) { spa = new StoredProcedureArgument(); } - else if (direction.equals(OUT)) { + else if (direction.equals(ParameterType.OUT)) { spa = new StoredProcedureOutArgument(); } - else if (direction.equals(INOUT)) { + else if (direction.equals(ParameterType.INOUT)) { spa = new StoredProcedureInOutArgument(); // outputArgumentName ?? } @@ -1046,10 +1044,10 @@ public void setAttributeValueInObject(Object domainObject, Object attributeValue Vector procedureArguments = (Vector)attributeValue; for (int i = 0; i < procedureArguments.size(); i++) { StoredProcedureArgument spa = (StoredProcedureArgument)procedureArguments.get(i); - Integer direction = spa.getDirection(); + ParameterType direction = spa.getDirection(); DatabaseField dbField = spa.getDatabaseField(); spc.getProcedureArgumentNames().add(spa.argumentName); - if (direction.equals(IN)) { + if (direction.equals(ParameterType.IN)) { if (spa.argumentValue != null) { spc.appendIn(spa.argumentValue); } @@ -1057,13 +1055,13 @@ public void setAttributeValueInObject(Object domainObject, Object attributeValue spc.appendIn(dbField); } } - else if (direction.equals(OUT)) { + else if (direction.equals(ParameterType.OUT)) { spc.appendOut(dbField); } - else if (direction.equals(OUT_CURSOR)) { + else if (direction.equals(ParameterType.OUT_CURSOR)) { spc.appendOutCursor(dbField); } - else if (direction.equals(INOUT)) { + else if (direction.equals(ParameterType.INOUT)) { StoredProcedureInOutArgument spaInOut = (StoredProcedureInOutArgument)spa; DatabaseField outField = new DatabaseField(spaInOut.outputArgumentName); outField.type = dbField.type; @@ -1138,7 +1136,7 @@ public void setAttributeValueInObject(Object domainObject, Object attributeValue sfc.getProcedureArgumentNames().set(0, spoa.argumentName); sfc.getParameters().set(0, spoa.getDatabaseField()); // Set argument type. - sfc.getParameterTypes().set(0, OUT); + sfc.getParameterTypes().set(0, ParameterType.OUT); } } @@ -1931,11 +1929,11 @@ protected ClassDescriptor buildPLSQLargumentDescriptor() { directionMapping.setAttributeName("direction"); directionMapping.setXPath(getPrimaryNamespaceXPath() + "direction/text()"); ObjectTypeConverter directionConverter = new ObjectTypeConverter(); - directionConverter.addConversionValue("IN", IN); - directionConverter.addConversionValue("INOUT", INOUT); - directionConverter.addConversionValue("OUT", OUT); + directionConverter.addConversionValue("IN", ParameterType.IN); + directionConverter.addConversionValue("INOUT", ParameterType.INOUT); + directionConverter.addConversionValue("OUT", ParameterType.OUT); directionMapping.setConverter(directionConverter); - directionMapping.setNullValue(IN); + directionMapping.setNullValue(ParameterType.IN); descriptor.addMapping(directionMapping); XMLDirectMapping lengthMapping = new XMLDirectMapping(); diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/DB2Platform.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/DB2Platform.java index 2ebf0278088..1a9d4e3cd0a 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/DB2Platform.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/DB2Platform.java @@ -39,7 +39,10 @@ import org.eclipse.persistence.internal.sessions.AbstractRecord; import org.eclipse.persistence.internal.sessions.AbstractSession; import org.eclipse.persistence.internal.databaseaccess.DatabaseCall; +import org.eclipse.persistence.internal.databaseaccess.DatasourceCall.ParameterType; import org.eclipse.persistence.internal.databaseaccess.FieldTypeDefinition; +import org.eclipse.persistence.internal.expressions.ConstantExpression; +import org.eclipse.persistence.internal.expressions.ExpressionJavaPrinter; import org.eclipse.persistence.internal.expressions.ExpressionSQLPrinter; import org.eclipse.persistence.internal.expressions.ParameterExpression; import org.eclipse.persistence.internal.expressions.SQLSelectStatement; @@ -428,7 +431,7 @@ public String getProcedureAsString() { * Obtain the platform specific argument string */ @Override - public String getProcedureArgument(String name, Object parameter, Integer parameterType, StoredProcedureCall call, AbstractSession session) { + public String getProcedureArgument(String name, Object parameter, ParameterType parameterType, StoredProcedureCall call, AbstractSession session) { if (name != null && shouldPrintStoredProcedureArgumentNameInCall()) { return getProcedureArgumentString() + name + " => " + "?"; } @@ -445,6 +448,15 @@ public boolean shouldPrintOutputTokenAtStart() { return true; } + /** + * Used to determine if the platform should perform partial parameter binding or not + * Enabled for DB2 and DB2 for zOS to add support for partial binding + */ + @Override + public boolean shouldBindPartialParameters() { + return this.shouldBindPartialParameters; + } + /** * INTERNAL: * This method returns the query to select the timestamp from the server for @@ -470,15 +482,1076 @@ protected void initializePlatformOperators() { addOperator(ExpressionOperator.simpleFunction(ExpressionOperator.ToUpperCase, "UCASE")); addOperator(ExpressionOperator.simpleFunction(ExpressionOperator.ToLowerCase, "LCASE")); + addOperator(count()); + addOperator(max()); + addOperator(min()); addOperator(concatOperator()); + addOperator(caseOperator()); + addOperator(caseConditionOperator()); + addOperator(distinct()); addOperator(ExpressionOperator.simpleTwoArgumentFunction(ExpressionOperator.Instring, "Locate")); // CR#2811076 some missing DB2 functions added. addOperator(ExpressionOperator.simpleFunction(ExpressionOperator.ToNumber, "DECIMAL")); addOperator(ExpressionOperator.simpleFunction(ExpressionOperator.ToChar, "CHAR")); addOperator(ExpressionOperator.simpleFunction(ExpressionOperator.DateToString, "CHAR")); addOperator(ExpressionOperator.simpleFunction(ExpressionOperator.ToDate, "DATE")); + + addOperator(ascendingOperator()); + addOperator(descendingOperator()); + + addOperator(trim2()); addOperator(ltrim2Operator()); addOperator(rtrim2Operator()); + + addOperator(lengthOperator()); + addOperator(nullifOperator()); + addOperator(coalesceOperator()); + } + + /** + * Create an ExpressionOperator that disables all parameter binding + */ + protected static ExpressionOperator disableAllBindingExpression() { + return new ExpressionOperator() { + @Override + public void printDuo(Expression first, Expression second, ExpressionSQLPrinter printer) { + if(!printer.getPlatform().shouldBindPartialParameters()) { + super.printDuo(first, second, printer); + return; + } + + if(first.isParameterExpression()) { + ((ParameterExpression) first).setCanBind(false); + } else if(first.isConstantExpression()) { + ((ConstantExpression) first).setCanBind(false); + } + if(second.isParameterExpression()) { + ((ParameterExpression) second).setCanBind(false); + } else if(second.isConstantExpression()) { + ((ConstantExpression) second).setCanBind(false); + } + super.printDuo(first, second, printer); + } + + @Override + public void printCollection(List items, ExpressionSQLPrinter printer) { + if(!printer.getPlatform().shouldBindPartialParameters()) { + super.printCollection(items, printer); + return; + } + + // Initialize argumentIndices + if (this.argumentIndices == null) { + this.argumentIndices = new int[items.size()]; + for (int i = 0; i < this.argumentIndices.length; i++){ + this.argumentIndices[i] = i; + } + } + + for(Expression item : items) { + if(item.isParameterExpression()) { + ((ParameterExpression) item).setCanBind(false); + } else if(item.isConstantExpression()) { + ((ConstantExpression) item).setCanBind(false); + } + } + super.printCollection(items, printer); + } + + @Override + public void printJavaDuo(Expression first, Expression second, ExpressionJavaPrinter printer) { + if(!printer.getPlatform().shouldBindPartialParameters()) { + super.printJavaDuo(first, second, printer); + return; + } + + if(first.isParameterExpression()) { + ((ParameterExpression) first).setCanBind(false); + } else if(first.isConstantExpression()) { + ((ConstantExpression) first).setCanBind(false); + } + if(second.isParameterExpression()) { + ((ParameterExpression) second).setCanBind(false); + } else if(second.isConstantExpression()) { + ((ConstantExpression) second).setCanBind(false); + } + super.printJavaDuo(first, second, printer); + } + + @Override + public void printJavaCollection(Vector items, ExpressionJavaPrinter printer) { + if(!printer.getPlatform().shouldBindPartialParameters()) { + super.printJavaCollection(items, printer); + return; + } + + for(Expression item : items) { + if(item.isParameterExpression()) { + ((ParameterExpression) item).setCanBind(false); + } else if(item.isConstantExpression()) { + ((ConstantExpression) item).setCanBind(false); + } + } + super.printJavaCollection(items, printer); + } + }; + } + + /** + * Create an ExpressionOperator that requires at least 1 typed argument + */ + protected static ExpressionOperator disableAtLeast1BindingExpression() { + return new ExpressionOperator() { + @Override + public void printDuo(Expression first, Expression second, ExpressionSQLPrinter printer) { + if(!printer.getPlatform().shouldBindPartialParameters()) { + super.printDuo(first, second, printer); + return; + } + + boolean firstBound = true; + if(second != null) { + boolean secondBound = true; + + // If both are parameters and/or constants, we need to determine which should be bound + if(first.isValueExpression() && second.isValueExpression()) { + if(printer.getPlatform().shouldBindLiterals()) { + // If literal binding is enabled, we should make sure parameters are favored + if(first.isConstantExpression() && second.isParameterExpression()) { + firstBound = false; + } else { + secondBound = false; + } + } else { + // Otherwise, we default to favor the first argument + if(first.isParameterExpression() && second.isParameterExpression()) { + secondBound = false; + } + } + } + + if(second.isParameterExpression()) { + ((ParameterExpression) second).setCanBind(secondBound); + } else if(second.isConstantExpression()) { + ((ConstantExpression) second).setCanBind(secondBound); + } + } + + if(first.isParameterExpression()) { + ((ParameterExpression) first).setCanBind(firstBound); + } else if(first.isConstantExpression()) { + ((ConstantExpression) first).setCanBind(firstBound); + } + super.printDuo(first, second, printer); + } + + @Override + public void printCollection(List items, ExpressionSQLPrinter printer) { + if(!printer.getPlatform().shouldBindPartialParameters()) { + super.printCollection(items, printer); + return; + } + + // Initialize argumentIndices + if (this.argumentIndices == null) { + this.argumentIndices = new int[items.size()]; + for (int i = 0; i < this.argumentIndices.length; i++){ + this.argumentIndices[i] = i; + } + } + + boolean allBind = true; + for (int i = 0; i < items.size(); i++) { + final int index = this.argumentIndices[i]; + Expression item = items.get(index); + boolean shouldBind = true; + + // If the item isn't a Constant/Parameter, this will suffice and the rest should bind + if(!item.isValueExpression()) { + allBind = false; + } + + if(allBind) { + if(printer.getPlatform().shouldBindLiterals()) { + if((i == (this.argumentIndices.length - 1))) { + // The last parameter has to be disabled + shouldBind = allBind = false; + } + } else { + if(item.isConstantExpression()) { + // The first literal has to be disabled + shouldBind = allBind = false; + } else if((i == (this.argumentIndices.length - 1)) && item.isParameterExpression()) { + // The last parameter has to be disabled + shouldBind = allBind = false; + } + } + } + + if(item.isParameterExpression()) { + ((ParameterExpression) item).setCanBind(shouldBind); + } else if(item.isConstantExpression()) { + ((ConstantExpression) item).setCanBind(shouldBind); + } + } + super.printCollection(items, printer); + } + + @Override + public void printJavaDuo(Expression first, Expression second, ExpressionJavaPrinter printer) { + if(!printer.getPlatform().shouldBindPartialParameters()) { + super.printJavaDuo(first, second, printer); + return; + } + + boolean firstBound = true; + if(second != null) { + boolean secondBound = true; + + // If both are parameters and/or constants, we need to determine which should be bound + if(first.isValueExpression() && second.isValueExpression()) { + if(printer.getPlatform().shouldBindLiterals()) { + // If literal binding is enabled, we should make sure parameters are favored + if(first.isConstantExpression() && second.isParameterExpression()) { + firstBound = false; + } else { + secondBound = false; + } + } else { + // Otherwise, we default to favor the first argument + if(first.isParameterExpression() && second.isParameterExpression()) { + secondBound = false; + } + } + } + + if(second.isParameterExpression()) { + ((ParameterExpression) second).setCanBind(secondBound); + } else if(second.isConstantExpression()) { + ((ConstantExpression) second).setCanBind(secondBound); + } + } + + if(first.isParameterExpression()) { + ((ParameterExpression) first).setCanBind(firstBound); + } else if(first.isConstantExpression()) { + ((ConstantExpression) first).setCanBind(firstBound); + } + super.printJavaDuo(first, second, printer); + } + + @Override + public void printJavaCollection(Vector items, ExpressionJavaPrinter printer) { + if(!printer.getPlatform().shouldBindPartialParameters()) { + super.printJavaCollection(items, printer); + return; + } + + boolean allBind = true; + for (int i = 0; i < items.size(); i++) { + Expression item = items.get(i); + + boolean shouldBind = true; + + // If the item isn't a Constant/Parameter, this will suffice and the rest should bind + if(!item.isValueExpression()) { + allBind = false; + } + + if(allBind) { + if(printer.getPlatform().shouldBindLiterals()) { + if((i == (items.size() - 1))) { + // The last parameter has to be disabled + shouldBind = allBind = false; + } + } else { + if(item.isConstantExpression()) { + // The first literal has to be disabled + shouldBind = allBind = false; + } else if((i == (items.size() - 1)) && item.isParameterExpression()) { + // The last parameter has to be disabled + shouldBind = allBind = false; + } + } + } + + if(item.isParameterExpression()) { + ((ParameterExpression) item).setCanBind(shouldBind); + } else if(item.isConstantExpression()) { + ((ConstantExpression) item).setCanBind(shouldBind); + } + } + super.printJavaCollection(items, printer); + } + }; + } + + /** + * Disable binding support. + *

+ * With binding enabled, DB2 & DB2 z/OS will throw an error: + *

The statement cannot be executed because a parameter marker has been used 
+     * in an invalid way. DB2 SQL Error: SQLCODE=-418, SQLSTATE=42610
+ *

+ * With binding enabled, Derby will throw an error: + *

ERROR 42X34: There is a ? parameter in the select list. This is not allowed.
+ */ + protected ExpressionOperator ascendingOperator() { + ExpressionOperator operator = disableAllBindingExpression(); + ExpressionOperator.ascending().copyTo(operator); + return operator; + } + + /** + * Disable binding support. + *

+ * With binding enabled, DB2 & DB2 z/OS will throw an error: + *

The statement cannot be executed because a parameter marker has been used 
+     * in an invalid way. DB2 SQL Error: SQLCODE=-418, SQLSTATE=42610
+ *

+ * With binding enabled, Derby will throw an error: + *

ERROR 42X34: There is a ? parameter in the select list. This is not allowed.
+ */ + protected ExpressionOperator descendingOperator() { + ExpressionOperator operator = disableAllBindingExpression(); + ExpressionOperator.descending().copyTo(operator); + return operator; + } + + /** + * INTERNAL: + * The concat operator is of the form .... VARCHAR ( || + * ) + */ + protected ExpressionOperator concatOperator() { + ExpressionOperator operator = new ExpressionOperator(); + operator.setType(ExpressionOperator.FunctionOperator); + operator.setSelector(ExpressionOperator.Concat); + Vector v = new Vector(5); + v.add("VARCHAR("); + v.add(" || "); + v.add(")"); + operator.printsAs(v); + operator.bePrefix(); + operator.setNodeClass(ClassConstants.FunctionExpression_Class); + return operator; + } + + /** + * Disable binding support. + *

+ * With binding enabled, DB2 will throw an error: + *

Db2 cannot determine how to implicitly cast the arguments between string and 
+     * numeric data types. DB2 SQL Error: SQLCODE=-245, SQLSTATE=428F5
+ *

+ * With binding enabled, DB2 z/OS will throw an error: + *

The statement cannot be executed because a parameter marker has been used 
+     * in an invalid way. DB2 SQL Error: SQLCODE=-418, SQLSTATE=42610
+ *

+ * With binding enabled, Derby will throw an error: + *

ERROR 42X36: The 'COUNT' operator is not allowed to take a ? parameter as an operand.
+ */ + protected ExpressionOperator count() { + ExpressionOperator operator = disableAllBindingExpression(); + ExpressionOperator.count().copyTo(operator); + return operator; + } + + /** + * Disable binding support. + *

+ * With binding enabled, DB2 will throw an error: + *

Db2 cannot determine how to implicitly cast the arguments between string and 
+     * numeric data types. DB2 SQL Error: SQLCODE=-245, SQLSTATE=428F5
+ *

+ * With binding enabled, DB2 z/OS will throw an error: + *

The statement cannot be executed because a parameter marker has been used 
+     * in an invalid way. DB2 SQL Error: SQLCODE=-418, SQLSTATE=42610
+ *

+ * With binding enabled, Derby will throw an error: + *

ERROR 42X36: The 'MAX' operator is not allowed to take a ? parameter as an operand.
+ */ + protected ExpressionOperator max() { + ExpressionOperator operator = disableAllBindingExpression(); + ExpressionOperator.maximum().copyTo(operator); + return operator; + } + + /** + * Disable binding support. + *

+ * With binding enabled, DB2 will throw an error: + *

Db2 cannot determine how to implicitly cast the arguments between string and 
+     * numeric data types. DB2 SQL Error: SQLCODE=-245, SQLSTATE=428F5
+ *

+ * With binding enabled, DB2 z/OS will throw an error: + *

The statement cannot be executed because a parameter marker has been used 
+     * in an invalid way. DB2 SQL Error: SQLCODE=-418, SQLSTATE=42610
+ *

+ * With binding enabled, Derby will throw an error: + *

ERROR 42X36: The 'MIN' operator is not allowed to take a ? parameter as an operand.
+ */ + protected ExpressionOperator min() { + ExpressionOperator operator = disableAllBindingExpression(); + ExpressionOperator.minimum().copyTo(operator); + return operator; + } + + /** + * Disable binding support. + *

+ * With binding enabled, DB2 will throw an error: + *

Db2 cannot determine how to implicitly cast the arguments between string and 
+     * numeric data types. DB2 SQL Error: SQLCODE=-245, SQLSTATE=428F5
+ *

+ * With binding enabled, DB2 & DB2 z/OS will throw an error: + *

The statement cannot be executed because a parameter marker has been used 
+     * in an invalid way. DB2 SQL Error: SQLCODE=-418, SQLSTATE=42610
+ *

+ * With binding enabled, Derby will throw an error: + *

ERROR 42X34: There is a ? parameter in the select list.  This is not allowed.
+ */ + protected ExpressionOperator distinct() { + ExpressionOperator operator = disableAllBindingExpression(); + ExpressionOperator.distinct().copyTo(operator); + return operator; + } + + /** + * DB2 does not allow untyped parameter binding for the THEN & ELSE 'result-expressions' of CASE expressions + *

+ * With binding enabled, DB2 & DB2 z/OS will throw an error: + *

The statement cannot be executed because a parameter marker has been used 
+     * in an invalid way. DB2 SQL Error: SQLCODE=-418, SQLSTATE=42610
+ * Examples of places where parameter markers cannot be used: + *
    + *
  • In a result-expression in any CASE expression when all the other result-expressions are either NULL or untyped parameter markers + *
+ *

+ * With binding enabled, Derby will throw an error: + *

ERROR 42X87: At least one result expression (THEN or ELSE) of the CASE expression must have a known type.
+     */
+    protected ExpressionOperator caseOperator() {
+        ListExpressionOperator operator = new ListExpressionOperator() {
+            @Override
+            public void printCollection(List items, ExpressionSQLPrinter printer) {
+                if(!printer.getPlatform().shouldBindPartialParameters()) {
+                    super.printCollection(items, printer);
+                    return;
+                }
+
+                // First, calculate all argument binding positions
+                int i = 0;
+                int numberOfItems = items.size();
+                boolean[] argumentBinding = new boolean[numberOfItems + 1];
+
+                // Enabled for CASE operator
+                argumentBinding[i] = true;
+                i++;
+
+                // Enabled for WHEN, but not for THEN
+                boolean[] separatorsBinding = new boolean[]{true, false};
+                // Disable for ELSE, but not for END
+                boolean[] terminationStringsBinding = new boolean[]{false, true};
+                while (i < numberOfItems - (terminationStringsBinding.length - 1)) {
+                    for (int j = 0; j < separatorsBinding.length; j++) {
+                        argumentBinding[i] = separatorsBinding[j];
+                        i++;
+                    }
+                }
+                while (i <= numberOfItems) {
+                    for (int j = 0; j < terminationStringsBinding.length; j++) {
+                        argumentBinding[i] = terminationStringsBinding[j];
+                        i++;
+                    }
+                }
+
+                // Initialize argumentIndices
+                if (this.argumentIndices == null) {
+                    this.argumentIndices = new int[items.size()];
+                    for (int k = 0; k < this.argumentIndices.length; k++){
+                        this.argumentIndices[k] = k;
+                    }
+                }
+
+                for (int j = 0; j < items.size(); j++) {
+                    final int index = this.argumentIndices[j];
+                    Expression item = items.get(index);
+
+                    if(item.isParameterExpression()) {
+                        ((ParameterExpression) item).setCanBind(argumentBinding[index]);
+                    } else if(item.isConstantExpression()) {
+                        ((ConstantExpression) item).setCanBind(argumentBinding[index]);
+                    }
+                }
+                super.printCollection(items, printer);
+            }
+
+            @Override
+            public void printJavaCollection(Vector items, ExpressionJavaPrinter printer) {
+                if(!printer.getPlatform().shouldBindPartialParameters()) {
+                    super.printJavaCollection(items, printer);
+                    return;
+                }
+
+                // First, calculate all argument binding positions
+                int i = 0;
+                int numberOfItems = items.size();
+                boolean[] argumentBinding = new boolean[numberOfItems + 1];
+
+                // Enabled for CASE operator
+                argumentBinding[i] = true;
+                i++;
+
+                // Enabled for WHEN, but not for THEN
+                boolean[] separatorsBinding = new boolean[]{true, false};
+                // Disable for ELSE, but not for END
+                boolean[] terminationStringsBinding = new boolean[]{false, true};
+                while (i < numberOfItems - (terminationStringsBinding.length - 1)) {
+                    for (int j = 0; j < separatorsBinding.length; j++) {
+                        argumentBinding[i] = separatorsBinding[j];
+                        i++;
+                    }
+                }
+                while (i <= numberOfItems) {
+                    for (int j = 0; j < terminationStringsBinding.length; j++) {
+                        argumentBinding[i] = terminationStringsBinding[j];
+                        i++;
+                    }
+                }
+
+                for (int j = 0; j < items.size(); j++) {
+                    Expression item = items.get(j);
+
+                    if(item.isParameterExpression()) {
+                        ((ParameterExpression) item).setCanBind(argumentBinding[j]);
+                    } else if(item.isConstantExpression()) {
+                        ((ConstantExpression) item).setCanBind(argumentBinding[j]);
+                    }
+                }
+                super.printJavaCollection(items, printer);
+            }
+        };
+        ExpressionOperator.caseStatement().copyTo(operator); 
+        return operator;
+    }
+
+    /**
+     * DB2 does not allow untyped parameter binding for the THEN & ELSE 'result-expressions' of CASE expressions
+     * 

+ * With binding enabled, DB2 & DB2 z/OS will throw an error: + *

The statement cannot be executed because a parameter marker has been used 
+     * in an invalid way. DB2 SQL Error: SQLCODE=-418, SQLSTATE=42610
+ * Examples of places where parameter markers cannot be used: + *
    + *
  • In a result-expression in any CASE expression when all the other result-expressions are either NULL or untyped parameter markers + *
+ *

+ * With binding enabled, Derby will throw an error: + *

ERROR 42X87: At least one result expression (THEN or ELSE) of the CASE expression must have a known type.
+     */
+    protected ExpressionOperator caseConditionOperator() {
+        ListExpressionOperator operator = new ListExpressionOperator() {
+            @Override
+            public void printCollection(List items, ExpressionSQLPrinter printer) {
+                if(!printer.getPlatform().shouldBindPartialParameters()) {
+                    super.printCollection(items, printer);
+                    return;
+                }
+
+                // First, calculate all argument binding positions
+                int i = 0;
+                int numberOfItems = items.size();
+                boolean[] argumentBinding = new boolean[numberOfItems + 1];
+
+                // Enabled for CASE WHEN operator
+                argumentBinding[i] = true;
+                i++;
+                // Disabled for THEN operator
+                argumentBinding[i] = false;
+                i++;
+
+                // Enabled for WHEN, but not for THEN
+                boolean[] separatorsBinding = new boolean[]{true, false};
+                // Disable for ELSE, but not for END
+                boolean[] terminationStringsBinding = new boolean[]{false, true};
+                while (i < numberOfItems - (terminationStringsBinding.length - 1)) {
+                    for (int j = 0; j < separatorsBinding.length; j++) {
+                        argumentBinding[i] = separatorsBinding[j];
+                        i++;
+                    }
+                }
+                while (i <= numberOfItems) {
+                    for (int j = 0; j < terminationStringsBinding.length; j++) {
+                        argumentBinding[i] = terminationStringsBinding[j];
+                        i++;
+                    }
+                }
+
+                // Initialize argumentIndices
+                if (this.argumentIndices == null) {
+                    this.argumentIndices = new int[items.size()];
+                    for (int k = 0; k < this.argumentIndices.length; k++){
+                        this.argumentIndices[k] = k;
+                    }
+                }
+
+                for (int j = 0; j < items.size(); j++) {
+                    final int index = this.argumentIndices[j];
+                    Expression item = items.get(index);
+
+                    if(item.isParameterExpression()) {
+                        ((ParameterExpression) item).setCanBind(argumentBinding[index]);
+                    } else if(item.isConstantExpression()) {
+                        ((ConstantExpression) item).setCanBind(argumentBinding[index]);
+                    }
+                }
+                super.printCollection(items, printer);
+            }
+
+            @Override
+            public void printJavaCollection(Vector items, ExpressionJavaPrinter printer) {
+                if(!printer.getPlatform().shouldBindPartialParameters()) {
+                    super.printJavaCollection(items, printer);
+                    return;
+                }
+
+                // First, calculate all argument binding positions
+                int i = 0;
+                int numberOfItems = items.size();
+                boolean[] argumentBinding = new boolean[numberOfItems + 1];
+
+                // Enabled for CASE WHEN operator
+                argumentBinding[i] = true;
+                i++;
+                // Disabled for THEN operator
+                argumentBinding[i] = false;
+                i++;
+
+                // Enabled for WHEN, but not for THEN
+                boolean[] separatorsBinding = new boolean[]{true, false};
+                // Disable for ELSE, but not for END
+                boolean[] terminationStringsBinding = new boolean[]{false, true};
+                while (i < numberOfItems - (terminationStringsBinding.length - 1)) {
+                    for (int j = 0; j < separatorsBinding.length; j++) {
+                        argumentBinding[i] = separatorsBinding[j];
+                        i++;
+                    }
+                }
+                while (i <= numberOfItems) {
+                    for (int j = 0; j < terminationStringsBinding.length; j++) {
+                        argumentBinding[i] = terminationStringsBinding[j];
+                        i++;
+                    }
+                }
+
+                for (int j = 0; j < items.size(); j++) {
+                    Expression item = items.get(j);
+
+                    if(item.isParameterExpression()) {
+                        ((ParameterExpression) item).setCanBind(argumentBinding[j]);
+                    } else if(item.isConstantExpression()) {
+                        ((ConstantExpression) item).setCanBind(argumentBinding[j]);
+                    }
+                }
+                super.printJavaCollection(items, printer);
+            }
+        };
+        ExpressionOperator.caseConditionStatement().copyTo(operator); 
+        return operator;
+    }
+
+    /**
+     * Disable binding support.
+     * 

+ * With binding enabled, DB2 will throw an error: + *

Db2 cannot determine how to implicitly cast the arguments between string and 
+     * numeric data types. DB2 SQL Error: SQLCODE=-245, SQLSTATE=428F5
+ *

+ * With binding enabled, DB2 z/OS will throw an error: + *

The statement cannot be executed because a parameter marker has been used 
+     * in an invalid way. DB2 SQL Error: SQLCODE=-418, SQLSTATE=42610
+ *

+ * With binding enabled, Derby will throw an error: + *

ERROR 42X36: The 'length' operator is not allowed to take a ? parameter as an operand.
+ */ + protected ExpressionOperator lengthOperator() { + ExpressionOperator operator = disableAllBindingExpression(); + ExpressionOperator.length().copyTo(operator); + return operator; + } + + /** + * DB2 requires that at least one argument be a known type + *

+ * With binding enabled, DB2 & DB2 z/OS will throw an error: + *

The statement cannot be executed because a parameter marker has been used 
+     * in an invalid way. DB2 SQL Error: SQLCODE=-418, SQLSTATE=42610
+ *

+ * With binding enabled, Derby will throw an error: + *

ERROR 42X35: It is not allowed for both operands of '=' to be ? parameters.
+ */ + protected ExpressionOperator nullifOperator() { + ExpressionOperator operator = disableAtLeast1BindingExpression(); + ExpressionOperator.nullIf().copyTo(operator); + return operator; + } + + /** + * DB2 requires that at least one argument be a known type + *

+ * With binding enabled, DB2 will throw an error: + *

The statement cannot be executed because a parameter marker has been used 
+     * in an invalid way. DB2 SQL Error: SQLCODE=-418, SQLSTATE=42610
+ *

+ * With binding enabled, DB2 z/OS will throw an error: + *

The statement string specified as the object of a PREPARE contains a 
+     * predicate or expression where parameter markers have been used as operands of 
+     * the same operator for example: ? > ?. DB2 SQL Error: SQLCODE=-417, SQLSTATE=42609
+ *

+ * With binding enabled, Derby will throw an error: + *

ERROR 42610: All the arguments to the COALESCE/VALUE function cannot be parameters. The function needs at least one argument that is not a parameter.
+ */ + protected ExpressionOperator coalesceOperator() { + ListExpressionOperator operator = new ListExpressionOperator() { + @Override + public void printCollection(List items, ExpressionSQLPrinter printer) { + if(!printer.getPlatform().shouldBindPartialParameters()) { + super.printCollection(items, printer); + return; + } + + // Initialize argumentIndices + if (this.argumentIndices == null) { + this.argumentIndices = new int[items.size()]; + for (int i = 0; i < this.argumentIndices.length; i++){ + this.argumentIndices[i] = i; + } + } + + boolean allBind = true; + for (int i = 0; i < items.size(); i++) { + final int index = this.argumentIndices[i]; + Expression item = items.get(index); + boolean shouldBind = true; + + // If the item isn't a Constant/Parameter, this will suffice and the rest should bind + if(!item.isValueExpression()) { + allBind = false; + } + + if(allBind) { + if(printer.getPlatform().shouldBindLiterals()) { + if((i == (this.argumentIndices.length - 1))) { + // The last parameter has to be disabled + shouldBind = allBind = false; + } + } else { + if(item.isConstantExpression()) { + // The first literal has to be disabled + shouldBind = allBind = false; + } else if((i == (this.argumentIndices.length - 1)) && item.isParameterExpression()) { + // The last parameter has to be disabled + shouldBind = allBind = false; + } + } + } + + if(item.isParameterExpression()) { + ((ParameterExpression) item).setCanBind(shouldBind); + } else if(item.isConstantExpression()) { + ((ConstantExpression) item).setCanBind(shouldBind); + } + } + super.printCollection(items, printer); + } + + @Override + public void printJavaCollection(Vector items, ExpressionJavaPrinter printer) { + if(!printer.getPlatform().shouldBindPartialParameters()) { + super.printJavaCollection(items, printer); + return; + } + + boolean allBind = true; + for (int i = 0; i < items.size(); i++) { + Expression item = items.get(i); + + boolean shouldBind = true; + + // If the item isn't a Constant/Parameter, this will suffice and the rest should bind + if(!item.isValueExpression()) { + allBind = false; + } + + if(allBind) { + if(printer.getPlatform().shouldBindLiterals()) { + if((i == (items.size() - 1))) { + // The last parameter has to be disabled + shouldBind = allBind = false; + } + } else { + if(item.isConstantExpression()) { + // The first literal has to be disabled + shouldBind = allBind = false; + } else if((i == (items.size() - 1)) && item.isParameterExpression()) { + // The last parameter has to be disabled + shouldBind = allBind = false; + } + } + } + + if(item.isParameterExpression()) { + ((ParameterExpression) item).setCanBind(shouldBind); + } else if(item.isConstantExpression()) { + ((ConstantExpression) item).setCanBind(shouldBind); + } + } + super.printJavaCollection(items, printer); + } + }; + ExpressionOperator.coalesce().copyTo(operator); + return operator; + } + + /** + * DB2 does not support untyped parameter binding for + *

+ * With binding enabled, DB2 & DB2 z/OS will throw an error: + *

The statement cannot be executed because a parameter marker has been used 
+     * in an invalid way. DB2 SQL Error: SQLCODE=-418, SQLSTATE=42610
+ */ + protected ExpressionOperator trim2() { + ExpressionOperator operator = new ExpressionOperator(){ + @Override + public void printCollection(List items, ExpressionSQLPrinter printer) { + if(!printer.getPlatform().shouldBindPartialParameters()) { + super.printCollection(items, printer); + return; + } + + // Initialize argumentIndices + if (this.argumentIndices == null) { + this.argumentIndices = new int[items.size()]; + for (int i = 0; i < this.argumentIndices.length; i++){ + this.argumentIndices[i] = i; + } + } + + for (int i = 0; i < items.size(); i++) { + final int index = this.argumentIndices[i]; + Expression item = items.get(index); + + // Disable the first item, which should be for this operator + if(i == 0) { + if(item.isParameterExpression()) { + ((ParameterExpression) item).setCanBind(false); + } else if(item.isConstantExpression()) { + ((ConstantExpression) item).setCanBind(false); + } + } + } + super.printCollection(items, printer); + } + + @Override + public void printJavaCollection(Vector items, ExpressionJavaPrinter printer) { + if(!printer.getPlatform().shouldBindPartialParameters()) { + super.printJavaCollection(items, printer); + return; + } + + for (int i = 0; i < items.size(); i++) { + Expression item = items.get(i); + + // Disable the first item, which should be for this operator + if(i == 0) { + if(item.isParameterExpression()) { + ((ParameterExpression) item).setCanBind(false); + } else if(item.isConstantExpression()) { + ((ConstantExpression) item).setCanBind(false); + } + } + } + super.printJavaCollection(items, printer); + } + }; + + operator.setType(ExpressionOperator.FunctionOperator); + operator.setSelector(ExpressionOperator.Trim2); + Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(5); + v.add("TRIM("); + v.add(" FROM "); + v.add(")"); + operator.printsAs(v); + operator.bePrefix(); + + // Bug 573094 + int[] indices = { 1, 0 }; + operator.setArgumentIndices(indices); + + operator.setNodeClass(ClassConstants.FunctionExpression_Class); + return operator; + } + + /** + * DB2 does not support untyped parameter binding for + *

+ * With binding enabled, DB2 & DB2 z/OS will throw an error: + *

The statement cannot be executed because a parameter marker has been used 
+     * in an invalid way. DB2 SQL Error: SQLCODE=-418, SQLSTATE=42610
+ */ + protected ExpressionOperator ltrim2Operator() { + ExpressionOperator operator = new ExpressionOperator(){ + @Override + public void printCollection(List items, ExpressionSQLPrinter printer) { + if(!printer.getPlatform().shouldBindPartialParameters()) { + super.printCollection(items, printer); + return; + } + + // Initialize argumentIndices + if (this.argumentIndices == null) { + this.argumentIndices = new int[items.size()]; + for (int i = 0; i < this.argumentIndices.length; i++){ + this.argumentIndices[i] = i; + } + } + + for (int i = 0; i < items.size(); i++) { + final int index = this.argumentIndices[i]; + Expression item = items.get(index); + + // Disable the first item, which should be for this operator + if(i == 0) { + if(item.isParameterExpression()) { + ((ParameterExpression) item).setCanBind(false); + } else if(item.isConstantExpression()) { + ((ConstantExpression) item).setCanBind(false); + } + } + } + super.printCollection(items, printer); + } + + @Override + public void printJavaCollection(Vector items, ExpressionJavaPrinter printer) { + if(!printer.getPlatform().shouldBindPartialParameters()) { + super.printJavaCollection(items, printer); + return; + } + + for (int i = 0; i < items.size(); i++) { + Expression item = items.get(i); + + // Disable the first item, which should be for this operator + if(i == 0) { + if(item.isParameterExpression()) { + ((ParameterExpression) item).setCanBind(false); + } else if(item.isConstantExpression()) { + ((ConstantExpression) item).setCanBind(false); + } + } + } + super.printJavaCollection(items, printer); + } + }; + + operator.setType(ExpressionOperator.FunctionOperator); + operator.setSelector(ExpressionOperator.LeftTrim2); + Vector v = new Vector(5); + v.add("TRIM(LEADING "); + v.add(" FROM "); + v.add(")"); + operator.printsAs(v); + operator.bePrefix(); + + // Bug 573094 + int[] indices = { 1, 0 }; + operator.setArgumentIndices(indices); + + operator.setNodeClass(ClassConstants.FunctionExpression_Class); + return operator; + } + + /** + * DB2 does not support untyped parameter binding for + *

+ * With binding enabled, DB2 & DB2 z/OS will throw an error: + *

The statement cannot be executed because a parameter marker has been used 
+     * in an invalid way. DB2 SQL Error: SQLCODE=-418, SQLSTATE=42610
+ */ + protected ExpressionOperator rtrim2Operator() { + ExpressionOperator operator = new ExpressionOperator(){ + @Override + public void printCollection(List items, ExpressionSQLPrinter printer) { + if(!printer.getPlatform().shouldBindPartialParameters()) { + super.printCollection(items, printer); + return; + } + + // Initialize argumentIndices + if (this.argumentIndices == null) { + this.argumentIndices = new int[items.size()]; + for (int i = 0; i < this.argumentIndices.length; i++){ + this.argumentIndices[i] = i; + } + } + + for (int i = 0; i < items.size(); i++) { + final int index = this.argumentIndices[i]; + Expression item = items.get(index); + + // Disable the first item, which should be for this operator + if(i == 0) { + if(item.isParameterExpression()) { + ((ParameterExpression) item).setCanBind(false); + } else if(item.isConstantExpression()) { + ((ConstantExpression) item).setCanBind(false); + } + } + } + super.printCollection(items, printer); + } + + @Override + public void printJavaCollection(Vector items, ExpressionJavaPrinter printer) { + if(!printer.getPlatform().shouldBindPartialParameters()) { + super.printJavaCollection(items, printer); + return; + } + + for (int i = 0; i < items.size(); i++) { + Expression item = items.get(i); + + // Disable the first item, which should be for this operator + if(i == 0) { + if(item.isParameterExpression()) { + ((ParameterExpression) item).setCanBind(false); + } else if(item.isConstantExpression()) { + ((ConstantExpression) item).setCanBind(false); + } + } + } + super.printJavaCollection(items, printer); + } + }; + + operator.setType(ExpressionOperator.FunctionOperator); + operator.setSelector(ExpressionOperator.RightTrim2); + Vector v = new Vector(5); + v.add("TRIM(TRAILING "); + v.add(" FROM "); + v.add(")"); + operator.printsAs(v); + operator.bePrefix(); + + // Bug 573094 + int[] indices = { 1, 0 }; + operator.setArgumentIndices(indices); + + operator.setNodeClass(ClassConstants.FunctionExpression_Class); + return operator; } @Override @@ -558,69 +1631,6 @@ public boolean shouldUseJDBCOuterJoinSyntax() { return false; } - /** - * INTERNAL: - * The Concat operator is of the form .... VARCHAR ( || - * ) - */ - private ExpressionOperator concatOperator() { - ExpressionOperator exOperator = new ExpressionOperator(); - exOperator.setType(ExpressionOperator.FunctionOperator); - exOperator.setSelector(ExpressionOperator.Concat); - Vector v = new Vector(5); - v.add("VARCHAR("); - v.add(" || "); - v.add(")"); - exOperator.printsAs(v); - exOperator.bePrefix(); - exOperator.setNodeClass(ClassConstants.FunctionExpression_Class); - return exOperator; - } - - /** - * INTERNAL: - * The 2 arg LTRIM operator is of the form .... TRIM (LEADING, FROM ) - */ - private ExpressionOperator ltrim2Operator() { - ExpressionOperator operator = new ExpressionOperator(); - operator.setType(ExpressionOperator.FunctionOperator); - operator.setSelector(ExpressionOperator.LeftTrim2); - Vector v = new Vector(5); - v.add("TRIM(LEADING "); - v.add(" FROM "); - v.add(")"); - operator.printsAs(v); - operator.bePrefix(); - // Bug 573094 - int[] indices = { 1, 0 }; - operator.setArgumentIndices(indices); - operator.setNodeClass(ClassConstants.FunctionExpression_Class); - operator.setIsBindingSupported(false); - return operator; - } - - /** - * INTERNAL: - * The 2 arg RTRIM operator is of the form .... TRIM (TRAILING, FROM ) - */ - private ExpressionOperator rtrim2Operator() { - ExpressionOperator operator = new ExpressionOperator(); - operator.setType(ExpressionOperator.FunctionOperator); - operator.setSelector(ExpressionOperator.RightTrim2); - Vector v = new Vector(5); - v.add("TRIM(TRAILING "); - v.add(" FROM "); - v.add(")"); - operator.printsAs(v); - operator.bePrefix(); - // Bug 573094 - int[] indices = { 1, 0 }; - operator.setArgumentIndices(indices); - operator.setNodeClass(ClassConstants.FunctionExpression_Class); - operator.setIsBindingSupported(false); - return operator; - } - /** * INTERNAL: Build the identity query for native sequencing. */ @@ -754,6 +1764,16 @@ public boolean isDynamicSQLRequiredForFunctions() { return !isCastRequired(); } + /** + * INTERNAL: DB2 does not allow stand alone, untyped parameter markers in select clause. + * @see org.eclipse.persistence.internal.expressions.ConstantExpression#writeFields(ExpressionSQLPrinter, List, SQLSelectStatement) + * @see org.eclipse.persistence.internal.expressions.ParameterExpression#writeFields(ExpressionSQLPrinter, List, SQLSelectStatement) + */ + @Override + public boolean allowBindingForSelectClause() { + return false; + } + /** * INTERNAL: * DB2 requires casting on certain operations, such as the CONCAT function, @@ -782,10 +1802,12 @@ public void writeParameterMarker(Writer writer, ParameterExpression parameter, A castType = "DOUBLE"; } else if (typeHelper.isStringType(type)) { castType = "VARCHAR(" + getCastSizeForVarcharParameter() + ")"; + } else if (typeHelper.isCharacterType(type)) { + castType = "CHAR"; } if (castType != null) { - paramaterMarker = "CAST (? AS " + castType + " )"; + paramaterMarker = "CAST (? AS " + castType + ")"; } } writer.write(paramaterMarker); @@ -817,6 +1839,16 @@ public boolean supportsSequenceObjects() { return true; } + /** + * DB2 disables single parameter usage in ORDER BY clause. + *

+ * If a parameter marker is used, DB2 & DB2 z/OS will throw an error: + *

The statement cannot be executed because a parameter marker has been used 
+     * in an invalid way. DB2 SQL Error: SQLCODE=-418, SQLSTATE=42610
+ *

+ * If a parameter marker is used, Derby will throw an error: + *

ERROR 42X34: There is a ? parameter in the select list.  This is not allowed.
+ */ @Override public boolean supportsOrderByParameters() { return false; diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/DB2ZPlatform.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/DB2ZPlatform.java index fa571ad4122..b0b74a0dd16 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/DB2ZPlatform.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/DB2ZPlatform.java @@ -1,6 +1,6 @@ /* - * Copyright (c) 2015, 2020 Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2015, 2020 IBM Corporation. All rights reserved. + * Copyright (c) 2015, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2022 IBM Corporation. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -28,10 +28,19 @@ import java.sql.SQLException; import java.sql.SQLXML; import java.util.Calendar; +import java.util.Collection; import java.util.Hashtable; +import org.eclipse.persistence.expressions.Expression; +import org.eclipse.persistence.expressions.ExpressionOperator; import org.eclipse.persistence.internal.databaseaccess.BindCallCustomParameter; import org.eclipse.persistence.internal.databaseaccess.DatasourceCall; +import org.eclipse.persistence.internal.databaseaccess.DatasourceCall.ParameterType; +import org.eclipse.persistence.internal.expressions.CollectionExpression; +import org.eclipse.persistence.internal.expressions.ConstantExpression; +import org.eclipse.persistence.internal.expressions.ExpressionJavaPrinter; +import org.eclipse.persistence.internal.expressions.ExpressionSQLPrinter; +import org.eclipse.persistence.internal.expressions.ParameterExpression; import org.eclipse.persistence.internal.databaseaccess.FieldTypeDefinition; import org.eclipse.persistence.internal.helper.ClassConstants; import org.eclipse.persistence.internal.helper.DatabaseField; @@ -88,7 +97,7 @@ public String getTableCreationSuffix() { } @Override - public String getProcedureArgument(String name, Object parameter, Integer parameterType, + public String getProcedureArgument(String name, Object parameter, ParameterType parameterType, StoredProcedureCall call, AbstractSession session) { if (name != null && shouldPrintStoredProcedureArgumentNameInCall()) { return ":" + name; @@ -109,6 +118,485 @@ public boolean isDB2Z() { return true; } + /** + * INTERNAL: + * Initialize any platform-specific operators + */ + @Override + protected void initializePlatformOperators() { + super.initializePlatformOperators(); + addOperator(avgOperator()); + addOperator(sumOperator()); + + addOperator(absOperator()); + addOperator(sqrtOperator()); + + addOperator(trimOperator()); + addOperator(ltrimOperator()); + addOperator(rtrimOperator()); + addOperator(locateOperator()); + addOperator(locate2Operator()); + + addOperator(equalOperator()); + addOperator(notEqualOperator()); + addOperator(lessThanOperator()); + addOperator(lessThanEqualOperator()); + addOperator(greaterThanOperator()); + addOperator(greaterThanEqualOperator()); + addOperator(isNullOperator()); + addOperator(isNotNullOperator()); + addOperator(modOperator()); + + addOperator(betweenOperator()); + addOperator(notBetweenOperator()); + addOperator(inOperator()); + } + + /** + * Disable binding support. + *

+ * With binding enabled, DB2 z/OS will throw an error: + *

The statement cannot be executed because a parameter marker has been used 
+     * in an invalid way. DB2 SQL Error: SQLCODE=-418, SQLSTATE=42610
+ */ + protected ExpressionOperator avgOperator() { + ExpressionOperator operator = disableAllBindingExpression(); + ExpressionOperator.average().copyTo(operator); + return operator; + } + + /** + * Disable binding support. + *

+ * With binding enabled, DB2 z/OS will throw an error: + *

The statement cannot be executed because a parameter marker has been used 
+     * in an invalid way. DB2 SQL Error: SQLCODE=-418, SQLSTATE=42610
+ */ + protected ExpressionOperator sumOperator() { + ExpressionOperator operator = disableAllBindingExpression(); + ExpressionOperator.sum().copyTo(operator); + return operator; + } + + /** + * Disable binding support. + *

+ * With binding enabled, DB2 z/OS will throw an error: + *

The statement cannot be executed because a parameter marker has been used 
+     * in an invalid way. DB2 SQL Error: SQLCODE=-418, SQLSTATE=42610
+ */ + protected ExpressionOperator absOperator() { + ExpressionOperator operator = disableAllBindingExpression(); + ExpressionOperator.abs().copyTo(operator); + return operator; + } + + /** + * DB2 z/OS requires that at least one argument be a known type + *

+ * With binding enabled, DB2 z/OS will throw an error: + *

The statement cannot be executed because a parameter marker has been used 
+     * in an invalid way. DB2 SQL Error: SQLCODE=-418, SQLSTATE=42610
+ */ + @Override + protected ExpressionOperator concatOperator() { + ExpressionOperator operatorS = super.concatOperator(); + ExpressionOperator operator = disableAtLeast1BindingExpression(); + operatorS.copyTo(operator); + return operator; + } + + /** + * DB2 z/OS requires that at least one argument be a known type + *

+ * With binding enabled, DB2 z/OS will throw an error: + *

The statement string specified as the object of a PREPARE contains a 
+     * predicate or expression where parameter markers have been used as operands of 
+     * the same operator for example: ? > ?. DB2 SQL Error: SQLCODE=-417, SQLSTATE=42609
+ */ + protected ExpressionOperator equalOperator() { + ExpressionOperator operator = disableAtLeast1BindingExpression(); + ExpressionOperator.equal().copyTo(operator); + return operator; + } + + /** + * DB2 z/OS requires that at least one argument be a known type + *

+ * With binding enabled, DB2 z/OS will throw an error: + *

The statement string specified as the object of a PREPARE contains a 
+     * predicate or expression where parameter markers have been used as operands of 
+     * the same operator for example: ? > ?. DB2 SQL Error: SQLCODE=-417, SQLSTATE=42609
+ */ + protected ExpressionOperator notEqualOperator() { + ExpressionOperator operator = disableAtLeast1BindingExpression(); + ExpressionOperator.notEqual().copyTo(operator); + return operator; + } + + /** + * DB2 z/OS requires that at least one argument be a known type + *

+ * With binding enabled, DB2 z/OS will throw an error: + *

The statement string specified as the object of a PREPARE contains a 
+     * predicate or expression where parameter markers have been used as operands of 
+     * the same operator for example: ? > ?. DB2 SQL Error: SQLCODE=-417, SQLSTATE=42609
+ */ + protected ExpressionOperator greaterThanOperator() { + ExpressionOperator operator = disableAtLeast1BindingExpression(); + ExpressionOperator.greaterThan().copyTo(operator); + return operator; + } + + /** + * DB2 z/OS requires that at least one argument be a known type + *

+ * With binding enabled, DB2 z/OS will throw an error: + *

The statement string specified as the object of a PREPARE contains a 
+     * predicate or expression where parameter markers have been used as operands of 
+     * the same operator for example: ? > ?. DB2 SQL Error: SQLCODE=-417, SQLSTATE=42609
+ */ + protected ExpressionOperator greaterThanEqualOperator() { + ExpressionOperator operator = disableAtLeast1BindingExpression(); + ExpressionOperator.greaterThanEqual().copyTo(operator); + return operator; + } + + /** + * DB2 z/OS requires that at least one argument be a known type + *

+ * For ALL, DB2 z/OS will throw an error: + *

The statement string specified as the object of a PREPARE contains a 
+     * predicate or expression where parameter markers have been used as operands of 
+     * the same operator for example: ? > ?. DB2 SQL Error: SQLCODE=-417, SQLSTATE=42609
+ */ + protected ExpressionOperator lessThanOperator() { + ExpressionOperator operator = disableAtLeast1BindingExpression(); + ExpressionOperator.lessThan().copyTo(operator); + return operator; + } + + /** + * DB2 z/OS requires that at least one argument be a known type + *

+ * With binding enabled, DB2 z/OS will throw an error: + *

The statement string specified as the object of a PREPARE contains a 
+     * predicate or expression where parameter markers have been used as operands of 
+     * the same operator for example: ? > ?. DB2 SQL Error: SQLCODE=-417, SQLSTATE=42609
+ */ + protected ExpressionOperator lessThanEqualOperator() { + ExpressionOperator operator = disableAtLeast1BindingExpression(); + ExpressionOperator.lessThanEqual().copyTo(operator); + return operator; + } + + /** + * Disable binding support. + *

+ * With binding enabled, DB2 z/OS will throw an error: + *

The statement string specified as the object of a PREPARE contains a 
+     * predicate or expression where parameter markers have been used as operands of 
+     * the same operator for example: ? > ?. DB2 SQL Error: SQLCODE=-417, SQLSTATE=42609
+ */ + protected ExpressionOperator isNullOperator() { + ExpressionOperator operator = disableAllBindingExpression(); + ExpressionOperator.isNull().copyTo(operator); + return operator; + } + + /** + * Disable binding support. + *

+ * With binding enabled, DB2 z/OS will throw an error: + *

The statement string specified as the object of a PREPARE contains a 
+     * predicate or expression where parameter markers have been used as operands of 
+     * the same operator for example: ? > ?. DB2 SQL Error: SQLCODE=-417, SQLSTATE=42609
+ */ + protected ExpressionOperator isNotNullOperator() { + ExpressionOperator operator = disableAllBindingExpression(); + ExpressionOperator.notNull().copyTo(operator); + return operator; + } + + /** + * DB2 z/OS requires that at least one argument be a known type + *

+ * With binding enabled, DB2 z/OS will throw an error: + *

The statement string specified as the object of a PREPARE contains a 
+     * predicate or expression where parameter markers have been used as operands of 
+     * the same operator for example: ? > ?. DB2 SQL Error: SQLCODE=-417, SQLSTATE=42609
+ */ + protected ExpressionOperator betweenOperator() { + ExpressionOperator operator = disableAtLeast1BindingExpression(); + ExpressionOperator.between().copyTo(operator); + return operator; + } + + /** + * DB2 z/OS requires that at least one argument be a known type + *

+ * With binding enabled, DB2 z/OS will throw an error: + *

The statement string specified as the object of a PREPARE contains a 
+     * predicate or expression where parameter markers have been used as operands of 
+     * the same operator for example: ? > ?. DB2 SQL Error: SQLCODE=-417, SQLSTATE=42609
+ */ + protected ExpressionOperator notBetweenOperator() { + ExpressionOperator operator = disableAtLeast1BindingExpression(); + ExpressionOperator.notBetween().copyTo(operator); + return operator; + } + + /** + * Disable binding support. + *

+ * With all binding enabled, DB2 z/OS will throw an error: + *

The statement cannot be executed because a parameter marker has been used 
+     * in an invalid way. DB2 SQL Error: SQLCODE=-418, SQLSTATE=42610
+ *

+ * With some binding enabled, DB2 z/OS will throw an error: + *

The data type, the length, or the value of an argument of a scalar function 
+     * is incorrect. DB2 SQL Error: SQLCODE=-171, SQLSTATE=42815
+ */ + protected ExpressionOperator locateOperator() { + ExpressionOperator operator = disableAllBindingExpression(); + ExpressionOperator.locate().copyTo(operator); + return operator; + } + + /** + * Disable binding support. + *

+ * With all binding enabled, DB2 z/OS will throw an error: + *

The statement cannot be executed because a parameter marker has been used 
+     * in an invalid way. DB2 SQL Error: SQLCODE=-418, SQLSTATE=42610
+ *

+ * With some binding enabled, DB2 z/OS will throw an error: + *

The data type, the length, or the value of an argument of a scalar function 
+     * is incorrect. DB2 SQL Error: SQLCODE=-171, SQLSTATE=42815
+ */ + protected ExpressionOperator locate2Operator() { + ExpressionOperator operator = disableAllBindingExpression(); + ExpressionOperator.locate2().copyTo(operator); + return operator; + } + + /** + * Disable binding support. + *

+ * With all binding enabled, DB2 z/OS will throw an error: + *

The statement cannot be executed because a parameter marker has been used 
+     * in an invalid way. DB2 SQL Error: SQLCODE=-418, SQLSTATE=42610
+ *

+ * With some binding enabled, DB2 z/OS will throw an error: + *

The data type, the length, or the value of an argument of a scalar function 
+     * is incorrect. DB2 SQL Error: SQLCODE=-171, SQLSTATE=42815
+ */ + protected ExpressionOperator modOperator() { + ExpressionOperator operator = disableAllBindingExpression(); + ExpressionOperator.mod().copyTo(operator); + return operator; + } + + /** + * Disable binding support. + *

+ * With binding enabled, DB2 z/OS will throw an error: + *

The statement cannot be executed because a parameter marker has been used 
+     * in an invalid way. DB2 SQL Error: SQLCODE=-418, SQLSTATE=42610
+ */ + protected ExpressionOperator sqrtOperator() { + ExpressionOperator operator = disableAllBindingExpression(); + ExpressionOperator.sqrt().copyTo(operator); + return operator; + } + + /** + * Disable binding support. + *

+ * With binding enabled, DB2 z/OS will throw an error: + *

The statement cannot be executed because a parameter marker has been used 
+     * in an invalid way. DB2 SQL Error: SQLCODE=-418, SQLSTATE=42610
+ */ + protected ExpressionOperator trimOperator() { + ExpressionOperator operator = disableAllBindingExpression(); + ExpressionOperator.trim().copyTo(operator); + return operator; + } + + /** + * Disable binding support. + *

+ * With binding enabled, DB2 z/OS will throw an error: + *

The data type, the length, or the value of an argument of a scalar function 
+     * is incorrect. DB2 SQL Error: SQLCODE=-171, SQLSTATE=42815
+ */ + @Override + protected ExpressionOperator trim2() { + ExpressionOperator operator = disableAllBindingExpression(); + ExpressionOperator.trim2().copyTo(operator); + return operator; + } + + /** + * Disable binding support. + *

+ * With binding enabled, DB2 z/OS will throw an error: + *

The statement cannot be executed because a parameter marker has been used 
+     * in an invalid way. DB2 SQL Error: SQLCODE=-418, SQLSTATE=42610
+ */ + protected ExpressionOperator ltrimOperator() { + ExpressionOperator operator = disableAllBindingExpression(); + ExpressionOperator.leftTrim().copyTo(operator); + return operator; + } + + /** + * Disable binding support. + *

+ * With binding enabled, DB2 z/OS will throw an error: + *

The data type, the length, or the value of an argument of a scalar function 
+     * is incorrect. DB2 SQL Error: SQLCODE=-171, SQLSTATE=42815
+ */ + @Override + protected ExpressionOperator ltrim2Operator() { + ExpressionOperator operatorS = super.ltrim2Operator(); + ExpressionOperator operator = disableAllBindingExpression(); + operatorS.copyTo(operator); + return operator; + } + + /** + * Disable binding support. + *

+ * With binding enabled, DB2 z/OS will throw an error: + *

The statement cannot be executed because a parameter marker has been used 
+     * in an invalid way. DB2 SQL Error: SQLCODE=-418, SQLSTATE=42610
+ */ + protected ExpressionOperator rtrimOperator() { + ExpressionOperator operator = disableAllBindingExpression(); + ExpressionOperator.rightTrim().copyTo(operator); + return operator; + } + + /** + * Disable binding support. + *

+ * With binding enabled, DB2 z/OS will throw an error: + *

The data type, the length, or the value of an argument of a scalar function 
+     * is incorrect. DB2 SQL Error: SQLCODE=-171, SQLSTATE=42815
+ */ + @Override + protected ExpressionOperator rtrim2Operator() { + ExpressionOperator operatorS = super.rtrim2Operator(); + ExpressionOperator operator = disableAllBindingExpression(); + operatorS.copyTo(operator); + return operator; + } + + /** + * DB2 z/OS requires that at least one argument be a known type + *

+ * With binding enabled, DB2 z/OS will throw an error: + *

The statement string specified as the object of a PREPARE contains a 
+     * predicate or expression where parameter markers have been used as operands of 
+     * the same operator for example: ? > ?. DB2 SQL Error: SQLCODE=-417, SQLSTATE=42609
+ */ + protected ExpressionOperator inOperator() { + ExpressionOperator operator = new ExpressionOperator() { + @Override + public void printDuo(Expression first, Expression second, ExpressionSQLPrinter printer) { + if(!printer.getPlatform().shouldBindPartialParameters()) { + super.printDuo(first, second, printer); + return; + } + + // If the first argument isn't a Constant/Parameter, this will suffice + if(!first.isValueExpression() || (first.isConstantExpression() && !printer.getPlatform().shouldBindLiterals())) { + super.printDuo(first, second, printer); + return; + } + + // Otherwise, we need to inspect the right, collection side of the IN expression + boolean firstBound = true; + if(second instanceof CollectionExpression) { + Object val = ((CollectionExpression) second).getValue(); + if (val instanceof Collection) { + firstBound = false; + Collection values = (Collection)val; + for(Object value : values) { + // If the value isn't a Constant/Parameter, this will suffice and the first should bind + if(value instanceof Expression && !((Expression)value).isValueExpression()) { + firstBound = true; + break; + } + + // If the value is a Constant and literal binding is disabled, this will suffice and the first should bind + if(value instanceof Expression && ((Expression)value).isConstantExpression() && !printer.getPlatform().shouldBindLiterals()) { + firstBound = true; + break; + } + } + } + } + + if(first.isParameterExpression()) { + ((ParameterExpression) first).setCanBind(firstBound); + } else if(first.isConstantExpression()) { + ((ConstantExpression) first).setCanBind(firstBound); + } + + super.printDuo(first, second, printer); + } + + @Override + public void printJavaDuo(Expression first, Expression second, ExpressionJavaPrinter printer) { + if(!printer.getPlatform().shouldBindPartialParameters()) { + super.printJavaDuo(first, second, printer); + return; + } + + // If the first argument isn't a Constant/Parameter, this will suffice + if(!first.isValueExpression() || (first.isConstantExpression() && !printer.getPlatform().shouldBindLiterals())) { + super.printJavaDuo(first, second, printer); + return; + } + + // Otherwise, we need to inspect the right, collection side of the IN expression + boolean firstBound = true; + if(second instanceof CollectionExpression) { + Object val = ((CollectionExpression) second).getValue(); + if (val instanceof Collection) { + firstBound = false; + Collection values = (Collection)val; + for(Object value : values) { + // If the value isn't a Constant/Parameter, this will suffice and the first should bind + if(value instanceof Expression && !((Expression)value).isValueExpression()) { + firstBound = true; + break; + } + + // If the value is a Constant and literal binding is disabled, this will suffice and the first should bind + if(value instanceof Expression && ((Expression)value).isConstantExpression() && !printer.getPlatform().shouldBindLiterals()) { + firstBound = true; + break; + } + } + } + } + + if(first.isParameterExpression()) { + ((ParameterExpression) first).setCanBind(firstBound); + } else if(first.isConstantExpression()) { + ((ConstantExpression) first).setCanBind(firstBound); + } + + super.printJavaDuo(first, second, printer); + } + }; + ExpressionOperator.in().copyTo(operator); + return operator; + } + /** * INTERNAL: Used for sp calls. PostGreSQL uses a different method for executing StoredProcedures than other platforms. */ @@ -128,7 +616,7 @@ public String buildProcedureCallString(StoredProcedureCall call, AbstractSession for (int index = indexFirst; index < size; index++) { String name = call.getProcedureArgumentNames().get(index); Object parameter = call.getParameters().get(index); - Integer parameterType = call.getParameterTypes().get(index); + ParameterType parameterType = call.getParameterTypes().get(index); // If the argument is optional and null, ignore it. if (!call.hasOptionalArguments() || !call.getOptionalArguments().contains(parameter) || (row.get(parameter) != null)) { diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/DerbyPlatform.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/DerbyPlatform.java index d4c7c04a28d..18b112af87b 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/DerbyPlatform.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/DerbyPlatform.java @@ -1,6 +1,6 @@ /* - * Copyright (c) 2005, 2020 Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2005, 2020 IBM Corporation. All rights reserved. + * Copyright (c) 2005, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2022 IBM Corporation. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -22,7 +22,11 @@ import org.eclipse.persistence.internal.databaseaccess.DatabaseCall; import org.eclipse.persistence.internal.databaseaccess.FieldTypeDefinition; +import org.eclipse.persistence.internal.expressions.CollectionExpression; +import org.eclipse.persistence.internal.expressions.ConstantExpression; +import org.eclipse.persistence.internal.expressions.ExpressionJavaPrinter; import org.eclipse.persistence.internal.expressions.ExpressionSQLPrinter; +import org.eclipse.persistence.internal.expressions.ParameterExpression; import org.eclipse.persistence.internal.expressions.SQLSelectStatement; import org.eclipse.persistence.internal.sessions.AbstractSession; import org.eclipse.persistence.internal.helper.ClassConstants; @@ -30,6 +34,7 @@ import org.eclipse.persistence.internal.helper.Helper; import org.eclipse.persistence.internal.helper.NonSynchronizedVector; import org.eclipse.persistence.exceptions.ValidationException; +import org.eclipse.persistence.expressions.Expression; import org.eclipse.persistence.expressions.ExpressionOperator; import org.eclipse.persistence.queries.ValueReadQuery; @@ -339,18 +344,134 @@ protected void initializePlatformOperators() { // Derby does not support DECIMAL, but does have a DOUBLE function. addOperator(ExpressionOperator.simpleFunction(ExpressionOperator.ToNumber, "DOUBLE")); addOperator(extractOperator()); + + addOperator(avgOperator()); + addOperator(sumOperator()); + + addOperator(equalOperator()); + addOperator(notEqualOperator()); + addOperator(lessThanOperator()); + addOperator(lessThanEqualOperator()); + addOperator(greaterThanOperator()); + addOperator(greaterThanEqualOperator()); + addOperator(modOperator()); + + addOperator(betweenOperator()); + addOperator(notBetweenOperator()); + addOperator(inOperator()); + + addOperator(addOperator()); + addOperator(subtractOperator()); + addOperator(multiplyOperator()); + addOperator(divideOperator()); + } + + /** + * Disable binding support. + *

+ * With binding enabled, Derby will throw an error: + *

ERROR 42X36: The 'AVG' operator is not allowed to take a ? parameter as an operand.
+ */ + protected ExpressionOperator avgOperator() { + ExpressionOperator operator = disableAllBindingExpression(); + ExpressionOperator.average().copyTo(operator); + return operator; + } + + /** + * Disable binding support. + *

+ * With binding enabled, Derby will throw an error: + *

ERROR 42X36: The 'SUM' operator is not allowed to take a ? parameter as an operand.
+ */ + protected ExpressionOperator sumOperator() { + ExpressionOperator operator = disableAllBindingExpression(); + ExpressionOperator.sum().copyTo(operator); + return operator; + } + + /** + * Derby requires that at least one argument be a known type + *

+ * With binding enabled, Derby will throw an error: + *

ERROR 42X35: It is not allowed for both operands of '=' to be ? parameters.
+ */ + protected ExpressionOperator equalOperator() { + ExpressionOperator operator = disableAtLeast1BindingExpression(); + ExpressionOperator.equal().copyTo(operator); + return operator; + } + + /** + * Derby requires that at least one argument be a known type + *

+ * With binding enabled, Derby will throw an error: + *

ERROR 42X35: It is not allowed for both operands of '<>' to be ? parameters.
+ */ + protected ExpressionOperator notEqualOperator() { + ExpressionOperator operator = disableAtLeast1BindingExpression(); + ExpressionOperator.notEqual().copyTo(operator); + return operator; + } + + /** + * Derby requires that at least one argument be a known type + *

+ * With binding enabled, Derby will throw an error: + *

ERROR 42X35: It is not allowed for both operands of '>' to be ? parameters.
+ */ + protected ExpressionOperator greaterThanOperator() { + ExpressionOperator operator = disableAtLeast1BindingExpression(); + ExpressionOperator.greaterThan().copyTo(operator); + return operator; + } + + /** + * Derby requires that at least one argument be a known type + *

+ * With binding enabled, Derby will throw an error: + *

ERROR 42X35: It is not allowed for both operands of '>=' to be ? parameters.
+ */ + protected ExpressionOperator greaterThanEqualOperator() { + ExpressionOperator operator = disableAtLeast1BindingExpression(); + ExpressionOperator.greaterThanEqual().copyTo(operator); + return operator; + } + + /** + * Derby requires that at least one argument be a known type + *

+ * With binding enabled, Derby will throw an error: + *

ERROR 42X35: It is not allowed for both operands of '<' to be ? parameters.
+ */ + protected ExpressionOperator lessThanOperator() { + ExpressionOperator operator = disableAtLeast1BindingExpression(); + ExpressionOperator.lessThan().copyTo(operator); + return operator; + } + + /** + * Derby requires that at least one argument be a known type + *

+ * With binding enabled, Derby will throw an error: + *

ERROR 42X35: It is not allowed for both operands of '<=' to be ? parameters.
+ */ + protected ExpressionOperator lessThanEqualOperator() { + ExpressionOperator operator = disableAtLeast1BindingExpression(); + ExpressionOperator.lessThanEqual().copyTo(operator); + return operator; } /** * INTERNAL: * Derby does not support EXTRACT, but does have YEAR, MONTH, DAY, etc. */ - public static ExpressionOperator extractOperator() { + protected ExpressionOperator extractOperator() { ExpressionOperator exOperator = new ExpressionOperator(); exOperator.setType(ExpressionOperator.FunctionOperator); exOperator.setSelector(ExpressionOperator.Extract); exOperator.setName("EXTRACT"); - Vector v = NonSynchronizedVector.newInstance(5); + Vector v = NonSynchronizedVector.newInstance(5); v.add(""); v.add("("); v.add(")"); @@ -364,6 +485,258 @@ public static ExpressionOperator extractOperator() { return exOperator; } + /** + * Derby requires that at least one argument be a known type + *

+ * With binding enabled, Derby will throw an error: + *

ERROR 42X35: It is not allowed for both operands of '+' to be ? parameters.
+ */ + protected ExpressionOperator addOperator() { + ExpressionOperator operator = disableAtLeast1BindingExpression(); + ExpressionOperator.add().copyTo(operator); + return operator; + } + + /** + * Derby requires that at least one argument be a known type + *

+ * With binding enabled, Derby will throw an error: + *

ERROR 42X35: It is not allowed for both operands of '-' to be ? parameters.
+ */ + protected ExpressionOperator subtractOperator() { + ExpressionOperator operator = disableAtLeast1BindingExpression(); + ExpressionOperator.subtract().copyTo(operator); + return operator; + } + + /** + * Derby requires that at least one argument be a known type + *

+ * With binding enabled, Derby will throw an error: + *

ERROR 42X35: It is not allowed for both operands of '*' to be ? parameters.
+ */ + protected ExpressionOperator multiplyOperator() { + ExpressionOperator operator = disableAtLeast1BindingExpression(); + ExpressionOperator.multiply().copyTo(operator); + return operator; + } + + /** + * Derby requires that at least one argument be a known type + *

+ * With binding enabled, Derby will throw an error: + *

ERROR 42X35: It is not allowed for both operands of '/' to be ? parameters.
+ */ + protected ExpressionOperator divideOperator() { + ExpressionOperator operator = disableAtLeast1BindingExpression(); + ExpressionOperator.divide().copyTo(operator); + return operator; + } + + /** + * Derby requires that at least one argument be a known type + *

+ * With binding enabled, Derby will throw an error: + *

ERROR 42X35: It is not allowed for both operands of '||' to be ? parameters.
+ */ + protected ExpressionOperator concatOperator() { + ExpressionOperator operatorS = super.concatOperator(); + ExpressionOperator operator = disableAtLeast1BindingExpression(); + operatorS.copyTo(operator); + return operator; + } + + /** + * Enable binding support. + *

+ * With binding enabled, Derby does not throw an exception + */ + @Override + protected ExpressionOperator trim2() { + ExpressionOperator operatorS = super.trim2(); + ExpressionOperator operator = ExpressionOperator.trim2(); + operatorS.copyTo(operator); + return operator; + } + + /** + * Derby requires that at least one argument be a known type + *

+ * With binding enabled, Derby will throw an error: + *

ERROR 42X35: It is not allowed for both operands of 'mod' to be ? parameters.
+ */ + protected ExpressionOperator modOperator() { + ExpressionOperator operator = disableAtLeast1BindingExpression(); + ExpressionOperator.mod().copyTo(operator); + return operator; + } + + /** + * Enable binding support. + *

+ * With binding enabled, Derby does not throw an exception + */ + @Override + protected ExpressionOperator ltrim2Operator() { + ExpressionOperator operatorS = super.ltrim2Operator(); + ExpressionOperator operator = ExpressionOperator.leftTrim2(); + operatorS.copyTo(operator); + return operator; + } + + /** + * Enable binding support. + *

+ * With binding enabled, Derby does not throw an exception + */ + @Override + protected ExpressionOperator rtrim2Operator() { + ExpressionOperator operatorS = super.rtrim2Operator(); + ExpressionOperator operator = ExpressionOperator.rightTrim2(); + operatorS.copyTo(operator); + return operator; + } + + /** + * Derby requires that at least one argument be a known type + *

+ * With binding enabled, Derby will throw an error: + *

ERROR 42X35: It is not allowed for both operands of 'BETWEEN' to be ? parameters.
+ */ + protected ExpressionOperator betweenOperator() { + ExpressionOperator operator = disableAtLeast1BindingExpression(); + ExpressionOperator.between().copyTo(operator); + return operator; + } + + /** + * Derby requires that at least one argument be a known type + *

+ * With binding enabled, Derby will throw an error: + *

ERROR 42X35: It is not allowed for both operands of 'BETWEEN' to be ? parameters.
+ */ + protected ExpressionOperator notBetweenOperator() { + ExpressionOperator operator = disableAtLeast1BindingExpression(); + ExpressionOperator.notBetween().copyTo(operator); + return operator; + } + + /** + * Derby requires that at least one argument be a known type + *

+ * With binding enabled, Derby will throw an error: + *

ERROR 42X35: It is not allowed for both operands of 'IN' to be ? parameters.
+ */ + protected ExpressionOperator inOperator() { + ExpressionOperator operator = new ExpressionOperator() { + @Override + public void printDuo(Expression first, Expression second, ExpressionSQLPrinter printer) { + if(!printer.getPlatform().shouldBindPartialParameters()) { + super.printDuo(first, second, printer); + return; + } + + // If the first argument isn't a Constant/Parameter, this will suffice + if(!first.isValueExpression() || (first.isConstantExpression() && !printer.getPlatform().shouldBindLiterals())) { + super.printDuo(first, second, printer); + return; + } + + // Otherwise, we need to inspect the right, collection side of the IN expression + boolean firstBound = true; + if(second instanceof CollectionExpression) { + Object val = ((CollectionExpression) second).getValue(); + if (val instanceof Collection) { + firstBound = false; + Collection values = (Collection)val; + for(Object value : values) { + // If the value isn't a Constant/Parameter, this will suffice and the first should bind + if(value instanceof Expression && !((Expression)value).isValueExpression()) { + firstBound = true; + break; + } + + // If the value is a Constant and literal binding is disabled, this will suffice and the first should bind + if(value instanceof Expression && ((Expression)value).isConstantExpression() && !printer.getPlatform().shouldBindLiterals()) { + firstBound = true; + break; + } + } + } + } + + if(first.isParameterExpression()) { + ((ParameterExpression) first).setCanBind(firstBound); + } else if(first.isConstantExpression()) { + ((ConstantExpression) first).setCanBind(firstBound); + } + + super.printDuo(first, second, printer); + } + + @Override + public void printJavaDuo(Expression first, Expression second, ExpressionJavaPrinter printer) { + if(!printer.getPlatform().shouldBindPartialParameters()) { + super.printJavaDuo(first, second, printer); + return; + } + + // If the first argument isn't a Constant/Parameter, this will suffice + if(!first.isValueExpression() || (first.isConstantExpression() && !printer.getPlatform().shouldBindLiterals())) { + super.printJavaDuo(first, second, printer); + return; + } + + // Otherwise, we need to inspect the right, collection side of the IN expression + boolean firstBound = true; + if(second instanceof CollectionExpression) { + Object val = ((CollectionExpression) second).getValue(); + if (val instanceof Collection) { + firstBound = false; + Collection values = (Collection)val; + for(Object value : values) { + // If the value isn't a Constant/Parameter, this will suffice and the first should bind + if(value instanceof Expression && !((Expression)value).isValueExpression()) { + firstBound = true; + break; + } + + // If the value is a Constant and literal binding is disabled, this will suffice and the first should bind + if(value instanceof Expression && ((Expression)value).isConstantExpression() && !printer.getPlatform().shouldBindLiterals()) { + firstBound = true; + break; + } + } + } + } + + if(first.isParameterExpression()) { + ((ParameterExpression) first).setCanBind(firstBound); + } else if(first.isConstantExpression()) { + ((ConstantExpression) first).setCanBind(firstBound); + } + + super.printJavaDuo(first, second, printer); + } + }; + ExpressionOperator.in().copyTo(operator); + return operator; + } + + /** + * INTERNAL + * Derby has some issues with using parameters on certain functions and relations. + * This allows statements to disable binding, for queries, only in these cases. + * If users set casting on, then casting is used instead of dynamic SQL. + */ + @Override + public boolean isDynamicSQLRequiredForFunctions() { + if(shouldForceBindAllParameters()) { + return false; + } + return !isCastRequired(); + } + /** * INTERNAL: * Use the JDBC maxResults and firstResultIndex setting to compute a value to use when diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/FirebirdPlatform.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/FirebirdPlatform.java index f35d736b3e3..9d6cc5568dc 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/FirebirdPlatform.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/FirebirdPlatform.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 1998, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022 IBM Corporation. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -362,6 +363,11 @@ public boolean isDynamicSQLRequiredForFunctions() { return true; } + @Override + public boolean allowBindingForSelectClause() { + return false; + } + /** * WITH LOCK is required on FB to hold the lock. diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/H2Platform.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/H2Platform.java index a18ee064453..931650750ec 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/H2Platform.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/H2Platform.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 1998, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022 IBM Corporation. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -125,6 +126,11 @@ public boolean isDynamicSQLRequiredForFunctions() { return true; } + @Override + public boolean allowBindingForSelectClause() { + return false; + } + @Override public ValueReadQuery buildSelectQueryForSequenceObject(String seqName, Integer size) { return new ValueReadQuery(new StringBuilder(20 + seqName.length()).append("CALL NEXT VALUE FOR ").append(seqName).toString()); diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/HANAPlatform.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/HANAPlatform.java index 6af047892f6..a2dfdbfdfb7 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/HANAPlatform.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/HANAPlatform.java @@ -1,7 +1,7 @@ /* - * Copyright (c) 2012, 2019 Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2019 IBM Corporation. All rights reserved. - * Copyright (c) 2012, 2019 SAP. All rights reserved. + * Copyright (c) 2012, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022 IBM Corporation. All rights reserved. + * Copyright (c) 2012, 2022 SAP. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -204,7 +204,7 @@ protected final void initializePlatformOperators() { this.addOperator(HANAPlatform.createLocateOperator()); this.addOperator(HANAPlatform.createLocate2Operator()); this.addOperator(HANAPlatform.createVarianceOperator()); - this.addNonBindingOperator(HANAPlatform.createNullValueOperator()); + this.addOperator(HANAPlatform.createNullValueOperator()); } private static final ExpressionOperator createConcatExpressionOperator() { @@ -319,7 +319,9 @@ private static final ExpressionOperator createNullifOperator() { } private static final ExpressionOperator createNullValueOperator() { - return ExpressionOperator.simpleTwoArgumentFunction(ExpressionOperator.Nvl, "IFNULL"); + ExpressionOperator exOperator = ExpressionOperator.simpleTwoArgumentFunction(ExpressionOperator.Nvl, "IFNULL"); + exOperator.setIsBindingSupported(false); + return exOperator; } @Override @@ -366,11 +368,6 @@ public boolean shouldOptimizeDataConversion() { return true; // TODO is this needed? (seems to default to true) } - private void addNonBindingOperator(ExpressionOperator operator) { - operator.setIsBindingSupported(false); - addOperator(operator); - } - @Override public final boolean supportsNativeSequenceNumbers() { return true; diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/HSQLPlatform.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/HSQLPlatform.java index 56c9f9b893b..102ae923dd8 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/HSQLPlatform.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/HSQLPlatform.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 1998, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022 IBM Corporation. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -224,6 +225,11 @@ public boolean isDynamicSQLRequiredForFunctions() { return true; } + @Override + public boolean allowBindingForSelectClause() { + return false; + } + /** * JDBC escape syntax for outer joins is not supported (not required). */ diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/Informix11Platform.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/Informix11Platform.java index bc6e2132506..24820e5e556 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/Informix11Platform.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/Informix11Platform.java @@ -1,6 +1,7 @@ /* - * Copyright (c) 2011, 2018 Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2011, 2018 Jenzabar, Inc. All rights reserved. + * Copyright (c) 2011, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022 IBM Corporation. All rights reserved. + * Copyright (c) 2011, 2022 Jenzabar, Inc. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -121,12 +122,10 @@ public Informix11Platform() { */ @Override protected void initializePlatformOperators() { - final ExpressionOperator distinctOverride = ExpressionOperator.getOperator(Integer.valueOf(ExpressionOperator.Distinct)); - assert distinctOverride != null; - distinctOverride.printsAs("DISTINCT "); // no parens, one space super.initializePlatformOperators(); this.addOperator(this.currentDateOperator()); this.addOperator(this.currentTimeOperator()); + this.addOperator(this.distinctOperator()); } /** @@ -167,6 +166,25 @@ protected ExpressionOperator currentTimeOperator() { return ExpressionOperator.simpleFunctionNoParentheses(ExpressionOperator.CurrentDate, "CURRENT YEAR TO FRACTION(3)"); } + /** + * Fixes EclipseLink + * bug 402600 by making sure that the {@link + * ExpressionOperator#distinct() Distinct} {@link + * ExpressionOperator} is set to {@linkplain + * ExpressionOperator#printsAs(String) print as} {@code + * DISTINCT } (no parentheses, one trailing space), and fixes + * + * @see EclipseLink + * bug 402600 + */ + protected ExpressionOperator distinctOperator() { + ExpressionOperator operator = ExpressionOperator.distinct(); + operator.printsAs("DISTINCT "); // no parens, one space + return operator; + } + /** * Overrides the default behavior to return {@code false}, * indicating that ANSI {@code OUTER JOIN} syntax should be used, diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/MaxDBPlatform.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/MaxDBPlatform.java index cb72d1ee47a..a049edc0f4a 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/MaxDBPlatform.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/MaxDBPlatform.java @@ -1,6 +1,7 @@ /* - * Copyright (c) 2009, 2018 Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2009, 2018 Markus Karg, SAP. All rights reserved. + * Copyright (c) 2009, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022 IBM Corporation. All rights reserved. + * Copyright (c) 2009, 2022 Markus Karg, SAP. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -181,7 +182,7 @@ protected final void initializePlatformOperators() { this.addOperator(MaxDBPlatform.createTodayExpressionOperator()); this.addOperator(MaxDBPlatform.createCurrentDateExpressionOperator()); this.addOperator(MaxDBPlatform.createCurrentTimeExpressionOperator()); - this.addNonBindingOperator(MaxDBPlatform.createNullValueOperator()); + this.addOperator(MaxDBPlatform.createNullValueOperator()); } private static final ExpressionOperator createConcatExpressionOperator() { @@ -220,7 +221,9 @@ private static final ExpressionOperator createTrim2ExpressionOperator() { } private static final ExpressionOperator createNullValueOperator() { - return ExpressionOperator.simpleTwoArgumentFunction(ExpressionOperator.Nvl, "VALUE"); + ExpressionOperator exOperator = ExpressionOperator.simpleTwoArgumentFunction(ExpressionOperator.Nvl, "VALUE"); + exOperator.setIsBindingSupported(false); + return exOperator; } /* see bug 316774 */ @@ -257,11 +260,6 @@ public boolean shouldOptimizeDataConversion() { return true; // TODO is this needed? (seems to default to true) } - private void addNonBindingOperator(ExpressionOperator operator) { - operator.setIsBindingSupported(false); - addOperator(operator); - } - @Override public final boolean supportsNativeSequenceNumbers() { return true; diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/OraclePlatform.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/OraclePlatform.java index d5b96daf69a..7cd0a9b13f1 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/OraclePlatform.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/OraclePlatform.java @@ -1,6 +1,6 @@ /* * Copyright (c) 1998, 2022 Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 1998, 2021 IBM Corporation. All rights reserved. + * Copyright (c) 1998, 2022 IBM Corporation. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -49,7 +49,7 @@ import org.eclipse.persistence.expressions.Expression; import org.eclipse.persistence.expressions.ExpressionOperator; import org.eclipse.persistence.internal.databaseaccess.DatabaseCall; -import org.eclipse.persistence.internal.databaseaccess.DatasourceCall; +import org.eclipse.persistence.internal.databaseaccess.DatasourceCall.ParameterType; import org.eclipse.persistence.internal.databaseaccess.FieldTypeDefinition; import org.eclipse.persistence.internal.expressions.ExpressionSQLPrinter; import org.eclipse.persistence.internal.expressions.FunctionExpression; @@ -202,14 +202,6 @@ protected void appendCalendar(Calendar calendar, Writer writer) throws IOExcepti } } - /** - * INTERNAL: - * Build operator. - */ - public ExpressionOperator atan2Operator() { - return ExpressionOperator.simpleTwoArgumentFunction(ExpressionOperator.Atan2, "ATAN2"); - } - /** * INTERNAL: */ @@ -587,25 +579,40 @@ protected void initializePlatformOperators() { addOperator(operatorOuterJoin()); addOperator(logOperator()); addOperator(ExpressionOperator.simpleTwoArgumentFunction(ExpressionOperator.Concat, "CONCAT")); - addOperator(todayOperator()); - addOperator(currentDateOperator()); - addOperator(currentTimeOperator()); + addOperator(ExpressionOperator.simpleFunctionNoParentheses(ExpressionOperator.Today, "SYSDATE")); + addOperator(ExpressionOperator.simpleFunctionNoParentheses(ExpressionOperator.CurrentDate, "TO_DATE(CURRENT_DATE)")); + addOperator(ExpressionOperator.simpleFunctionNoParentheses(ExpressionOperator.CurrentTime, "SYSDATE")); addOperator(ExpressionOperator.truncateDate()); addOperator(ExpressionOperator.newTime()); addOperator(ExpressionOperator.ifNull()); - addOperator(atan2Operator()); - addOperator(ExpressionOperator.oracleDateName()); + addOperator(ExpressionOperator.simpleTwoArgumentFunction(ExpressionOperator.Atan2, "ATAN2")); + addOperator(oracleDateName()); addOperator(operatorLocate()); addOperator(operatorLocate2()); addOperator(regexpOperator()); addOperator(exceptOperator()); } + /** + * Create the outer join operator for this platform + */ + protected static ExpressionOperator operatorOuterJoin() { + ExpressionOperator result = new ExpressionOperator(); + result.setSelector(ExpressionOperator.EqualOuterJoin); + Vector v = NonSynchronizedVector.newInstance(2); + v.addElement(" (+) = "); + result.printsAs(v); + result.bePostfix(); + result.setNodeClass(RelationExpression.class); + return result; + + } + /** * INTERNAL: * Create the EXCEPT operator, MINUS in Oracle. */ - public static ExpressionOperator exceptOperator() { + protected static ExpressionOperator exceptOperator() { ExpressionOperator exOperator = new ExpressionOperator(); exOperator.setType(ExpressionOperator.FunctionOperator); exOperator.setSelector(ExpressionOperator.Except); @@ -619,7 +626,7 @@ public static ExpressionOperator exceptOperator() { * INTERNAL: * Create the REGEXP_LIKE operator. */ - public static ExpressionOperator regexpOperator() { + protected static ExpressionOperator regexpOperator() { ExpressionOperator result = new ExpressionOperator(); result.setSelector(ExpressionOperator.Regexp); result.setType(ExpressionOperator.FunctionOperator); @@ -639,23 +646,43 @@ public static ExpressionOperator regexpOperator() { /** * INTERNAL: - * Used by derived platforms (Oracle8Platform and higher) - * to indicate whether app. server should unwrap connection - * to use lob locator. + * Override the default locate operator */ - public boolean isNativeConnectionRequiredForLobLocator() { - return false; + protected static ExpressionOperator operatorLocate() { + ExpressionOperator result = new ExpressionOperator(); + result.setSelector(ExpressionOperator.Locate); + Vector v = NonSynchronizedVector.newInstance(2); + v.addElement("INSTR("); + v.addElement(", "); + v.addElement(")"); + result.printsAs(v); + result.bePrefix(); + result.setNodeClass(RelationExpression.class); + return result; } - @Override - public boolean isOracle() { - return true; + /** + * INTERNAL: + * Override the default locate operator + */ + protected static ExpressionOperator operatorLocate2() { + ExpressionOperator result = new ExpressionOperator(); + result.setSelector(ExpressionOperator.Locate2); + Vector v = NonSynchronizedVector.newInstance(2); + v.addElement("INSTR("); + v.addElement(", "); + v.addElement(", "); + v.addElement(")"); + result.printsAs(v); + result.bePrefix(); + result.setNodeClass(RelationExpression.class); + return result; } /** * Create the log operator for this platform */ - protected ExpressionOperator logOperator() { + protected static ExpressionOperator logOperator() { ExpressionOperator result = new ExpressionOperator(); result.setSelector(ExpressionOperator.Log); Vector v = NonSynchronizedVector.newInstance(2); @@ -668,6 +695,41 @@ protected ExpressionOperator logOperator() { } + /** + * INTERNAL: + * Oracle equivalent to DATENAME is TO_CHAR. + */ + protected static ExpressionOperator oracleDateName() { + ExpressionOperator exOperator = new ExpressionOperator(); + exOperator.setType(ExpressionOperator.FunctionOperator); + exOperator.setSelector(ExpressionOperator.DateName); + Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(3); + v.add("TO_CHAR("); + v.add(", '"); + v.add("')"); + exOperator.printsAs(v); + exOperator.bePrefix(); + int[] indices = { 1, 0 }; + exOperator.setArgumentIndices(indices); + exOperator.setNodeClass(ClassConstants.FunctionExpression_Class); + return exOperator; + } + + /** + * INTERNAL: + * Used by derived platforms (Oracle8Platform and higher) + * to indicate whether app. server should unwrap connection + * to use lob locator. + */ + public boolean isNativeConnectionRequiredForLobLocator() { + return false; + } + + @Override + public boolean isOracle() { + return true; + } + /** * Builds a table of maximum numeric values keyed on java class. This is used for type testing but * might also be useful to end users attempting to sanitize values. @@ -730,56 +792,6 @@ public ValueReadQuery buildSelectQueryForIdentity(String qualifiedSeqName, Integ return new ValueReadQuery("SELECT " + qualifiedSeqName + ".CURRVAL FROM DUAL"); } - /** - * Create the outer join operator for this platform - */ - protected ExpressionOperator operatorOuterJoin() { - ExpressionOperator result = new ExpressionOperator(); - result.setSelector(ExpressionOperator.EqualOuterJoin); - Vector v = NonSynchronizedVector.newInstance(2); - v.addElement(" (+) = "); - result.printsAs(v); - result.bePostfix(); - result.setNodeClass(RelationExpression.class); - return result; - - } - - /** - * INTERNAL: - * Override the default locate operator - */ - protected ExpressionOperator operatorLocate() { - ExpressionOperator result = new ExpressionOperator(); - result.setSelector(ExpressionOperator.Locate); - Vector v = NonSynchronizedVector.newInstance(2); - v.addElement("INSTR("); - v.addElement(", "); - v.addElement(")"); - result.printsAs(v); - result.bePrefix(); - result.setNodeClass(RelationExpression.class); - return result; - } - - /** - * INTERNAL: - * Override the default locate operator - */ - protected ExpressionOperator operatorLocate2() { - ExpressionOperator result = new ExpressionOperator(); - result.setSelector(ExpressionOperator.Locate2); - Vector v = NonSynchronizedVector.newInstance(2); - v.addElement("INSTR("); - v.addElement(", "); - v.addElement(", "); - v.addElement(")"); - result.printsAs(v); - result.bePrefix(); - result.setNodeClass(RelationExpression.class); - return result; - } - /** * INTERNAL: * Append the receiver's field 'NULL' constraint clause to a writer. @@ -811,9 +823,9 @@ public boolean shouldPrintStoredProcedureArgumentNameInCall() { } @Override - public String getProcedureArgument(String name, Object parameter, Integer parameterType, + public String getProcedureArgument(String name, Object parameter, ParameterType parameterType, StoredProcedureCall call, AbstractSession session) { - if(name != null && DatasourceCall.IN.equals(parameterType) && !call.usesBinding(session)) { + if(name != null && ParameterType.IN.equals(parameterType) && !call.usesBinding(session)) { return name + "=>" + "?"; } return "?"; @@ -906,21 +918,6 @@ public boolean supportsSelectForUpdateNoWait() { return true; } - /** - * Create the sysdate operator for this platform - */ - protected ExpressionOperator todayOperator() { - return ExpressionOperator.simpleFunctionNoParentheses(ExpressionOperator.Today, "SYSDATE"); - } - - protected ExpressionOperator currentDateOperator() { - return ExpressionOperator.simpleFunctionNoParentheses(ExpressionOperator.CurrentDate, "TO_DATE(CURRENT_DATE)"); - } - - protected ExpressionOperator currentTimeOperator() { - return ExpressionOperator.simpleFunctionNoParentheses(ExpressionOperator.CurrentTime, "SYSDATE"); - } - /** * INTERNAL: * Indicates whether this Oracle platform can unwrap Oracle connection. @@ -1076,7 +1073,7 @@ private void duplicateCallParameters(DatabaseCall call) { ArrayList newParameterList = new ArrayList(call.getParameters()); newParameterList.addAll(call.getParameters()); call.setParameters(newParameterList); - ArrayList newParameterTypesList = new ArrayList(call.getParameterTypes()); + ArrayList newParameterTypesList = new ArrayList(call.getParameterTypes()); newParameterTypesList.addAll(call.getParameterTypes()); call.setParameterTypes(newParameterTypesList); } diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/PostgreSQLPlatform.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/PostgreSQLPlatform.java index 33933594be0..7e8ba2029d1 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/PostgreSQLPlatform.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/PostgreSQLPlatform.java @@ -1,6 +1,6 @@ /* - * Copyright (c) 1998, 2020 Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2019 IBM Corporation. All rights reserved. + * Copyright (c) 1998, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022 IBM Corporation. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -32,6 +32,7 @@ import org.eclipse.persistence.expressions.ExpressionOperator; import org.eclipse.persistence.internal.databaseaccess.DatabaseCall; import org.eclipse.persistence.internal.databaseaccess.DatasourceCall; +import org.eclipse.persistence.internal.databaseaccess.DatasourceCall.ParameterType; import org.eclipse.persistence.internal.databaseaccess.FieldTypeDefinition; import org.eclipse.persistence.internal.expressions.ExpressionSQLPrinter; import org.eclipse.persistence.internal.expressions.RelationExpression; @@ -453,7 +454,7 @@ public String buildProcedureCallString(StoredProcedureCall call, AbstractSession for (int index = indexFirst; index < size; index++) { String name = call.getProcedureArgumentNames().get(index); Object parameter = call.getParameters().get(index); - Integer parameterType = call.getParameterTypes().get(index); + ParameterType parameterType = call.getParameterTypes().get(index); // If the argument is optional and null, ignore it. if (!call.hasOptionalArguments() || !call.getOptionalArguments().contains(parameter) || (row.get(parameter) != null)) { if (!DatasourceCall.isOutputParameterType(parameterType)) { diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/SQLServerPlatform.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/SQLServerPlatform.java index fed894fdcaa..3539691a15b 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/SQLServerPlatform.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/SQLServerPlatform.java @@ -1,6 +1,6 @@ /* - * Copyright (c) 1998, 2019 Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 1998, 2019 IBM Corporation. All rights reserved. + * Copyright (c) 1998, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022 IBM Corporation. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -437,17 +437,17 @@ protected void initializePlatformOperators() { addOperator(ExpressionOperator.replicate()); addOperator(ExpressionOperator.right()); addOperator(ExpressionOperator.cot()); - addOperator(ExpressionOperator.sybaseAtan2Operator()); - addOperator(ExpressionOperator.sybaseAddMonthsOperator()); - addOperator(ExpressionOperator.sybaseInStringOperator()); + addOperator(ExpressionOperator.simpleTwoArgumentFunction(ExpressionOperator.Atan2, "ATN2")); + addOperator(addMonthsOperator()); + addOperator(inStringOperator()); // bug 3061144 addOperator(ExpressionOperator.simpleTwoArgumentFunction(ExpressionOperator.Nvl, "ISNULL")); // CR### TO_NUMBER, TO_CHAR, TO_DATE is CONVERT(type, ?) - addOperator(ExpressionOperator.sybaseToNumberOperator()); - addOperator(ExpressionOperator.sybaseToDateToStringOperator()); - addOperator(ExpressionOperator.sybaseToDateOperator()); - addOperator(ExpressionOperator.sybaseToCharOperator()); - addOperator(ExpressionOperator.sybaseLocateOperator()); + addOperator(toNumberOperator()); + addOperator(toDateToStringOperator()); + addOperator(toDateOperator()); + addOperator(toCharOperator()); + addOperator(locateOperator()); addOperator(locate2Operator()); addOperator(ExpressionOperator.simpleFunction(ExpressionOperator.Ceil, "CEILING")); addOperator(ExpressionOperator.simpleFunction(ExpressionOperator.Length, "LEN")); @@ -462,7 +462,7 @@ protected void initializePlatformOperators() { * INTERNAL: * Derby does not support EXTRACT, but does have DATEPART. */ - public static ExpressionOperator extractOperator() { + protected static ExpressionOperator extractOperator() { ExpressionOperator exOperator = new ExpressionOperator(); exOperator.setType(ExpressionOperator.FunctionOperator); exOperator.setSelector(ExpressionOperator.Extract); @@ -485,7 +485,7 @@ public static ExpressionOperator extractOperator() { * INTERNAL: * Use RTRIM(LTRIM(?)) function for trim. */ - public static ExpressionOperator trimOperator() { + protected static ExpressionOperator trimOperator() { ExpressionOperator exOperator = new ExpressionOperator(); exOperator.setType(ExpressionOperator.FunctionOperator); exOperator.setSelector(ExpressionOperator.Trim); @@ -502,7 +502,7 @@ public static ExpressionOperator trimOperator() { * INTERNAL: * Build Trim operator. */ - public static ExpressionOperator trim2Operator() { + protected static ExpressionOperator trim2Operator() { ExpressionOperator exOperator = new ExpressionOperator(); exOperator.setType(ExpressionOperator.FunctionOperator); exOperator.setSelector(ExpressionOperator.Trim2); @@ -521,61 +521,10 @@ public static ExpressionOperator trim2Operator() { return exOperator; } - /** - * INTERNAL: - * Return true if output parameters can be built with result sets. - */ - @Override - public boolean isOutputAllowWithResultSet() { - return false; - } - - public boolean isSQLServer() { - return true; - } - - /** - * Builds a table of maximum numeric values keyed on java class. This is used for type testing but - * might also be useful to end users attempting to sanitize values. - *

NOTE: BigInteger {@literal &} BigDecimal maximums are dependent upon their precision {@literal &} Scale - */ - public Hashtable maximumNumericValues() { - Hashtable values = new Hashtable(); - - values.put(Integer.class, Integer.valueOf(Integer.MAX_VALUE)); - values.put(Long.class, Long.valueOf(Long.MAX_VALUE)); - values.put(Double.class, Double.valueOf(0)); - values.put(Short.class, Short.valueOf(Short.MAX_VALUE)); - values.put(Byte.class, Byte.valueOf(Byte.MAX_VALUE)); - values.put(Float.class, Float.valueOf(0)); - values.put(java.math.BigInteger.class, new java.math.BigInteger("9999999999999999999999999999")); - values.put(java.math.BigDecimal.class, new java.math.BigDecimal("999999999.9999999999999999999")); - return values; - } - - /** - * Builds a table of minimum numeric values keyed on java class. This is used for type testing but - * might also be useful to end users attempting to sanitize values. - *

NOTE: BigInteger {@literal &} BigDecimal minimums are dependent upon their precision {@literal &} Scale - */ - public Hashtable minimumNumericValues() { - Hashtable values = new Hashtable(); - - values.put(Integer.class, Integer.valueOf(Integer.MIN_VALUE)); - values.put(Long.class, Long.valueOf(Long.MIN_VALUE)); - values.put(Double.class, Double.valueOf(-9)); - values.put(Short.class, Short.valueOf(Short.MIN_VALUE)); - values.put(Byte.class, Byte.valueOf(Byte.MIN_VALUE)); - values.put(Float.class, Float.valueOf(-9)); - values.put(java.math.BigInteger.class, new java.math.BigInteger("-9999999999999999999999999999")); - values.put(java.math.BigDecimal.class, new java.math.BigDecimal("-999999999.9999999999999999999")); - return values; - } - /** * Override the default MOD operator. */ - public ExpressionOperator modOperator() { + protected ExpressionOperator modOperator() { ExpressionOperator result = new ExpressionOperator(); result.setSelector(ExpressionOperator.Mod); Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(); @@ -589,7 +538,7 @@ public ExpressionOperator modOperator() { /** * Override the default SubstringSingleArg operator. */ - public ExpressionOperator singleArgumentSubstringOperator() { + protected static ExpressionOperator singleArgumentSubstringOperator() { ExpressionOperator result = new ExpressionOperator(); result.setSelector(ExpressionOperator.SubstringSingleArg); result.setType(ExpressionOperator.FunctionOperator); @@ -613,7 +562,7 @@ public ExpressionOperator singleArgumentSubstringOperator() { /* * Create the outer join operator for this platform */ - protected ExpressionOperator operatorOuterJoin() { + protected static ExpressionOperator operatorOuterJoin() { ExpressionOperator result = new ExpressionOperator(); result.setSelector(ExpressionOperator.EqualOuterJoin); Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(); @@ -628,7 +577,7 @@ protected ExpressionOperator operatorOuterJoin() { * INTERNAL: * create the Locate2 Operator for this platform */ - public static ExpressionOperator locate2Operator() { + protected static ExpressionOperator locate2Operator() { ExpressionOperator result = ExpressionOperator.simpleThreeArgumentFunction(ExpressionOperator.Locate2, "CHARINDEX"); int[] argumentIndices = new int[3]; argumentIndices[0] = 1; @@ -638,7 +587,177 @@ public static ExpressionOperator locate2Operator() { return result; } + /** + * INTERNAL: + * Function, to add months to a date. + */ + protected static ExpressionOperator addMonthsOperator() { + ExpressionOperator exOperator = new ExpressionOperator(); + exOperator.setType(ExpressionOperator.FunctionOperator); + exOperator.setSelector(ExpressionOperator.AddMonths); + Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(3); + v.add("DATEADD(month, "); + v.add(", "); + v.add(")"); + exOperator.printsAs(v); + exOperator.bePrefix(); + int[] indices = { 1, 0 }; + exOperator.setArgumentIndices(indices); + exOperator.setNodeClass(ClassConstants.FunctionExpression_Class); + return exOperator; + } + /** + * INTERNAL: + * Build instring operator + */ + protected static ExpressionOperator inStringOperator() { + ExpressionOperator exOperator = new ExpressionOperator(); + exOperator.setType(ExpressionOperator.FunctionOperator); + exOperator.setSelector(ExpressionOperator.Instring); + Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(3); + v.add("CHARINDEX("); + v.add(", "); + v.add(")"); + exOperator.printsAs(v); + exOperator.bePrefix(); + int[] indices = { 1, 0 }; + exOperator.setArgumentIndices(indices); + exOperator.setNodeClass(ClassConstants.FunctionExpression_Class); + return exOperator; + } + + /** + * INTERNAL: + * Build Sybase equivalent to TO_NUMBER. + */ + protected static ExpressionOperator toNumberOperator() { + ExpressionOperator exOperator = new ExpressionOperator(); + exOperator.setType(ExpressionOperator.FunctionOperator); + exOperator.setSelector(ExpressionOperator.ToNumber); + Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(2); + v.add("CONVERT(NUMERIC, "); + v.add(")"); + exOperator.printsAs(v); + exOperator.bePrefix(); + exOperator.setNodeClass(ClassConstants.FunctionExpression_Class); + return exOperator; + } + + /** + * INTERNAL: + * Build Sybase equivalent to TO_CHAR. + */ + protected static ExpressionOperator toDateToStringOperator() { + ExpressionOperator exOperator = new ExpressionOperator(); + exOperator.setType(ExpressionOperator.FunctionOperator); + exOperator.setSelector(ExpressionOperator.DateToString); + Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(2); + v.add("CONVERT(CHAR, "); + v.add(")"); + exOperator.printsAs(v); + exOperator.bePrefix(); + exOperator.setNodeClass(ClassConstants.FunctionExpression_Class); + return exOperator; + } + + /** + * INTERNAL: + * Build Sybase equivalent to TO_DATE. + */ + protected static ExpressionOperator toDateOperator() { + ExpressionOperator exOperator = new ExpressionOperator(); + exOperator.setType(ExpressionOperator.FunctionOperator); + exOperator.setSelector(ExpressionOperator.ToDate); + Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(2); + v.add("CONVERT(DATETIME, "); + v.add(")"); + exOperator.printsAs(v); + exOperator.bePrefix(); + exOperator.setNodeClass(ClassConstants.FunctionExpression_Class); + return exOperator; + } + + /** + * INTERNAL: + * Build Sybase equivalent to TO_CHAR. + */ + protected static ExpressionOperator toCharOperator() { + ExpressionOperator exOperator = new ExpressionOperator(); + exOperator.setType(ExpressionOperator.FunctionOperator); + exOperator.setSelector(ExpressionOperator.ToChar); + Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(2); + v.add("CONVERT(CHAR, "); + v.add(")"); + exOperator.printsAs(v); + exOperator.bePrefix(); + exOperator.setNodeClass(ClassConstants.FunctionExpression_Class); + return exOperator; + } + + /** + * INTERNAL: + * Build the Sybase equivalent to Locate + */ + protected static ExpressionOperator locateOperator() { + ExpressionOperator result = ExpressionOperator.simpleTwoArgumentFunction(ExpressionOperator.Locate, "CHARINDEX"); + int[] argumentIndices = new int[2]; + argumentIndices[0] = 1; + argumentIndices[1] = 0; + result.setArgumentIndices(argumentIndices); + return result; + } + + /** + * INTERNAL: + * Return true if output parameters can be built with result sets. + */ + @Override + public boolean isOutputAllowWithResultSet() { + return false; + } + + public boolean isSQLServer() { + return true; + } + + /** + * Builds a table of maximum numeric values keyed on java class. This is used for type testing but + * might also be useful to end users attempting to sanitize values. + *

NOTE: BigInteger {@literal &} BigDecimal maximums are dependent upon their precision {@literal &} Scale + */ + public Hashtable maximumNumericValues() { + Hashtable values = new Hashtable(); + + values.put(Integer.class, Integer.valueOf(Integer.MAX_VALUE)); + values.put(Long.class, Long.valueOf(Long.MAX_VALUE)); + values.put(Double.class, Double.valueOf(0)); + values.put(Short.class, Short.valueOf(Short.MAX_VALUE)); + values.put(Byte.class, Byte.valueOf(Byte.MAX_VALUE)); + values.put(Float.class, Float.valueOf(0)); + values.put(java.math.BigInteger.class, new java.math.BigInteger("9999999999999999999999999999")); + values.put(java.math.BigDecimal.class, new java.math.BigDecimal("999999999.9999999999999999999")); + return values; + } + + /** + * Builds a table of minimum numeric values keyed on java class. This is used for type testing but + * might also be useful to end users attempting to sanitize values. + *

NOTE: BigInteger {@literal &} BigDecimal minimums are dependent upon their precision {@literal &} Scale + */ + public Hashtable minimumNumericValues() { + Hashtable values = new Hashtable(); + + values.put(Integer.class, Integer.valueOf(Integer.MIN_VALUE)); + values.put(Long.class, Long.valueOf(Long.MIN_VALUE)); + values.put(Double.class, Double.valueOf(-9)); + values.put(Short.class, Short.valueOf(Short.MIN_VALUE)); + values.put(Byte.class, Byte.valueOf(Byte.MIN_VALUE)); + values.put(Float.class, Float.valueOf(-9)); + values.put(java.math.BigInteger.class, new java.math.BigInteger("-9999999999999999999999999999")); + values.put(java.math.BigDecimal.class, new java.math.BigDecimal("-999999999.9999999999999999999")); + return values; + } /** * INTERNAL: diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/SybasePlatform.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/SybasePlatform.java index 6df37ec1f79..3a300a45d49 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/SybasePlatform.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/SybasePlatform.java @@ -1,6 +1,6 @@ /* - * Copyright (c) 1998, 2019 Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 1998, 2019 IBM Corporation. All rights reserved. + * Copyright (c) 1998, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022 IBM Corporation. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -236,14 +236,6 @@ protected void appendSybaseCalendar(Calendar calendar, Writer writer) throws IOE writer.write("'"); } - /** - * INTERNAL: - * Build operator. - */ - public ExpressionOperator atan2Operator() { - return ExpressionOperator.simpleTwoArgumentFunction(ExpressionOperator.Atan2, "ATN2"); - } - @Override protected Hashtable buildFieldTypes() { Hashtable fieldTypeMapping; @@ -463,8 +455,8 @@ protected void initializePlatformOperators() { addOperator(ExpressionOperator.simpleFunction(ExpressionOperator.CurrentDate, "GETDATE")); addOperator(ExpressionOperator.simpleFunction(ExpressionOperator.CurrentTime, "GETDATE")); addOperator(ExpressionOperator.simpleFunction(ExpressionOperator.Length, "CHAR_LENGTH")); - addOperator(ExpressionOperator.sybaseLocateOperator()); - addOperator(ExpressionOperator.sybaseLocate2Operator()); + addOperator(sybaseLocateOperator()); + addOperator(sybaseLocate2Operator()); addOperator(ExpressionOperator.simpleThreeArgumentFunction(ExpressionOperator.Substring, "SUBSTRING")); addOperator(singleArgumentSubstringOperator()); addOperator(ExpressionOperator.addDate()); @@ -478,16 +470,16 @@ protected void initializePlatformOperators() { addOperator(ExpressionOperator.replicate()); addOperator(ExpressionOperator.right()); addOperator(ExpressionOperator.cot()); - addOperator(ExpressionOperator.sybaseAtan2Operator()); - addOperator(ExpressionOperator.sybaseAddMonthsOperator()); - addOperator(ExpressionOperator.sybaseInStringOperator()); + addOperator(ExpressionOperator.simpleTwoArgumentFunction(ExpressionOperator.Atan2, "ATN2")); + addOperator(sybaseAddMonthsOperator()); + addOperator(sybaseInStringOperator()); // bug 3061144 addOperator(ExpressionOperator.simpleTwoArgumentFunction(ExpressionOperator.Nvl, "ISNULL")); // CR### TO_NUMBER, TO_CHAR, TO_DATE is CONVERT(type, ?) - addOperator(ExpressionOperator.sybaseToNumberOperator()); - addOperator(ExpressionOperator.sybaseToDateToStringOperator()); - addOperator(ExpressionOperator.sybaseToDateOperator()); - addOperator(ExpressionOperator.sybaseToCharOperator()); + addOperator(sybaseToNumberOperator()); + addOperator(sybaseToDateToStringOperator()); + addOperator(sybaseToDateOperator()); + addOperator(sybaseToCharOperator()); addOperator(ExpressionOperator.simpleFunction(ExpressionOperator.Ceil, "CEILING")); addOperator(modOperator()); addOperator(trimOperator()); @@ -497,11 +489,240 @@ protected void initializePlatformOperators() { addOperator(extractOperator()); } + /** + * Override the default MOD operator. + */ + protected static ExpressionOperator modOperator() { + ExpressionOperator result = new ExpressionOperator(); + result.setSelector(ExpressionOperator.Mod); + Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(); + v.addElement(" % "); + result.printsAs(v); + result.bePostfix(); + result.setNodeClass(org.eclipse.persistence.internal.expressions.FunctionExpression.class); + return result; + } + + /** + * Create the outer join operator for this platform + */ + protected static ExpressionOperator operatorOuterJoin() { + ExpressionOperator result = new ExpressionOperator(); + result.setSelector(ExpressionOperator.EqualOuterJoin); + Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(); + v.addElement(" =* "); + result.printsAs(v); + result.bePostfix(); + result.setNodeClass(RelationExpression.class); + return result; + } + + /** + * Override the default SubstringSingleArg operator. + */ + protected static ExpressionOperator singleArgumentSubstringOperator() { + ExpressionOperator result = new ExpressionOperator(); + result.setSelector(ExpressionOperator.SubstringSingleArg); + result.setType(ExpressionOperator.FunctionOperator); + Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(); + v.addElement("SUBSTRING("); + v.addElement(","); + v.addElement(", CHAR_LENGTH("); + v.addElement("))"); + result.printsAs(v); + int[] indices = new int[3]; + indices[0] = 0; + indices[1] = 1; + indices[2] = 0; + + result.setArgumentIndices(indices); + result.setNodeClass(ClassConstants.FunctionExpression_Class); + result.bePrefix(); + return result; + } + + /** + * INTERNAL: + * Function, to add months to a date. + */ + protected static ExpressionOperator sybaseAddMonthsOperator() { + ExpressionOperator exOperator = new ExpressionOperator(); + exOperator.setType(ExpressionOperator.FunctionOperator); + exOperator.setSelector(ExpressionOperator.AddMonths); + Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(3); + v.add("DATEADD(month, "); + v.add(", "); + v.add(")"); + exOperator.printsAs(v); + exOperator.bePrefix(); + int[] indices = { 1, 0 }; + exOperator.setArgumentIndices(indices); + exOperator.setNodeClass(ClassConstants.FunctionExpression_Class); + return exOperator; + } + + /** + * INTERNAL: + * Build instring operator + */ + protected static ExpressionOperator sybaseInStringOperator() { + ExpressionOperator exOperator = new ExpressionOperator(); + exOperator.setType(ExpressionOperator.FunctionOperator); + exOperator.setSelector(ExpressionOperator.Instring); + Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(3); + v.add("CHARINDEX("); + v.add(", "); + v.add(")"); + exOperator.printsAs(v); + exOperator.bePrefix(); + int[] indices = { 1, 0 }; + exOperator.setArgumentIndices(indices); + exOperator.setNodeClass(ClassConstants.FunctionExpression_Class); + return exOperator; + } + + /** + * INTERNAL: + * Build Sybase equivalent to TO_NUMBER. + */ + protected static ExpressionOperator sybaseToNumberOperator() { + ExpressionOperator exOperator = new ExpressionOperator(); + exOperator.setType(ExpressionOperator.FunctionOperator); + exOperator.setSelector(ExpressionOperator.ToNumber); + Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(2); + v.add("CONVERT(NUMERIC, "); + v.add(")"); + exOperator.printsAs(v); + exOperator.bePrefix(); + exOperator.setNodeClass(ClassConstants.FunctionExpression_Class); + return exOperator; + } + + /** + * INTERNAL: + * Build Sybase equivalent to TO_CHAR. + */ + protected static ExpressionOperator sybaseToDateToStringOperator() { + ExpressionOperator exOperator = new ExpressionOperator(); + exOperator.setType(ExpressionOperator.FunctionOperator); + exOperator.setSelector(ExpressionOperator.DateToString); + Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(2); + v.add("CONVERT(CHAR, "); + v.add(")"); + exOperator.printsAs(v); + exOperator.bePrefix(); + exOperator.setNodeClass(ClassConstants.FunctionExpression_Class); + return exOperator; + } + + /** + * INTERNAL: + * Build Sybase equivalent to TO_DATE. + */ + protected static ExpressionOperator sybaseToDateOperator() { + ExpressionOperator exOperator = new ExpressionOperator(); + exOperator.setType(ExpressionOperator.FunctionOperator); + exOperator.setSelector(ExpressionOperator.ToDate); + Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(2); + v.add("CONVERT(DATETIME, "); + v.add(")"); + exOperator.printsAs(v); + exOperator.bePrefix(); + exOperator.setNodeClass(ClassConstants.FunctionExpression_Class); + return exOperator; + } + + /** + * INTERNAL: + * Build Sybase equivalent to TO_CHAR. + */ + protected static ExpressionOperator sybaseToCharOperator() { + ExpressionOperator exOperator = new ExpressionOperator(); + exOperator.setType(ExpressionOperator.FunctionOperator); + exOperator.setSelector(ExpressionOperator.ToChar); + Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(2); + v.add("CONVERT(CHAR, "); + v.add(")"); + exOperator.printsAs(v); + exOperator.bePrefix(); + exOperator.setNodeClass(ClassConstants.FunctionExpression_Class); + return exOperator; + } + + /** + * INTERNAL: + * Build Sybase equivalent to TO_CHAR. + */ + protected static ExpressionOperator sybaseToCharWithFormatOperator() { + ExpressionOperator exOperator = new ExpressionOperator(); + exOperator.setType(ExpressionOperator.FunctionOperator); + exOperator.setSelector(ExpressionOperator.ToCharWithFormat); + Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(3); + v.add("CONVERT(CHAR, "); + v.add(","); + v.add(")"); + exOperator.printsAs(v); + exOperator.bePrefix(); + exOperator.setNodeClass(ClassConstants.FunctionExpression_Class); + return exOperator; + } + + /** + * INTERNAL: + * Build the Sybase equivalent to Locate + */ + protected static ExpressionOperator sybaseLocateOperator() { + ExpressionOperator result = ExpressionOperator.simpleTwoArgumentFunction(ExpressionOperator.Locate, "CHARINDEX"); + int[] argumentIndices = new int[2]; + argumentIndices[0] = 1; + argumentIndices[1] = 0; + result.setArgumentIndices(argumentIndices); + return result; + } + + /** + * INTERNAL: + * Build the Sybase equivalent to Locate with a start index. + * Sybase does not define this, so this gets a little complex... + */ + protected static ExpressionOperator sybaseLocate2Operator() { + ExpressionOperator result = new ExpressionOperator(); + result.setSelector(ExpressionOperator.Locate2); + result.setType(ExpressionOperator.FunctionOperator); + Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(); + v.add("CASE (CHARINDEX("); + v.add(", SUBSTRING("); + v.add(","); + v.add(", CHAR_LENGTH("); + v.add(")))) WHEN 0 THEN 0 ELSE (CHARINDEX("); + v.add(", SUBSTRING("); + v.add(","); + v.add(", CHAR_LENGTH("); + v.add("))) + "); + v.add(" - 1) END"); + result.printsAs(v); + int[] indices = new int[9]; + indices[0] = 1; + indices[1] = 0; + indices[2] = 2; + indices[3] = 0; + indices[4] = 1; + indices[5] = 0; + indices[6] = 2; + indices[7] = 0; + indices[8] = 2; + + result.setArgumentIndices(indices); + result.setNodeClass(ClassConstants.FunctionExpression_Class); + result.bePrefix(); + return result; + } + /** * INTERNAL: * Derby does not support EXTRACT, but does have DATEPART. */ - public static ExpressionOperator extractOperator() { + protected static ExpressionOperator extractOperator() { ExpressionOperator exOperator = new ExpressionOperator(); exOperator.setType(ExpressionOperator.FunctionOperator); exOperator.setSelector(ExpressionOperator.Extract); @@ -524,7 +745,7 @@ public static ExpressionOperator extractOperator() { * INTERNAL: * Use RTRIM(LTRIM(?)) function for trim. */ - public static ExpressionOperator trimOperator() { + protected static ExpressionOperator trimOperator() { ExpressionOperator exOperator = new ExpressionOperator(); exOperator.setType(ExpressionOperator.FunctionOperator); exOperator.setSelector(ExpressionOperator.Trim); @@ -541,7 +762,7 @@ public static ExpressionOperator trimOperator() { * INTERNAL: * Build Trim operator. */ - public static ExpressionOperator trim2Operator() { + protected static ExpressionOperator trim2Operator() { ExpressionOperator exOperator = new ExpressionOperator(); exOperator.setType(ExpressionOperator.FunctionOperator); exOperator.setSelector(ExpressionOperator.Trim2); @@ -608,34 +829,6 @@ public Hashtable, Number> minimumNumericValues() { return values; } - /** - * Override the default MOD operator. - */ - public ExpressionOperator modOperator() { - ExpressionOperator result = new ExpressionOperator(); - result.setSelector(ExpressionOperator.Mod); - Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(); - v.addElement(" % "); - result.printsAs(v); - result.bePostfix(); - result.setNodeClass(org.eclipse.persistence.internal.expressions.FunctionExpression.class); - return result; - } - - /* - * Create the outer join operator for this platform - */ - protected ExpressionOperator operatorOuterJoin() { - ExpressionOperator result = new ExpressionOperator(); - result.setSelector(ExpressionOperator.EqualOuterJoin); - Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(); - v.addElement(" =* "); - result.printsAs(v); - result.bePostfix(); - result.setNodeClass(RelationExpression.class); - return result; - } - /** Append the receiver's field 'identity' constraint clause to a writer.*/ @Override public void printFieldIdentityClause(Writer writer) throws ValidationException { @@ -721,30 +914,6 @@ public boolean shouldUseJDBCOuterJoinSyntax() { return false; } - /** - * Override the default SubstringSingleArg operator. - */ - public ExpressionOperator singleArgumentSubstringOperator() { - ExpressionOperator result = new ExpressionOperator(); - result.setSelector(ExpressionOperator.SubstringSingleArg); - result.setType(ExpressionOperator.FunctionOperator); - Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(); - v.addElement("SUBSTRING("); - v.addElement(","); - v.addElement(", CHAR_LENGTH("); - v.addElement("))"); - result.printsAs(v); - int[] indices = new int[3]; - indices[0] = 0; - indices[1] = 1; - indices[2] = 0; - - result.setArgumentIndices(indices); - result.setNodeClass(ClassConstants.FunctionExpression_Class); - result.bePrefix(); - return result; - } - /** * INTERNAL: * Indicates whether the platform supports identity. diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/SymfowarePlatform.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/SymfowarePlatform.java index c8722b28371..592262aa20e 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/SymfowarePlatform.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/SymfowarePlatform.java @@ -1,6 +1,7 @@ /* - * Copyright (c) 2009, 2018 Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2009, 2018 Fujitsu Limited. All rights reserved. + * Copyright (c) 2009, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022 IBM Corporation. All rights reserved. + * Copyright (c) 2009, 2022 Fujitsu Limited. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -344,6 +345,11 @@ public boolean isDynamicSQLRequiredForFunctions() { return true; } + @Override + public boolean allowBindingForSelectClause() { + return false; + } + /** * Indicates whether SELECT DISTINCT ... FOR UPDATE is allowed by the * platform. (Symfoware doesn't allow this). diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/jdbc/JDBCTypes.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/jdbc/JDBCTypes.java index 7d2ccc91b74..59ed3ee4d1d 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/jdbc/JDBCTypes.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/jdbc/JDBCTypes.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 1998, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022 IBM Corporation. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -64,6 +65,7 @@ import java.util.List; import java.util.ListIterator; +import org.eclipse.persistence.internal.databaseaccess.DatasourceCall.ParameterType; import org.eclipse.persistence.internal.helper.ClassConstants; import org.eclipse.persistence.internal.helper.DatabaseField; import org.eclipse.persistence.internal.helper.DatabaseType; @@ -300,8 +302,15 @@ public void buildOutputRow(PLSQLargument outArg, AbstractRecord outputRow, } @Override + @Deprecated public void logParameter(StringBuilder sb, Integer direction, PLSQLargument arg, AbstractRecord translationRow, DatabasePlatform platform) { + logParameter(sb, ParameterType.valueOf(direction), arg, translationRow, platform); + } + + @Override + public void logParameter(StringBuilder sb, ParameterType direction, PLSQLargument arg, + AbstractRecord translationRow, DatabasePlatform platform) { databaseTypeHelper.logParameter(sb, direction, arg, translationRow, platform); } diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/oracle/plsql/OraclePLSQLTypes.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/oracle/plsql/OraclePLSQLTypes.java index 410b1675e1b..6f29f1fe0c0 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/oracle/plsql/OraclePLSQLTypes.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/oracle/plsql/OraclePLSQLTypes.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 1998, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022 IBM Corporation. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -19,6 +20,7 @@ import java.util.ListIterator; import static java.sql.Types.OTHER; +import org.eclipse.persistence.internal.databaseaccess.DatasourceCall.ParameterType; import org.eclipse.persistence.internal.helper.DatabaseField; import org.eclipse.persistence.internal.helper.DatabaseType; import org.eclipse.persistence.internal.helper.SimpleDatabaseType; @@ -237,8 +239,20 @@ public void buildOutputRow(PLSQLargument outArg, AbstractRecord outputRow, * INTERNAL: * Append the parameter for logging purposes. */ + @Deprecated + @Override public void logParameter(StringBuilder sb, Integer direction, PLSQLargument arg, AbstractRecord translationRow, DatabasePlatform platform) { + logParameter(sb, ParameterType.valueOf(direction), arg, translationRow, platform); + } + + /** + * INTERNAL: + * Append the parameter for logging purposes. + */ + @Override + public void logParameter(StringBuilder sb, ParameterType direction, PLSQLargument arg, + AbstractRecord translationRow, DatabasePlatform platform) { databaseTypeHelper.logParameter(sb, direction, arg, translationRow, platform); } diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/oracle/plsql/PLSQLStoredFunctionCall.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/oracle/plsql/PLSQLStoredFunctionCall.java index 5ea227a181b..2d6c341fff8 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/oracle/plsql/PLSQLStoredFunctionCall.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/oracle/plsql/PLSQLStoredFunctionCall.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 1998, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022 IBM Corporation. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -35,28 +36,28 @@ public class PLSQLStoredFunctionCall extends PLSQLStoredProcedureCall { public PLSQLStoredFunctionCall() { super(); - this.arguments.add(new PLSQLargument("RESULT", this.originalIndex++, OUT, JDBCTypes.VARCHAR_TYPE)); + this.arguments.add(new PLSQLargument("RESULT", this.originalIndex++, ParameterType.OUT, JDBCTypes.VARCHAR_TYPE)); } public PLSQLStoredFunctionCall(DatabaseType databaseType) { super(); DatabaseType dt = databaseType.isComplexDatabaseType() ? ((ComplexDatabaseType)databaseType).clone() : databaseType; - this.arguments.add(new PLSQLargument("RESULT", this.originalIndex++, OUT, dt)); + this.arguments.add(new PLSQLargument("RESULT", this.originalIndex++, ParameterType.OUT, dt)); } public PLSQLStoredFunctionCall(DatabaseType databaseType, int length) { super(); DatabaseType dt = databaseType.isComplexDatabaseType() ? ((ComplexDatabaseType)databaseType).clone() : databaseType; - this.arguments.add(new PLSQLargument("RESULT", this.originalIndex++, OUT, dt, length)); + this.arguments.add(new PLSQLargument("RESULT", this.originalIndex++, ParameterType.OUT, dt, length)); } public PLSQLStoredFunctionCall(DatabaseType databaseType, int length, int scale) { super(); DatabaseType dt = databaseType.isComplexDatabaseType() ? ((ComplexDatabaseType)databaseType).clone() : databaseType; - this.arguments.add(new PLSQLargument("RESULT", this.originalIndex++, OUT, dt, length, scale)); + this.arguments.add(new PLSQLargument("RESULT", this.originalIndex++, ParameterType.OUT, dt, length, scale)); } /** diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/oracle/plsql/PLSQLStoredProcedureCall.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/oracle/plsql/PLSQLStoredProcedureCall.java index 550d80e1b52..3e76801e59c 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/oracle/plsql/PLSQLStoredProcedureCall.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/oracle/plsql/PLSQLStoredProcedureCall.java @@ -1,6 +1,6 @@ /* - * Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2019 IBM Corporation. All rights reserved. + * Copyright (c) 1998, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022 IBM Corporation. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -113,7 +113,7 @@ public PLSQLStoredProcedureCall() { public void addNamedArgument(String procedureParameterName, DatabaseType databaseType) { DatabaseType dt = databaseType.isComplexDatabaseType() ? ((ComplexDatabaseType)databaseType).clone() : databaseType; - arguments.add(new PLSQLargument(procedureParameterName, originalIndex++, IN, dt)); + arguments.add(new PLSQLargument(procedureParameterName, originalIndex++, ParameterType.IN, dt)); } /** @@ -126,7 +126,7 @@ public void addNamedArgument(String procedureParameterName, DatabaseType databas int length) { DatabaseType dt = databaseType.isComplexDatabaseType() ? ((ComplexDatabaseType)databaseType).clone() : databaseType; - arguments.add(new PLSQLargument(procedureParameterName, originalIndex++, IN, dt, length)); + arguments.add(new PLSQLargument(procedureParameterName, originalIndex++, ParameterType.IN, dt, length)); } /** @@ -140,19 +140,19 @@ public void addNamedArgument(String procedureParameterName, DatabaseType databas int precision, int scale) { DatabaseType dt = databaseType.isComplexDatabaseType() ? ((ComplexDatabaseType)databaseType).clone() : databaseType; - arguments.add(new PLSQLargument(procedureParameterName, originalIndex++, IN, dt, precision, scale)); + arguments.add(new PLSQLargument(procedureParameterName, originalIndex++, ParameterType.IN, dt, precision, scale)); } @Override public void addNamedArgument(String procedureParameterName, String argumentFieldName, int type) { - arguments.add(new PLSQLargument(procedureParameterName, originalIndex++, IN, + arguments.add(new PLSQLargument(procedureParameterName, originalIndex++, ParameterType.IN, getDatabaseTypeForCode(type))); // figure out databaseType from the sqlType } @Override public void addNamedArgument(String procedureParameterName, String argumentFieldName, int type, String typeName) { - arguments.add(new PLSQLargument(procedureParameterName, originalIndex++, IN, + arguments.add(new PLSQLargument(procedureParameterName, originalIndex++, ParameterType.IN, getDatabaseTypeForCode(type))); } @@ -163,7 +163,7 @@ public void addNamedArgument(String procedureParameterName, String argumentField public void addNamedInOutputArgument(String procedureParameterName, DatabaseType databaseType) { DatabaseType dt = databaseType.isComplexDatabaseType() ? ((ComplexDatabaseType)databaseType).clone() : databaseType; - arguments.add(new PLSQLargument(procedureParameterName, originalIndex++, INOUT, dt)); + arguments.add(new PLSQLargument(procedureParameterName, originalIndex++, ParameterType.INOUT, dt)); } /** @@ -176,7 +176,7 @@ public void addNamedInOutputArgument(String procedureParameterName, DatabaseType int length) { DatabaseType dt = databaseType.isComplexDatabaseType() ? ((ComplexDatabaseType)databaseType).clone() : databaseType; - arguments.add(new PLSQLargument(procedureParameterName, originalIndex++, INOUT, dt, length)); + arguments.add(new PLSQLargument(procedureParameterName, originalIndex++, ParameterType.INOUT, dt, length)); } /** @@ -189,28 +189,28 @@ public void addNamedInOutputArgument(String procedureParameterName, DatabaseType int precision, int scale) { DatabaseType dt = databaseType.isComplexDatabaseType() ? ((ComplexDatabaseType)databaseType).clone() : databaseType; - arguments.add(new PLSQLargument(procedureParameterName, originalIndex++, INOUT, dt, + arguments.add(new PLSQLargument(procedureParameterName, originalIndex++, ParameterType.INOUT, dt, precision, scale)); } @Override public void addNamedInOutputArgument(String procedureParameterName, String inArgumentFieldName, String outArgumentFieldName, int type) { - arguments.add(new PLSQLargument(procedureParameterName, originalIndex++, INOUT, + arguments.add(new PLSQLargument(procedureParameterName, originalIndex++, ParameterType.INOUT, getDatabaseTypeForCode(type))); } @Override public void addNamedInOutputArgument(String procedureParameterName, String inArgumentFieldName, String outArgumentFieldName, int type, String typeName) { - arguments.add(new PLSQLargument(procedureParameterName, originalIndex++, INOUT, + arguments.add(new PLSQLargument(procedureParameterName, originalIndex++, ParameterType.INOUT, getDatabaseTypeForCode(type))); } @Override public void addNamedInOutputArgument(String procedureParameterName, String inArgumentFieldName, String outArgumentFieldName, int type, String typeName, Class classType) { - arguments.add(new PLSQLargument(procedureParameterName, originalIndex++, INOUT, + arguments.add(new PLSQLargument(procedureParameterName, originalIndex++, ParameterType.INOUT, getDatabaseTypeForCode(type))); } @@ -218,7 +218,7 @@ public void addNamedInOutputArgument(String procedureParameterName, String inArg public void addNamedInOutputArgument(String procedureParameterName, String inArgumentFieldName, String outArgumentFieldName, int type, String typeName, Class javaType, DatabaseField nestedType) { - arguments.add(new PLSQLargument(procedureParameterName, originalIndex++, INOUT, + arguments.add(new PLSQLargument(procedureParameterName, originalIndex++, ParameterType.INOUT, getDatabaseTypeForCode(type))); } @@ -229,7 +229,7 @@ public void addNamedInOutputArgument(String procedureParameterName, String inArg public void addNamedOutputArgument(String procedureParameterName, DatabaseType databaseType) { DatabaseType dt = databaseType.isComplexDatabaseType() ? ((ComplexDatabaseType)databaseType).clone() : databaseType; - arguments.add(new PLSQLargument(procedureParameterName, originalIndex++, OUT, dt)); + arguments.add(new PLSQLargument(procedureParameterName, originalIndex++, ParameterType.OUT, dt)); } /** @@ -242,7 +242,7 @@ public void addNamedOutputArgument(String procedureParameterName, DatabaseType d int length) { DatabaseType dt = databaseType.isComplexDatabaseType() ? ((ComplexDatabaseType)databaseType).clone() : databaseType; - arguments.add(new PLSQLargument(procedureParameterName, originalIndex++, OUT, dt, length)); + arguments.add(new PLSQLargument(procedureParameterName, originalIndex++, ParameterType.OUT, dt, length)); } /** @@ -255,35 +255,35 @@ public void addNamedOutputArgument(String procedureParameterName, DatabaseType d int precision, int scale) { DatabaseType dt = databaseType.isComplexDatabaseType() ? ((ComplexDatabaseType)databaseType).clone() : databaseType; - arguments.add(new PLSQLargument(procedureParameterName, originalIndex++, OUT, dt, + arguments.add(new PLSQLargument(procedureParameterName, originalIndex++, ParameterType.OUT, dt, precision, scale)); } @Override public void addNamedOutputArgument(String procedureParameterName, String argumentFieldName, int jdbcType, String typeName, Class javaType) { - arguments.add(new PLSQLargument(procedureParameterName, originalIndex++, OUT, + arguments.add(new PLSQLargument(procedureParameterName, originalIndex++, ParameterType.OUT, getDatabaseTypeForCode(jdbcType))); } @Override public void addNamedOutputArgument(String procedureParameterName, String argumentFieldName, int jdbcType, String typeName, Class javaType, DatabaseField nestedType) { - arguments.add(new PLSQLargument(procedureParameterName, originalIndex++, OUT, + arguments.add(new PLSQLargument(procedureParameterName, originalIndex++, ParameterType.OUT, getDatabaseTypeForCode(jdbcType))); } @Override public void addNamedOutputArgument(String procedureParameterName, String argumentFieldName, int type, String typeName) { - arguments.add(new PLSQLargument(procedureParameterName, originalIndex++, OUT, + arguments.add(new PLSQLargument(procedureParameterName, originalIndex++, ParameterType.OUT, getDatabaseTypeForCode(type))); } @Override public void addNamedOutputArgument(String procedureParameterName, String argumentFieldName, int type) { - arguments.add(new PLSQLargument(procedureParameterName, originalIndex++, OUT, + arguments.add(new PLSQLargument(procedureParameterName, originalIndex++, ParameterType.OUT, getDatabaseTypeForCode(type))); } @@ -475,7 +475,7 @@ public void useUnnamedCursorOutputAsResultSet() { public void useNamedCursorOutputAsResultSet(String argumentName, DatabaseType databaseType) { DatabaseType dt = databaseType.isComplexDatabaseType() ? ((ComplexDatabaseType)databaseType).clone() : databaseType; - PLSQLargument newArg = new PLSQLargument(argumentName, originalIndex++, OUT, dt); + PLSQLargument newArg = new PLSQLargument(argumentName, originalIndex++, ParameterType.OUT, dt); newArg.cursorOutput = true; arguments.add(newArg); } @@ -486,8 +486,8 @@ public void useNamedCursorOutputAsResultSet(String argumentName, DatabaseType da * the INOUT args */ protected void assignIndices() { - List inArguments = getArguments(arguments, IN); - List inOutArguments = getArguments(arguments, INOUT); + List inArguments = getArguments(arguments, ParameterType.IN); + List inOutArguments = getArguments(arguments, ParameterType.INOUT); inArguments.addAll(inOutArguments); int newIndex = 1; List expandedArguments = new ArrayList(); @@ -550,7 +550,7 @@ protected void assignIndices() { } } } - List outArguments = getArguments(arguments, OUT); + List outArguments = getArguments(arguments, ParameterType.OUT); outArguments.addAll(inOutArguments); for (ListIterator outArgsIter = outArguments.listIterator(); outArgsIter.hasNext();) { PLSQLargument outArg = outArgsIter.next(); @@ -621,10 +621,10 @@ protected void assignIndices() { * in the DECLARE section. */ protected void buildDeclareBlock(StringBuilder sb, List arguments) { - List inArguments = getArguments(arguments, IN); - List inOutArguments = getArguments(arguments, INOUT); + List inArguments = getArguments(arguments, ParameterType.IN); + List inOutArguments = getArguments(arguments, ParameterType.INOUT); inArguments.addAll(inOutArguments); - List outArguments = getArguments(arguments, OUT); + List outArguments = getArguments(arguments, ParameterType.OUT); Collections.sort(inArguments, new InArgComparer()); for (PLSQLargument arg : inArguments) { arg.databaseType.buildInDeclare(sb, arg); @@ -675,18 +675,18 @@ protected void addNestedFunctionsForArgument(List functions, PLSQLargument argum functions.add(info.pl2SqlConv); } } else { - if (argument.direction == IN) { + if (argument.pdirection == ParameterType.IN) { if (!functions.contains(info.sql2PlConv)) { functions.add(info.sql2PlConv); } - } else if (argument.direction == INOUT) { + } else if (argument.pdirection == ParameterType.INOUT) { if (!functions.contains(info.sql2PlConv)) { functions.add(info.sql2PlConv); } if (!functions.contains(info.pl2SqlConv)) { functions.add(info.pl2SqlConv); } - } else if (argument.direction == OUT) { + } else if (argument.pdirection == ParameterType.OUT) { if (!functions.contains(info.pl2SqlConv)) { functions.add(info.pl2SqlConv); } @@ -991,8 +991,8 @@ protected void buildNestedFunctions(StringBuilder stream, List ar * of the BEGIN block (before invoking the target procedure). */ protected void buildBeginBlock(StringBuilder sb, List arguments) { - List inArguments = getArguments(arguments, IN); - inArguments.addAll(getArguments(arguments, INOUT)); + List inArguments = getArguments(arguments, ParameterType.IN); + inArguments.addAll(getArguments(arguments, ParameterType.INOUT)); for (PLSQLargument arg : inArguments) { arg.databaseType.buildBeginBlock(sb, arg, this); } @@ -1024,8 +1024,8 @@ protected void buildProcedureInvocation(StringBuilder sb, List ar * invoked and OUT parameters must be handled. */ protected void buildOutAssignments(StringBuilder sb, List arguments) { - List outArguments = getArguments(arguments, OUT); - outArguments.addAll(getArguments(arguments, INOUT)); + List outArguments = getArguments(arguments, ParameterType.OUT); + outArguments.addAll(getArguments(arguments, ParameterType.INOUT)); for (PLSQLargument arg : outArguments) { arg.databaseType.buildOutAssignment(sb, arg, this); } @@ -1134,7 +1134,7 @@ public void translate(AbstractRecord translationRow, AbstractRecord modifyRow, A Vector translationRowValues = translationRow.getValues(); translationRowValues.setSize(len); for (PLSQLargument arg : arguments) { - if (arg.direction == IN || arg.direction == INOUT) { + if (arg.pdirection == ParameterType.IN || arg.pdirection == ParameterType.INOUT) { arg.databaseType.translate(arg, translationRow, copyOfTranslationRow, copyOfTranslationFields, translationRowFields, translationRowValues, this); @@ -1161,8 +1161,8 @@ public AbstractRecord buildOutputRow(CallableStatement statement, DatabaseAccess Vector outputRowFields = outputRow.getFields(); Vector outputRowValues = outputRow.getValues(); DatabaseRecord newOutputRow = new DatabaseRecord(); - List outArguments = getArguments(arguments, OUT); - outArguments.addAll(getArguments(arguments, INOUT)); + List outArguments = getArguments(arguments, ParameterType.OUT); + outArguments.addAll(getArguments(arguments, ParameterType.INOUT)); Collections.sort(outArguments, new Comparator() { @Override public int compare(PLSQLargument o1, PLSQLargument o2) { @@ -1199,8 +1199,8 @@ public String getLogString(Accessor accessor) { } } } - List inArguments = getArguments(specifiedArguments, IN); - inArguments.addAll(getArguments(specifiedArguments, INOUT)); + List inArguments = getArguments(specifiedArguments, ParameterType.IN); + inArguments.addAll(getArguments(specifiedArguments, ParameterType.INOUT)); Collections.sort(inArguments, new Comparator() { @Override public int compare(PLSQLargument o1, PLSQLargument o2) { @@ -1209,14 +1209,14 @@ public int compare(PLSQLargument o1, PLSQLargument o2) { }); for (Iterator i = inArguments.iterator(); i.hasNext();) { PLSQLargument inArg = i.next(); - inArg.databaseType.logParameter(sb, IN, inArg, translationRow, + inArg.databaseType.logParameter(sb, ParameterType.IN, inArg, translationRow, getQuery().getSession().getPlatform()); if (i.hasNext()) { sb.append(", "); } } - List outArguments = getArguments(specifiedArguments, OUT); - outArguments.addAll(getArguments(specifiedArguments, INOUT)); + List outArguments = getArguments(specifiedArguments, ParameterType.OUT); + outArguments.addAll(getArguments(specifiedArguments, ParameterType.INOUT)); Collections.sort(outArguments, new Comparator() { @Override public int compare(PLSQLargument o1, PLSQLargument o2) { @@ -1228,7 +1228,7 @@ public int compare(PLSQLargument o1, PLSQLargument o2) { } for (Iterator i = outArguments.iterator(); i.hasNext();) { PLSQLargument outArg = i.next(); - outArg.databaseType.logParameter(sb, OUT, outArg, translationRow, + outArg.databaseType.logParameter(sb, ParameterType.OUT, outArg, translationRow, getQuery().getSession().getPlatform()); if (i.hasNext()) { sb.append(", "); @@ -1246,9 +1246,20 @@ public int compare(PLSQLargument o1, PLSQLargument o2) { * @return list of arguments with the specified direction */ protected static List getArguments(List args, Integer direction) { + return getArguments(args, ParameterType.valueOf(direction)); + } + + /** + * INTERNAL + * + * @param args + * @param direction + * @return list of arguments with the specified direction + */ + protected static List getArguments(List args, ParameterType direction) { List inArgs = new ArrayList(); for (PLSQLargument arg : args) { - if (arg.direction == direction) { + if (arg.pdirection == direction) { inArgs.add(arg); } } diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/oracle/plsql/PLSQLargument.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/oracle/plsql/PLSQLargument.java index 11902df861a..40453d2f58a 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/oracle/plsql/PLSQLargument.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/oracle/plsql/PLSQLargument.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 1998, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022 IBM Corporation. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -21,10 +22,7 @@ import org.eclipse.persistence.internal.helper.ComplexDatabaseType; // EclipseLink imports import org.eclipse.persistence.internal.helper.DatabaseType; -import static org.eclipse.persistence.internal.databaseaccess.DatasourceCall.IN; -import static org.eclipse.persistence.internal.databaseaccess.DatasourceCall.INOUT; -import static org.eclipse.persistence.internal.databaseaccess.DatasourceCall.OUT; -import static org.eclipse.persistence.internal.databaseaccess.DatasourceCall.OUT_CURSOR; +import org.eclipse.persistence.internal.databaseaccess.DatasourceCall.ParameterType; /** *

@@ -35,7 +33,9 @@ public class PLSQLargument implements Cloneable { public String name; - public int direction = IN; + @Deprecated + public int direction = ParameterType.IN.val; + public ParameterType pdirection = ParameterType.IN; public int originalIndex = MIN_VALUE; public int inIndex = MIN_VALUE; // re-computed positional index for IN argument public int outIndex = MIN_VALUE; // re-computed positional index for OUT argument @@ -49,6 +49,7 @@ public PLSQLargument() { super(); } + @Deprecated public PLSQLargument(String name, int originalIndex, int direction, DatabaseType databaseType) { this(); @@ -56,14 +57,33 @@ public PLSQLargument(String name, int originalIndex, int direction, this.databaseType = databaseType; this.originalIndex = originalIndex; this.direction = direction; + this.pdirection = ParameterType.valueOf(direction); } + public PLSQLargument(String name, int originalIndex, ParameterType direction, + DatabaseType databaseType) { + this(); + this.name = name; + this.databaseType = databaseType; + this.originalIndex = originalIndex; + this.direction = direction.val; + this.pdirection = direction; + } + + @Deprecated public PLSQLargument(String name, int originalIndex, int direction, DatabaseType databaseType, int length) { this(name, originalIndex, direction, databaseType); this.length = length; } + public PLSQLargument(String name, int originalIndex, ParameterType direction, + DatabaseType databaseType, int length) { + this(name, originalIndex, direction, databaseType); + this.length = length; + } + + @Deprecated public PLSQLargument(String name, int originalIndex, int direction, DatabaseType databaseType, int precision, int scale) { this(name, originalIndex, direction, databaseType); @@ -71,6 +91,13 @@ public PLSQLargument(String name, int originalIndex, int direction, this.scale = scale; } + public PLSQLargument(String name, int originalIndex, ParameterType direction, + DatabaseType databaseType, int precision, int scale) { + this(name, originalIndex, direction, databaseType); + this.precision = precision; + this.scale = scale; + } + @Override protected PLSQLargument clone() { try { @@ -112,16 +139,16 @@ public void setIsNonAssociativeCollection(boolean isNonAsscociative) { public String toString() { StringBuilder sb = new StringBuilder(name); sb.append('{'); - if (direction == IN) { + if (pdirection == ParameterType.IN) { sb.append("IN"); } - else if (direction == INOUT) { + else if (pdirection == ParameterType.INOUT) { sb.append("IN"); } - else if (direction == OUT) { + else if (pdirection == ParameterType.OUT) { sb.append("OUT"); } - else if (direction == OUT_CURSOR) { + else if (pdirection == ParameterType.OUT_CURSOR) { sb.append("OUT CURSOR"); } sb.append(','); diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/oracle/plsql/PLSQLrecord.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/oracle/plsql/PLSQLrecord.java index dd56e4f6664..c422817ff0e 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/oracle/plsql/PLSQLrecord.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/oracle/plsql/PLSQLrecord.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 1998, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022 IBM Corporation. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -17,9 +18,6 @@ import static java.sql.Types.OTHER; import static java.sql.Types.STRUCT; -import static org.eclipse.persistence.internal.databaseaccess.DatasourceCall.IN; -import static org.eclipse.persistence.internal.databaseaccess.DatasourceCall.INOUT; -import static org.eclipse.persistence.internal.databaseaccess.DatasourceCall.OUT; import static org.eclipse.persistence.internal.helper.DatabaseType.DatabaseTypeHelper.databaseTypeHelper; import java.util.ArrayList; @@ -28,6 +26,7 @@ import java.util.ListIterator; import org.eclipse.persistence.exceptions.QueryException; +import org.eclipse.persistence.internal.databaseaccess.DatasourceCall.ParameterType; import org.eclipse.persistence.internal.helper.ComplexDatabaseType; import org.eclipse.persistence.internal.helper.DatabaseField; import org.eclipse.persistence.internal.helper.DatabaseType; @@ -86,13 +85,13 @@ public void addField(PLSQLargument field) { } public void addField(String fieldName, DatabaseType databaseType) { - fields.add(new PLSQLargument(fieldName, -1, IN, databaseType)); + fields.add(new PLSQLargument(fieldName, -1, ParameterType.IN, databaseType)); } public void addField(String fieldName, DatabaseType databaseType, int precision, int scale) { - fields.add(new PLSQLargument(fieldName, -1, IN, databaseType, precision, scale)); + fields.add(new PLSQLargument(fieldName, -1, ParameterType.IN, databaseType, precision, scale)); } public void addField(String fieldName, DatabaseType databaseType, int length) { - fields.add(new PLSQLargument(fieldName, -1, IN, databaseType, length)); + fields.add(new PLSQLargument(fieldName, -1, ParameterType.IN, databaseType, length)); } @Override @@ -122,7 +121,7 @@ public int computeOutIndex(PLSQLargument outArg, int newIndex, outArg.outIndex = newIndex; for (PLSQLargument argument : fields) { argument.outIndex = newIndex++; - argument.direction = OUT; + argument.pdirection = ParameterType.OUT; iterator.add(argument); } return newIndex; @@ -167,7 +166,7 @@ public void buildBeginBlock(StringBuilder sb, PLSQLargument arg, PLSQLStoredProc super.buildBeginBlock(sb, arg, call); } else { String target = databaseTypeHelper.buildTarget(arg); - if (arg.direction == IN || arg.direction == INOUT) { + if (arg.pdirection == ParameterType.IN || arg.pdirection == ParameterType.INOUT) { for (PLSQLargument f : fields) { sb.append(" "); sb.append(target); @@ -231,7 +230,7 @@ public void buildOutputRow(PLSQLargument outArg, AbstractRecord outputRow, } @Override - public void logParameter(StringBuilder sb, Integer direction, PLSQLargument arg, + public void logParameter(StringBuilder sb, ParameterType direction, PLSQLargument arg, AbstractRecord translationRow, DatabasePlatform platform) { if (hasCompatibleType()) { super.logParameter(sb, direction, arg, translationRow, platform); diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/queries/DatabaseQuery.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/queries/DatabaseQuery.java index 9d64f755395..e3f63d57119 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/queries/DatabaseQuery.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/queries/DatabaseQuery.java @@ -1505,7 +1505,7 @@ public String getTranslatedSQLString(org.eclipse.persistence.sessions.Session se return null; } SQLCall call = (SQLCall) queryMechanism.getCall().clone(); - call.setUsesBinding(false); + call.setUsesBinding(false); call.translate((AbstractRecord) translationRow, queryMechanism.getModifyRow(), (AbstractSession) session); return call.getSQLString(); } @@ -1528,7 +1528,7 @@ public List getTranslatedSQLStrings(org.eclipse.persistence.sessions.Session ses while (iterator.hasNext()) { SQLCall call = (SQLCall) iterator.next(); call = (SQLCall) call.clone(); - call.setUsesBinding(false); + call.setUsesBinding(false); call.translate((AbstractRecord) translationRow, queryMechanism.getModifyRow(), (AbstractSession) session); calls.add(call.getSQLString()); } diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/queries/SQLCall.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/queries/SQLCall.java index b2981b2b8b9..b895ca90d1b 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/queries/SQLCall.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/queries/SQLCall.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 1998, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022 IBM Corporation. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -58,17 +59,17 @@ public SQLCall(String sqlString) { * INTERNAL: * Set the data passed through setCustomSQLArgumentType and useCustomSQLCursorOutputAsResultSet methods. */ - protected void afterTranslateCustomQuery(List updatedParameters, List updatedParameterTypes) { + protected void afterTranslateCustomQuery(List updatedParameters, List updatedParameterTypes) { int size = getParameters().size(); for (int i = 0; i < size; i++) { - Integer parameterType = this.parameterTypes.get(i); + ParameterType parameterType = this.parameterTypes.get(i); Object parameter = this.parameters.get(i); - if ((parameterType == MODIFY) || (parameterType == OUT) || (parameterType == OUT_CURSOR) || ((parameterType == IN) && parameter instanceof DatabaseField)) { + if ((parameterType == ParameterType.MODIFY) || (parameterType == ParameterType.OUT) || (parameterType == ParameterType.OUT_CURSOR) || ((parameterType == ParameterType.IN) && parameter instanceof DatabaseField)) { DatabaseField field = afterTranslateCustomQueryUpdateParameter((DatabaseField)parameter, i, parameterType, updatedParameters, updatedParameterTypes); if (field!=null){ this.parameters.set(i, field); } - } else if (parameterType == INOUT) { + } else if (parameterType == ParameterType.INOUT) { DatabaseField outField = afterTranslateCustomQueryUpdateParameter((DatabaseField)((Object[])parameter)[1], i, parameterType, updatedParameters, updatedParameterTypes); if (outField != null) { if (((Object[])parameter)[0] instanceof DatabaseField){ @@ -82,7 +83,7 @@ protected void afterTranslateCustomQuery(List updatedParameters, List u } ((Object[])parameter)[1] = outField; } - } else if ((parameterType == IN) && (parameter instanceof DatabaseField)){ + } else if ((parameterType == ParameterType.IN) && (parameter instanceof DatabaseField)){ DatabaseField field = afterTranslateCustomQueryUpdateParameter((DatabaseField)parameter, i, parameterType, updatedParameters, updatedParameterTypes); if (field != null) { this.parameters.set(i, field); @@ -96,17 +97,17 @@ protected void afterTranslateCustomQuery(List updatedParameters, List u * Set the data passed through setCustomSQLArgumentType and useCustomSQLCursorOutputAsResultSet methods. * This will return the null if the user did not add the field/type using the setCustomSQLArgumentType method */ - protected DatabaseField afterTranslateCustomQueryUpdateParameter(DatabaseField field, int index, Integer parameterType, List updatedParameters, List updatedParameterTypes) { + protected DatabaseField afterTranslateCustomQueryUpdateParameter(DatabaseField field, int index, ParameterType parameterType, List updatedParameters, List updatedParameterTypes) { int size = updatedParameters.size(); for (int j = 0; j < size; j++) { DatabaseField updateField = (DatabaseField)updatedParameters.get(j); if (field.equals(updateField)) { - Integer updateParameterType = updatedParameterTypes.get(j); + ParameterType updateParameterType = updatedParameterTypes.get(j); if (updateParameterType == null) { return updateField; - } else if (updateParameterType == OUT_CURSOR) { - if (parameterType == OUT) { - this.parameterTypes.set(index, OUT_CURSOR); + } else if (updateParameterType == ParameterType.OUT_CURSOR) { + if (parameterType == ParameterType.OUT) { + this.parameterTypes.set(index, ParameterType.OUT_CURSOR); return updateField; } else { throw ValidationException.cannotSetCursorForParameterTypeOtherThanOut(field.getName(), toString()); @@ -145,7 +146,7 @@ protected void prepareInternal(AbstractSession session) { if (hasCustomSQLArguments()) { // hold results of setCustomSQLArgumentType and useCustomSQLCursorOutputAsResultSet methods List updatedParameters = null; - List updatedParameterTypes = null; + List updatedParameterTypes = null; if (getParameters().size() > 0) { updatedParameters = getParameters(); setParameters(org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance()); @@ -181,6 +182,7 @@ public void setCustomSQLArgumentType(String customParameterName, Class type) { field.setType(type); getParameters().add(field); getParameterTypes().add(null); + getParameterBindings().add(true); } /** @@ -195,6 +197,7 @@ public void setCustomSQLArgumentType(String argumentFieldName, int type) { field.setSqlType(type); getParameters().add(field); getParameterTypes().add(null); + getParameterBindings().add(true); } /** @@ -211,6 +214,7 @@ public void setCustomSQLArgumentType(String argumentFieldName, int type, String field.setSqlTypeName(typeName); getParameters().add(field); getParameterTypes().add(null); + getParameterBindings().add(true); } /** @@ -229,6 +233,7 @@ public void setCustomSQLArgumentType(String argumentFieldName, int type, String field.setType(javaType); getParameters().add(field); getParameterTypes().add(null); + getParameterBindings().add(true); } /** @@ -247,6 +252,7 @@ public void setCustomSQLArgumentType(String argumentFieldName, int type, String field.setNestedTypeField(nestedType); getParameters().add(field); getParameterTypes().add(null); + getParameterBindings().add(true); } /** @@ -267,6 +273,7 @@ public void setCustomSQLArgumentType(String argumentFieldName, int type, String field.setNestedTypeField(nestedType); getParameters().add(field); getParameterTypes().add(null); + getParameterBindings().add(true); } /** @@ -319,7 +326,8 @@ public void appendTranslationParameter(Writer writer, ParameterExpression expres throw ValidationException.fileError(exception); } getParameters().add(expression); - getParameterTypes().add(TRANSLATION); + getParameterTypes().add(ParameterType.TRANSLATION); + getParameterBindings().add(expression.canBind()); } /** @@ -332,7 +340,8 @@ public void appendTranslationParameter(Writer writer, ParameterExpression expres public void useCustomSQLCursorOutputAsResultSet(String customParameterName) { DatabaseField field = new DatabaseField(customParameterName); getParameters().add(field); - getParameterTypes().add(OUT_CURSOR); + getParameterTypes().add(ParameterType.OUT_CURSOR); + getParameterBindings().add(true); setIsCursorOutputProcedure(true); } } diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/queries/StoredFunctionCall.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/queries/StoredFunctionCall.java index 51c648dc68b..2b23e51dc66 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/queries/StoredFunctionCall.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/queries/StoredFunctionCall.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 1998, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022 IBM Corporation. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -176,7 +177,7 @@ public void setResult(String name, int type) { * Define to return cursor as result. */ public void setResultCursor() { - getParameterTypes().set(0, OUT_CURSOR); + getParameterTypes().set(0, ParameterType.OUT_CURSOR); setIsCursorOutputProcedure(!hasOutputCursors()); setIsMultipleCursorOutputProcedure(hasOutputCursors()); } diff --git a/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/EntityManagerSetupImpl.java b/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/EntityManagerSetupImpl.java index 982d9644f3c..d9d8d27162f 100644 --- a/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/EntityManagerSetupImpl.java +++ b/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/EntityManagerSetupImpl.java @@ -2792,6 +2792,11 @@ protected void updateSession(Map m, ClassLoader loader) { session.getPlatform().setShouldForceBindAllParameters(Boolean.parseBoolean(shouldForceBindString)); } + String allowPartialBindString = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.JDBC_ALLOW_PARTIAL_PARAMETERS, m, session); + if(allowPartialBindString != null) { + session.getPlatform().setShouldBindPartialParameters(Boolean.parseBoolean(allowPartialBindString)); + } + updateLogins(m); } if (!session.getDatasourceLogin().shouldUseExternalTransactionController()) { diff --git a/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/QueryImpl.java b/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/QueryImpl.java index 8a7ba9b62bd..e5e6450f7b0 100644 --- a/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/QueryImpl.java +++ b/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/QueryImpl.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 2012, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022 IBM Corporation. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -67,7 +68,6 @@ import org.eclipse.persistence.queries.DataModifyQuery; import org.eclipse.persistence.queries.DataReadQuery; import org.eclipse.persistence.queries.DatabaseQuery; -import org.eclipse.persistence.queries.DatabaseQuery.ParameterType; import org.eclipse.persistence.queries.ModifyQuery; import org.eclipse.persistence.queries.ObjectLevelReadQuery; import org.eclipse.persistence.queries.ReadAllQuery; @@ -412,11 +412,11 @@ protected Map> getInternalParameters() { boolean checkParameterType = query.getArgumentParameterTypes().size() == query.getArguments().size(); for (String argName : query.getArguments()) { Parameter param = null; - ParameterType type = null; + org.eclipse.persistence.queries.DatabaseQuery.ParameterType type = null; if (checkParameterType){ type = query.getArgumentParameterTypes().get(count); } - if (type == ParameterType.POSITIONAL){ + if (type == org.eclipse.persistence.queries.DatabaseQuery.ParameterType.POSITIONAL){ Integer position = Integer.parseInt(argName); param = new ParameterExpressionImpl(null, query.getArgumentTypes().get(count), position); } else { @@ -675,8 +675,9 @@ protected static void applyArguments(StoredProcedureCall call, DatabaseQuery que PLSQLStoredProcedureCall plsqlCall = (PLSQLStoredProcedureCall)call; for (int index = 0; index < plsqlCall.getArguments().size(); index++) { PLSQLargument argument = plsqlCall.getArguments().get(index); - int type = argument.direction; - if ((type == StoredProcedureCall.IN) || (type == StoredProcedureCall.INOUT)) { + org.eclipse.persistence.internal.databaseaccess.DatasourceCall.ParameterType type = argument.pdirection; + if ((type == org.eclipse.persistence.internal.databaseaccess.DatasourceCall.ParameterType.IN) + || (type == org.eclipse.persistence.internal.databaseaccess.DatasourceCall.ParameterType.INOUT)) { if (call.hasOptionalArguments()) { query.addArgument(argument.name, Object.class, call.getOptionalArguments().contains(new DatabaseField(argument.name))); } else { @@ -686,8 +687,9 @@ protected static void applyArguments(StoredProcedureCall call, DatabaseQuery que } } else { for (int index = 0; index < call.getParameters().size(); index++) { - int type = call.getParameterTypes().get(index); - if ((type == StoredProcedureCall.IN) || (type == StoredProcedureCall.INOUT)) { + org.eclipse.persistence.internal.databaseaccess.DatasourceCall.ParameterType type = call.getParameterTypes().get(index); + if ((type == org.eclipse.persistence.internal.databaseaccess.DatasourceCall.ParameterType.IN) + || (type == org.eclipse.persistence.internal.databaseaccess.DatasourceCall.ParameterType.INOUT)) { Object value = call.getParameters().get(index); DatabaseField parameter = null; if (value instanceof Object[]) { diff --git a/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/StoredProcedureQueryImpl.java b/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/StoredProcedureQueryImpl.java index fd5a8b300c6..416164164b0 100644 --- a/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/StoredProcedureQueryImpl.java +++ b/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/StoredProcedureQueryImpl.java @@ -1,6 +1,6 @@ /* - * Copyright (c) 2012, 2019 Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2019 IBM Corporation. All rights reserved. + * Copyright (c) 2012, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022 IBM Corporation. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -60,6 +60,7 @@ import org.eclipse.persistence.internal.databaseaccess.Accessor; import org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor; import org.eclipse.persistence.internal.databaseaccess.DatabaseCall; +import org.eclipse.persistence.internal.databaseaccess.DatasourceCall.ParameterType; import org.eclipse.persistence.internal.databaseaccess.OutputParameterForCallableStatement; import org.eclipse.persistence.internal.helper.DatabaseField; import org.eclipse.persistence.internal.jpa.querydef.ParameterExpressionImpl; @@ -430,16 +431,16 @@ protected Map> getInternalParameters() { int index = 0; for (Object parameter : getCall().getParameters()) { - Integer parameterType = getCall().getParameterTypes().get(index); + ParameterType parameterType = getCall().getParameterTypes().get(index); String argumentName = getCall().getProcedureArgumentNames().get(index); DatabaseField field = null; - if (parameterType == getCall().INOUT) { + if (parameterType == ParameterType.INOUT) { field = (DatabaseField) ((Object[]) parameter)[0]; - } else if (parameterType == getCall().IN) { + } else if (parameterType == ParameterType.IN) { field = (DatabaseField) parameter; - } else if (parameterType == getCall().OUT || parameterType == getCall().OUT_CURSOR) { + } else if (parameterType == ParameterType.OUT || parameterType == ParameterType.OUT_CURSOR) { if (parameter instanceof OutputParameterForCallableStatement) { field = ((OutputParameterForCallableStatement) parameter).getOutputField(); } else { diff --git a/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/metadata/queries/PLSQLParameterMetadata.java b/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/metadata/queries/PLSQLParameterMetadata.java index ecf0dcb80e3..86c786efeac 100644 --- a/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/metadata/queries/PLSQLParameterMetadata.java +++ b/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/metadata/queries/PLSQLParameterMetadata.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 2011, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022 IBM Corporation. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -15,6 +16,7 @@ package org.eclipse.persistence.internal.jpa.metadata.queries; import org.eclipse.persistence.annotations.Direction; +import org.eclipse.persistence.internal.databaseaccess.DatasourceCall.ParameterType; import org.eclipse.persistence.internal.helper.DatabaseField; import org.eclipse.persistence.internal.helper.DatabaseType; import org.eclipse.persistence.internal.jpa.metadata.MetadataProject; @@ -267,7 +269,7 @@ public void process(PLSQLStoredProcedureCall call, boolean functionReturn) { } } else if (m_direction.equals(Direction.OUT_CURSOR.name())) { boolean multipleCursors = false; - if (call.getParameterTypes().contains(call.OUT_CURSOR)) { + if (call.getParameterTypes().contains(ParameterType.OUT_CURSOR)) { multipleCursors = true; } call.useNamedCursorOutputAsResultSet(procedureParameterName, type); diff --git a/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/querydef/CriteriaBuilderImpl.java b/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/querydef/CriteriaBuilderImpl.java index 28114d8a6b3..a2d48d06206 100644 --- a/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/querydef/CriteriaBuilderImpl.java +++ b/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/querydef/CriteriaBuilderImpl.java @@ -315,9 +315,10 @@ public Expression countDistinct(Expression x){ * @return exists predicate */ @Override - public Predicate exists(Subquery subquery){ + public Predicate exists(Subquery subquery) { // Setting SubQuery's SubSelectExpression as a base for the expression created by operator allows setting a new ExpressionBuilder later in the SubSelectExpression (see integrateRoot method in SubQueryImpl). - return new CompoundExpressionImpl(metamodel, ExpressionOperator.getOperator(Integer.valueOf(ExpressionOperator.Exists)).expressionFor(((SubQueryImpl)subquery).getCurrentNode()), buildList(subquery), "exists"); + ExpressionOperator operator = org.eclipse.persistence.expressions.Expression.getOperator(ExpressionOperator.Exists); + return new CompoundExpressionImpl(metamodel, operator.expressionFor(((SubQueryImpl)subquery).getCurrentNode()), buildList(subquery), "exists"); } /** @@ -497,7 +498,7 @@ public Predicate or(Predicate... restrictions){ * @return not predicate */ @Override - public Predicate not(Expression restriction){ + public Predicate not(Expression restriction) { if (((InternalExpression)restriction).isPredicate()){ return ((Predicate)restriction).not(); } @@ -507,10 +508,10 @@ public Predicate not(Expression restriction){ if (((InternalExpression)restriction).isCompoundExpression() && ((CompoundExpressionImpl)restriction).getOperation().equals("exists")){ FunctionExpression exp = (FunctionExpression) ((InternalSelection)restriction).getCurrentNode(); SubSelectExpression sub = (SubSelectExpression) exp.getChildren().get(0); - parentNode = ExpressionOperator.getOperator(Integer.valueOf(ExpressionOperator.NotExists)).expressionFor(sub); + parentNode = org.eclipse.persistence.expressions.Expression.getOperator(ExpressionOperator.NotExists).expressionFor(sub); name = "notExists"; compoundExpressions = ((CompoundExpressionImpl)restriction).getChildExpressions(); - }else{ + } else { parentNode = ((InternalSelection)restriction).getCurrentNode().not(); compoundExpressions = buildList(restriction); } diff --git a/utils/eclipselink.utils.workbench/mappingsmodel/source/org/eclipse/persistence/tools/workbench/mappingsmodel/query/MWProcedure.java b/utils/eclipselink.utils.workbench/mappingsmodel/source/org/eclipse/persistence/tools/workbench/mappingsmodel/query/MWProcedure.java index 412c8e3a59f..d4b416667cc 100644 --- a/utils/eclipselink.utils.workbench/mappingsmodel/source/org/eclipse/persistence/tools/workbench/mappingsmodel/query/MWProcedure.java +++ b/utils/eclipselink.utils.workbench/mappingsmodel/source/org/eclipse/persistence/tools/workbench/mappingsmodel/query/MWProcedure.java @@ -620,11 +620,12 @@ public static MWProcedure convertFromEclipseLinkRuntime(MWStoredProcedureQueryFo Iterator argumentNames = (Iterator)call.getProcedureArgumentNames().iterator(); Iterator parameters = (Iterator)call.getParameters().iterator(); - Iterator parameterTypes = (Iterator)call.getParameterTypes().iterator(); + Iterator parameterTypes = + (Iterator)call.getParameterTypes().iterator(); while (argumentNames.hasNext()) { String name = argumentNames.next(); - Integer type = parameterTypes.next(); + org.eclipse.persistence.internal.databaseaccess.DatasourceCall.ParameterType type = parameterTypes.next(); MWAbstractProcedureArgument arg = null; org.eclipse.persistence.internal.helper.DatabaseField field = null; org.eclipse.persistence.internal.helper.DatabaseField outField = null; @@ -638,23 +639,23 @@ public static MWProcedure convertFromEclipseLinkRuntime(MWStoredProcedureQueryFo } if (name == null) { - if (type.equals(org.eclipse.persistence.internal.databaseaccess.DatasourceCall.IN)) { + if (type.equals(org.eclipse.persistence.internal.databaseaccess.DatasourceCall.ParameterType.IN)) { arg = procedure.addUnamedInArgument(); - } else if (type.equals(org.eclipse.persistence.internal.databaseaccess.DatasourceCall.INOUT)) { + } else if (type.equals(org.eclipse.persistence.internal.databaseaccess.DatasourceCall.ParameterType.INOUT)) { arg = procedure.addUnamedInOutputArgument(); ((MWAbstractProcedureInOutputArgument)arg).setOutFieldName(outField.getName()); - } else if (type.equals(org.eclipse.persistence.internal.databaseaccess.DatasourceCall.OUT)) { + } else if (type.equals(org.eclipse.persistence.internal.databaseaccess.DatasourceCall.ParameterType.OUT)) { arg = procedure.addUnamedOutputArgument(); } } else { - if (type.equals(org.eclipse.persistence.internal.databaseaccess.DatasourceCall.IN)) { + if (type.equals(org.eclipse.persistence.internal.databaseaccess.DatasourceCall.ParameterType.IN)) { arg = procedure.addNamedInArgument(name); - } else if (type.equals(org.eclipse.persistence.internal.databaseaccess.DatasourceCall.INOUT)) { + } else if (type.equals(org.eclipse.persistence.internal.databaseaccess.DatasourceCall.ParameterType.INOUT)) { arg = procedure.addNamedInOutputArgument(name); ((MWAbstractProcedureInOutputArgument)arg).setOutFieldName(outField.getName()); - } else if (type.equals(org.eclipse.persistence.internal.databaseaccess.DatasourceCall.OUT)) { + } else if (type.equals(org.eclipse.persistence.internal.databaseaccess.DatasourceCall.ParameterType.OUT)) { arg = procedure.addNamedOutputArgument(name); - } else if (type.equals(org.eclipse.persistence.internal.databaseaccess.DatasourceCall.OUT_CURSOR)) { + } else if (type.equals(org.eclipse.persistence.internal.databaseaccess.DatasourceCall.ParameterType.OUT_CURSOR)) { unamedCursor = false; procedure.setCursorOutputName(name); procedure.setUseUnamedCursorOutput(Boolean.FALSE); diff --git a/utils/org.eclipse.persistence.dbws.builder/src/org/eclipse/persistence/tools/dbws/XmlEntityMappingsGenerator.java b/utils/org.eclipse.persistence.dbws.builder/src/org/eclipse/persistence/tools/dbws/XmlEntityMappingsGenerator.java index 83706d74703..913f96a772f 100644 --- a/utils/org.eclipse.persistence.dbws.builder/src/org/eclipse/persistence/tools/dbws/XmlEntityMappingsGenerator.java +++ b/utils/org.eclipse.persistence.dbws.builder/src/org/eclipse/persistence/tools/dbws/XmlEntityMappingsGenerator.java @@ -14,9 +14,6 @@ // David McCann - 2.5.0 - Sept.18, 2012 - Initial Implementation package org.eclipse.persistence.tools.dbws; -import static org.eclipse.persistence.internal.databaseaccess.DatasourceCall.IN; -import static org.eclipse.persistence.internal.databaseaccess.DatasourceCall.INOUT; -import static org.eclipse.persistence.internal.databaseaccess.DatasourceCall.OUT; import static org.eclipse.persistence.internal.jpa.metadata.MetadataConstants.EL_ACCESS_VIRTUAL; import static org.eclipse.persistence.internal.jpa.metadata.MetadataConstants.JPA_PARAMETER_IN; import static org.eclipse.persistence.internal.jpa.metadata.MetadataConstants.JPA_PARAMETER_INOUT; @@ -50,6 +47,7 @@ import org.eclipse.persistence.config.QueryHints; import org.eclipse.persistence.descriptors.ClassDescriptor; import org.eclipse.persistence.internal.databaseaccess.DatabaseCall; +import org.eclipse.persistence.internal.databaseaccess.DatasourceCall.ParameterType; import org.eclipse.persistence.internal.helper.DatabaseField; import org.eclipse.persistence.internal.jpa.metadata.accessors.classes.ClassAccessor; import org.eclipse.persistence.internal.jpa.metadata.accessors.classes.EmbeddableAccessor; @@ -233,7 +231,7 @@ public static XMLEntityMappings generateXmlEntityMappings(Project orProject, Lis param.setDirection(CURSOR_STR); } } else { - param.setDirection(getDirectionAsString(arg.direction)); + param.setDirection(getDirectionAsString(arg.pdirection)); params.add(param); } } @@ -256,7 +254,7 @@ public static XMLEntityMappings generateXmlEntityMappings(Project orProject, Lis DatabaseField arg; StoredProcedureParameterMetadata param; List paramFields = call.getParameters(); - List types = call.getParameterTypes(); + List types = call.getParameterTypes(); for (int i=0; i < paramFields.size(); i++) { arg = paramFields.get(i); param = new StoredProcedureParameterMetadata(); @@ -274,7 +272,7 @@ public static XMLEntityMappings generateXmlEntityMappings(Project orProject, Lis // first arg is the return arg metadata.setReturnParameter(param); // handle CURSOR types - want name/value pairs returned - if (types.get(i) == 8) { + if (types.get(i) == ParameterType.OUT_CURSOR) { addQueryHint(metadata); } } else { @@ -311,7 +309,7 @@ public static XMLEntityMappings generateXmlEntityMappings(Project orProject, Lis if (arg.cursorOutput) { param.setDirection(CURSOR_STR); } else { - param.setDirection(getDirectionAsString(arg.direction)); + param.setDirection(getDirectionAsString(arg.pdirection)); } if (arg.databaseType == XMLType) { @@ -338,9 +336,9 @@ public static XMLEntityMappings generateXmlEntityMappings(Project orProject, Lis DatabaseField arg; StoredProcedureParameterMetadata param; List paramFields = call.getParameters(); - List types = call.getParameterTypes(); + List types = call.getParameterTypes(); for (int i = 0; i < paramFields.size(); i++) { - if (types.get(i) == DatabaseCall.INOUT) { + if (types.get(i) == ParameterType.INOUT) { // for INOUT we get Object[IN, OUT] arg = (DatabaseField) ((Object[]) paramFields.get(i))[1]; } else { @@ -360,7 +358,7 @@ public static XMLEntityMappings generateXmlEntityMappings(Project orProject, Lis param.setMode(getParameterModeAsString(types.get(i))); // handle CURSOR types - want name/value pairs returned - if (types.get(i) == 8) { + if (types.get(i) == ParameterType.OUT_CURSOR) { addQueryHint(metadata); } @@ -625,21 +623,35 @@ protected static EmbeddedAccessor processEmbeddedMapping(AggregateMapping mappin * * Expected 'direction' value is one of: *
    - *
  • org.eclipse.persistence.internal.databaseaccess.DatasourceCall.IN - *
  • org.eclipse.persistence.internal.databaseaccess.DatasourceCall.INOUT - *
  • org.eclipse.persistence.internal.databaseaccess.DatasourceCall.OUT - *
  • org.eclipse.persistence.internal.databaseaccess.DatasourceCall.OUT_CURSOR + *
  • org.eclipse.persistence.internal.databaseaccess.DatasourceCall.ParameterType.IN + *
  • org.eclipse.persistence.internal.databaseaccess.DatasourceCall.ParameterType.INOUT + *
  • org.eclipse.persistence.internal.databaseaccess.DatasourceCall.ParameterType.OUT + *
  • org.eclipse.persistence.internal.databaseaccess.DatasourceCall.ParameterType.OUT_CURSOR *
- * */ public static String getDirectionAsString(int direction) { - if (direction == IN) { + return getDirectionAsString(ParameterType.valueOf(direction)); + } + + /** + * Return a parameter direction as a String based on a given in value. + * + * Expected 'direction' value is one of: + *
    + *
  • org.eclipse.persistence.internal.databaseaccess.DatasourceCall.ParameterType.IN + *
  • org.eclipse.persistence.internal.databaseaccess.DatasourceCall.ParameterType.INOUT + *
  • org.eclipse.persistence.internal.databaseaccess.DatasourceCall.ParameterType.OUT + *
  • org.eclipse.persistence.internal.databaseaccess.DatasourceCall.ParameterType.OUT_CURSOR + *
+ */ + public static String getDirectionAsString(ParameterType direction) { + if (direction == ParameterType.IN) { return IN_STR; } - if (direction == OUT) { + if (direction == ParameterType.OUT) { return OUT_STR; } - if (direction == INOUT) { + if (direction == ParameterType.INOUT) { return INOUT_STR; } return CURSOR_STR; @@ -650,10 +662,10 @@ public static String getDirectionAsString(int direction) { * * Expected 'direction' value is one of: *
    - *
  • org.eclipse.persistence.internal.databaseaccess.DatasourceCall.IN - *
  • org.eclipse.persistence.internal.databaseaccess.DatasourceCall.INOUT - *
  • org.eclipse.persistence.internal.databaseaccess.DatasourceCall.OUT - *
  • org.eclipse.persistence.internal.databaseaccess.DatasourceCall.OUT_CURSOR + *
  • org.eclipse.persistence.internal.databaseaccess.DatasourceCall.ParameterType.IN + *
  • org.eclipse.persistence.internal.databaseaccess.DatasourceCall.ParameterType.INOUT + *
  • org.eclipse.persistence.internal.databaseaccess.DatasourceCall.ParameterType.OUT + *
  • org.eclipse.persistence.internal.databaseaccess.DatasourceCall.ParameterType.OUT_CURSOR *
* * Will return one of: @@ -665,13 +677,36 @@ public static String getDirectionAsString(int direction) { * */ public static String getParameterModeAsString(int direction) { - if (direction == IN) { + return getParameterModeAsString(ParameterType.valueOf(direction)); + } + + /** + * Return a parameter mode as a String based on a given in value. + * + * Expected 'direction' value is one of: + *
    + *
  • org.eclipse.persistence.internal.databaseaccess.DatasourceCall.ParameterType.IN + *
  • org.eclipse.persistence.internal.databaseaccess.DatasourceCall.ParameterType.INOUT + *
  • org.eclipse.persistence.internal.databaseaccess.DatasourceCall.ParameterType.OUT + *
  • org.eclipse.persistence.internal.databaseaccess.DatasourceCall.ParameterType.OUT_CURSOR + *
+ * + * Will return one of: + *
    + *
  • org.eclipse.persistence.internal.jpa.metadata.MetadataConstants.JPA_PARAMETER_IN + *
  • org.eclipse.persistence.internal.jpa.metadata.MetadataConstants.JPA_PARAMETER_INOUT + *
  • org.eclipse.persistence.internal.jpa.metadata.MetadataConstants.JPA_PARAMETER_OUT + *
  • org.eclipse.persistence.internal.jpa.metadata.MetadataConstants.JPA_PARAMETER_REF_CURSOR + *
+ */ + public static String getParameterModeAsString(ParameterType direction) { + if (direction == ParameterType.IN) { return JPA_PARAMETER_IN; } - if (direction == OUT) { + if (direction == ParameterType.OUT) { return JPA_PARAMETER_OUT; } - if (direction == INOUT) { + if (direction == ParameterType.INOUT) { return JPA_PARAMETER_INOUT; } return JPA_PARAMETER_REF_CURSOR;