Bug 392109 - Pervasive PSQL JPA support
diff --git a/extensions/org.eclipse.persistence.platrom.database.pervasive/src/org/eclipse/persistence/platform/database/PervasivePlatform.java b/extensions/org.eclipse.persistence.platrom.database.pervasive/src/org/eclipse/persistence/platform/database/PervasivePlatform.java
new file mode 100644
index 0000000..1b28f77
--- /dev/null
+++ b/extensions/org.eclipse.persistence.platrom.database.pervasive/src/org/eclipse/persistence/platform/database/PervasivePlatform.java
@@ -0,0 +1,460 @@
+/*
+
+ For minimal implementation, compare with:
+ C:\PL\JPA\EclipseLink\SVN\org.eclipse.persistence\foundation\org.eclipse.persistence.core\src\org\eclipse\persistence\platform\database\CloudscapePlatform.java
+
+ For PVSW data type mapping, see: getColumnClassName():C:\cmsynergy\psql11.20_pnl\psql\comp\sdk\jdbc\pvjdbc2\src\com\pervasive\jdbc\v2\ResultSetMetaData.java
+
+*/
+
+/*******************************************************************************
+ * Copyright (c) 2012 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:
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.platform.database;
+
+import java.util.*;
+
+import org.eclipse.persistence.internal.databaseaccess.FieldTypeDefinition;
+
+import java.io.*;
+import java.sql.CallableStatement;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.*;
+
+import org.eclipse.persistence.exceptions.*;
+import org.eclipse.persistence.expressions.*;
+import org.eclipse.persistence.internal.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.*;
+import org.eclipse.persistence.tools.schemaframework.FieldDefinition;
+import org.eclipse.persistence.queries.*;
+import org.eclipse.persistence.sessions.SessionProfiler;
+
+/**
+ * <p><b>Purpose</b>: Provides Pervasive DBMS specific behavior.
+ *
+ *
+ **/
+public class PervasivePlatform extends org.eclipse.persistence.platform.database.DatabasePlatform {
+
+ public static final int DEFAULT_CHAR_SIZE = 80;
+
+ //
+ // Cloned from AccessPlatform.java
+ //
+ protected Map<String, Class> buildClassTypes() {
+ Map<String, Class> classTypeMapping = super.buildClassTypes();
+
+ // Causes BLOB to translate to LONGVARBINARY(via java.sql.Blob) instead of BINARY (via Byte[])
+ classTypeMapping.put("BLOB", java.sql.Blob.class);
+
+ return classTypeMapping;
+ }
+
+
+ protected Hashtable buildFieldTypes() {
+ Hashtable fieldTypeMapping;
+
+ fieldTypeMapping = new Hashtable();
+ fieldTypeMapping.put(String.class, new FieldTypeDefinition("VARCHAR", DEFAULT_CHAR_SIZE));
+ // fieldTypeMapping.put(java.math.BigDecimal.class, new FieldTypeDefinition("BIGINT", false));
+ fieldTypeMapping.put(java.math.BigInteger.class, new FieldTypeDefinition("BIGINT", false));
+ fieldTypeMapping.put(Integer.class, new FieldTypeDefinition("INTEGER", false));
+ fieldTypeMapping.put(Long.class, new FieldTypeDefinition("INTEGER", false));
+ fieldTypeMapping.put(Short.class, new FieldTypeDefinition("SMALLINT", false));
+ fieldTypeMapping.put(Byte.class, new FieldTypeDefinition("TINYINT", false));
+ fieldTypeMapping.put(Float.class, new FieldTypeDefinition("REAL", false));
+ fieldTypeMapping.put(Double.class, new FieldTypeDefinition("DOUBLE", false));
+ fieldTypeMapping.put(Character.class, new FieldTypeDefinition("CHAR", 1));
+ 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(byte[].class, new FieldTypeDefinition("BINARY", DEFAULT_CHAR_SIZE ));
+ fieldTypeMapping.put(Byte[].class, new FieldTypeDefinition("BINARY", DEFAULT_CHAR_SIZE));
+ fieldTypeMapping.put(Character[].class, new FieldTypeDefinition("CHAR", DEFAULT_CHAR_SIZE));
+ fieldTypeMapping.put(Boolean.class, new FieldTypeDefinition("BIT", false));
+ fieldTypeMapping.put(java.sql.Blob.class, new FieldTypeDefinition("LONGVARBINARY", false));
+ fieldTypeMapping.put(java.sql.Clob.class, new FieldTypeDefinition("LONGVARCHAR", false));
+
+ fieldTypeMapping.put(java.math.BigDecimal.class, new FieldTypeDefinition("DECIMAL",38, 0)); // From MySQL
+ fieldTypeMapping.put(Number.class, new FieldTypeDefinition("DECIMAL",38,0)); // From MySQL
+
+
+ // fieldTypeMapping.put(java.lang.Number.class, new FieldTypeDefinition("BIGINT", false));
+ fieldTypeMapping.put(char[].class, new FieldTypeDefinition("LONGVARCHAR", false));
+ fieldTypeMapping.put(java.util.Calendar.class, new FieldTypeDefinition("TIMESTAMP"));
+ fieldTypeMapping.put(java.util.Date.class, new FieldTypeDefinition("TIMESTAMP"));
+
+ return fieldTypeMapping;
+ }
+
+ /**
+ *
+ * Pervasive uses the INOUT keyword, as opposed to "IN OUT".
+ */
+ @Override
+ public String getInOutputProcedureToken() {
+ return "INOUT";
+ }
+
+ /**
+ * Pervasive uses IN prefix for INPUT parameters.
+ *
+ */
+ @Override
+ public String getInputProcedureToken() {
+ return "IN";
+ }
+
+ /**
+ * Pervasive uses ":" as prefix for procedure arguments.
+ */
+ public String getProcedureArgumentString() {
+ return ":";
+ }
+
+ /**
+ *
+ * Pervasive requires BEGIN in a procedure statement.
+ */
+ @Override
+ public String getProcedureBeginString() {
+ return "BEGIN ";
+ }
+
+ /**
+ * In CREATE PROCEDURE, Pervasive requires brackets after the procedure name, even if there are no arguments.
+ */
+ public boolean requiresProcedureBrackets() {
+ return true;
+ }
+
+ /**
+ * Pervasive uses CALL or EXECUTE not CALL PROCEDURE or EXECUTE PROCEDURE
+ */
+ public String getProcedureCallHeader() {
+ return "CALL ";
+ }
+
+ /**
+ *
+ * Pervasive requires END in a procedure statement.
+ */
+ @Override
+ public String getProcedureEndString() {
+ return "END";
+ }
+
+
+ /**
+ * Pervasive uses ":" as prefix for procedure parameters.
+ */
+ public String getStoredProcedureParameterPrefix() {
+ return ":";
+ }
+
+
+ /**
+ * Pervasive requires the OUTPUT keyword for output parameters
+ */
+ @Override
+ public boolean requiresProcedureCallOuputToken() {
+ return true;
+ }
+
+
+ protected void initializePlatformOperators() {
+ super.initializePlatformOperators();
+
+ addOperator(ExpressionOperator.simpleThreeArgumentFunction(ExpressionOperator.Substring, "SUBSTRING"));
+ addOperator(singleArgumentSubstringOperator());
+ addOperator(ExpressionOperator.simpleTwoArgumentFunction(ExpressionOperator.Nvl, "ISNULL"));
+ addOperator(ExpressionOperator.simpleFunction(ExpressionOperator.Ceil, "CEILING"));
+ addOperator(toNumberOperator());
+ addOperator(toCharOperator());
+ addOperator(toDateOperator());
+ }
+
+ /**
+ * Cloned from MySQLPlatform.java
+ *
+ */
+
+ /**
+ * INTERNAL:
+ * Pervasive SQL stored procedure calls do not require the argument name be printed in the call string
+ * e.g. call MyStoredProc(?) instead of call MyStoredProc(myvariable = ?)
+ */
+ @Override
+ public boolean shouldPrintStoredProcedureArgumentNameInCall(){
+ return false;
+ }
+
+
+ protected ExpressionOperator toNumberOperator() {
+ ExpressionOperator exOperator = new ExpressionOperator();
+ exOperator.setType(ExpressionOperator.FunctionOperator);
+ exOperator.setSelector(ExpressionOperator.ToNumber);
+ Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(2);
+ v.addElement("CONVERT(");
+ v.addElement(", SQL_NUMERIC)");
+ exOperator.printsAs(v);
+ exOperator.bePrefix();
+ exOperator.setNodeClass(ClassConstants.FunctionExpression_Class);
+ return exOperator;
+ }
+
+ /**
+ * Cloned from MySQLPlatform.java
+ */
+ protected ExpressionOperator toDateOperator() {
+ ExpressionOperator exOperator = new ExpressionOperator();
+ exOperator.setType(ExpressionOperator.FunctionOperator);
+ exOperator.setSelector(ExpressionOperator.ToDate);
+ Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(2);
+ v.addElement("CONVERT(");
+ v.addElement(", DATETIME)");
+ exOperator.printsAs(v);
+ exOperator.bePrefix();
+ exOperator.setNodeClass(ClassConstants.FunctionExpression_Class);
+ return exOperator;
+ }
+
+ /**
+ * Cloned from MySQLPlatform.java
+ */
+ protected ExpressionOperator toCharOperator() {
+ ExpressionOperator exOperator = new ExpressionOperator();
+ exOperator.setType(ExpressionOperator.FunctionOperator);
+ exOperator.setSelector(ExpressionOperator.ToChar);
+ Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(2);
+ v.addElement("CONVERT(");
+ v.addElement(", SQL_CHAR)");
+ exOperator.printsAs(v);
+ exOperator.bePrefix();
+ exOperator.setNodeClass(ClassConstants.FunctionExpression_Class);
+ return exOperator;
+ }
+
+ /**
+ *
+ * Cloned from MySQLPlatform.java
+ */
+ protected ExpressionOperator dateToStringOperator() {
+ ExpressionOperator exOperator = new ExpressionOperator();
+ exOperator.setType(ExpressionOperator.FunctionOperator);
+ exOperator.setSelector(ExpressionOperator.DateToString);
+ Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(2);
+ v.addElement("CONVERT(");
+ v.addElement(", SQL_CHAR)");
+ exOperator.printsAs(v);
+ exOperator.bePrefix();
+ exOperator.setNodeClass(ClassConstants.FunctionExpression_Class);
+ return exOperator;
+ }
+
+
+
+ /**
+ * Answers whether platform is Pervasive
+ */
+ public boolean isPervasive() {
+ return true;
+ }
+
+ /**
+ * JDBC defines an outer join syntax which many drivers do not support. So we normally avoid it.
+ */
+ public boolean shouldUseJDBCOuterJoinSyntax() {
+ return false; // not sure about this
+ }
+
+ /** Append the receiver's field 'identity' constraint clause to
+ * a writer.
+ *
+ * Taken from
+ * org.eclipse.persistence\foundation\org.eclipse.persistence.core\src\org\eclipse\persistence\platform\database\AccessPlatform.java
+ */
+ public void printFieldIdentityClause(Writer writer) throws ValidationException {
+ try {
+ writer.write(" IDENTITY");
+ } catch (IOException ioException) {
+ throw ValidationException.fileError(ioException);
+ }
+ }
+
+
+ /**
+ * Override the default SubstringSingleArg operator.
+ * Cloned from SybasePlatform.java
+ */
+ public ExpressionOperator singleArgumentSubstringOperator() {
+ ExpressionOperator result = new ExpressionOperator();
+ result.setSelector(ExpressionOperator.SubstringSingleArg);
+ result.setType(ExpressionOperator.FunctionOperator);
+ Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance();
+ v.addElement("SUBSTRING(");
+ v.addElement(",");
+ v.addElement(", CHAR_LENGTH(");
+ v.addElement("))");
+ result.printsAs(v);
+ int[] indices = new int[3];
+ indices[0] = 0;
+ indices[1] = 1;
+ indices[2] = 0;
+
+ result.setArgumentIndices(indices);
+ result.setNodeClass(ClassConstants.FunctionExpression_Class);
+ result.bePrefix();
+ return result;
+ }
+
+
+
+
+ /**
+ *
+ * Indicates whether the platform supports identity.
+ *
+ */
+ public boolean supportsIdentity() {
+ return true;
+ }
+
+ //
+ // Most Temp Table settings cloned from SQLServerPlatform.java
+ //
+ /**
+ * INTERNAL:
+ */
+ public boolean supportsLocalTempTables() {
+ return true;
+ }
+
+
+ public boolean supportsGlobalTempTables() {
+ return true;
+ }
+
+
+ /**
+ * INTERNAL:
+ */
+ protected String getCreateTempTableSqlPrefix() {
+ return "CREATE TABLE ";
+ }
+
+ /**
+ * INTERNAL:
+ */
+ public DatabaseTable getTempTableForTable(DatabaseTable table) {
+ return new DatabaseTable("#" + table.getName(), table.getTableQualifier(), table.shouldUseDelimiters(), getStartDelimiter(), getEndDelimiter());
+ }
+
+
+ /**
+ *
+ * Taken from org.eclipse.persistence\foundation\org.eclipse.persistence.core\src\org\eclipse\persistence\platform\database\AccessPlatform.java
+ */
+ public void printFieldTypeSize(Writer writer, FieldDefinition field,FieldTypeDefinition fieldType, boolean shouldPrintFieldIdentityClause) throws IOException {
+ if (!shouldPrintFieldIdentityClause) {
+ // if type requires both precision and scale: NUMERIC, DECIMAL
+ if ((fieldType.getName().equals("NUMERIC")) || (fieldType.getName().equals("DECIMAL"))) {
+ writer.write(fieldType.getName());
+ writer.write("(");
+ if (field.getSize() == 0) {
+ writer.write(Integer.valueOf(fieldType.getDefaultSize()).toString());
+ } else {
+ writer.write(Integer.valueOf(field.getSize()).toString());
+ }
+ writer.write(",");
+ if (field.getSubSize() != 0) {
+ writer.write(Integer.valueOf(field.getSubSize()).toString());
+ } else {
+ writer.write(Integer.valueOf(fieldType.getDefaultSubSize()).toString());
+ }
+ writer.write(")");
+ } else {
+ super.printFieldTypeSize(writer, field, fieldType,
+ shouldPrintFieldIdentityClause);
+ }
+ }
+ }
+
+ /**
+ * INTERNAL:
+ * Build the identity query for native sequencing.
+ *
+ * Taken verbatim from org.eclipse.persistence\foundation\org.eclipse.persistence.core\src\org\eclipse\persistence\platform\database\SQLServerPlatform.java
+ *
+ */
+ @Override
+ public ValueReadQuery buildSelectQueryForIdentity() {
+ ValueReadQuery selectQuery = new ValueReadQuery();
+ selectQuery.setSQLString("SELECT @@IDENTITY");
+ return selectQuery;
+ }
+
+ /**
+ * Temporary workaround to avoid joined queries with FOR UPDATE
+ * in them
+ *
+ */
+ public String getSelectForUpdateString() {
+ return "";
+ }
+
+
+
+
+ /**
+ * INTERNAL:
+ * Indicates whether SELECT DISTINCT ... FOR UPDATE is allowed by the platform (Oracle doesn't allow this).
+ */
+ public boolean isForUpdateCompatibleWithDistinct() {
+ return false;
+ }
+
+
+ /**
+ * Setting this to false (cf. Sybase) to work around problem
+ * that unspecified default delete rule is RESTRICT, even when
+ * not allowed due to self-referencing table.
+ */
+ @Override
+ public boolean supportsDeleteOnCascade() {
+ return true;
+ }
+
+
+ /** Attempts to remove FOR UPDATE from queries */
+ @Override
+ public boolean shouldPrintLockingClauseAfterWhereClause() {
+ return false;
+ }
+
+ /**
+ * INTERNAL:
+ * Indicates whether locking clause could be applied to the query that has more than one table
+ */
+ public boolean supportsLockingQueriesWithMultipleTables() {
+ return false;
+ }
+
+
+
+
+}