Skip to content

Commit

Permalink
jakartaee/persistence#431 - add SchemaManager
Browse files Browse the repository at this point in the history
Initial implementation.

Signed-off-by: Tomáš Kraus <[email protected]>
  • Loading branch information
Tomas-Kraus committed Dec 13, 2023
1 parent 149e9ce commit 7bd80a7
Show file tree
Hide file tree
Showing 35 changed files with 2,510 additions and 416 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@
// - 533148 : Add the eclipselink.jpa.sql-call-deferral property
// 12/06/2018 - Will Dazey
// - 542491: Add new 'eclipselink.jdbc.force-bind-parameters' property to force enable binding
// 12/05/2023: Tomas Kraus
// - New Jakarta Persistence 3.2 Features
package org.eclipse.persistence.config;

import jakarta.persistence.EntityManager;
Expand Down Expand Up @@ -2357,6 +2359,14 @@ public class PersistenceUnitProperties {
*/
public static final String SCHEMA_GENERATION_NONE_ACTION = "none";

/**
* The parameter value "<code>verify</code>"
* <p>For use with the "<code>jakarta.persistence.schema-generation.database.action</code>"
* and "<code>jakarta.persistence.schema-generation.scripts.action</code>" properties.</p>
* <p>Specifies that database tables should be verified.</p>
*/
public static final String SCHEMA_GENERATION_VERIFY_ACTION = "verify";

/**
* The parameter value "<code>metadata</code>"
* <p>For use with the "<code>jakarta.persistence.schema-generation.create-source</code>"
Expand Down Expand Up @@ -3032,7 +3042,7 @@ public class PersistenceUnitProperties {
* should be automatically generated for foreign key constraints. It is normally recommended to have
* an index for a foreign key.
* <p>
* By default indexes are not generated, most database also do not auto generate indexes, although some do.
* By default, indexes are not generated, most database also do not auto generate indexes, although some do.
* <p>
* <b>Allowed Values:</b>
* <ul>
Expand All @@ -3044,6 +3054,39 @@ public class PersistenceUnitProperties {
*/
public static final String DDL_GENERATION_INDEX_FOREIGN_KEYS = "eclipselink.ddl-generation.index-foreign-keys";

/**
* The "<code>eclipselink.schema-validation.mode</code>" property specifies database schema validation mode.
* By default, the "<code>simple</code>" validation mode is selected.
* <b>Allowed Values:</b>
* <ul>
* <li>"<code>simple</code>" (DEFAULT)
* <li>"<code>full</code>" (experimental feature, may not work properly)
* </ul>
*
* @see #SCHEMA_VALIDATION_MODE_SIMPLE
* @see #SCHEMA_VALIDATION_MODE_FULL
*/
public static final String SCHEMA_VALIDATION_MODE = "eclipselink.schema-validation.mode";

/**
* The "<code>simple</code>" value of the "<code>eclipselink.schema-validation.mode</code>" property.
* Specifies, that simple schema validation shall be performed.
* Simple schema validation checks missing tables and missing or surplus columns in the existing tables.
*
* @see #SCHEMA_VALIDATION_MODE
*/
public static final String SCHEMA_VALIDATION_MODE_SIMPLE = "simple";

/**
* The "<code>full</code>" value of the "<code>eclipselink.schema-validation.mode</code>" property.
* Specifies, that full schema validation shall be performed.
* This feature is experimental and may not work properly on all supported databases.
* Full schema validation also checks differences in columns definitions.
*
* @see #SCHEMA_VALIDATION_MODE
*/
public static final String SCHEMA_VALIDATION_MODE_FULL = "full";

/**
* The parameter value "<code>sql-script</code>" specifies that DDL will be written to file(s).
* <p>For use with the "<code>eclipselink.ddl-generation.output-mode</code>" property.</p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@
// - 542491: Add new 'eclipselink.jdbc.force-bind-parameters' property to force enable binding
// 13/01/2022-4.0.0 Tomas Kraus
// - 1391: JSON support in JPA
// 12/05/2023: Tomas Kraus
// - New Jakarta Persistence 3.2 Features
package org.eclipse.persistence.internal.databaseaccess;

// javase imports

import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.exceptions.DatabaseException;
import org.eclipse.persistence.exceptions.ValidationException;
Expand Down Expand Up @@ -3802,7 +3802,34 @@ public void initializeConnectionData(Connection connection) throws SQLException
*/
public void writeAddColumnClause(Writer writer, AbstractSession session, TableDefinition table, FieldDefinition field) throws IOException {
writer.write("ADD ");
field.appendDBString(writer, session, table);
field.appendDBCreateString(writer, session, table);
}

/**
* INTERNAL:
* May need to override this method if the platform supports ALTER TABLE DROP COLUMN &lt;column&gt;
* and the generated sql doesn't work.
* Write the string that follows ALTER TABLE to create a sql statement for
* the platform in order to drop existing column from an existing table.
*/
public void writeDropColumnClause(Writer writer, AbstractSession session, TableDefinition table, String fieldName) throws IOException {
writer.write("DROP COLUMN ");
writer.write(fieldName);
}

/**
* INTERNAL:
* May need to override this method if the platform supports TRUNCATE TABLE &lt;table&gt;
* and the generated sql doesn't work.
* Write the string that creates TRUNCATE TABLE sql statement for the platform in order
* to truncate an existing table.
*/
public void writeTruncateTable(Writer writer, AbstractSession session, TableDefinition table) throws IOException {
String tableName = table.getTable() == null
? table.getName()
: table.getTable().getName();
writer.write("TRUNCATE TABLE ");
writer.write(tableName);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,15 @@

// Contributors:
// Oracle - initial API and implementation from Oracle TopLink
// 12/05/2023: Tomas Kraus
// - New Jakarta Persistence 3.2 Features
package org.eclipse.persistence.internal.databaseaccess;

import java.io.Serializable;
import java.util.Collections;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

/**
* INTERNAL:
Expand All @@ -39,8 +45,10 @@ public class FieldTypeDefinition implements Serializable {
protected int maxScale;
protected boolean shouldAllowNull; //allow for specific types/platforms to not allow null
protected String typesuffix;
// All type aliases, including primary name. Type names are converted to upper case to be case-insensitive.
private final Set<String> aliases;

public FieldTypeDefinition() {
private FieldTypeDefinition(Set<String> aliasesSet) {
defaultSize = 10;
isSizeRequired = false;
isSizeAllowed = true;
Expand All @@ -49,19 +57,33 @@ public FieldTypeDefinition() {
maxScale = 0;
shouldAllowNull = true;
typesuffix = null;
aliases = aliasesSet;
}

/**
* Return a new field type.
* @see #setName(String)
*/
/**
* Creates a new instance of {@link FieldTypeDefinition}
*/
public FieldTypeDefinition() {
this(Collections.emptySet());
}

/**
* Creates a new instance of {@link FieldTypeDefinition} with database type name,
* see {@link #setName(String)}.
*
* @param databaseTypeName database type name
*/
public FieldTypeDefinition(String databaseTypeName) {
this();
name = databaseTypeName;
}

/**
* Return a new field type with a required size defaulting to the defaultSize.
* Creates a new instance of {@link FieldTypeDefinition} with database type name
* and default required size.
*
* @param databaseTypeName database type name
* @param defaultSize default required size
*/
public FieldTypeDefinition(String databaseTypeName, int defaultSize) {
this();
Expand All @@ -72,7 +94,12 @@ public FieldTypeDefinition(String databaseTypeName, int defaultSize) {
}

/**
* Return a new field type with a required size defaulting to the defaultSize.
* Creates a new instance of {@link FieldTypeDefinition} with database type name
* and default required size and sub-size.
*
* @param databaseTypeName database type name
* @param defaultSize default required size
* @param defaultSubSize default required sub-size
*/
public FieldTypeDefinition(String databaseTypeName, int defaultSize, int defaultSubSize) {
this();
Expand All @@ -84,23 +111,53 @@ public FieldTypeDefinition(String databaseTypeName, int defaultSize, int default
setMaxScale(defaultSubSize);
}

public FieldTypeDefinition(String databaseTypeName, int defaultSize, String aTypesuffix) {
/**
* Creates a new instance of {@link FieldTypeDefinition} with database type name,
* default required size and type suffix.
*
* @param databaseTypeName database type name
* @param defaultSize default required size
* @param typeSuffix type suffix
*/
public FieldTypeDefinition(String databaseTypeName, int defaultSize, String typeSuffix) {
this(databaseTypeName, defaultSize);
this.typesuffix = aTypesuffix;
this.typesuffix = typeSuffix;
this.isSizeAllowed = true;
}

/**
* Return a new field type with a required size defaulting to the defaultSize.
* Creates a new instance of {@link FieldTypeDefinition} with database type name.
*
* @param databaseTypeName database type name
* @param allowsSize whether database type allows size definition (e.g. {@code VARCHAR(8)}, {@code DECIMAL(15)})
*/
public FieldTypeDefinition(String databaseTypeName, boolean allowsSize) {
this();
this.name = databaseTypeName;
this.isSizeAllowed = allowsSize;
}

/** Return a new field type with a required size defaulting to the defaultSize and
* shouldAllowNull set to allowsNull.
/**
* Creates a new instance of {@link FieldTypeDefinition} with database type name
* and allowable size definition.
*
* @param databaseTypeName database type name
* @param allowsSize whether database type allows size definition (e.g. {@code VARCHAR(8)}, {@code DECIMAL(15)})
* @param typeNameAliases database type name aliases (used to match type name provided by the database in schema validation)
*/
public FieldTypeDefinition(String databaseTypeName, boolean allowsSize, String... typeNameAliases) {
this(createAliasesSet(typeNameAliases));
this.name = databaseTypeName;
this.isSizeAllowed = allowsSize;
}

/**
* Creates a new instance of {@link FieldTypeDefinition} with database type name
* and allowable size definition and {@code NULL} values.
*
* @param databaseTypeName database type name
* @param allowsSize whether database type allows size definition (e.g. {@code VARCHAR(8)}, {@code DECIMAL(15)})
* @param allowsNull whether database type allows @code NULL} values.
*/
public FieldTypeDefinition(String databaseTypeName, boolean allowsSize, boolean allowsNull) {
this(databaseTypeName, allowsSize);
Expand Down Expand Up @@ -284,6 +341,19 @@ public void setName(String name) {
this.name = name;
}

/**
* Check whether provided type name matches any known type alias.
* Check is case-insensitive. Provided type name shall not be null.
*
* @param nameAlias type name to check, not {@code null}
* @return Value of {@code true} when provided name matches type name
* or any of its name aliases or {@code false} otherwise.
*/
public boolean isTypeName(String nameAlias) {
Objects.requireNonNull(nameAlias, "Checked type name is null.");
return nameAlias.equalsIgnoreCase(name) || aliases.contains(nameAlias.toUpperCase());
}

/**
* Set this type to not allow a size specification.
*/
Expand All @@ -310,4 +380,18 @@ public void setSizeRequired() {
public String toString() {
return getClass().getSimpleName() + "(" + getName() + ")";
}

// Constructor helper to build database type name aliases set
// Type name aliases are converted to upper case.
private static Set<String> createAliasesSet(String... typeNameAliases) {
if (typeNameAliases == null || typeNameAliases.length == 0) {
return Collections.emptySet();
}
Set<String> aliasesSet = new HashSet<>(typeNameAliases.length);
for (String typeNameAlias : typeNameAliases) {
aliasesSet.add(typeNameAlias.toUpperCase());
}
return Set.copyOf(aliasesSet);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
// - 454189 : Misc message cleanup.#2
// 03/09/2016-2.6 Dalia Abo Sheasha
// - 489298: Wrap EclipseLink's Bean Validation calls in doPrivileged blocks when security is enabled
// 12/05/2023: Tomas Kraus
// - New Jakarta Persistence 3.2 Features
package org.eclipse.persistence.internal.localization.i18n;

import java.util.ListResourceBundle;
Expand Down Expand Up @@ -265,7 +267,13 @@ public class ExceptionLocalizationResource extends ListResourceBundle {
{ "json_pgsql_pgobject_conversion", "Database PGobject conversion failed."},
{ "json_pgsql_unknown_type", "Unknown JSON type returned from database."},
{ "json_ora21c_jsonvalue_to_oraclevalue", "Could not convert JsonValue to OracleJsonValue."},
{ "json_ora21c_resultset_to_jsonvalue", "Could not convert JDBC ResultSet type to JsonValue."}
{ "json_ora21c_resultset_to_jsonvalue", "Could not convert JDBC ResultSet type to JsonValue."},
{ "schema_validation", "Schema validation"},
{ "schema_validation_failed", "Schema validation failed"},
{ "schema_validation_missing_table", "The {0} table vas not found in the schema"},
{ "schema_validation_table_surplus_columns", "The {0} table has surplus columns in the schema"},
{ "schema_validation_table_missing_columns", "The {0} table has missing columns in the schema"},
{ "schema_validation_table_different_columns", "The {0} table has different columns in the schema"}
};
/**
* Return the lookup table.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@
// - 526957 : Split the logging and trace messages
// 11/14/2017 - Dalia Abo Sheasha
// - 527273 : Minor message improvements
// 12/05/2023: Tomas Kraus
// - New Jakarta Persistence 3.2 Features
package org.eclipse.persistence.internal.localization.i18n;

import java.util.ListResourceBundle;
Expand Down Expand Up @@ -477,7 +479,13 @@ public class LoggingLocalizationResource extends ListResourceBundle {
// JPA 3.2
{ "unknown_property_type", "Unknown {0} type of {1} persistence property"},
{ "error_queryTimeoutParse", "Could not parse jakarta.persistence.query.timeout property value {0}: {1}"},
{ "schema_default_truncate_tables_failed", "Failed to truncate tables in the default table schema: {0}"},

{ "schema_default_create_tables_failed", "Failed to create tables in the default table schema: {0}"},
{ "schema_default_drop_tables_failed", "Failed to drop tables in the default table schema: {0}"},
{ "schema_default_replace_tables_failed", "Failed to replace tables in the default table schema: {0}"},
{ "schema_default_extend_tables_failed", "Failed to extend tables in the default table schema: {0}"},
{ "schema_drop_object_failed", "Failed to drop object in the default table schema: {0}"},
{ "validate_object_space", "validate object space." },
{ "stack_of_visited_objects_that_refer_to_the_corrupt_object", "stack of visited objects that refer to the corrupt object: {0}" },
{ "corrupt_object_referenced_through_mapping", "The following corrupt object is referenced through mapping: {0}" },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,7 @@ protected void appendCalendar(Calendar calendar, Writer writer) throws IOExcepti
@Override
public void writeAddColumnClause(Writer writer, AbstractSession session, TableDefinition table, FieldDefinition field) throws IOException {
writer.write("ADD (");
field.appendDBString(writer, session, table);
field.appendDBCreateString(writer, session, table);
writer.write(")");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
// - 440278: Support fractional seconds in time values
// 02/19/2015 - Rick Curtis
// - 458877 : Add national character support
// 12/05/2023: Tomas Kraus
// - New Jakarta Persistence 3.2 Features
package org.eclipse.persistence.platform.database;

import org.eclipse.persistence.exceptions.ValidationException;
Expand Down Expand Up @@ -179,7 +181,7 @@ protected Hashtable<Class<?>, FieldTypeDefinition> buildFieldTypes() {
Hashtable<Class<?>, FieldTypeDefinition> fieldTypeMapping = new Hashtable<>();
fieldTypeMapping.put(Boolean.class, new FieldTypeDefinition("TINYINT(1) default 0", false));

fieldTypeMapping.put(Integer.class, new FieldTypeDefinition("INTEGER", false));
fieldTypeMapping.put(Integer.class, new FieldTypeDefinition("INTEGER", false, "INT"));
fieldTypeMapping.put(Long.class, new FieldTypeDefinition("BIGINT", false));
fieldTypeMapping.put(Float.class, new FieldTypeDefinition("FLOAT", false));
fieldTypeMapping.put(Double.class, new FieldTypeDefinition("DOUBLE", false));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@
// Contributors:
// 01/19/2012-2.4 Chris Delahunt
// - 368490: Add support for Metadata to be refreshed through RCM
// 12/05/2023: Tomas Kraus
// - New Jakarta Persistence 3.2 Features
package org.eclipse.persistence.sessions.coordination;

import java.util.Map;

public interface MetadataRefreshListener {
void triggerMetadataRefresh(Map properties);
void triggerMetadataRefresh(Map<String, ?> properties);
}
Loading

0 comments on commit 7bd80a7

Please sign in to comment.