All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.persistence.platform.database.DB2Platform Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 1998, 2024 Oracle and/or its affiliates. All rights reserved.
 * Copyright (c) 1998, 2024 IBM Corporation. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0,
 * or the Eclipse Distribution License v. 1.0 which is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 */

// 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 org.eclipse.persistence.exceptions.ValidationException;
import org.eclipse.persistence.expressions.Expression;
import org.eclipse.persistence.expressions.ExpressionOperator;
import org.eclipse.persistence.expressions.ListExpressionOperator;
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.internal.helper.BasicTypeHelperImpl;
import org.eclipse.persistence.internal.helper.ClassConstants;
import org.eclipse.persistence.internal.helper.DatabaseTable;
import org.eclipse.persistence.internal.helper.Helper;
import org.eclipse.persistence.internal.sessions.AbstractRecord;
import org.eclipse.persistence.internal.sessions.AbstractSession;
import org.eclipse.persistence.queries.StoredProcedureCall;
import org.eclipse.persistence.queries.ValueReadQuery;
import org.eclipse.persistence.tools.schemaframework.FieldDefinition;

import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Hashtable;
import java.util.List;
import java.util.Vector;

/**
 * 

* Purpose: Provides DB2 specific behavior. *

* Responsibilities: *

    *
  • Support for schema creation. *
  • Native SQL for byte[], Date, Time, {@literal &} Timestamp. *
  • Support for table qualified names. *
  • Support for stored procedures. *
  • Support for temp tables. *
  • Support for casting. *
  • Support for database functions. *
  • Support for identity sequencing. *
  • Support for SEQUENCE sequencing. *
* * @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.shouldBindPartialParameters = true; this.pingSQL = "VALUES(1)"; this.supportsReturnGeneratedKeys = true; } @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, FieldTypeDefinition> buildFieldTypes() { Hashtable, FieldTypeDefinition> 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)); fieldTypeMapping.put(java.time.LocalDate.class, new FieldTypeDefinition("DATE")); fieldTypeMapping.put(java.time.LocalDateTime.class, new FieldTypeDefinition("TIMESTAMP")); fieldTypeMapping.put(java.time.LocalTime.class, new FieldTypeDefinition("TIME")); fieldTypeMapping.put(java.time.OffsetDateTime.class, new FieldTypeDefinition("TIMESTAMP")); fieldTypeMapping.put(java.time.OffsetTime.class, new FieldTypeDefinition("TIMESTAMP")); 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()); addOperator(roundOperator()); } /** * Create an ExpressionOperator that disables all parameter binding */ protected static ExpressionOperator disableAllBindingExpression() { return new ExpressionOperator() { @Override public void printDuo(Expression first, Expression second, ExpressionSQLPrinter printer) { if(!printer.getPlatform().shouldBindPartialParameters()) { super.printDuo(first, second, printer); return; } if(first.isParameterExpression()) { ((ParameterExpression) first).setCanBind(false); } else if(first.isConstantExpression()) { ((ConstantExpression) first).setCanBind(false); } if(second.isParameterExpression()) { ((ParameterExpression) second).setCanBind(false); } else if(second.isConstantExpression()) { ((ConstantExpression) second).setCanBind(false); } super.printDuo(first, second, printer); } @Override public void printCollection(List items, ExpressionSQLPrinter printer) { if(!printer.getPlatform().shouldBindPartialParameters()) { super.printCollection(items, printer); return; } for(Expression item : items) { if(item.isParameterExpression()) { ((ParameterExpression) item).setCanBind(false); } else if(item.isConstantExpression()) { ((ConstantExpression) item).setCanBind(false); } } super.printCollection(items, printer); } @Override public void printJavaDuo(Expression first, Expression second, ExpressionJavaPrinter printer) { if(!printer.getPlatform().shouldBindPartialParameters()) { super.printJavaDuo(first, second, printer); return; } if(first.isParameterExpression()) { ((ParameterExpression) first).setCanBind(false); } else if(first.isConstantExpression()) { ((ConstantExpression) first).setCanBind(false); } if(second.isParameterExpression()) { ((ParameterExpression) second).setCanBind(false); } else if(second.isConstantExpression()) { ((ConstantExpression) second).setCanBind(false); } super.printJavaDuo(first, second, printer); } @Override public void printJavaCollection(List items, ExpressionJavaPrinter printer) { if(!printer.getPlatform().shouldBindPartialParameters()) { super.printJavaCollection(items, printer); return; } for(Expression item : items) { if(item.isParameterExpression()) { ((ParameterExpression) item).setCanBind(false); } else if(item.isConstantExpression()) { ((ConstantExpression) item).setCanBind(false); } } super.printJavaCollection(items, printer); } }; } /** * Create an ExpressionOperator that requires at least 1 typed argument */ protected static ExpressionOperator disableAtLeast1BindingExpression() { return new ExpressionOperator() { @Override public void printDuo(Expression first, Expression second, ExpressionSQLPrinter printer) { if(!printer.getPlatform().shouldBindPartialParameters()) { super.printDuo(first, second, printer); return; } boolean firstBound = true; if(second != null) { boolean secondBound = true; // If both are parameters and/or constants, we need to determine which should be bound if(first.isValueExpression() && second.isValueExpression()) { if(printer.getPlatform().shouldBindLiterals()) { // If literal binding is enabled, we should make sure parameters are favored if(first.isConstantExpression() && second.isParameterExpression()) { firstBound = false; } else { secondBound = false; } } else { // Otherwise, we default to favor the first argument if(first.isParameterExpression() && second.isParameterExpression()) { secondBound = false; } } } if(second.isParameterExpression()) { ((ParameterExpression) second).setCanBind(secondBound); } else if(second.isConstantExpression()) { ((ConstantExpression) second).setCanBind(secondBound); } } if(first.isParameterExpression()) { ((ParameterExpression) first).setCanBind(firstBound); } else if(first.isConstantExpression()) { ((ConstantExpression) first).setCanBind(firstBound); } super.printDuo(first, second, printer); } @Override public void printCollection(List items, ExpressionSQLPrinter printer) { if(!printer.getPlatform().shouldBindPartialParameters()) { super.printCollection(items, printer); return; } int[] indices = getArgumentIndices(items.size()); boolean allBind = true; for (int i = 0; i < items.size(); i++) { final int index = indices[i]; Expression item = items.get(index); boolean shouldBind = true; // If the item isn't a Constant/Parameter, this will suffice and the rest should bind if(!item.isValueExpression()) { allBind = false; } if(allBind) { if(printer.getPlatform().shouldBindLiterals()) { if((i == (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(List items, ExpressionJavaPrinter printer) { if(!printer.getPlatform().shouldBindPartialParameters()) { super.printJavaCollection(items, printer); return; } boolean allBind = true; for (int i = 0; i < items.size(); i++) { Expression item = items.get(i); boolean shouldBind = true; // If the item isn't a Constant/Parameter, this will suffice and the rest should bind if(!item.isValueExpression()) { allBind = false; } if(allBind) { if(printer.getPlatform().shouldBindLiterals()) { if((i == (items.size() - 1))) { // The last parameter has to be disabled shouldBind = allBind = false; } } else { if(item.isConstantExpression()) { // The first literal has to be disabled shouldBind = allBind = false; } else if((i == (items.size() - 1)) && item.isParameterExpression()) { // The last parameter has to be disabled shouldBind = allBind = false; } } } if(item.isParameterExpression()) { ((ParameterExpression) item).setCanBind(shouldBind); } else if(item.isConstantExpression()) { ((ConstantExpression) item).setCanBind(shouldBind); } } super.printJavaCollection(items, printer); } }; } /** * Disable binding support. *

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

The statement cannot be executed because a parameter marker has been used 
     * in an invalid way. DB2 SQL Error: SQLCODE=-418, SQLSTATE=42610
*/ protected ExpressionOperator trim2() { ExpressionOperator operator = new ExpressionOperator(){ @Override public void printCollection(List items, ExpressionSQLPrinter printer) { if(!printer.getPlatform().shouldBindPartialParameters()) { super.printCollection(items, printer); return; } int[] indices = getArgumentIndices(items.size()); for (int i = 0; i < items.size(); i++) { final int index = indices[i]; Expression item = items.get(index); // Disable the first item, which should be for this operator if(i == 0) { if(item.isParameterExpression()) { ((ParameterExpression) item).setCanBind(false); } else if(item.isConstantExpression()) { ((ConstantExpression) item).setCanBind(false); } } } super.printCollection(items, printer); } @Override public void printJavaCollection(List items, ExpressionJavaPrinter printer) { if(!printer.getPlatform().shouldBindPartialParameters()) { super.printJavaCollection(items, printer); return; } for (int i = 0; i < items.size(); i++) { Expression item = items.get(i); // Disable the first item, which should be for this operator if(i == 0) { if(item.isParameterExpression()) { ((ParameterExpression) item).setCanBind(false); } else if(item.isConstantExpression()) { ((ConstantExpression) item).setCanBind(false); } } } super.printJavaCollection(items, printer); } }; operator.setType(ExpressionOperator.FunctionOperator); operator.setSelector(ExpressionOperator.Trim2); List v = new ArrayList<>(3); 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 <operand2> *

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

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

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

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

* 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
*/ protected ExpressionOperator roundOperator() { ExpressionOperator operator = disableAtLeast1BindingExpression(); ExpressionOperator.round().copyTo(operator); 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, ? super Number> maximumNumericValues() { Hashtable, ? super Number> values = new Hashtable<>(); values.put(Integer.class, Integer.MAX_VALUE); values.put(Long.class, (long) Integer.MAX_VALUE); values.put(Float.class, 123456789F); values.put(Double.class, (double) Float.MAX_VALUE); values.put(Short.class, Short.MAX_VALUE); values.put(Byte.class, 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, ? super Number> minimumNumericValues() { Hashtable, ? super Number> values = new Hashtable<>(); values.put(Integer.class, Integer.MIN_VALUE); values.put(Long.class, (long) Integer.MIN_VALUE); values.put(Float.class, (float) -123456789); values.put(Double.class, (double) Float.MIN_VALUE); values.put(Short.class, Short.MIN_VALUE); values.put(Byte.class, 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 org.eclipse.persistence.internal.expressions.ConstantExpression#writeFields(ExpressionSQLPrinter, List, SQLSelectStatement) * @see org.eclipse.persistence.internal.expressions.ParameterExpression#writeFields(ExpressionSQLPrinter, List, SQLSelectStatement) */ @Override public boolean allowBindingForSelectClause() { return false; } /** * INTERNAL: * DB2 requires casting on certain operations, such as the CONCAT function, * 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); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy