From e3b5fe27c77e35168f89bf3e600ec5e428f43b49 Mon Sep 17 00:00:00 2001 From: Will Dazey Date: Thu, 19 May 2022 13:17:15 -0500 Subject: [PATCH] Fix NPE initializing EclipseLink ExpressionOperator Signed-off-by: Will Dazey --- .../bnd.bnd | 7 +- .../descriptors/TimestampLockingPolicy.java | 310 -- .../expressions/ExpressionOperator.java | 3294 +++++++++++++++++ .../platform/database/DB2Platform.java | 1851 +++++++++ .../testlogic/JPATestOLGH19342Logic.java | 6 +- 5 files changed, 5154 insertions(+), 314 deletions(-) delete mode 100644 dev/com.ibm.websphere.appserver.thirdparty.eclipselink/src/org/eclipse/persistence/descriptors/TimestampLockingPolicy.java create mode 100644 dev/com.ibm.websphere.appserver.thirdparty.eclipselink/src/org/eclipse/persistence/expressions/ExpressionOperator.java create mode 100644 dev/com.ibm.websphere.appserver.thirdparty.eclipselink/src/org/eclipse/persistence/platform/database/DB2Platform.java diff --git a/dev/com.ibm.websphere.appserver.thirdparty.eclipselink/bnd.bnd b/dev/com.ibm.websphere.appserver.thirdparty.eclipselink/bnd.bnd index 6d5bfae3dad2..97acba0ad61f 100644 --- a/dev/com.ibm.websphere.appserver.thirdparty.eclipselink/bnd.bnd +++ b/dev/com.ibm.websphere.appserver.thirdparty.eclipselink/bnd.bnd @@ -116,8 +116,9 @@ Include-Resource: \ @${repo;com.ibm.ws.org.eclipse.persistence:org.eclipse.persistence.jpa.jpql;${eclFullVersion};EXACT}!/!META-INF/maven/*,\ @${repo;com.ibm.ws.org.eclipse.persistence:org.eclipse.persistence.jpa.modelgen;${eclFullVersion};EXACT}!/!META-INF/maven/*,\ @${repo;com.ibm.ws.org.eclipse.persistence:org.eclipse.persistence.jpa;${eclFullVersion};EXACT}!/!META-INF/maven/*,\ + org/eclipse/persistence/expressions=${bin}/org/eclipse/persistence/expressions,\ org/eclipse/persistence/internal/helper=${bin}/org/eclipse/persistence/internal/helper,\ - org/eclipse/persistence/descriptors=${bin}/org/eclipse/persistence/descriptors + org/eclipse/persistence/platform/database=${bin}/org/eclipse/persistence/platform/database publish.wlp.jar.suffix: dev/api/third-party @@ -126,7 +127,9 @@ publish.wlp.jar.suffix: dev/api/third-party instrument.classesExcludes: \ org/eclipse/persistence/exceptions/i18n/*.class, \ org/eclipse/persistence/internal/localization/i18n/*.class, \ - org/eclipse/persistence/internal/helper/*.class + org/eclipse/persistence/expressions/*.class, \ + org/eclipse/persistence/internal/helper/*.class, \ + org/eclipse/persistence/platform/database/*.class -buildpath: \ com.ibm.ws.org.eclipse.persistence:org.eclipse.persistence.core;version=${eclFullVersion};strategy=exact,\ diff --git a/dev/com.ibm.websphere.appserver.thirdparty.eclipselink/src/org/eclipse/persistence/descriptors/TimestampLockingPolicy.java b/dev/com.ibm.websphere.appserver.thirdparty.eclipselink/src/org/eclipse/persistence/descriptors/TimestampLockingPolicy.java deleted file mode 100644 index 935758db7c1d..000000000000 --- a/dev/com.ibm.websphere.appserver.thirdparty.eclipselink/src/org/eclipse/persistence/descriptors/TimestampLockingPolicy.java +++ /dev/null @@ -1,310 +0,0 @@ -/******************************************************************************* - * Copyright (c) 1998, 2022 Oracle, IBM Corporation, and/or their affiliates. All rights reserved. - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 - * which accompanies this distribution. - * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * Contributors: - * Oracle - initial API and implementation from Oracle TopLink - ******************************************************************************/ -package org.eclipse.persistence.descriptors; - -import org.eclipse.persistence.internal.sessions.*; - -import java.sql.Timestamp; -import org.eclipse.persistence.expressions.*; -import org.eclipse.persistence.internal.helper.*; -import org.eclipse.persistence.queries.*; -import org.eclipse.persistence.exceptions.*; - -/** - *

Purpose: Used to allow a single version timestamp to be used for optimistic locking. - * - * @since TOPLink/Java 2.0 - */ -public class TimestampLockingPolicy extends VersionLockingPolicy { - protected int retrieveTimeFrom; - public final static int SERVER_TIME = 1; - public final static int LOCAL_TIME = 2; - - /** - * PUBLIC: - * Create a new TimestampLockingPolicy. - * Defaults to using the time retrieved from the server. - */ - public TimestampLockingPolicy() { - super(); - this.useServerTime(); - } - - /** - * PUBLIC: - * Create a new TimestampLockingPolicy. - * Defaults to using the time retrieved from the server. - * @param fieldName the field where the write lock value will be stored. - */ - public TimestampLockingPolicy(String fieldName) { - super(fieldName); - this.useServerTime(); - } - - /** - * INTERNAL: - * Create a new TimestampLockingPolicy. - * Defaults to using the time retrieved from the server. - * @param field the field where the write lock value will be stored. - */ - public TimestampLockingPolicy(DatabaseField field) { - super(field); - this.useServerTime(); - } - - /** - * INTERNAL: - * This method compares two writeLockValues. - * The writeLockValues should be non-null and of type java.sql.Timestamp. - * Returns: - * -1 if value1 is less (older) than value2; - * 0 if value1 equals value2; - * 1 if value1 is greater (newer) than value2. - * Throws: - * NullPointerException if the passed value is null; - * ClassCastException if the passed value is of a wrong type. - */ - public int compareWriteLockValues(Object value1, Object value2) { - java.sql.Timestamp timestampValue1 = (java.sql.Timestamp)value1; - java.sql.Timestamp timestampValue2 = (java.sql.Timestamp)value2; - return timestampValue1.compareTo(timestampValue2); - } - - /** - * INTERNAL: - * Return the default timestamp locking filed java type, default is Timestamp. - */ - protected Class getDefaultLockingFieldType() { - return ClassConstants.TIMESTAMP; - } - - /** - * INTERNAL: - * This is the base value that is older than all other values, it is used in the place of - * null in some situations. - */ - public Object getBaseValue(){ - return new Timestamp(0); - } - - /** - * INTERNAL: - * returns the initial locking value - */ - protected Object getInitialWriteValue(AbstractSession session) { - if (usesLocalTime()) { - return new Timestamp(System.currentTimeMillis()); - } - if (usesServerTime()) { - AbstractSession readSession = session.getSessionForClass(getDescriptor().getJavaClass()); - while (readSession.isUnitOfWork()) { - readSession = ((UnitOfWorkImpl)readSession).getParent().getSessionForClass(getDescriptor().getJavaClass()); - } - - return readSession.getDatasourceLogin().getDatasourcePlatform().getTimestampFromServer(session, readSession.getName()); - } - return null; - - } - - /** - * INTERNAL: - * Returns the new Timestamp value. - */ - public Object getNewLockValue(ModifyQuery query) { - return getInitialWriteValue(query.getSession()); - } - - /** - * INTERNAL: - * Return the value that should be stored in the identity map. If the value - * is stored in the object, then return a null. - */ - public Object getValueToPutInCache(AbstractRecord row, AbstractSession session) { - if (isStoredInCache()) { - return session.getDatasourcePlatform().convertObject(row.get(getWriteLockField()), ClassConstants.TIMESTAMP); - } else { - return null; - } - } - - /** - * INTERNAL: - * Return the number of versions different between these objects. - */ - @Override - public int getVersionDifference(Object currentValue, Object domainObject, Object primaryKeys, AbstractSession session) { - java.sql.Timestamp writeLockFieldValue; - java.sql.Timestamp newWriteLockFieldValue = (java.sql.Timestamp)currentValue; - if (newWriteLockFieldValue == null) { - return 0;//merge it as either the object is new or being forced merged. - } - if (isStoredInCache()) { - writeLockFieldValue = (java.sql.Timestamp)session.getIdentityMapAccessorInstance().getWriteLockValue(primaryKeys, domainObject.getClass(), getDescriptor()); - } else { - writeLockFieldValue = (java.sql.Timestamp)lockValueFromObject(domainObject); - } - if ((writeLockFieldValue != null) && (newWriteLockFieldValue.equals(writeLockFieldValue))) { - return 0; - } - if ((writeLockFieldValue != null) && !(newWriteLockFieldValue.after(writeLockFieldValue))) { - return -1; - } - - return 1; - } - - /** - * INTERNAL: - * This method will return the optimistic lock value for the object. - */ - @Override - public Object getWriteLockValue(Object domainObject, Object primaryKey, AbstractSession session) { - java.sql.Timestamp writeLockFieldValue = null; - if (isStoredInCache()) { - writeLockFieldValue = (java.sql.Timestamp)session.getIdentityMapAccessorInstance().getWriteLockValue(primaryKey, domainObject.getClass(), getDescriptor()); - } else { - //CR#2281 notStoredInCache prevent ClassCastException - Object lockValue = lockValueFromObject(domainObject); - if (lockValue != null) { - if (lockValue instanceof java.sql.Timestamp) { - writeLockFieldValue = (java.sql.Timestamp)lockValueFromObject(domainObject); - } else { - throw OptimisticLockException.needToMapJavaSqlTimestampWhenStoredInObject(); - } - } - } - return writeLockFieldValue; - } - - /** - * INTERNAL: - * Return an expression that updates the write lock - */ - public Expression getWriteLockUpdateExpression(ExpressionBuilder builder, AbstractSession session) { - return builder.currentTimeStamp(); - } - - /** - * INTERNAL: - * Timestamp versioning should not be able to do this. Override the superclass behavior. - */ - protected Number incrementWriteLockValue(Number numberValue) { - return null; - } - - /** - * INTERNAL: - * Compares the value with the value from the object (or cache). - * Will return true if the currentValue is newer than the domainObject. - */ - @Override - public boolean isNewerVersion(Object currentValue, Object domainObject, Object primaryKey, AbstractSession session) { - java.sql.Timestamp writeLockFieldValue; - java.sql.Timestamp newWriteLockFieldValue = (java.sql.Timestamp)currentValue; - if (isStoredInCache()) { - writeLockFieldValue = (java.sql.Timestamp)session.getIdentityMapAccessorInstance().getWriteLockValue(primaryKey, domainObject.getClass(), getDescriptor()); - } else { - writeLockFieldValue = (java.sql.Timestamp)lockValueFromObject(domainObject); - } - - return isNewerVersion(newWriteLockFieldValue, writeLockFieldValue); - } - - /** - * INTERNAL: - * Compares the value from the row and from the object (or cache). - * Will return true if the row is newer than the object. - */ - @Override - public boolean isNewerVersion(AbstractRecord databaseRow, Object domainObject, Object primaryKey, AbstractSession session) { - java.sql.Timestamp writeLockFieldValue; - java.sql.Timestamp newWriteLockFieldValue = (java.sql.Timestamp)session.getDatasourcePlatform().convertObject(databaseRow.get(getWriteLockField()), ClassConstants.TIMESTAMP); - if (isStoredInCache()) { - writeLockFieldValue = (java.sql.Timestamp)session.getIdentityMapAccessorInstance().getWriteLockValue(primaryKey, domainObject.getClass(), getDescriptor()); - } else { - writeLockFieldValue = (java.sql.Timestamp)lockValueFromObject(domainObject); - } - - return isNewerVersion(newWriteLockFieldValue, writeLockFieldValue); - } - - /** - * INTERNAL: - * Compares two values. - * Will return true if the firstLockFieldValue is newer than the secondWriteLockFieldValue. - */ - public boolean isNewerVersion(Object firstLockFieldValue, Object secondWriteLockFieldValue) { - java.sql.Timestamp firstValue = (java.sql.Timestamp)firstLockFieldValue; - java.sql.Timestamp secondValue = (java.sql.Timestamp)secondWriteLockFieldValue; - - // 2.5.1.6 if the write lock value is null, then what ever we have is treated as newer. - if (firstValue == null) { - return false; - } - - // bug 6342382: first is not null, second is null, so we know first>second. - if(secondValue == null) { - return true; - } - - if (firstValue.after(secondValue)){ - return true; - } - return false; - } - - /** - * PUBLIC: - * Set if policy uses server time. - */ - public void setUsesServerTime(boolean usesServerTime) { - if (usesServerTime) { - useServerTime(); - } else { - useLocalTime(); - } - } - - /** - * PUBLIC: - * set this policy to get the time from the local machine. - */ - public void useLocalTime() { - retrieveTimeFrom = LOCAL_TIME; - } - - /** - * PUBLIC: - * set this policy to get the time from the server. - */ - public void useServerTime() { - retrieveTimeFrom = SERVER_TIME; - } - - /** - * PUBLIC: - * Return true if policy uses local time. - */ - public boolean usesLocalTime() { - return (retrieveTimeFrom == LOCAL_TIME); - } - - /** - * PUBLIC: - * Return true if policy uses server time. - */ - public boolean usesServerTime() { - return (retrieveTimeFrom == SERVER_TIME); - } -} diff --git a/dev/com.ibm.websphere.appserver.thirdparty.eclipselink/src/org/eclipse/persistence/expressions/ExpressionOperator.java b/dev/com.ibm.websphere.appserver.thirdparty.eclipselink/src/org/eclipse/persistence/expressions/ExpressionOperator.java new file mode 100644 index 000000000000..26df5dae641e --- /dev/null +++ b/dev/com.ibm.websphere.appserver.thirdparty.eclipselink/src/org/eclipse/persistence/expressions/ExpressionOperator.java @@ -0,0 +1,3294 @@ +/******************************************************************************* + * Copyright (c) 1998, 2022 Oracle, IBM Corporation, and/or its affiliates. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 + * which accompanies this distribution. + * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Oracle - initial API and implementation from Oracle TopLink + * Markus Karg - allow arguments to be specified multiple times in argumentIndices + * 05/07/2009-1.1.1 Dave Brosius + * - 263904: [PATCH] ExpressionOperator doesn't compare arrays correctly + * 01/23/2018-2.6 Will Dazey + * - 530214: trim operation should not bind parameters + ******************************************************************************/ +package org.eclipse.persistence.expressions; + +import java.security.AccessController; +import java.security.PrivilegedActionException; +import java.util.*; +import java.io.*; +import org.eclipse.persistence.internal.expressions.*; +import org.eclipse.persistence.internal.helper.*; +import org.eclipse.persistence.exceptions.*; +import org.eclipse.persistence.internal.helper.ClassConstants; +import org.eclipse.persistence.internal.security.PrivilegedAccessHelper; +import org.eclipse.persistence.internal.security.PrivilegedNewInstanceFromClass; + +/** + *

+ * Purpose: ADVANCED: The expression operator is used internally to define SQL operations and functions. + * It is possible for an advanced user to define their own operators. + */ +public class ExpressionOperator implements Serializable { + + /** Required for serialization compatibility. */ + static final long serialVersionUID = -7066100204792043980L; + protected int selector; + protected String name; + + // 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; + protected int[] argumentIndices = null; + + /** Contains user defined operators */ + protected static Map allOperators = initializeOperators(); + /** Contains internal defined operators meant as placeholders for platform operators */ + protected static Map allInternalOperators = initializeInternalOperators(); + + protected static Map platformOperatorSelectors = initializePlatformOperatorSelectors(); + protected static Map platformOperatorNames = initializePlatformOperatorNames(); + protected String[] javaStrings; + + /** 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; + public static final int ComparisonOperator = 2; + public static final int AggregateOperator = 3; + public static final int OrderOperator = 4; + public static final int FunctionOperator = 5; + + /** Logical operators */ + public static final int And = 1; + public static final int Or = 2; + public static final int Not = 3; + + /** Comparison operators */ + public static final int Equal = 4; + public static final int NotEqual = 5; + public static final int EqualOuterJoin = 6; + public static final int LessThan = 7; + public static final int LessThanEqual = 8; + public static final int GreaterThan = 9; + public static final int GreaterThanEqual = 10; + public static final int Like = 11; + public static final int NotLike = 12; + public static final int In = 13; + public static final int InSubQuery = 129; + public static final int NotIn = 14; + public static final int NotInSubQuery = 130; + public static final int Between = 15; + public static final int NotBetween = 16; + public static final int IsNull = 17; + public static final int NotNull = 18; + public static final int Exists = 86; + public static final int NotExists = 88; + public static final int LikeEscape = 89; + public static final int NotLikeEscape = 134; + public static final int Decode = 105; + public static final int Case = 117; + public static final int NullIf = 131; + public static final int Coalesce = 132; + public static final int CaseCondition = 136; + public static final int Regexp = 141; + + /** Aggregate operators */ + public static final int Count = 19; + public static final int Sum = 20; + public static final int Average = 21; + public static final int Maximum = 22; + public static final int Minimum = 23; + public static final int StandardDeviation = 24; + public static final int Variance = 25; + public static final int Distinct = 87; + + public static final int As = 148; + + /** Union operators */ + public static final int Union = 142; + public static final int UnionAll = 143; + public static final int Intersect = 144; + public static final int IntersectAll = 145; + public static final int Except = 146; + public static final int ExceptAll = 147; + + /** Ordering operators */ + public static final int Ascending = 26; + public static final int Descending = 27; + public static final int NullsFirst = 139; + public static final int NullsLast = 140; + + /** Function operators */ + + // General + public static final int ToUpperCase = 28; + public static final int ToLowerCase = 29; + public static final int Chr = 30; + public static final int Concat = 31; + public static final int HexToRaw = 32; + public static final int Initcap = 33; + public static final int Instring = 34; + public static final int Soundex = 35; + public static final int LeftPad = 36; + public static final int LeftTrim = 37; + public static final int Replace = 38; + public static final int RightPad = 39; + public static final int RightTrim = 40; + public static final int Substring = 41; + public static final int ToNumber = 42; + public static final int Translate = 43; + public static final int Trim = 44; + public static final int Ascii = 45; + public static final int Length = 46; + public static final int CharIndex = 96; + public static final int CharLength = 97; + public static final int Difference = 98; + public static final int Reverse = 99; + public static final int Replicate = 100; + public static final int Right = 101; + public static final int Locate = 112; + public static final int Locate2 = 113; + public static final int ToChar = 114; + public static final int ToCharWithFormat = 115; + public static final int RightTrim2 = 116; + public static final int Any = 118; + public static final int Some = 119; + public static final int All = 120; + public static final int Trim2 = 121; + public static final int LeftTrim2 = 122; + public static final int SubstringSingleArg = 133; + public static final int Cast = 137; + public static final int Extract = 138; + + // Date + public static final int AddMonths = 47; + public static final int DateToString = 48; + public static final int LastDay = 49; + public static final int MonthsBetween = 50; + public static final int NextDay = 51; + public static final int RoundDate = 52; + public static final int ToDate = 53; + /** + * Function to obtain the current timestamp on the database including date + * and time components. This corresponds to the JPQL function + * current_timestamp. + */ + public static final int Today = 54; + public static final int AddDate = 90; + public static final int DateName = 92; + public static final int DatePart = 93; + public static final int DateDifference = 94; + public static final int TruncateDate = 102; + public static final int NewTime = 103; + public static final int Nvl = 104; + /** + * Function to obtain the current date on the database with date components + * only but without time components. This corresponds to the JPQL function + * current_date. + */ + public static final int CurrentDate = 123; + /** + * Function to obtain the current time on the database with time components + * only but without date components. This corresponds to the JPQL function + * current_time. + */ + public static final int CurrentTime = 128; + + // Math + public static final int Ceil = 55; + public static final int Cos = 56; + public static final int Cosh = 57; + public static final int Abs = 58; + public static final int Acos = 59; + public static final int Asin = 60; + public static final int Atan = 61; + public static final int Exp = 62; + public static final int Sqrt = 63; + public static final int Floor = 64; + public static final int Ln = 65; + public static final int Log = 66; + public static final int Mod = 67; + public static final int Power = 68; + public static final int Round = 69; + public static final int Sign = 70; + public static final int Sin = 71; + public static final int Sinh = 72; + public static final int Tan = 73; + public static final int Tanh = 74; + public static final int Trunc = 75; + public static final int Greatest = 76; + public static final int Least = 77; + public static final int Add = 78; + public static final int Subtract = 79; + public static final int Divide = 80; + public static final int Multiply = 81; + public static final int Atan2 = 91; + public static final int Cot = 95; + public static final int Negate = 135; + + // Object-relational + public static final int Deref = 82; + public static final int Ref = 83; + public static final int RefToHex = 84; + public static final int Value = 85; + + //XML Specific + public static final int ExtractXml = 106; + public static final int ExtractValue = 107; + public static final int ExistsNode = 108; + public static final int GetStringVal = 109; + public static final int GetNumberVal = 110; + public static final int IsFragment = 111; + + // Spatial + public static final int SDO_WITHIN_DISTANCE = 124; + public static final int SDO_RELATE = 125; + public static final int SDO_FILTER = 126; + public static final int SDO_NN = 127; + + /** + * ADVANCED: + * Create a new operator. + */ + public ExpressionOperator() { + this.type = FunctionOperator; + // For bug 2780072 provide default behavior to make this class more useable. + setNodeClass(ClassConstants.FunctionExpression_Class); + } + + /** + * ADVANCED: + * Create a new operator with the given name(s) and strings to print. + */ + public ExpressionOperator(int selector, Vector newDatabaseStrings) { + this.type = FunctionOperator; + // For bug 2780072 provide default behavior to make this class more useable. + setNodeClass(ClassConstants.FunctionExpression_Class); + this.selector = selector; + this.printsAs(newDatabaseStrings); + } + + /** + * PUBLIC: + * Return if binding is compatible with this operator. + */ + @Deprecated + public Boolean isBindingSupported() { + return isBindingSupported; + } + + /** + * PUBLIC: + * Set if binding is compatible with this operator. + * Some databases do not allow binding, or require casting with certain operators. + */ + @Deprecated + public void setIsBindingSupported(Boolean isBindingSupported) { + this.isBindingSupported = isBindingSupported; + } + + /** + * INTERNAL: + * Return if the operator is equal to the other. + */ + public boolean equals(Object object) { + if (this == object) { + return true; + } + if ((object == null) || (getClass() != object.getClass())) { + return false; + } + ExpressionOperator operator = (ExpressionOperator) object; + if (getSelector() == 0) { + return Arrays.equals(getDatabaseStrings(0), operator.getDatabaseStrings(0)); + } else { + return getSelector() == operator.getSelector(); + } + } + + /** + * INTERNAL: + * Return the hash-code based on the unique selector. + */ + public int hashCode() { + return getSelector(); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator abs() { + return simpleFunction(Abs, "ABS"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator acos() { + return simpleFunction(Acos, "ACOS"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator add() { + return ExpressionOperator.simpleMath(ExpressionOperator.Add, "+"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator addDate() { + ExpressionOperator exOperator = simpleThreeArgumentFunction(AddDate, "DATEADD"); + int[] indices = new int[3]; + indices[0] = 1; + indices[1] = 2; + indices[2] = 0; + + exOperator.setArgumentIndices(indices); + return exOperator; + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator addMonths() { + return simpleTwoArgumentFunction(AddMonths, "ADD_MONTHS"); + } + + /** + * ADVANCED: + * 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. + */ + public static void registerOperator(int selector, String name) { + platformOperatorNames.put(selector, name); + platformOperatorSelectors.put(name, selector); + } + + /** + * INTERNAL: + * Create the AND operator. + */ + public static ExpressionOperator and() { + return simpleLogical(And, "AND", "and"); + } + + /** + * INTERNAL: + * Apply this to an object in memory. + * Throw an error if the function is not supported. + */ + public Object applyFunction(Object source, Vector arguments) { + if (source instanceof String) { + if (this.selector == ToUpperCase) { + return ((String)source).toUpperCase(); + } else if (this.selector == ToLowerCase) { + return ((String)source).toLowerCase(); + } else if ((this.selector == Concat) && (arguments.size() == 1) && (arguments.elementAt(0) instanceof String)) { + return ((String)source).concat((String)arguments.elementAt(0)); + } else if ((this.selector == Substring) && (arguments.size() == 2) && (arguments.elementAt(0) instanceof Number) && (arguments.elementAt(1) instanceof Number)) { + // assume the first parameter to be 1-based first index of the substring, the second - substring length. + int beginIndexInclusive = ((Number)arguments.elementAt(0)).intValue() - 1; + int endIndexExclusive = beginIndexInclusive + ((Number)arguments.elementAt(1)).intValue(); + return ((String)source).substring(beginIndexInclusive, endIndexExclusive); + } else if ((this.selector == SubstringSingleArg) && (arguments.size() == 1) && (arguments.elementAt(0) instanceof Number)) { + int beginIndexInclusive = ((Number)arguments.elementAt(0)).intValue() - 1; + int endIndexExclusive = ((String)source).length(); + return ((String)source).substring(beginIndexInclusive, endIndexExclusive); + } else if (this.selector == ToNumber) { + return new java.math.BigDecimal((String)source); + } else if (this.selector == Trim) { + return ((String)source).trim(); + } else if (this.selector == Length) { + return Integer.valueOf(((String)source).length()); + } + } else if (source instanceof Number) { + if (this.selector == Ceil) { + return Double.valueOf(Math.ceil(((Number)source).doubleValue())); + } else if (this.selector == Cos) { + return Double.valueOf(Math.cos(((Number)source).doubleValue())); + } else if (this.selector == Abs) { + return Double.valueOf(Math.abs(((Number)source).doubleValue())); + } else if (this.selector == Acos) { + return Double.valueOf(Math.acos(((Number)source).doubleValue())); + } else if (this.selector == Asin) { + return Double.valueOf(Math.asin(((Number)source).doubleValue())); + } else if (this.selector == Atan) { + return Double.valueOf(Math.atan(((Number)source).doubleValue())); + } else if (this.selector == Exp) { + return Double.valueOf(Math.exp(((Number)source).doubleValue())); + } else if (this.selector == Sqrt) { + return Double.valueOf(Math.sqrt(((Number)source).doubleValue())); + } else if (this.selector == Floor) { + return Double.valueOf(Math.floor(((Number)source).doubleValue())); + } else if (this.selector == Log) { + return Double.valueOf(Math.log(((Number)source).doubleValue())); + } else if ((this.selector == Power) && (arguments.size() == 1) && (arguments.elementAt(0) instanceof Number)) { + return Double.valueOf(Math.pow(((Number)source).doubleValue(), (((Number)arguments.elementAt(0)).doubleValue()))); + } else if (this.selector == Round) { + return Double.valueOf(Math.round(((Number)source).doubleValue())); + } else if (this.selector == Sin) { + return Double.valueOf(Math.sin(((Number)source).doubleValue())); + } else if (this.selector == Tan) { + return Double.valueOf(Math.tan(((Number)source).doubleValue())); + } else if ((this.selector == Greatest) && (arguments.size() == 1) && (arguments.elementAt(0) instanceof Number)) { + return Double.valueOf(Math.max(((Number)source).doubleValue(), (((Number)arguments.elementAt(0)).doubleValue()))); + } else if ((this.selector == Least) && (arguments.size() == 1) && (arguments.elementAt(0) instanceof Number)) { + return Double.valueOf(Math.min(((Number)source).doubleValue(), (((Number)arguments.elementAt(0)).doubleValue()))); + } else if ((this.selector == Add) && (arguments.size() == 1) && (arguments.elementAt(0) instanceof Number)) { + return Double.valueOf(((Number)source).doubleValue() + (((Number)arguments.elementAt(0)).doubleValue())); + } else if ((this.selector == Subtract) && (arguments.size() == 1) && (arguments.elementAt(0) instanceof Number)) { + return Double.valueOf(((Number)source).doubleValue() - (((Number)arguments.elementAt(0)).doubleValue())); + } else if ((this.selector == Divide) && (arguments.size() == 1) && (arguments.elementAt(0) instanceof Number)) { + return Double.valueOf(((Number)source).doubleValue() / (((Number)arguments.elementAt(0)).doubleValue())); + } else if ((this.selector == Multiply) && (arguments.size() == 1) && (arguments.elementAt(0) instanceof Number)) { + return Double.valueOf(((Number)source).doubleValue() * (((Number)arguments.elementAt(0)).doubleValue())); + } + } + + throw QueryException.cannotConformExpression(); + } + + /** + * INTERNAL: + * Create the ASCENDING operator. + */ + public static ExpressionOperator ascending() { + return simpleOrdering(Ascending, "ASC", "ascending"); + } + + /** + * INTERNAL: + * Create the AS operator. + */ + public static ExpressionOperator as() { + ExpressionOperator exOperator = new ExpressionOperator(); + exOperator.setType(FunctionOperator); + exOperator.setSelector(As); + exOperator.printsAs(" AS "); + exOperator.bePostfix(); + exOperator.setNodeClass(ClassConstants.FunctionExpression_Class); + return exOperator; + } + + /** + * INTERNAL: + * Create the NULLS FIRST ordering operator. + */ + public static ExpressionOperator nullsFirst() { + return simpleOrdering(NullsFirst, "NULLS FIRST", "nullsFirst"); + } + + /** + * INTERNAL: + * Create the NULLS LAST ordering operator. + */ + public static ExpressionOperator nullsLast() { + return simpleOrdering(NullsLast, "NULLS LAST", "nullsLast"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator ascii() { + return simpleFunction(Ascii, "ASCII"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator asin() { + return simpleFunction(Asin, "ASIN"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator atan() { + return simpleFunction(Atan, "ATAN"); + } + + /** + * INTERNAL: + * Create the AVERAGE operator. + */ + public static ExpressionOperator average() { + return simpleAggregate(Average, "AVG", "average"); + } + + /** + * ADVANCED: + * Tell the operator to be postfix, i.e. its strings start printing after + * those of its first argument. + */ + public void bePostfix() { + isPrefix = false; + } + + /** + * ADVANCED: + * Tell the operator to be pretfix, i.e. its strings start printing before + * those of its first argument. + */ + public void bePrefix() { + isPrefix = true; + } + + /** + * INTERNAL: + * Make this a repeating argument. Currently unused. + */ + public void beRepeating() { + isRepeating = true; + } + + /** + * INTERNAL: + * Create the BETWEEN Operator + */ + public static ExpressionOperator between() { + ExpressionOperator result = new ExpressionOperator(); + result.setSelector(Between); + result.setType(ComparisonOperator); + Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(); + v.add("("); + v.add(" BETWEEN "); + v.add(" AND "); + v.add(")"); + result.printsAs(v); + result.bePrefix(); + result.setNodeClass(ClassConstants.FunctionExpression_Class); + return result; + } + + /** + * INTERNAL: + * Create the LIKE operator with ESCAPE. + */ + 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. + * Note: This operator works differently from other operators. + * @see Expression#caseStatement(Map, Object) + */ + public static ExpressionOperator caseStatement() { + ListExpressionOperator exOperator = new ListExpressionOperator(); + exOperator.setType(FunctionOperator); + exOperator.setSelector(Case); + exOperator.bePrefix(); + exOperator.setNodeClass(ClassConstants.ArgumentListFunctionExpression_Class); + exOperator.setIsBindingSupported(false); + exOperator.setStartString("CASE "); + exOperator.setSeparators(new String[]{" WHEN ", " THEN "}); + exOperator.setTerminationStrings(new String[]{" ELSE ", " END"}); + return exOperator; + } + + /** + * INTERNAL: + * Build operator. + * Note: This operator works differently from other operators. + * @see Expression#caseStatement(Map, Object) + */ + public static ExpressionOperator caseConditionStatement() { + ListExpressionOperator exOperator = new ListExpressionOperator(); + exOperator.setType(FunctionOperator); + exOperator.setSelector(CaseCondition); + exOperator.bePrefix(); + exOperator.setNodeClass(ClassConstants.ArgumentListFunctionExpression_Class); + exOperator.setIsBindingSupported(false); + exOperator.setStartStrings(new String[]{"CASE WHEN ", " THEN "}); + exOperator.setSeparators(new String[]{" WHEN ", " THEN "}); + exOperator.setTerminationStrings(new String[]{" ELSE ", " END "}); + return exOperator; + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator ceil() { + return simpleFunction(Ceil, "CEIL"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator charIndex() { + return simpleTwoArgumentFunction(CharIndex, "CHARINDEX"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator charLength() { + return simpleFunction(CharLength, "CHAR_LENGTH"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator chr() { + return simpleFunction(Chr, "CHR"); + } + + /** + * INTERNAL: + * Build operator. + * Note: This operator works differently from other operators. + * @see Expression#caseStatement(Map, Object) + */ + public static ExpressionOperator coalesce() { + ListExpressionOperator exOperator = new ListExpressionOperator(); + exOperator.setType(FunctionOperator); + exOperator.setSelector(Coalesce); + exOperator.bePrefix(); + exOperator.setNodeClass(ClassConstants.ArgumentListFunctionExpression_Class); + exOperator.setStartString("COALESCE("); + exOperator.setSeparator(", "); + exOperator.setTerminationString(")"); + return exOperator; + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator concat() { + ExpressionOperator operator = simpleMath(Concat, "+"); + operator.setIsBindingSupported(false); + return operator; + } + + /** + * INTERNAL: + * Compare between in memory. + */ + public boolean conformBetween(Object left, Object right) { + Object start = ((Vector)right).elementAt(0); + Object end = ((Vector)right).elementAt(1); + if ((left == null) || (start == null) || (end == null)) { + return false; + } + if ((left instanceof Number) && (start instanceof Number) && (end instanceof Number)) { + return ((((Number)left).doubleValue()) >= (((Number)start).doubleValue())) && ((((Number)left).doubleValue()) <= (((Number)end).doubleValue())); + } else if ((left instanceof String) && (start instanceof String) && (end instanceof String)) { + return ((((String)left).compareTo(((String)start)) > 0) || (((String)left).compareTo(((String)start)) == 0)) && ((((String)left).compareTo(((String)end)) < 0) || (((String)left).compareTo(((String)end)) == 0)); + } else if ((left instanceof java.util.Date) && (start instanceof java.util.Date) && (end instanceof java.util.Date)) { + return (((java.util.Date)left).after(((java.util.Date)start)) || ((java.util.Date)left).equals((start))) && (((java.util.Date)left).before(((java.util.Date)end)) || ((java.util.Date)left).equals((end))); + } else if ((left instanceof java.util.Calendar) && (start instanceof java.util.Calendar) && (end instanceof java.util.Calendar)) { + return (((java.util.Calendar)left).after(start) || ((java.util.Calendar)left).equals((start))) && (((java.util.Calendar)left).before(end) || ((java.util.Calendar)left).equals((end))); + } + + throw QueryException.cannotConformExpression(); + } + + /** + * INTERNAL: + * Compare like in memory. + * This only works for % not _. + * @author Christian Weeks aka ChristianLink + */ + public boolean conformLike(Object left, Object right) { + if ((right == null) && (left == null)) { + return true; + } + if (!(right instanceof String) || !(left instanceof String)) { + throw QueryException.cannotConformExpression(); + } + String likeString = (String)right; + if (likeString.indexOf("_") != -1) { + throw QueryException.cannotConformExpression(); + } + String value = (String)left; + if (likeString.indexOf("%") == -1) { + // No % symbols + return left.equals(right); + } + boolean strictStart = !likeString.startsWith("%"); + boolean strictEnd = !likeString.endsWith("%"); + StringTokenizer tokens = new StringTokenizer(likeString, "%"); + int lastPosition = 0; + String lastToken = null; + if (strictStart) { + lastToken = tokens.nextToken(); + if (!value.startsWith(lastToken)) { + return false; + } + } + while (tokens.hasMoreTokens()) { + lastToken = tokens.nextToken(); + lastPosition = value.indexOf(lastToken, lastPosition); + if (lastPosition < 0) { + return false; + } + } + if (strictEnd) { + return value.endsWith(lastToken); + } + return true; + } + + public ExpressionOperator clone(){ + ExpressionOperator clone = new ExpressionOperator(); + this.copyTo(clone); + return clone; + } + + /** Copies this into argument ExpressionOperator */ + public void copyTo(ExpressionOperator operator){ + if(operator == null) + return; + + operator.selector = selector; + operator.isPrefix = isPrefix; + operator.isRepeating = isRepeating; + operator.nodeClass = nodeClass; + operator.type = type; + 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 == null ? null : new Boolean(isBindingSupported); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator cos() { + return simpleFunction(Cos, "COS"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator cosh() { + return simpleFunction(Cosh, "COSH"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator cot() { + return simpleFunction(Cot, "COT"); + } + + /** + * INTERNAL: + * Create the COUNT operator. + */ + public static ExpressionOperator count() { + return simpleAggregate(Count, "COUNT", "count"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator dateDifference() { + return simpleThreeArgumentFunction(DateDifference, "DATEDIFF"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator dateName() { + return simpleTwoArgumentFunction(DateName, "DATENAME"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator datePart() { + return simpleTwoArgumentFunction(DatePart, "DATEPART"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator dateToString() { + return simpleFunction(DateToString, "TO_CHAR"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator toChar() { + return simpleFunction(ToChar, "TO_CHAR"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator toCharWithFormat() { + return simpleTwoArgumentFunction(ToCharWithFormat, "TO_CHAR"); + } + + /** + * INTERNAL: + * Build operator. + * Note: This operator works differently from other operators. + * @see Expression#decode(Map, String) + */ + public static ExpressionOperator decode() { + ExpressionOperator exOperator = new ExpressionOperator(); + + exOperator.setSelector(Decode); + + exOperator.setNodeClass(FunctionExpression.class); + exOperator.setType(FunctionOperator); + exOperator.bePrefix(); + return exOperator; + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator deref() { + return simpleFunction(Deref, "DEREF"); + } + + /** + * INTERNAL: + * Create the DESCENDING operator. + */ + public static ExpressionOperator descending() { + return simpleOrdering(Descending, "DESC", "descending"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator difference() { + return simpleTwoArgumentFunction(Difference, "DIFFERENCE"); + } + + /** + * INTERNAL: + * Create the DISTINCT operator. + */ + 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. + * Used for in-memory querying, all operators are not support. + */ + public boolean doesRelationConform(Object left, Object right) { + // Big ugly case statement follows. + // Java is really verbose, the Smalltalk equivalent to this... left perform: self selector with: right + // Note, compareTo for String returns a number <= -1 if the String is less than. We assumed that + // it would return -1. The same thing for strings that are greater than (ie it returns >= 1). PWK + // Equals + + if (this.selector == Equal || this.selector == NotEqual) { + if ((left == null) && (right == null)) { + return this.selector == Equal; + } else if ((left == null) || (right == null)) { + return this.selector == NotEqual; + } + if (left instanceof Number && left instanceof Comparable && right instanceof Comparable + && left.getClass().equals (right.getClass())) { + return (((Comparable) left).compareTo( (Comparable) right) == 0) == (this.selector == Equal); + } + if (((left instanceof Number) && (right instanceof Number)) && (left.getClass() != right.getClass())) { + double leftDouble = ((Number)left).doubleValue(); + double rightDouble = ((Number)right).doubleValue(); + if (Double.isNaN(leftDouble) && Double.isNaN(rightDouble)){ + return this.selector == Equal; + } + return (leftDouble == rightDouble) == (this.selector == Equal); + } + return left.equals( right) == (this.selector == Equal); + } else if (this.selector == IsNull) { + return (left == null); + } + if (this.selector == NotNull) { + return (left != null); + } + // Less thans, greater thans + else if (this.selector == LessThan) {// You have got to love polymorphism in Java, NOT!!! + if ((left == null) || (right == null)) { + return false; + } + if ((left instanceof Number) && (right instanceof Number)) { + return (((Number)left).doubleValue()) < (((Number)right).doubleValue()); + } else if ((left instanceof String) && (right instanceof String)) { + return ((String)left).compareTo(((String)right)) < 0; + } else if ((left instanceof java.util.Date) && (right instanceof java.util.Date)) { + return ((java.util.Date)left).before(((java.util.Date)right)); + } else if ((left instanceof java.util.Calendar) && (right instanceof java.util.Calendar)) { + return ((java.util.Calendar)left).before(right); + } + } else if (this.selector == LessThanEqual) { + if ((left == null) && (right == null)) { + return true; + } else if ((left == null) || (right == null)) { + return false; + } + if ((left instanceof Number) && (right instanceof Number)) { + return (((Number)left).doubleValue()) <= (((Number)right).doubleValue()); + } else if ((left instanceof String) && (right instanceof String)) { + int compareValue = ((String)left).compareTo(((String)right)); + return (compareValue < 0) || (compareValue == 0); + } else if ((left instanceof java.util.Date) && (right instanceof java.util.Date)) { + return ((java.util.Date)left).equals((right)) || ((java.util.Date)left).before(((java.util.Date)right)); + } else if ((left instanceof java.util.Calendar) && (right instanceof java.util.Calendar)) { + return ((java.util.Calendar)left).equals((right)) || ((java.util.Calendar)left).before(right); + } + } else if (this.selector == GreaterThan) { + if ((left == null) || (right == null)) { + return false; + } + if ((left instanceof Number) && (right instanceof Number)) { + return (((Number)left).doubleValue()) > (((Number)right).doubleValue()); + } else if ((left instanceof String) && (right instanceof String)) { + int compareValue = ((String)left).compareTo(((String)right)); + return (compareValue > 0); + } else if ((left instanceof java.util.Date) && (right instanceof java.util.Date)) { + return ((java.util.Date)left).after(((java.util.Date)right)); + } else if ((left instanceof java.util.Calendar) && (right instanceof java.util.Calendar)) { + return ((java.util.Calendar)left).after(right); + } + } else if (this.selector == GreaterThanEqual) { + if ((left == null) && (right == null)) { + return true; + } else if ((left == null) || (right == null)) { + return false; + } + if ((left instanceof Number) && (right instanceof Number)) { + return (((Number)left).doubleValue()) >= (((Number)right).doubleValue()); + } else if ((left instanceof String) && (right instanceof String)) { + int compareValue = ((String)left).compareTo(((String)right)); + return (compareValue > 0) || (compareValue == 0); + } else if ((left instanceof java.util.Date) && (right instanceof java.util.Date)) { + return ((java.util.Date)left).equals((right)) || ((java.util.Date)left).after(((java.util.Date)right)); + } else if ((left instanceof java.util.Calendar) && (right instanceof java.util.Calendar)) { + return ((java.util.Calendar)left).equals((right)) || ((java.util.Calendar)left).after(right); + } + } + // Between + else if ((this.selector == Between) && (right instanceof Vector) && (((Vector)right).size() == 2)) { + return conformBetween(left, right); + } else if ((this.selector == NotBetween) && (right instanceof Vector) && (((Vector)right).size() == 2)) { + return !conformBetween(left, right); + } + // In + else if ((this.selector == In) && (right instanceof Collection)) { + return ((Collection)right).contains(left); + } else if ((this.selector == NotIn) && (right instanceof Collection)) { + return !((Collection)right).contains(left); + } + // Like + //conformLike(left, right); + else if (((this.selector == Like) || (this.selector == NotLike)) && (right instanceof Vector) && (((Vector)right).size() == 1)) { + Boolean doesLikeConform = JavaPlatform.conformLike(left, ((Vector)right).get(0)); + if (doesLikeConform != null) { + if (doesLikeConform.booleanValue()) { + return this.selector == Like;// Negate for NotLike + } else { + return this.selector != Like;// Negate for NotLike + } + } + } + // Regexp + else if ((this.selector == Regexp) && (right instanceof Vector) && (((Vector)right).size() == 1)) { + Boolean doesConform = JavaPlatform.conformRegexp(left, ((Vector)right).get(0)); + if (doesConform != null) { + return doesConform.booleanValue(); + } + } + + throw QueryException.cannotConformExpression(); + } + + public static ExpressionOperator equal() { + return ExpressionOperator.simpleRelation(ExpressionOperator.Equal, "=", "equal"); + } + + /** + * INTERNAL: + * Initialize the outer join operator + * Note: This is merely a shell which is incomplete, and + * so will be replaced by the platform's operator when we + * go to print. We need to create this here so that the expression + * class is correct, normally it assumes functions for unknown operators. + */ + public static ExpressionOperator equalOuterJoin() { + return simpleRelation(EqualOuterJoin, "=*"); + } + + /** + * INTERNAL: + * Create the EXISTS operator. + */ + public static ExpressionOperator exists() { + ExpressionOperator exOperator = new ExpressionOperator(); + exOperator.setType(FunctionOperator); + exOperator.setSelector(Exists); + Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(2); + v.add("EXISTS "); + v.add(""); + exOperator.printsAs(v); + exOperator.bePrefix(); + exOperator.setNodeClass(ClassConstants.FunctionExpression_Class); + return exOperator; + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator exp() { + return simpleFunction(Exp, "EXP"); + } + + /** + * INTERNAL: + * Create an expression for this operator, using the given base. + */ + public Expression expressionFor(Expression base) { + return expressionForArguments(base, org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(0)); + } + + /** + * INTERNAL: + * Create an expression for this operator, using the given base and a single argument. + */ + public Expression expressionFor(Expression base, Object value) { + return newExpressionForArgument(base, value); + } + + /** + * INTERNAL: + * Create an expression for this operator, using the given base and a single argument. + * Base is used last in the expression + */ + public Expression expressionForWithBaseLast(Expression base, Object value) { + return newExpressionForArgumentWithBaseLast(base, value); + } + + /** + * INTERNAL: + * Create an expression for this operator, using the given base and arguments. + */ + @Deprecated + public Expression expressionForArguments(Expression base, Vector arguments) { + return newExpressionForArguments(base, arguments); + } + + /** + * INTERNAL: + * Create an expression for this operator, using the given base and arguments. + */ + public Expression expressionForArguments(Expression base, List arguments) { + return newExpressionForArguments(base, arguments); + } + + /** + * INTERNAL: + * Create the extract expression operator + */ + public static ExpressionOperator extractXml() { + ExpressionOperator result = new ExpressionOperator(); + Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(); + v.add("extract("); + v.add(","); + v.add(")"); + result.printsAs(v); + result.bePrefix(); + result.setSelector(ExtractXml); + result.setNodeClass(ClassConstants.FunctionExpression_Class); + return result; + } + + /** + * INTERNAL: + * Create the extractValue expression operator + */ + public static ExpressionOperator extractValue() { + ExpressionOperator result = new ExpressionOperator(); + Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(); + v.add("extractValue("); + v.add(","); + v.add(")"); + result.printsAs(v); + result.bePrefix(); + result.setSelector(ExtractValue); + result.setNodeClass(ClassConstants.FunctionExpression_Class); + return result; + } + + /** + * INTERNAL: + * Create the existsNode expression operator + */ + public static ExpressionOperator existsNode() { + ExpressionOperator result = new ExpressionOperator(); + Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(); + v.add("existsNode("); + v.add(","); + v.add(")"); + result.printsAs(v); + result.bePrefix(); + result.setSelector(ExistsNode); + result.setNodeClass(ClassConstants.FunctionExpression_Class); + return result; + } + + public static ExpressionOperator getStringVal() { + ExpressionOperator result = new ExpressionOperator(); + Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(); + v.add(".getStringVal()"); + result.printsAs(v); + result.bePostfix(); + result.setSelector(GetStringVal); + result.setNodeClass(ClassConstants.FunctionExpression_Class); + return result; + } + + public static ExpressionOperator getNumberVal() { + ExpressionOperator result = new ExpressionOperator(); + Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(); + v.add(".getNumberVal()"); + result.printsAs(v); + result.bePostfix(); + result.setSelector(GetNumberVal); + result.setNodeClass(ClassConstants.FunctionExpression_Class); + return result; + } + + public static ExpressionOperator isFragment() { + ExpressionOperator result = new ExpressionOperator(); + Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(); + v.add(".isFragment()"); + result.printsAs(v); + result.bePostfix(); + result.setSelector(IsFragment); + result.setNodeClass(ClassConstants.FunctionExpression_Class); + return result; + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator floor() { + return simpleFunction(Floor, "FLOOR"); + } + + /** + * ADVANCED: + * Return the map of all operators. + */ + public static Map getAllOperators() { + return allOperators; + } + + /** + * INTERNAL: + */ + public static Map getAllInternalOperators() { + return allInternalOperators; + } + + public static Map getPlatformOperatorSelectors() { + return platformOperatorSelectors; + } + + /** + * INTERNAL: + */ + @Deprecated + public String[] getDatabaseStrings() { + return databaseStrings; + } + + /** + * INTERNAL: + */ + public String[] getDatabaseStrings(int arguments) { + return databaseStrings; + } + + /** + * INTERNAL: + */ + public String[] getJavaStrings() { + return javaStrings; + } + + /** + * INTERNAL: + */ + public Class getNodeClass() { + return nodeClass; + } + + /** + * 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. + */ + public int getSelector() { + return selector; + } + + /** + * INTERNAL: + * Return the name. + */ + public String getName() { + return name; + } + + /** + * INTERNAL: + * Set the name. + */ + public void setName(String name) { + this.name = name; + } + + /** + * ADVANCED: + * Return the type of function. + * This must be one of the static function types defined in this class. + */ + 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. + */ + public static ExpressionOperator greatest() { + return simpleTwoArgumentFunction(Greatest, "GREATEST"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator hexToRaw() { + return simpleFunction(HexToRaw, "HEXTORAW"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator ifNull() { + return simpleTwoArgumentFunction(Nvl, "NVL"); + } + + /** + * INTERNAL: + * Create the IN operator. + */ + public static ExpressionOperator in() { + return simpleRelation(In, "IN"); + } + + /** + * INTERNAL: + * Create the IN operator taking a subquery. + * Note, the subquery itself comes with parenethesis, so the IN operator + * should not add any parenethesis. + */ + public static ExpressionOperator inSubQuery() { + ExpressionOperator result = new ExpressionOperator(); + result.setType(ExpressionOperator.FunctionOperator); + result.setSelector(InSubQuery); + Vector v = new Vector(1); + v.add(" IN "); + result.printsAs(v); + result.bePostfix(); + result.setNodeClass(ClassConstants.FunctionExpression_Class); + return result; + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator initcap() { + return simpleFunction(Initcap, "INITCAP"); + } + + /** + * INTERNAL: + */ + protected static void initializeAggregateFunctionOperators() { + addOperator(count()); + addOperator(sum()); + addOperator(average()); + addOperator(minimum()); + addOperator(maximum()); + } + + /** + * 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(as()); + addOperator(any()); + addOperator(some()); + addOperator(all()); + addOperator(inSubQuery()); + addOperator(notInSubQuery()); + addOperator(coalesce()); + addOperator(caseStatement()); + addOperator(caseConditionStatement()); + addOperator(distinct()); + } + + /** + * INTERNAL: + */ + protected static void initializeLogicalOperators() { + // Logical Operators + addOperator(and()); + addOperator(or()); + } + + /** + * 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()); + } + + /** + * INTERNAL: + */ + public static Map initializeOperators() { + resetOperators(); + 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. + */ + public static String getPlatformOperatorName(int operator) { + String name = (String)getPlatformOperatorNames().get(Integer.valueOf(operator)); + if (name == null) { + name = String.valueOf(operator); + } + return name; + } + + /** + * INTERNAL: + * Initialize a mapping to the platform operator names for usage with exceptions. + */ + public static Map getPlatformOperatorNames() { + return platformOperatorNames; + } + + /** + * INTERNAL: + * Initialize a mapping to the platform operator names for usage with exceptions. + */ + public static Map initializePlatformOperatorNames() { + Map platformOperatorNames = new HashMap(); + platformOperatorNames.put(Integer.valueOf(ToUpperCase), "ToUpperCase"); + platformOperatorNames.put(Integer.valueOf(ToLowerCase), "ToLowerCase"); + platformOperatorNames.put(Integer.valueOf(Chr), "Chr"); + platformOperatorNames.put(Integer.valueOf(Concat), "Concat"); + platformOperatorNames.put(Integer.valueOf(Coalesce), "Coalesce"); + platformOperatorNames.put(Integer.valueOf(Case), "Case"); + platformOperatorNames.put(Integer.valueOf(CaseCondition), "Case(codition)"); + platformOperatorNames.put(Integer.valueOf(HexToRaw), "HexToRaw"); + platformOperatorNames.put(Integer.valueOf(Initcap), "Initcap"); + platformOperatorNames.put(Integer.valueOf(Instring), "Instring"); + platformOperatorNames.put(Integer.valueOf(Soundex), "Soundex"); + platformOperatorNames.put(Integer.valueOf(LeftPad), "LeftPad"); + platformOperatorNames.put(Integer.valueOf(LeftTrim), "LeftTrim"); + platformOperatorNames.put(Integer.valueOf(RightPad), "RightPad"); + platformOperatorNames.put(Integer.valueOf(RightTrim), "RightTrim"); + platformOperatorNames.put(Integer.valueOf(Substring), "Substring"); + platformOperatorNames.put(Integer.valueOf(SubstringSingleArg), "Substring"); + platformOperatorNames.put(Integer.valueOf(Translate), "Translate"); + platformOperatorNames.put(Integer.valueOf(Ascii), "Ascii"); + platformOperatorNames.put(Integer.valueOf(Length), "Length"); + platformOperatorNames.put(Integer.valueOf(CharIndex), "CharIndex"); + platformOperatorNames.put(Integer.valueOf(CharLength), "CharLength"); + platformOperatorNames.put(Integer.valueOf(Difference), "Difference"); + platformOperatorNames.put(Integer.valueOf(Reverse), "Reverse"); + platformOperatorNames.put(Integer.valueOf(Replicate), "Replicate"); + platformOperatorNames.put(Integer.valueOf(Right), "Right"); + platformOperatorNames.put(Integer.valueOf(Locate), "Locate"); + platformOperatorNames.put(Integer.valueOf(Locate2), "Locate"); + platformOperatorNames.put(Integer.valueOf(ToNumber), "ToNumber"); + platformOperatorNames.put(Integer.valueOf(ToChar), "ToChar"); + platformOperatorNames.put(Integer.valueOf(ToCharWithFormat), "ToChar"); + platformOperatorNames.put(Integer.valueOf(AddMonths), "AddMonths"); + platformOperatorNames.put(Integer.valueOf(DateToString), "DateToString"); + platformOperatorNames.put(Integer.valueOf(MonthsBetween), "MonthsBetween"); + platformOperatorNames.put(Integer.valueOf(NextDay), "NextDay"); + platformOperatorNames.put(Integer.valueOf(RoundDate), "RoundDate"); + platformOperatorNames.put(Integer.valueOf(AddDate), "AddDate"); + platformOperatorNames.put(Integer.valueOf(DateName), "DateName"); + platformOperatorNames.put(Integer.valueOf(DatePart), "DatePart"); + platformOperatorNames.put(Integer.valueOf(DateDifference), "DateDifference"); + platformOperatorNames.put(Integer.valueOf(TruncateDate), "TruncateDate"); + platformOperatorNames.put(Integer.valueOf(Extract), "Extract"); + platformOperatorNames.put(Integer.valueOf(Cast), "Cast"); + platformOperatorNames.put(Integer.valueOf(NewTime), "NewTime"); + platformOperatorNames.put(Integer.valueOf(Nvl), "Nvl"); + platformOperatorNames.put(Integer.valueOf(NewTime), "NewTime"); + platformOperatorNames.put(Integer.valueOf(Ceil), "Ceil"); + platformOperatorNames.put(Integer.valueOf(Cos), "Cos"); + platformOperatorNames.put(Integer.valueOf(Cosh), "Cosh"); + platformOperatorNames.put(Integer.valueOf(Abs), "Abs"); + platformOperatorNames.put(Integer.valueOf(Acos), "Acos"); + platformOperatorNames.put(Integer.valueOf(Asin), "Asin"); + platformOperatorNames.put(Integer.valueOf(Atan), "Atan"); + platformOperatorNames.put(Integer.valueOf(Exp), "Exp"); + platformOperatorNames.put(Integer.valueOf(Sqrt), "Sqrt"); + platformOperatorNames.put(Integer.valueOf(Floor), "Floor"); + platformOperatorNames.put(Integer.valueOf(Ln), "Ln"); + platformOperatorNames.put(Integer.valueOf(Log), "Log"); + platformOperatorNames.put(Integer.valueOf(Mod), "Mod"); + platformOperatorNames.put(Integer.valueOf(Power), "Power"); + platformOperatorNames.put(Integer.valueOf(Round), "Round"); + platformOperatorNames.put(Integer.valueOf(Sign), "Sign"); + platformOperatorNames.put(Integer.valueOf(Sin), "Sin"); + platformOperatorNames.put(Integer.valueOf(Sinh), "Sinh"); + platformOperatorNames.put(Integer.valueOf(Tan), "Tan"); + platformOperatorNames.put(Integer.valueOf(Tanh), "Tanh"); + platformOperatorNames.put(Integer.valueOf(Trunc), "Trunc"); + platformOperatorNames.put(Integer.valueOf(Greatest), "Greatest"); + platformOperatorNames.put(Integer.valueOf(Least), "Least"); + platformOperatorNames.put(Integer.valueOf(Add), "Add"); + platformOperatorNames.put(Integer.valueOf(Subtract), "Subtract"); + platformOperatorNames.put(Integer.valueOf(Divide), "Divide"); + platformOperatorNames.put(Integer.valueOf(Multiply), "Multiply"); + platformOperatorNames.put(Integer.valueOf(Atan2), "Atan2"); + platformOperatorNames.put(Integer.valueOf(Cot), "Cot"); + platformOperatorNames.put(Integer.valueOf(Deref), "Deref"); + platformOperatorNames.put(Integer.valueOf(Ref), "Ref"); + platformOperatorNames.put(Integer.valueOf(RefToHex), "RefToHex"); + platformOperatorNames.put(Integer.valueOf(Value), "Value"); + platformOperatorNames.put(Integer.valueOf(ExtractXml), "ExtractXml"); + platformOperatorNames.put(Integer.valueOf(ExtractValue), "ExtractValue"); + platformOperatorNames.put(Integer.valueOf(ExistsNode), "ExistsNode"); + platformOperatorNames.put(Integer.valueOf(GetStringVal), "GetStringVal"); + platformOperatorNames.put(Integer.valueOf(GetNumberVal), "GetNumberVal"); + platformOperatorNames.put(Integer.valueOf(IsFragment), "IsFragment"); + platformOperatorNames.put(Integer.valueOf(SDO_WITHIN_DISTANCE), "MDSYS.SDO_WITHIN_DISTANCE"); + platformOperatorNames.put(Integer.valueOf(SDO_RELATE), "MDSYS.SDO_RELATE"); + platformOperatorNames.put(Integer.valueOf(SDO_FILTER), "MDSYS.SDO_FILTER"); + platformOperatorNames.put(Integer.valueOf(SDO_NN), "MDSYS.SDO_NN"); + platformOperatorNames.put(Integer.valueOf(NullIf), "NullIf"); + platformOperatorNames.put(Integer.valueOf(Regexp), "REGEXP"); + platformOperatorNames.put(Integer.valueOf(Union), "UNION"); + platformOperatorNames.put(Integer.valueOf(UnionAll), "UNION ALL"); + platformOperatorNames.put(Integer.valueOf(Intersect), "INTERSECT"); + platformOperatorNames.put(Integer.valueOf(IntersectAll), "INTERSECT ALL"); + platformOperatorNames.put(Integer.valueOf(Except), "EXCEPT"); + platformOperatorNames.put(Integer.valueOf(ExceptAll), "EXCEPT ALL"); + return platformOperatorNames; + } + + /** + * INTERNAL: + * Initialize a mapping to the platform operator names for usage with exceptions. + */ + public static Map initializePlatformOperatorSelectors() { + Map platformOperatorNames = new HashMap(); + platformOperatorNames.put("ToUpperCase", Integer.valueOf(ToUpperCase)); + platformOperatorNames.put("ToLowerCase", Integer.valueOf(ToLowerCase)); + platformOperatorNames.put("Chr", Integer.valueOf(Chr)); + platformOperatorNames.put("Concat", Integer.valueOf(Concat)); + platformOperatorNames.put("Coalesce", Integer.valueOf(Coalesce)); + platformOperatorNames.put("Case", Integer.valueOf(Case)); + platformOperatorNames.put("HexToRaw", Integer.valueOf(HexToRaw)); + platformOperatorNames.put("Initcap", Integer.valueOf(Initcap)); + platformOperatorNames.put("Instring", Integer.valueOf(Instring)); + platformOperatorNames.put("Soundex", Integer.valueOf(Soundex)); + platformOperatorNames.put("LeftPad", Integer.valueOf(LeftPad)); + platformOperatorNames.put("LeftTrim", Integer.valueOf(LeftTrim)); + platformOperatorNames.put("RightPad", Integer.valueOf(RightPad)); + platformOperatorNames.put("RightTrim", Integer.valueOf(RightTrim)); + platformOperatorNames.put("Substring", Integer.valueOf(Substring)); + platformOperatorNames.put("Translate", Integer.valueOf(Translate)); + platformOperatorNames.put("Ascii", Integer.valueOf(Ascii)); + platformOperatorNames.put("Length", Integer.valueOf(Length)); + platformOperatorNames.put("CharIndex", Integer.valueOf(CharIndex)); + platformOperatorNames.put("CharLength", Integer.valueOf(CharLength)); + platformOperatorNames.put("Difference", Integer.valueOf(Difference)); + platformOperatorNames.put("Reverse", Integer.valueOf(Reverse)); + platformOperatorNames.put("Replicate", Integer.valueOf(Replicate)); + platformOperatorNames.put("Right", Integer.valueOf(Right)); + platformOperatorNames.put("Locate", Integer.valueOf(Locate)); + platformOperatorNames.put("ToNumber", Integer.valueOf(ToNumber)); + platformOperatorNames.put("ToChar", Integer.valueOf(ToChar)); + platformOperatorNames.put("AddMonths", Integer.valueOf(AddMonths)); + platformOperatorNames.put("DateToString", Integer.valueOf(DateToString)); + platformOperatorNames.put("MonthsBetween", Integer.valueOf(MonthsBetween)); + platformOperatorNames.put("NextDay", Integer.valueOf(NextDay)); + platformOperatorNames.put("RoundDate", Integer.valueOf(RoundDate)); + platformOperatorNames.put("AddDate", Integer.valueOf(AddDate)); + platformOperatorNames.put("DateName", Integer.valueOf(DateName)); + platformOperatorNames.put("DatePart", Integer.valueOf(DatePart)); + platformOperatorNames.put("DateDifference", Integer.valueOf(DateDifference)); + platformOperatorNames.put("TruncateDate", Integer.valueOf(TruncateDate)); + platformOperatorNames.put("NewTime", Integer.valueOf(NewTime)); + platformOperatorNames.put("Nvl", Integer.valueOf(Nvl)); + platformOperatorNames.put("NewTime", Integer.valueOf(NewTime)); + platformOperatorNames.put("Ceil", Integer.valueOf(Ceil)); + platformOperatorNames.put("Cos", Integer.valueOf(Cos)); + platformOperatorNames.put("Cosh", Integer.valueOf(Cosh)); + platformOperatorNames.put("Abs", Integer.valueOf(Abs)); + platformOperatorNames.put("Acos", Integer.valueOf(Acos)); + platformOperatorNames.put("Asin", Integer.valueOf(Asin)); + platformOperatorNames.put("Atan", Integer.valueOf(Atan)); + platformOperatorNames.put("Exp", Integer.valueOf(Exp)); + platformOperatorNames.put("Sqrt", Integer.valueOf(Sqrt)); + platformOperatorNames.put("Floor", Integer.valueOf(Floor)); + platformOperatorNames.put("Ln", Integer.valueOf(Ln)); + platformOperatorNames.put("Log", Integer.valueOf(Log)); + platformOperatorNames.put("Mod", Integer.valueOf(Mod)); + platformOperatorNames.put("Power", Integer.valueOf(Power)); + platformOperatorNames.put("Round", Integer.valueOf(Round)); + platformOperatorNames.put("Sign", Integer.valueOf(Sign)); + platformOperatorNames.put("Sin", Integer.valueOf(Sin)); + platformOperatorNames.put("Sinh", Integer.valueOf(Sinh)); + platformOperatorNames.put("Tan", Integer.valueOf(Tan)); + platformOperatorNames.put("Tanh", Integer.valueOf(Tanh)); + platformOperatorNames.put("Trunc", Integer.valueOf(Trunc)); + platformOperatorNames.put("Greatest", Integer.valueOf(Greatest)); + platformOperatorNames.put("Least", Integer.valueOf(Least)); + platformOperatorNames.put("Add", Integer.valueOf(Add)); + platformOperatorNames.put("Subtract", Integer.valueOf(Subtract)); + platformOperatorNames.put("Divide", Integer.valueOf(Divide)); + platformOperatorNames.put("Multiply", Integer.valueOf(Multiply)); + platformOperatorNames.put("Atan2", Integer.valueOf(Atan2)); + platformOperatorNames.put("Cot", Integer.valueOf(Cot)); + platformOperatorNames.put("Deref", Integer.valueOf(Deref)); + platformOperatorNames.put("Ref", Integer.valueOf(Ref)); + platformOperatorNames.put("RefToHex", Integer.valueOf(RefToHex)); + platformOperatorNames.put("Value", Integer.valueOf(Value)); + platformOperatorNames.put("Cast", Integer.valueOf(Cast)); + platformOperatorNames.put("Extract", Integer.valueOf(Extract)); + platformOperatorNames.put("ExtractXml", Integer.valueOf(ExtractXml)); + platformOperatorNames.put("ExtractValue", Integer.valueOf(ExtractValue)); + platformOperatorNames.put("ExistsNode", Integer.valueOf(ExistsNode)); + platformOperatorNames.put("GetStringVal", Integer.valueOf(GetStringVal)); + platformOperatorNames.put("GetNumberVal", Integer.valueOf(GetNumberVal)); + platformOperatorNames.put("IsFragment", Integer.valueOf(IsFragment)); + platformOperatorNames.put("SDO_WITHIN_DISTANCE", Integer.valueOf(SDO_WITHIN_DISTANCE)); + platformOperatorNames.put("SDO_RELATE", Integer.valueOf(SDO_RELATE)); + platformOperatorNames.put("SDO_FILTER", Integer.valueOf(SDO_FILTER)); + platformOperatorNames.put("SDO_NN", Integer.valueOf(SDO_NN)); + platformOperatorNames.put("NullIf", Integer.valueOf(NullIf)); + return platformOperatorNames; + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator instring() { + return simpleTwoArgumentFunction(Instring, "INSTR"); + } + + /** + * Aggregate functions are function in the select such as COUNT. + */ + public boolean isAggregateOperator() { + return getType() == AggregateOperator; + } + + /** + * Comparison functions are functions such as = and {@literal >}. + */ + public boolean isComparisonOperator() { + return getType() == ComparisonOperator; + } + + /** + * INTERNAL: + * If we have all the required information, this operator is complete + * and can be used as is. Otherwise we will need to look up a platform- + * specific operator. + */ + public boolean isComplete() { + return (databaseStrings != null) && (databaseStrings.length != 0); + } + + /** + * General functions are any normal function such as UPPER. + */ + public boolean isFunctionOperator() { + return getType() == FunctionOperator; + } + + /** + * Logical functions are functions such as and and or. + */ + public boolean isLogicalOperator() { + return getType() == LogicalOperator; + } + + /** + * INTERNAL: + * Create the ISNULL operator. + */ + public static ExpressionOperator isNull() { + ExpressionOperator result = new ExpressionOperator(); + result.setType(ComparisonOperator); + result.setSelector(IsNull); + Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(); + v.add("("); + v.add(" IS NULL)"); + result.printsAs(v); + result.bePrefix(); + result.printsJavaAs(".isNull()"); + result.setNodeClass(ClassConstants.FunctionExpression_Class); + return result; + } + + /** + * Order functions are used in the order by such as ASC. + */ + public boolean isOrderOperator() { + return getType() == OrderOperator; + } + + /** + * ADVANCED: + * Return true if this is a prefix operator. + */ + public boolean isPrefix() { + return isPrefix; + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator lastDay() { + return simpleFunction(LastDay, "LAST_DAY"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator least() { + return simpleTwoArgumentFunction(Least, "LEAST"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator leftPad() { + return simpleThreeArgumentFunction(LeftPad, "LPAD"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator leftTrim() { + return simpleFunction(LeftTrim, "LTRIM"); + } + + /** + * INTERNAL: + * Build leftTrim operator that takes one parameter. + */ + public static ExpressionOperator leftTrim2() { + ExpressionOperator operator = simpleTwoArgumentFunction(LeftTrim2, "LTRIM"); + return operator; + } + + /** + * INTERNAL: + * Build operator. + */ + 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. + */ + public static ExpressionOperator like() { + ExpressionOperator result = new ExpressionOperator(); + result.setSelector(Like); + result.setType(FunctionOperator); + Vector v = NonSynchronizedVector.newInstance(3); + v.add(""); + v.add(" LIKE "); + v.add(""); + result.printsAs(v); + result.bePrefix(); + result.setNodeClass(ClassConstants.FunctionExpression_Class); + v = NonSynchronizedVector.newInstance(2); + v.add(".like("); + v.add(")"); + result.printsJavaAs(v); + return result; + } + + /** + * INTERNAL: + * Create the REGEXP operator. + * REGEXP allows for comparison through regular expression, + * this is supported by many databases and with be part of the next SQL standard. + */ + public static ExpressionOperator regexp() { + ExpressionOperator result = new ExpressionOperator(); + result.setSelector(Regexp); + result.setType(FunctionOperator); + Vector v = NonSynchronizedVector.newInstance(3); + v.add(""); + v.add(" REGEXP "); + v.add(""); + result.printsAs(v); + result.bePrefix(); + result.setNodeClass(ClassConstants.FunctionExpression_Class); + v = NonSynchronizedVector.newInstance(2); + v.add(".regexp("); + v.add(")"); + result.printsJavaAs(v); + return result; + } + + /** + * INTERNAL: + * Create the LIKE operator with ESCAPE. + */ + public static ExpressionOperator likeEscape() { + ExpressionOperator result = new ExpressionOperator(); + result.setSelector(LikeEscape); + result.setType(FunctionOperator); + Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(); + v.add(""); + v.add(" LIKE "); + v.add(" ESCAPE "); + v.add(""); + result.printsAs(v); + result.bePrefix(); + result.setNodeClass(ClassConstants.FunctionExpression_Class); + result.setIsBindingSupported(false); + return result; + } + + /** + * INTERNAL: + * Create the LIKE operator with ESCAPE. + */ + public static ExpressionOperator notLikeEscape() { + ExpressionOperator result = new ExpressionOperator(); + result.setSelector(NotLikeEscape); + result.setType(FunctionOperator); + Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(); + v.add(""); + v.add(" NOT LIKE "); + v.add(" ESCAPE "); + v.add(""); + result.printsAs(v); + result.bePrefix(); + result.setNodeClass(ClassConstants.FunctionExpression_Class); + result.setIsBindingSupported(false); + return result; + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator ln() { + return simpleFunction(Ln, "LN"); + } + + /** + * INTERNAL: + * Build locate operator i.e. LOCATE("ob", t0.F_NAME) + */ + public static ExpressionOperator locate() { + ExpressionOperator expOperator = simpleTwoArgumentFunction(Locate, "LOCATE"); + int[] argumentIndices = new int[2]; + argumentIndices[0] = 1; + argumentIndices[1] = 0; + expOperator.setArgumentIndices(argumentIndices); + expOperator.setIsBindingSupported(false); + return expOperator; + } + + /** + * INTERNAL: + * Build locate operator with 3 params i.e. LOCATE("coffee", t0.DESCRIP, 4). + * Last parameter is a start at. + */ + public static ExpressionOperator locate2() { + ExpressionOperator expOperator = simpleThreeArgumentFunction(Locate2, "LOCATE"); + int[] argumentIndices = new int[3]; + argumentIndices[0] = 1; + argumentIndices[1] = 0; + argumentIndices[2] = 2; + expOperator.setArgumentIndices(argumentIndices); + expOperator.setIsBindingSupported(false); + return expOperator; + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator log() { + return simpleFunction(Log, "LOG"); + } + + /** + * INTERNAL: + * Create the MAXIMUM operator. + */ + public static ExpressionOperator maximum() { + return simpleAggregate(Maximum, "MAX", "maximum"); + } + + /** + * INTERNAL: + * Create the MINIMUM operator. + */ + public static ExpressionOperator minimum() { + return simpleAggregate(Minimum, "MIN", "minimum"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator mod() { + ExpressionOperator operator = simpleTwoArgumentFunction(Mod, "MOD"); + operator.setIsBindingSupported(false); + return operator; + } + + /** + * INTERNAL: + * Build operator. + */ + 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. + */ + public Expression newExpressionForArgument(Expression base, Object singleArgument) { + if (singleArgument == null) { + if (this.selector == Equal) { + return base.isNull(); + } else if (this.selector == NotEqual) { + return base.notNull(); + } + } + Expression node = createNode(); + node.create(base, singleArgument, this); + return node; + } + + /** + * INTERNAL: + * Instantiate an instance of the operator's node class. + */ + protected Expression createNode() { + // PERF: Avoid reflection for common cases. + if (this.nodeClass == ClassConstants.ArgumentListFunctionExpression_Class){ + return new ArgumentListFunctionExpression(); + } else if (this.nodeClass == ClassConstants.FunctionExpression_Class) { + return new FunctionExpression(); + + } else if (this.nodeClass == ClassConstants.RelationExpression_Class) { + return new RelationExpression(); + } else if (this.nodeClass == ClassConstants.LogicalExpression_Class) { + return new LogicalExpression(); + } + try { + Expression node = null; + if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){ + try { + node = (Expression)AccessController.doPrivileged(new PrivilegedNewInstanceFromClass(getNodeClass())); + } catch (PrivilegedActionException exception) { + return null; + } + } else { + node = (Expression)PrivilegedAccessHelper.newInstanceFromClass(getNodeClass()); + } + return node; + } catch (InstantiationException exception) { + throw new InternalError(exception.toString()); + } catch (IllegalAccessException exception) { + throw new InternalError(exception.toString()); + } + } + + /** + * INTERNAL: + * Create a new expression. Optimized for the single argument case with base last + */ + public Expression newExpressionForArgumentWithBaseLast(Expression base, Object singleArgument) { + if (singleArgument == null) { + if (this.selector == Equal) { + return base.isNull(); + } else if (this.selector == NotEqual) { + return base.notNull(); + } + } + Expression node = createNode(); + node.createWithBaseLast(base, singleArgument, this); + return node; + } + + /** + * INTERNAL: + * The general case. + */ + public Expression newExpressionForArguments(Expression base, List arguments) { + if ((arguments.size() == 1) && (arguments.get(0) == null)) { + if (this.selector == Equal) { + return base.isNull(); + } else if (this.selector == NotEqual) { + return base.notNull(); + } + } + Expression node = createNode(); + node.create(base, arguments, this); + return node; + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator negate() { + return simpleFunction(Negate, "-"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator newTime() { + return simpleThreeArgumentFunction(NewTime, "NEW_TIME"); + } + + /** + * INTERNAL: + * Build operator. + */ + 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. + */ + public static ExpressionOperator notExists() { + ExpressionOperator exOperator = new ExpressionOperator(); + exOperator.setType(FunctionOperator); + exOperator.setSelector(NotExists); + Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(2); + v.add("NOT EXISTS "); + v.add(""); + exOperator.printsAs(v); + exOperator.bePrefix(); + exOperator.setNodeClass(ClassConstants.FunctionExpression_Class); + return exOperator; + } + + /** + * INTERNAL: + * Create the NOTIN operator. + */ + public static ExpressionOperator notIn() { + return simpleRelation(NotIn, "NOT IN"); + } + + /** + * INTERNAL: + * Create the NOTIN operator taking a subQuery. + * Note, the subquery itself comes with parenethesis, so the IN operator + * should not add any parenethesis. + */ + public static ExpressionOperator notInSubQuery() { + ExpressionOperator result = new ExpressionOperator(); + result.setType(ExpressionOperator.FunctionOperator); + result.setSelector(NotInSubQuery); + Vector v = new Vector(1); + v.add(" NOT IN "); + result.printsAs(v); + result.bePostfix(); + result.setNodeClass(ClassConstants.FunctionExpression_Class); + return result; + } + + /** + * INTERNAL: + * Create the NOTLIKE operator. + */ + public static ExpressionOperator notLike() { + ExpressionOperator result = new ExpressionOperator(); + result.setSelector(NotLike); + result.setType(FunctionOperator); + Vector v = NonSynchronizedVector.newInstance(); + v.add(""); + v.add(" NOT LIKE "); + v.add(""); + result.printsAs(v); + result.bePrefix(); + result.setNodeClass(ClassConstants.FunctionExpression_Class); + v = NonSynchronizedVector.newInstance(2); + v.add(".notLike("); + v.add(")"); + result.printsJavaAs(v); + return result; + } + + /** + * INTERNAL: + * Create the NOTNULL operator. + */ + public static ExpressionOperator notNull() { + ExpressionOperator result = new ExpressionOperator(); + result.setType(ComparisonOperator); + result.setSelector(NotNull); + Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(); + v.add("("); + v.add(" IS NOT NULL)"); + result.printsAs(v); + result.bePrefix(); + result.printsJavaAs(".notNull()"); + result.setNodeClass(ClassConstants.FunctionExpression_Class); + return result; + } + + /** + * INTERNAL: + * Create the NOT operator. + */ + public static ExpressionOperator notOperator() { + ExpressionOperator result = new ExpressionOperator(); + result.setSelector(Not); + Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(); + v.add("NOT ("); + v.add(")"); + result.printsAs(v); + result.bePrefix(); + result.printsJavaAs(".not()"); + result.setNodeClass(ClassConstants.FunctionExpression_Class); + return result; + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator nullIf() { + return simpleTwoArgumentFunction(NullIf, "NULLIF"); + } + + /** + * INTERNAL: + * Create the OR operator. + */ + public static ExpressionOperator or() { + return simpleLogical(Or, "OR", "or"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator power() { + return simpleTwoArgumentFunction(Power, "POWER"); + } + + /** + * INTERNAL: Print the collection onto the SQL stream. + */ + public void printCollection(Vector 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; + if (isPrefix()) { + printer.printString(getDatabaseStrings()[0]); + dbStringIndex = 1; + } + + int[] indices = getArgumentIndices(items.size()); + String[] dbStrings = getDatabaseStrings(items.size()); + for (int i = 0; i < indices.length; i++) { + final int index = indices[i]; + Expression item = (Expression)items.elementAt(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())); + } else if ((this.selector == Count) && (item.isExpressionBuilder())) { + printer.printString("*"); + } else { + item.printSQL(printer); + } + if (dbStringIndex < dbStrings.length) { + printer.printString(dbStrings[dbStringIndex++]); + } + } + } + + /** + * INTERNAL: Print the collection onto the SQL stream. + */ + public void printJavaCollection(Vector items, ExpressionJavaPrinter printer) { + int javaStringIndex = 0; + + for (int i = 0; i < items.size(); i++) { + Expression item = (Expression)items.elementAt(i); + item.printJava(printer); + if (javaStringIndex < getJavaStrings().length) { + printer.printString(getJavaStrings()[javaStringIndex++]); + } + } + } + + /** + * INTERNAL: + * For performance, special case printing two children, since it's by far the most common + */ + public void printDuo(Expression first, Expression second, 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; + if (isPrefix()) { + printer.printString(getDatabaseStrings()[0]); + dbStringIndex = 1; + } + + first.printSQL(printer); + if (dbStringIndex < getDatabaseStrings().length) { + printer.printString(getDatabaseStrings()[dbStringIndex++]); + } + if (second != null) { + second.printSQL(printer); + if (dbStringIndex < getDatabaseStrings().length) { + printer.printString(getDatabaseStrings()[dbStringIndex++]); + } + } + } + + /** + * INTERNAL: + * For performance, special case printing two children, since it's by far the most common + */ + public void printJavaDuo(Expression first, Expression second, ExpressionJavaPrinter printer) { + int javaStringIndex = 0; + + first.printJava(printer); + if (javaStringIndex < getJavaStrings().length) { + printer.printString(getJavaStrings()[javaStringIndex++]); + } + if (second != null) { + second.printJava(printer); + if (javaStringIndex < getJavaStrings().length) { + printer.printString(getJavaStrings()[javaStringIndex]); + } + } + } + + /** + * ADVANCED: + * Set the single string for this operator. + */ + public void printsAs(String s) { + Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(1); + v.add(s); + printsAs(v); + } + + /** + * ADVANCED: + * Set the strings for this operator. + */ + public void printsAs(Vector dbStrings) { + this.databaseStrings = new String[dbStrings.size()]; + for (int i = 0; i < dbStrings.size(); i++) { + getDatabaseStrings()[i] = (String)dbStrings.elementAt(i); + } + } + + /** + * ADVANCED: + * Set the single string for this operator. + */ + public void printsJavaAs(String s) { + Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(1); + v.add(s); + printsJavaAs(v); + } + + /** + * ADVANCED: + * Set the strings for this operator. + */ + public void printsJavaAs(Vector dbStrings) { + this.javaStrings = new String[dbStrings.size()]; + for (int i = 0; i < dbStrings.size(); i++) { + getJavaStrings()[i] = (String)dbStrings.elementAt(i); + } + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator ref() { + return simpleFunction(Ref, "REF"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator refToHex() { + return simpleFunction(RefToHex, "REFTOHEX"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator replace() { + ExpressionOperator operator = simpleThreeArgumentFunction(Replace, "REPLACE"); + operator.setIsBindingSupported(false); + return operator; + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator replicate() { + return simpleTwoArgumentFunction(Replicate, "REPLICATE"); + } + + /** + * INTERNAL: + * Reset all the operators. + */ + public static void resetOperators() { + allOperators = new HashMap(); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator reverse() { + return simpleFunction(Reverse, "REVERSE"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator right() { + return simpleTwoArgumentFunction(Right, "RIGHT"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator rightPad() { + return simpleThreeArgumentFunction(RightPad, "RPAD"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator rightTrim() { + return simpleFunction(RightTrim, "RTRIM"); + } + + /** + * INTERNAL: + * Build rightTrim operator that takes one parameter. + * @bug 2916893 rightTrim(substring) broken. + */ + public static ExpressionOperator rightTrim2() { + ExpressionOperator operator = simpleTwoArgumentFunction(RightTrim2, "RTRIM"); + return operator; + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator round() { + return simpleTwoArgumentFunction(Round, "ROUND"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator roundDate() { + return simpleTwoArgumentFunction(RoundDate, "ROUND"); + } + + /** + * ADVANCED: Set the array of indexes to use when building the SQL function. + * + * The index of the array is the position in the printout, from left to right, starting with zero. + * The value of the array entry is the number of the argument to print at that particular output position. + * So each argument can be used zero, one or many times. + */ + public void setArgumentIndices(int[] indices) { + argumentIndices = indices; + } + + /** + * Return the argumentIndices if set, otherwise initialize argumentIndices to the provided size + */ + public int[] getArgumentIndices(int size) { + int[] indices = this.argumentIndices; + if (indices != null) { + return indices; + } + + indices = new int[size]; + for (int i = 0; i < indices.length; i++) { + indices[i] = i; + } + this.argumentIndices = indices; + return indices; + } + + /** + * ADVANCED: + * Set the node class for this operator. For user-defined functions this is + * set automatically but can be changed. + *

A list of Operator types, an example, and the node class used follows. + *

LogicalOperator AND LogicalExpression + *

ComparisonOperator {@literal <>} RelationExpression + *

AggregateOperator COUNT FunctionExpression + *

OrderOperator ASCENDING " + *

FunctionOperator RTRIM " + *

Node classes given belong to org.eclipse.persistence.internal.expressions. + */ + public void setNodeClass(Class nodeClass) { + this.nodeClass = nodeClass; + } + + /** + * INTERNAL: + * Set the selector id. + */ + public void setSelector(int selector) { + this.selector = selector; + } + + /** + * ADVANCED: + * Set the type of function. + * This must be one of the static function types defined in this class. + */ + public void setType(int type) { + this.type = type; + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator sign() { + return simpleFunction(Sign, "SIGN"); + } + + /** + * INTERNAL: + * Create an operator for a simple aggregate given a Java name and a single + * String for the database (parentheses will be added automatically). + */ + public static ExpressionOperator simpleAggregate(int selector, String databaseName, String javaName) { + ExpressionOperator exOperator = new ExpressionOperator(); + exOperator.setType(AggregateOperator); + exOperator.setSelector(selector); + Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(2); + v.add(databaseName + "("); + v.add(")"); + exOperator.printsAs(v); + exOperator.bePrefix(); + exOperator.printsJavaAs("." + javaName + "()"); + exOperator.setNodeClass(ClassConstants.FunctionExpression_Class); + return exOperator; + } + + /** + * INTERNAL: + * Create an operator for a simple function given a Java name and a single + * String for the database (parentheses will be added automatically). + */ + public static ExpressionOperator simpleFunction(int selector, String databaseName) { + ExpressionOperator exOperator = new ExpressionOperator(); + exOperator.setType(FunctionOperator); + exOperator.setSelector(selector); + exOperator.setName(databaseName); + Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(2); + v.add(databaseName + "("); + v.add(")"); + exOperator.printsAs(v); + exOperator.bePrefix(); + exOperator.setNodeClass(ClassConstants.FunctionExpression_Class); + return exOperator; + } + + /** + * INTERNAL: + * Create an operator for a simple function call without parentheses + */ + public static ExpressionOperator simpleFunctionNoParentheses(int selector, String databaseName) { + ExpressionOperator exOperator = new ExpressionOperator(); + exOperator.setType(FunctionOperator); + exOperator.setSelector(selector); + Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(1); + v.add(databaseName); + exOperator.printsAs(v); + exOperator.bePrefix(); + exOperator.setNodeClass(ClassConstants.FunctionExpression_Class); + return exOperator; + } + + + /** + * INTERNAL: + * Create an operator for a simple function given a Java name and a single + * String for the database (parentheses will be added automatically). + */ + public static ExpressionOperator simpleFunction(int selector, String databaseName, String javaName) { + ExpressionOperator exOperator = simpleFunction(selector, databaseName); + exOperator.printsJavaAs("." + javaName + "()"); + return exOperator; + } + + /** + * INTERNAL: + * Create an operator for a simple logical given a Java name and a single + * String for the database (parentheses will be added automatically). + */ + public static ExpressionOperator simpleLogical(int selector, String databaseName, String javaName) { + ExpressionOperator exOperator = new ExpressionOperator(); + exOperator.setType(LogicalOperator); + exOperator.setSelector(selector); + exOperator.printsAs(" " + databaseName + " "); + exOperator.bePostfix(); + Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(2); + v.add("." + javaName + "("); + v.add(")"); + exOperator.printsJavaAs(v); + exOperator.setNodeClass(ClassConstants.LogicalExpression_Class); + return exOperator; + } + + /** + * INTERNAL: + * Create an operator for a simple math operation, i.e. +, -, *, / + */ + public static ExpressionOperator simpleMath(int selector, String databaseName) { + ExpressionOperator exOperator = new ExpressionOperator(); + exOperator.setType(FunctionOperator); + exOperator.setSelector(selector); + Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(3); + v.add("("); + v.add(" " + databaseName + " "); + v.add(")"); + exOperator.printsAs(v); + exOperator.bePrefix(); + exOperator.setNodeClass(ClassConstants.FunctionExpression_Class); + exOperator.setIsBindingSupported(false); + return exOperator; + } + + /** + * INTERNAL: + * Create an operator for a simple ordering given a Java name and a single + * String for the database (parentheses will be added automatically). + */ + public static ExpressionOperator simpleOrdering(int selector, String databaseName, String javaName) { + ExpressionOperator exOperator = new ExpressionOperator(); + exOperator.setType(OrderOperator); + exOperator.setSelector(selector); + exOperator.printsAs(" " + databaseName); + exOperator.bePostfix(); + exOperator.printsJavaAs("." + javaName + "()"); + exOperator.setNodeClass(ClassConstants.FunctionExpression_Class); + return exOperator; + } + + /** + * INTERNAL: + * Create an operator for a simple relation given a Java name and a single + * String for the database (parentheses will be added automatically). + */ + public static ExpressionOperator simpleRelation(int selector, String databaseName) { + ExpressionOperator exOperator = new ExpressionOperator(); + exOperator.setType(ComparisonOperator); + exOperator.setSelector(selector); + exOperator.printsAs(" " + databaseName + " "); + exOperator.bePostfix(); + exOperator.setNodeClass(ClassConstants.RelationExpression_Class); + return exOperator; + } + + /** + * INTERNAL: + * Create an operator for a simple relation given a Java name and a single + * String for the database (parentheses will be added automatically). + */ + public static ExpressionOperator simpleRelation(int selector, String databaseName, String javaName) { + ExpressionOperator exOperator = simpleRelation(selector, databaseName); + Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(2); + v.add("." + javaName + "("); + v.add(")"); + exOperator.printsJavaAs(v); + return exOperator; + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator simpleThreeArgumentFunction(int selector, String dbString) { + ExpressionOperator exOperator = new ExpressionOperator(); + exOperator.setType(FunctionOperator); + exOperator.setSelector(selector); + exOperator.setName(dbString); + Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(4); + v.add(dbString + "("); + v.add(", "); + v.add(", "); + v.add(")"); + exOperator.printsAs(v); + exOperator.bePrefix(); + exOperator.setNodeClass(ClassConstants.FunctionExpression_Class); + return exOperator; + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator simpleTwoArgumentFunction(int selector, String dbString) { + ExpressionOperator exOperator = new ExpressionOperator(); + exOperator.setType(FunctionOperator); + exOperator.setSelector(selector); + exOperator.setName(dbString); + Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(5); + v.add(dbString + "("); + v.add(", "); + v.add(")"); + exOperator.printsAs(v); + exOperator.bePrefix(); + exOperator.setNodeClass(ClassConstants.FunctionExpression_Class); + return exOperator; + } + + /** + * INTERNAL: + * e.g.: ... "Bob" CONCAT "Smith" ... + * Parentheses will not be addded. [RMB - March 5 2000] + */ + public static ExpressionOperator simpleLogicalNoParens(int selector, String dbString) { + ExpressionOperator exOperator = new ExpressionOperator(); + exOperator.setType(FunctionOperator); + exOperator.setSelector(selector); + Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(5); + v.add(""); + v.add(" " + dbString + " "); + v.add(""); + exOperator.printsAs(v); + exOperator.bePrefix(); + exOperator.setNodeClass(ClassConstants.FunctionExpression_Class); + return exOperator; + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator sin() { + return simpleFunction(Sin, "SIN"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator sinh() { + return simpleFunction(Sinh, "SINH"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator soundex() { + return simpleFunction(Soundex, "SOUNDEX"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator sqrt() { + return simpleFunction(Sqrt, "SQRT"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator standardDeviation() { + return simpleAggregate(StandardDeviation, "STDDEV", "standardDeviation"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator substring() { + ExpressionOperator operator = simpleThreeArgumentFunction(Substring, "SUBSTR"); + operator.setIsBindingSupported(false); + return operator; + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator substringSingleArg() { + return simpleTwoArgumentFunction(SubstringSingleArg, "SUBSTR"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator subtract() { + return ExpressionOperator.simpleMath(ExpressionOperator.Subtract, "-"); + } + + /** + * INTERNAL: + * Create the SUM operator. + */ + public static ExpressionOperator sum() { + return simpleAggregate(Sum, "SUM", "sum"); + } + + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator tan() { + return simpleFunction(Tan, "TAN"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator tanh() { + return simpleFunction(Tanh, "TANH"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator toDate() { + return simpleFunction(ToDate, "TO_DATE"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator today() { + return currentTimeStamp(); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator currentTimeStamp() { + return simpleFunctionNoParentheses(Today, "CURRENT_TIMESTAMP"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator currentDate() { + return simpleFunctionNoParentheses(CurrentDate, "CURRENT_DATE"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator currentTime() { + return simpleFunctionNoParentheses(CurrentTime, "CURRENT_TIME"); + } + + /** + * INTERNAL: + * Create the toLowerCase operator. + */ + public static ExpressionOperator toLowerCase() { + return simpleFunction(ToLowerCase, "LOWER", "toLowerCase"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator toNumber() { + return simpleFunction(ToNumber, "TO_NUMBER"); + } + + /** + * Print a debug representation of this operator. + */ + public String toString() { + 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(dbStrings); + } + } + + /** + * INTERNAL: + * Create the TOUPPERCASE operator. + */ + public static ExpressionOperator toUpperCase() { + return simpleFunction(ToUpperCase, "UPPER", "toUpperCase"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator translate() { + ExpressionOperator operator = simpleThreeArgumentFunction(Translate, "TRANSLATE"); + operator.setIsBindingSupported(false); + return operator; + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator trim() { + return simpleFunction(Trim, "TRIM"); + } + + /** + * INTERNAL: + * Build Trim operator. + */ + public static ExpressionOperator trim2() { + ExpressionOperator exOperator = new ExpressionOperator(); + exOperator.setType(FunctionOperator); + exOperator.setSelector(Trim2); + Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(5); + v.add("TRIM("); + v.add(" FROM "); + v.add(")"); + exOperator.printsAs(v); + exOperator.bePrefix(); + // Bug 573094 + int[] indices = { 1, 0 }; + exOperator.setArgumentIndices(indices); + exOperator.setNodeClass(ClassConstants.FunctionExpression_Class); + exOperator.setIsBindingSupported(false); + return exOperator; + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator trunc() { + return simpleTwoArgumentFunction(Trunc, "TRUNC"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator truncateDate() { + return simpleTwoArgumentFunction(TruncateDate, "TRUNC"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator cast() { + ExpressionOperator exOperator = new ExpressionOperator(); + exOperator.setType(FunctionOperator); + exOperator.setSelector(Cast); + exOperator.setName("CAST"); + Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(5); + v.add("CAST("); + v.add(" AS "); + v.add(")"); + exOperator.printsAs(v); + exOperator.bePrefix(); + exOperator.setNodeClass(ClassConstants.FunctionExpression_Class); + return exOperator; + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator extract() { + ExpressionOperator exOperator = new ExpressionOperator(); + exOperator.setType(FunctionOperator); + exOperator.setSelector(Extract); + exOperator.setName("EXTRACT"); + Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(5); + v.add("EXTRACT("); + v.add(" FROM "); + v.add(")"); + exOperator.printsAs(v); + int[] indices = new int[2]; + indices[0] = 1; + indices[1] = 0; + exOperator.setArgumentIndices(indices); + exOperator.bePrefix(); + exOperator.setNodeClass(ClassConstants.FunctionExpression_Class); + return exOperator; + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator value() { + return simpleFunction(Value, "VALUE"); + } + + /** + * INTERNAL: + * Build operator. + */ + public static ExpressionOperator variance() { + return simpleAggregate(Variance, "VARIANCE", "variance"); + } + + /** + * INTERNAL: + * Create the ANY operator. + */ + public static ExpressionOperator any() { + ExpressionOperator exOperator = new ExpressionOperator(); + exOperator.setType(FunctionOperator); + exOperator.setSelector(Any); + exOperator.printsAs("ANY"); + exOperator.bePostfix(); + exOperator.setNodeClass(ClassConstants.FunctionExpression_Class); + return exOperator; + } + + /** + * INTERNAL: + * Create the SOME operator. + */ + public static ExpressionOperator some() { + ExpressionOperator exOperator = new ExpressionOperator(); + exOperator.setType(FunctionOperator); + exOperator.setSelector(Some); + exOperator.printsAs("SOME"); + exOperator.bePostfix(); + exOperator.setNodeClass(ClassConstants.FunctionExpression_Class); + return exOperator; + } + + /** + * INTERNAL: + * Create the ALL operator. + */ + public static ExpressionOperator all() { + ExpressionOperator exOperator = new ExpressionOperator(); + exOperator.setType(FunctionOperator); + exOperator.setSelector(All); + exOperator.printsAs("ALL"); + exOperator.bePostfix(); + exOperator.setNodeClass(ClassConstants.FunctionExpression_Class); + return exOperator; + } + + /** + * INTERNAL: + * Create the UNION operator. + */ + public static ExpressionOperator union() { + ExpressionOperator exOperator = new ExpressionOperator(); + exOperator.setType(FunctionOperator); + exOperator.setSelector(Union); + exOperator.printsAs("UNION "); + exOperator.bePostfix(); + exOperator.setNodeClass(ClassConstants.FunctionExpression_Class); + return exOperator; + } + + /** + * INTERNAL: + * Create the UNION ALL operator. + */ + public static ExpressionOperator unionAll() { + ExpressionOperator exOperator = new ExpressionOperator(); + exOperator.setType(FunctionOperator); + exOperator.setSelector(UnionAll); + exOperator.printsAs("UNION ALL "); + exOperator.bePostfix(); + exOperator.setNodeClass(ClassConstants.FunctionExpression_Class); + return exOperator; + } + + /** + * INTERNAL: + * Create the INTERSECT operator. + */ + public static ExpressionOperator intersect() { + ExpressionOperator exOperator = new ExpressionOperator(); + exOperator.setType(FunctionOperator); + exOperator.setSelector(Intersect); + exOperator.printsAs("INTERSECT "); + exOperator.bePostfix(); + exOperator.setNodeClass(ClassConstants.FunctionExpression_Class); + return exOperator; + } + + /** + * INTERNAL: + * Create the INTERSECT ALL operator. + */ + public static ExpressionOperator intersectAll() { + ExpressionOperator exOperator = new ExpressionOperator(); + exOperator.setType(FunctionOperator); + exOperator.setSelector(IntersectAll); + exOperator.printsAs("INTERSECT ALL "); + exOperator.bePostfix(); + exOperator.setNodeClass(ClassConstants.FunctionExpression_Class); + return exOperator; + } + + /** + * INTERNAL: + * Create the EXCEPT operator. + */ + public static ExpressionOperator except() { + ExpressionOperator exOperator = new ExpressionOperator(); + exOperator.setType(FunctionOperator); + exOperator.setSelector(Except); + exOperator.printsAs("EXCEPT "); + exOperator.bePostfix(); + exOperator.setNodeClass(ClassConstants.FunctionExpression_Class); + return exOperator; + } + + /** + * INTERNAL: + * Create the EXCEPT ALL operator. + */ + public static ExpressionOperator exceptAll() { + ExpressionOperator exOperator = new ExpressionOperator(); + exOperator.setType(FunctionOperator); + exOperator.setSelector(ExceptAll); + exOperator.printsAs("EXCEPT ALL "); + exOperator.bePostfix(); + exOperator.setNodeClass(ClassConstants.FunctionExpression_Class); + return exOperator; + } + + /** + * INTERNAL: + * Indicates whether operator has selector Any or Some + */ + public boolean isAny() { + return selector == ExpressionOperator.Any || + selector == ExpressionOperator.Some; + } + /** + * INTERNAL: + * Indicates whether operator has selector All + */ + public boolean isAll() { + return selector == ExpressionOperator.All; + } + /** + * INTERNAL: + * Indicates whether operator has selector Any, Some or All + */ + public boolean isAnyOrAll() { + return isAny() || isAll(); + } +} diff --git a/dev/com.ibm.websphere.appserver.thirdparty.eclipselink/src/org/eclipse/persistence/platform/database/DB2Platform.java b/dev/com.ibm.websphere.appserver.thirdparty.eclipselink/src/org/eclipse/persistence/platform/database/DB2Platform.java new file mode 100644 index 000000000000..30554b538248 --- /dev/null +++ b/dev/com.ibm.websphere.appserver.thirdparty.eclipselink/src/org/eclipse/persistence/platform/database/DB2Platform.java @@ -0,0 +1,1851 @@ +/******************************************************************************* + * Copyright (c) 1998, 2022 Oracle, IBM Corporation, and/or its affiliates. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 + * which accompanies this distribution. + * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Oracle - initial API and implementation from Oracle TopLink + * 09/14/2011-2.3.1 Guy Pelletier + * - 357533: Allow DDL queries to execute even when Multitenant entities are part of the PU + * 02/19/2015 - Rick Curtis + * - 458877 : Add national character support + * 02/24/2016-2.6.0 Rick Curtis + * - 460740: Fix pessimistic locking with setFirst/Max results on DB2 + * 03/13/2015 - Jody Grassel + * - 462103 : SQL for Stored Procedure named parameter with DB2 generated with incorrect marker + * 04/15/2016 - Dalia Abo Sheasha + * - 491824: Setting lock timeout to 0 issues a NOWAIT causing an error in DB2 + * 08/22/2017 - Will Dazey + * - 521037: DB2 default schema is doubled for sequence queries + * 12/06/2018 - Will Dazey + * - 542491: Add new 'eclipselink.jdbc.force-bind-parameters' property to force enable binding + *****************************************************************************/ +package org.eclipse.persistence.platform.database; + +import java.io.*; +import java.sql.*; +import java.util.*; + +import org.eclipse.persistence.exceptions.ValidationException; +import org.eclipse.persistence.expressions.*; +import org.eclipse.persistence.internal.helper.*; +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; +import org.eclipse.persistence.queries.*; +import org.eclipse.persistence.tools.schemaframework.FieldDefinition; + +/** + *

+ * Purpose: Provides DB2 specific behavior. + *

+ * Responsibilities: + *

+ * + * @since TOPLink/Java 1.0 + */ +public class DB2Platform extends org.eclipse.persistence.platform.database.DatabasePlatform { + + public DB2Platform() { + super(); + //com.ibm.db2.jcc.DB2Types.CURSOR + this.cursorCode = -100008; + this.shouldBindLiterals = false; + this.pingSQL = "VALUES(1)"; + } + + @Override + public void initializeConnectionData(Connection connection) throws SQLException { + // DB2 database doesn't support NVARCHAR column types and as such doesn't support calling + // get/setNString() on the driver. + this.driverSupportsNationalCharacterVarying = false; + } + + /** + * INTERNAL: + * Append a byte[] in native DB@ format BLOB(hexString) if usesNativeSQL(), + * otherwise use ODBC format from DatabasePLatform. + */ + @Override + protected void appendByteArray(byte[] bytes, Writer writer) throws IOException { + if (usesNativeSQL()) { + writer.write("BLOB(x'"); + Helper.writeHexString(bytes, writer); + writer.write("')"); + } else { + super.appendByteArray(bytes, writer); + } + } + + /** + * INTERNAL: + * Appends the Date in native format if usesNativeSQL() otherwise use ODBC + * format from DatabasePlatform. Native format: 'mm/dd/yyyy' + */ + @Override + protected void appendDate(java.sql.Date date, Writer writer) throws IOException { + if (usesNativeSQL()) { + appendDB2Date(date, writer); + } else { + super.appendDate(date, writer); + } + } + + /** + * INTERNAL: + * Write a timestamp in DB2 specific format (mm/dd/yyyy). + */ + protected void appendDB2Date(java.sql.Date date, Writer writer) throws IOException { + writer.write("'"); + // PERF: Avoid deprecated get methods, that are now very inefficient and + // used from toString. + Calendar calendar = Helper.allocateCalendar(); + calendar.setTime(date); + + if ((calendar.get(Calendar.MONTH) + 1) < 10) { + writer.write('0'); + } + writer.write(Integer.toString(calendar.get(Calendar.MONTH) + 1)); + writer.write('/'); + if (calendar.get(Calendar.DATE) < 10) { + writer.write('0'); + } + writer.write(Integer.toString(calendar.get(Calendar.DATE))); + writer.write('/'); + writer.write(Integer.toString(calendar.get(Calendar.YEAR))); + writer.write("'"); + + Helper.releaseCalendar(calendar); + } + + /** + * INTERNAL: + * Write a timestamp in DB2 specific format (yyyy-mm-dd-hh.mm.ss.ffffff). + */ + protected void appendDB2Timestamp(java.sql.Timestamp timestamp, Writer writer) throws IOException { + // PERF: Avoid deprecated get methods, that are now very inefficient and + // used from toString. + Calendar calendar = Helper.allocateCalendar(); + calendar.setTime(timestamp); + + writer.write(Helper.printDate(calendar)); + writer.write('-'); + if (calendar.get(Calendar.HOUR_OF_DAY) < 10) { + writer.write('0'); + } + writer.write(Integer.toString(calendar.get(Calendar.HOUR_OF_DAY))); + writer.write('.'); + if (calendar.get(Calendar.MINUTE) < 10) { + writer.write('0'); + } + writer.write(Integer.toString(calendar.get(Calendar.MINUTE))); + writer.write('.'); + if (calendar.get(Calendar.SECOND) < 10) { + writer.write('0'); + } + writer.write(Integer.toString(calendar.get(Calendar.SECOND))); + writer.write('.'); + + Helper.releaseCalendar(calendar); + + // Must truncate the nanos to six decimal places, + // it is actually a complex algorithm... + String nanoString = Integer.toString(timestamp.getNanos()); + int numberOfZeros = 0; + for (int num = Math.min(9 - nanoString.length(), 6); num > 0; num--) { + writer.write('0'); + numberOfZeros++; + } + if ((nanoString.length() + numberOfZeros) > 6) { + nanoString = nanoString.substring(0, (6 - numberOfZeros)); + } + writer.write(nanoString); + } + + /** + * Write a timestamp in DB2 specific format (yyyy-mm-dd-hh.mm.ss.ffffff). + */ + protected void appendDB2Calendar(Calendar calendar, Writer writer) throws IOException { + int hour; + int minute; + int second; + if (!Helper.getDefaultTimeZone().equals(calendar.getTimeZone())) { + // Must convert the calendar to the local timezone if different, as + // dates have no timezone (always local). + Calendar localCalendar = Helper.allocateCalendar(); + localCalendar.setTimeInMillis(calendar.getTimeInMillis()); + hour = calendar.get(Calendar.HOUR_OF_DAY); + minute = calendar.get(Calendar.MINUTE); + second = calendar.get(Calendar.SECOND); + Helper.releaseCalendar(localCalendar); + } else { + hour = calendar.get(Calendar.HOUR_OF_DAY); + minute = calendar.get(Calendar.MINUTE); + second = calendar.get(Calendar.SECOND); + } + writer.write(Helper.printDate(calendar)); + writer.write('-'); + if (hour < 10) { + writer.write('0'); + } + writer.write(Integer.toString(hour)); + writer.write('.'); + if (minute < 10) { + writer.write('0'); + } + writer.write(Integer.toString(minute)); + writer.write('.'); + if (second < 10) { + writer.write('0'); + } + writer.write(Integer.toString(second)); + writer.write('.'); + + // Must truncate the nanos to six decimal places, + // it is actually a complex algorithm... + String millisString = Integer.toString(calendar.get(Calendar.MILLISECOND)); + int numberOfZeros = 0; + for (int num = Math.min(3 - millisString.length(), 3); num > 0; num--) { + writer.write('0'); + numberOfZeros++; + } + if ((millisString.length() + numberOfZeros) > 3) { + millisString = millisString.substring(0, (3 - numberOfZeros)); + } + writer.write(millisString); + } + + /** + * INTERNAL: + * Append the Time in Native format if usesNativeSQL() otherwise use ODBC + * format from DAtabasePlatform. Native Format: 'hh:mm:ss' + */ + @Override + protected void appendTime(java.sql.Time time, Writer writer) throws IOException { + if (usesNativeSQL()) { + writer.write("'"); + writer.write(Helper.printTime(time)); + writer.write("'"); + } else { + super.appendTime(time, writer); + } + } + + /** + * INTERNAL: + * Append the Timestamp in native format if usesNativeSQL() is true + * otherwise use ODBC format from DatabasePlatform. Native format: + * 'YYYY-MM-DD-hh.mm.ss.SSSSSS' + */ + @Override + protected void appendTimestamp(java.sql.Timestamp timestamp, Writer writer) throws IOException { + if (usesNativeSQL()) { + writer.write("'"); + appendDB2Timestamp(timestamp, writer); + writer.write("'"); + } else { + super.appendTimestamp(timestamp, writer); + } + } + + /** + * INTERNAL: + * Append the Timestamp in native format if usesNativeSQL() is true + * otherwise use ODBC format from DatabasePlatform. Native format: + * 'YYYY-MM-DD-hh.mm.ss.SSSSSS' + */ + @Override + protected void appendCalendar(Calendar calendar, Writer writer) throws IOException { + if (usesNativeSQL()) { + writer.write("'"); + appendDB2Calendar(calendar, writer); + writer.write("'"); + } else { + super.appendCalendar(calendar, writer); + } + } + + @Override + protected Hashtable buildFieldTypes() { + Hashtable fieldTypeMapping = new Hashtable(); + + fieldTypeMapping.put(Boolean.class, new FieldTypeDefinition("SMALLINT DEFAULT 0", false)); + + fieldTypeMapping.put(Integer.class, new FieldTypeDefinition("INTEGER", false)); + fieldTypeMapping.put(Long.class, new FieldTypeDefinition("BIGINT", false)); + fieldTypeMapping.put(Float.class, new FieldTypeDefinition("FLOAT", false)); + fieldTypeMapping.put(Double.class, new FieldTypeDefinition("FLOAT", false)); + fieldTypeMapping.put(Short.class, new FieldTypeDefinition("SMALLINT", false)); + fieldTypeMapping.put(Byte.class, new FieldTypeDefinition("SMALLINT", false)); + fieldTypeMapping.put(java.math.BigInteger.class, new FieldTypeDefinition("BIGINT", false)); + fieldTypeMapping.put(java.math.BigDecimal.class, new FieldTypeDefinition("DECIMAL", 15)); + fieldTypeMapping.put(Number.class, new FieldTypeDefinition("DECIMAL", 15)); + if(getUseNationalCharacterVaryingTypeForString()){ + fieldTypeMapping.put(String.class, new FieldTypeDefinition("VARCHAR", DEFAULT_VARCHAR_SIZE, "FOR MIXED DATA")); + }else { + fieldTypeMapping.put(String.class, new FieldTypeDefinition("VARCHAR", DEFAULT_VARCHAR_SIZE)); + } + fieldTypeMapping.put(Character.class, new FieldTypeDefinition("CHAR", 1)); + fieldTypeMapping.put(Byte[].class, new FieldTypeDefinition("BLOB", 64000)); + fieldTypeMapping.put(Character[].class, new FieldTypeDefinition("CLOB", 64000)); + fieldTypeMapping.put(byte[].class, new FieldTypeDefinition("BLOB", 64000)); + fieldTypeMapping.put(char[].class, new FieldTypeDefinition("CLOB", 64000)); + fieldTypeMapping.put(java.sql.Blob.class, new FieldTypeDefinition("BLOB", 64000)); + fieldTypeMapping.put(java.sql.Clob.class, new FieldTypeDefinition("CLOB", 64000)); + + fieldTypeMapping.put(java.sql.Date.class, new FieldTypeDefinition("DATE", false)); + fieldTypeMapping.put(java.sql.Time.class, new FieldTypeDefinition("TIME", false)); + fieldTypeMapping.put(java.sql.Timestamp.class, new FieldTypeDefinition("TIMESTAMP", false)); + + return fieldTypeMapping; + } + + /** + * INTERNAL: returns the maximum number of characters that can be used in a + * field name on this platform. + */ + @Override + public int getMaxFieldNameSize() { + return 128; + } + + /** + * INTERNAL: returns the maximum number of characters that can be used in a + * foreign key name on this platform. + */ + @Override + public int getMaxForeignKeyNameSize() { + return 18; + } + + /** + * INTERNAL: + * returns the maximum number of characters that can be used in a unique key + * name on this platform. + */ + @Override + public int getMaxUniqueKeyNameSize() { + return 18; + } + + /** + * INTERNAL: + * Return the catalog information through using the native SQL catalog + * selects. This is required because many JDBC driver do not support + * meta-data. Wildcards can be passed as arguments. + * This is currently not used. + */ + public Vector getNativeTableInfo(String table, String creator, AbstractSession session) { + String query = "SELECT * FROM SYSIBM.SYSTABLES WHERE TBCREATOR NOT IN ('SYS', 'SYSTEM')"; + if (table != null) { + if (table.indexOf('%') != -1) { + query = query + " AND TBNAME LIKE " + table; + } else { + query = query + " AND TBNAME = " + table; + } + } + if (creator != null) { + if (creator.indexOf('%') != -1) { + query = query + " AND TBCREATOR LIKE " + creator; + } else { + query = query + " AND TBCREATOR = " + creator; + } + } + return session.executeSelectingCall(new org.eclipse.persistence.queries.SQLCall(query)); + } + + /** + * INTERNAL: + * Used for sp calls. + */ + @Override + public String getProcedureCallHeader() { + return "CALL "; + } + + /** + * INTERNAL: + * Used for pessimistic locking in DB2. + * Without the "WITH RS" the lock is not held. + */ + // public String getSelectForUpdateString() { return " FOR UPDATE"; } + @Override + public String getSelectForUpdateString() { + return " FOR READ ONLY WITH RS USE AND KEEP UPDATE LOCKS"; + //return " FOR READ ONLY WITH RR"; + //return " FOR READ ONLY WITH RS"; + //return " FOR UPDATE WITH RS"; + } + + /** + * INTERNAL: + * Used for stored procedure defs. + */ + @Override + public String getProcedureEndString() { + return "END"; + } + + /** + * Used for stored procedure defs. + */ + @Override + public String getProcedureBeginString() { + return "BEGIN"; + } + + /** + * INTERNAL: + * Used for stored procedure defs. + */ + @Override + public String getProcedureAsString() { + return ""; + } + + /** + * Obtain the platform specific argument string + */ + @Override + public String getProcedureArgument(String name, Object parameter, ParameterType parameterType, StoredProcedureCall call, AbstractSession session) { + if (name != null && shouldPrintStoredProcedureArgumentNameInCall()) { + return getProcedureArgumentString() + name + " => " + "?"; + } + return "?"; + } + + /** + * INTERNAL: + * This is required in the construction of the stored procedures with output + * parameters. + */ + @Override + 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 + * DB2. + */ + @Override + public ValueReadQuery getTimestampQuery() { + if (timestampQuery == null) { + timestampQuery = new ValueReadQuery(); + timestampQuery.setSQLString("SELECT CURRENT TIMESTAMP FROM SYSIBM.SYSDUMMY1"); + timestampQuery.setAllowNativeSQLQuery(true); + } + return timestampQuery; + } + + /** + * INTERNAL: + * Initialize any platform-specific operators + */ + @Override + protected void initializePlatformOperators() { + super.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(Vector items, ExpressionSQLPrinter printer) { + if(!printer.getPlatform().shouldBindPartialParameters()) { + super.printCollection(items, printer); + return; + } + + for(Object item : items) { + if(((Expression)item).isParameterExpression()) { + ((ParameterExpression) item).setCanBind(false); + } else if(((Expression)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(Object item : items) { + if(((Expression)item).isParameterExpression()) { + ((ParameterExpression) item).setCanBind(false); + } else if(((Expression)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(Vector items, ExpressionSQLPrinter printer) { + if(!printer.getPlatform().shouldBindPartialParameters()) { + super.printCollection(items, printer); + return; + } + + int[] indices = getArgumentIndices(items.size()); + boolean allBind = true; + for (int i = 0; i < items.size(); i++) { + final int index = indices[i]; + Expression item = (Expression)items.elementAt(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 == (indices.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 == (indices.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 = (Expression)items.elementAt(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(Vector 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++;
+                    }
+                }
+
+                int[] indices = getArgumentIndices(items.size());
+                for (int j = 0; j < items.size(); j++) {
+                    final int index = indices[j];
+                    Expression item = (Expression)items.elementAt(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 = (Expression)items.elementAt(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(Vector 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++;
+                    }
+                }
+
+                int[] indices = getArgumentIndices(items.size());
+                for (int j = 0; j < items.size(); j++) {
+                    final int index = indices[j];
+                    Expression item = (Expression)items.elementAt(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 = (Expression)items.elementAt(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(Vector items, ExpressionSQLPrinter printer) { + if(!printer.getPlatform().shouldBindPartialParameters()) { + super.printCollection(items, printer); + return; + } + + int[] indices = getArgumentIndices(items.size()); + boolean allBind = true; + for (int i = 0; i < items.size(); i++) { + final int index = indices[i]; + Expression item = (Expression)items.elementAt(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 == (indices.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 == (indices.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 = (Expression)items.elementAt(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(Vector items, ExpressionSQLPrinter printer) { + if(!printer.getPlatform().shouldBindPartialParameters()) { + super.printCollection(items, printer); + return; + } + + int[] indices = getArgumentIndices(items.size()); + for (int i = 0; i < items.size(); i++) { + final int index = indices[i]; + Expression item = (Expression)items.elementAt(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 = (Expression)items.elementAt(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(Vector items, ExpressionSQLPrinter printer) { + if(!printer.getPlatform().shouldBindPartialParameters()) { + super.printCollection(items, printer); + return; + } + + int[] indices = getArgumentIndices(items.size()); + for (int i = 0; i < items.size(); i++) { + final int index = indices[i]; + Expression item = (Expression)items.elementAt(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 = (Expression)items.elementAt(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(Vector items, ExpressionSQLPrinter printer) { + if(!printer.getPlatform().shouldBindPartialParameters()) { + super.printCollection(items, printer); + return; + } + + int[] indices = getArgumentIndices(items.size()); + for (int i = 0; i < items.size(); i++) { + final int index = indices[i]; + Expression item = (Expression)items.elementAt(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 = (Expression)items.elementAt(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 + public boolean isDB2() { + return true; + } + + /** + * INTERNAL: + * 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 + */ + @Override + public Hashtable maximumNumericValues() { + Hashtable values = new Hashtable(); + + values.put(Integer.class, Integer.valueOf(Integer.MAX_VALUE)); + values.put(Long.class, Long.valueOf(Integer.MAX_VALUE)); + values.put(Float.class, Float.valueOf(123456789)); + values.put(Double.class, Double.valueOf(Float.MAX_VALUE)); + values.put(Short.class, Short.valueOf(Short.MAX_VALUE)); + values.put(Byte.class, Byte.valueOf(Byte.MAX_VALUE)); + values.put(java.math.BigInteger.class, new java.math.BigInteger("999999999999999")); + values.put(java.math.BigDecimal.class, new java.math.BigDecimal("0.999999999999999")); + return values; + } + + /** + * INTERNAL: + * 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 + */ + @Override + public Hashtable minimumNumericValues() { + Hashtable values = new Hashtable(); + + values.put(Integer.class, Integer.valueOf(Integer.MIN_VALUE)); + values.put(Long.class, Long.valueOf(Integer.MIN_VALUE)); + values.put(Float.class, Float.valueOf(-123456789)); + values.put(Double.class, Double.valueOf(Float.MIN_VALUE)); + values.put(Short.class, Short.valueOf(Short.MIN_VALUE)); + values.put(Byte.class, Byte.valueOf(Byte.MIN_VALUE)); + values.put(java.math.BigInteger.class, new java.math.BigInteger("-999999999999999")); + values.put(java.math.BigDecimal.class, new java.math.BigDecimal("-0.999999999999999")); + return values; + } + + /** + * INTERNAL: + * Allow for the platform to ignore exceptions. This is required for DB2 + * which throws no-data modified as an exception. + */ + @Override + public boolean shouldIgnoreException(SQLException exception) { + if (exception.getMessage().equals("No data found") || exception.getMessage().equals("No row was found for FETCH, UPDATE or DELETE; or the result of a query is an empty table") + || (exception.getErrorCode() == 100)) { + return true; + } + return super.shouldIgnoreException(exception); + } + + /** + * INTERNAL: + * JDBC defines and outer join syntax, many drivers do not support this. So + * we normally avoid it. + */ + @Override + public boolean shouldUseJDBCOuterJoinSyntax() { + return false; + } + + /** + * INTERNAL: Build the identity query for native sequencing. + */ + @Override + public ValueReadQuery buildSelectQueryForIdentity() { + ValueReadQuery selectQuery = new ValueReadQuery(); + StringWriter writer = new StringWriter(); + writer.write("SELECT IDENTITY_VAL_LOCAL() FROM SYSIBM.SYSDUMMY1"); + + selectQuery.setSQLString(writer.toString()); + return selectQuery; + } + + /** + * INTERNAL: Append the receiver's field 'identity' constraint clause to a + * writer. + * Used by table creation with sequencing. + */ + @Override + public void printFieldIdentityClause(Writer writer) throws ValidationException { + try { + writer.write(" GENERATED ALWAYS AS IDENTITY"); + } catch (IOException ioException) { + throw ValidationException.fileError(ioException); + } + } + + @Override + protected void printFieldTypeSize(Writer writer, FieldDefinition field, FieldTypeDefinition ftd) throws IOException { + super.printFieldTypeSize(writer, field, ftd); + String suffix = ftd.getTypesuffix(); + if (suffix != null) { + writer.append(" " + suffix); + } + } + + /** + * INTERNAL: Indicates whether the platform supports identity. DB2 does + * through AS IDENTITY field types. + * This is used by sequencing. + */ + @Override + public boolean supportsIdentity() { + return true; + } + + /** + * INTERNAL: DB2 supports temp tables. + * This is used by UpdateAllQuerys. + */ + @Override + public boolean supportsGlobalTempTables() { + return true; + } + + /** + * INTERNAL: DB2 temp table syntax. + * This is used by UpdateAllQuerys. + */ + @Override + protected String getCreateTempTableSqlPrefix() { + return "DECLARE GLOBAL TEMPORARY TABLE "; + } + + /** + * INTERNAL: DB2 temp table syntax. + * This is used by UpdateAllQuerys. + */ + @Override + public DatabaseTable getTempTableForTable(DatabaseTable table) { + DatabaseTable tempTable = super.getTempTableForTable(table); + tempTable.setTableQualifier("session"); + return tempTable; + } + + /** + * INTERNAL: DB2 temp table syntax. + * This is used by UpdateAllQuerys. + */ + @Override + protected String getCreateTempTableSqlSuffix() { + return " ON COMMIT DELETE ROWS NOT LOGGED"; + } + + /** + * INTERNAL: DB2 allows LIKE to be used to create temp tables, which avoids having to know the types. + * This is used by UpdateAllQuerys. + */ + @Override + protected String getCreateTempTableSqlBodyForTable(DatabaseTable table) { + return " LIKE " + table.getQualifiedNameDelimited(this); + } + + /** + * INTERNAL: DB2 does not support NOWAIT. + */ + @Override + public String getNoWaitString() { + return ""; + } + + /** + * INTERNAL: DB2 has issues with binding with temp table queries. + * This is used by UpdateAllQuerys. + */ + @Override + public boolean dontBindUpdateAllQueryUsingTempTables() { + return true; + } + + /** + * INTERNAL: DB2 does not allow NULL in select clause. + * This is used by UpdateAllQuerys. + */ + @Override + public boolean isNullAllowedInSelectClause() { + return false; + } + + /** + * INTERNAL + * DB2 has some issues with using parameters on certain functions and relations. + * This allows statements to disable binding 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: DB2 does not allow stand alone, untyped parameter markers in select clause. + * @see {@link org.eclipse.persistence.internal.expressions.ParameterExpression#writeFields(ExpressionSQLPrinter printer, Vector newFields, SQLSelectStatement statement)} + */ + @Override + public boolean allowBindingForSelectClause() { + return false; + } + + /** + * INTERNAL: + * DB2 requires casting on certain operations, such as the CONCAT function, + * and parameterized queries of the form, ":param = :param". This method + * will write CAST operation to parameters if the type is known. + * This is not used by default, only if isCastRequired is set to true, + * by default dynamic SQL is used to avoid the issue in only the required cases. + */ + @Override + public void writeParameterMarker(Writer writer, ParameterExpression parameter, AbstractRecord record, DatabaseCall call) throws IOException { + String paramaterMarker = "?"; + Object type = parameter.getType(); + // Update-all query requires casting of null parameter values in select into. + if ((type != null) && (this.isCastRequired || ((call.getQuery() != null) && call.getQuery().isUpdateAllQuery()))) { + BasicTypeHelperImpl typeHelper = BasicTypeHelperImpl.getInstance(); + String castType = null; + if (typeHelper.isBooleanType(type) || typeHelper.isByteType(type) || typeHelper.isShortType(type)) { + castType = "SMALLINT"; + } else if (typeHelper.isIntType(type)) { + castType = "INTEGER"; + } else if (typeHelper.isLongType(type)) { + castType = "BIGINT"; + } else if (typeHelper.isFloatType(type)) { + castType = "REAL"; + } else if (typeHelper.isDoubleType(type)) { + castType = "DOUBLE"; + } else if (typeHelper.isStringType(type)) { + castType = "VARCHAR(" + getCastSizeForVarcharParameter() + ")"; + } else if (typeHelper.isCharacterType(type)) { + castType = "CHAR"; + } + + if (castType != null) { + paramaterMarker = "CAST (? AS " + castType + ")"; + } + } + writer.write(paramaterMarker); + } + + /** + * INTERNAL: + * DB2 does not seem to allow FOR UPDATE on queries with multiple tables. + * This is only used by testing to exclude these tests. + */ + @Override + public boolean supportsLockingQueriesWithMultipleTables() { + return false; + } + + /** + * INTERNAL: DB2 added SEQUENCE support as of (I believe) v8. + */ + @Override + public ValueReadQuery buildSelectQueryForSequenceObject(String qualifiedSeqName, Integer size) { + return new ValueReadQuery("VALUES(NEXT VALUE FOR " + qualifiedSeqName + ")"); + } + + /** + * INTERNAL: DB2 added SEQUENCE support as of (I believe) v8. + */ + @Override + 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; + } + + /** + * INTERNAL: DB2 added SEQUENCE support as of (I believe) v8. + */ + @Override + public boolean isAlterSequenceObjectSupported() { + return true; + } + + @Override + public boolean shouldPrintForUpdateClause() { + return false; + } + /** + * INTERNAL: + * Print the SQL representation of the statement on a stream, storing the fields + * in the DatabaseCall. This implementation works MaxRows and FirstResult into the SQL using + * DB2's ROWNUMBER() OVER() to filter values if shouldUseRownumFiltering is true. + */ + @Override + public void printSQLSelectStatement(DatabaseCall call, ExpressionSQLPrinter printer, SQLSelectStatement statement){ + int max = 0; + int firstRow = 0; + + if (statement.getQuery()!=null){ + max = statement.getQuery().getMaxRows(); + firstRow = statement.getQuery().getFirstResult(); + } + + if ( !(this.shouldUseRownumFiltering()) || ( !(max>0) && !(firstRow>0) ) ){ + super.printSQLSelectStatement(call, printer, statement); + statement.appendForUpdateClause(printer); + return; + } else if ( max > 0 ){ + statement.setUseUniqueFieldAliases(true); + printer.printString("SELECT * FROM (SELECT * FROM (SELECT "); + printer.printString("EL_TEMP.*, ROWNUMBER() OVER() AS EL_ROWNM FROM ("); + call.setFields(statement.printSQL(printer)); + printer.printString(") AS EL_TEMP) AS EL_TEMP2 WHERE EL_ROWNM <= "); + printer.printParameter(DatabaseCall.MAXROW_FIELD); + printer.printString(") AS EL_TEMP3 WHERE EL_ROWNM > "); + printer.printParameter(DatabaseCall.FIRSTRESULT_FIELD); + // If we have a ForUpdate clause, it must be on the outermost query + statement.appendForUpdateClause(printer); + } else {// firstRow>0 + statement.setUseUniqueFieldAliases(true); + printer.printString("SELECT * FROM (SELECT EL_TEMP.*, ROWNUMBER() OVER() AS EL_ROWNM FROM ("); + call.setFields(statement.printSQL(printer)); + printer.printString(") AS EL_TEMP) AS EL_TEMP2 WHERE EL_ROWNM > "); + printer.printParameter(DatabaseCall.FIRSTRESULT_FIELD); + statement.appendForUpdateClause(printer); + } + call.setIgnoreFirstRowSetting(true); + call.setIgnoreMaxResultsSetting(true); + } + +} diff --git a/dev/com.ibm.ws.jpa.tests.spec10.query_fat.common/test-applications/olgh19342/src/com/ibm/ws/jpa/olgh19342/testlogic/JPATestOLGH19342Logic.java b/dev/com.ibm.ws.jpa.tests.spec10.query_fat.common/test-applications/olgh19342/src/com/ibm/ws/jpa/olgh19342/testlogic/JPATestOLGH19342Logic.java index eda6847c734e..66b670c87902 100644 --- a/dev/com.ibm.ws.jpa.tests.spec10.query_fat.common/test-applications/olgh19342/src/com/ibm/ws/jpa/olgh19342/testlogic/JPATestOLGH19342Logic.java +++ b/dev/com.ibm.ws.jpa.tests.spec10.query_fat.common/test-applications/olgh19342/src/com/ibm/ws/jpa/olgh19342/testlogic/JPATestOLGH19342Logic.java @@ -93,8 +93,10 @@ public void run() { query.setParameter("id", "Key30"); query.getSingleResult(); } catch (Exception e) { - error.incrementAndGet(); - System.out.println(e.getMessage()); + // print the stack for the first exception + if (error.incrementAndGet() == 1) { + e.printStackTrace(); + } } finally { if (em != null) { if (jpaResource.getTj().isTransactionActive()) {