Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue 1822 - Add Vacuum Setting support for PostgreSQL #2628

Merged
merged 7 commits into from
Jul 21, 2021
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import com.ibm.fhir.database.utils.model.PrimaryKeyDef;
import com.ibm.fhir.database.utils.model.Privilege;
import com.ibm.fhir.database.utils.model.Table;
import com.ibm.fhir.database.utils.model.With;

/**
* Abstraction of the SQL to use for a given database. This allows us to hide as
Expand Down Expand Up @@ -74,9 +75,10 @@ public interface IDatabaseAdapter {
* @param primaryKey
* @param identity
* @param tablespaceName
* @param withs
*/
public void createTable(String schemaName, String name, String tenantColumnName, List<ColumnBase> columns,
PrimaryKeyDef primaryKey, IdentityDef identity, String tablespaceName);
PrimaryKeyDef primaryKey, IdentityDef identity, String tablespaceName, List<With> withs);

/**
* Add a new column to an existing table
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import com.ibm.fhir.database.utils.model.Privilege;
import com.ibm.fhir.database.utils.model.Table;
import com.ibm.fhir.database.utils.model.Tenant;
import com.ibm.fhir.database.utils.model.With;
import com.ibm.fhir.database.utils.tenant.AddTenantDAO;
import com.ibm.fhir.database.utils.tenant.AddTenantKeyDAO;
import com.ibm.fhir.database.utils.tenant.CreateOrReplaceViewDAO;
Expand Down Expand Up @@ -134,9 +135,10 @@ else if (!column.isNullable()) {
* @param columns
* @param pkDef
* @param tablespaceName
prb112 marked this conversation as resolved.
Show resolved Hide resolved
* @param withs the list of table metadata parameters
* @return
*/
protected String buildCreateTableStatement(String schema, String name, List<ColumnBase> columns, PrimaryKeyDef pkDef, IdentityDef identity, String tablespaceName) {
protected String buildCreateTableStatement(String schema, String name, List<ColumnBase> columns, PrimaryKeyDef pkDef, IdentityDef identity, String tablespaceName, List<With> withs) {
StringBuilder result = new StringBuilder();
result.append("CREATE TABLE ");
result.append(getQualifiedName(schema, name));
Expand All @@ -162,6 +164,17 @@ protected String buildCreateTableStatement(String schema, String name, List<Colu
}
result.append(')');

// Creates WITH (fillfactor=70, key2=val2);
if (withs != null && !withs.isEmpty()) {
StringBuilder builder = new StringBuilder(" WITH (");
builder.append(
withs.stream()
.map(with -> with.buildWithComponent())
.collect(Collectors.joining(",")));
builder.append(")");
result.append(builder.toString());
}

if (tablespaceName != null) {
DataDefinitionUtil.assertValidName(tablespaceName);
result.append(" IN ");
Expand Down Expand Up @@ -458,12 +471,10 @@ public void runStatement(IDatabaseStatement stmt) {
if (this.connectionProvider != null) {
try (Connection c = connectionProvider.getConnection()) {
stmt.run(getTranslator(), c);
}
catch (SQLException x) {
} catch (SQLException x) {
throw translator.translate(x);
}
}
else {
} else {
this.target.runStatement(getTranslator(), stmt);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* (C) Copyright IBM Corp. 2019, 2020
* (C) Copyright IBM Corp. 2019, 2021
*
* SPDX-License-Identifier: Apache-2.0
*/
Expand Down Expand Up @@ -40,6 +40,7 @@
import com.ibm.fhir.database.utils.model.IntColumn;
import com.ibm.fhir.database.utils.model.PrimaryKeyDef;
import com.ibm.fhir.database.utils.model.Table;
import com.ibm.fhir.database.utils.model.With;
import com.ibm.fhir.database.utils.transaction.TransactionFactory;
prb112 marked this conversation as resolved.
Show resolved Hide resolved

/**
Expand Down Expand Up @@ -69,7 +70,7 @@ public Db2Adapter() {

@Override
public void createTable(String schemaName, String name, String tenantColumnName, List<ColumnBase> columns, PrimaryKeyDef primaryKey,
IdentityDef identity, String tablespaceName) {
IdentityDef identity, String tablespaceName, List<With> withs) {

// With DB2 we can implement support for multi-tenancy, which we do by injecting a MT_ID column
// to the definition and partitioning on that column
Expand All @@ -93,7 +94,7 @@ public void createTable(String schemaName, String name, String tenantColumnName,
// Now append all the actual columns we want in the table
cols.addAll(columns);

String ddl = buildCreateTableStatement(schemaName, name, cols, primaryKey, identity, tablespaceName);
String ddl = buildCreateTableStatement(schemaName, name, cols, primaryKey, identity, tablespaceName, With.EMPTY);

// Our multi-tenant tables are range-partitioned as part of our data isolation strategy
// We reserve partition 0. Real tenant partitions start at 1...
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* (C) Copyright IBM Corp. 2019, 2020
* (C) Copyright IBM Corp. 2019, 2021
*
* SPDX-License-Identifier: Apache-2.0
*/
Expand Down Expand Up @@ -30,6 +30,7 @@
import com.ibm.fhir.database.utils.model.OrderedColumnDef;
import com.ibm.fhir.database.utils.model.PrimaryKeyDef;
import com.ibm.fhir.database.utils.model.Table;
import com.ibm.fhir.database.utils.model.With;

prb112 marked this conversation as resolved.
Show resolved Hide resolved
/**
* A Derby database target
Expand Down Expand Up @@ -75,14 +76,14 @@ public void warnOnce(MessageKey messageKey, String msg) {

@Override
public void createTable(String schemaName, String name, String tenantColumnName, List<ColumnBase> columns, PrimaryKeyDef primaryKey,
IdentityDef identity, String tablespaceName) {
IdentityDef identity, String tablespaceName, List<With> withs) {
// Derby doesn't support partitioning, so we ignore tenantColumnName
if (tenantColumnName != null) {
warnOnce(MessageKey.MULTITENANCY, "Derby does not support multi-tenancy on: [" + name + "]");
}

// We also ignore tablespace for Derby
String ddl = buildCreateTableStatement(schemaName, name, columns, primaryKey, identity, null);
String ddl = buildCreateTableStatement(schemaName, name, columns, primaryKey, identity, null, With.EMPTY);
runStatement(ddl);
}

Expand Down Expand Up @@ -194,12 +195,12 @@ public void createSequence(String schemaName, String sequenceName, long startWit
// Derby doesn't support CACHE
final String sname = DataDefinitionUtil.getQualifiedName(schemaName, sequenceName);
final String ddl = "CREATE SEQUENCE " + sname + " AS BIGINT "
+ " START WITH " + startWith
+ " START WITH " + startWith
+ " INCREMENT BY " + incrementBy
+ " NO CYCLE";
runStatement(ddl);
}

@Override
public void dropSequence(String schemaName, String sequenceName) {
// the "RESTRICT" keyword is mandatory in Derby
Expand All @@ -213,7 +214,7 @@ public void dropSequence(String schemaName, String sequenceName) {
}
}


@Override
public void alterSequenceRestartWith(String schemaName, String sequenceName, long restartWith, int cache, int incrementBy) {
// Derby doesn't support ALTER SEQUENCE, so we have to drop and create again with the start value.
Expand All @@ -224,22 +225,22 @@ public void alterSequenceRestartWith(String schemaName, String sequenceName, lon
if (maxValue != null && maxValue > restartWith) {
restartWith = maxValue;
}

// Derby doesn't use the CACHE attribute, so cache will be ignored. This change is important,
// so we log it as info.
final String sname = DataDefinitionUtil.getQualifiedName(schemaName, sequenceName);
logger.info("Recreating sequence '" + sname + "' START WITH " + restartWith);
dropSequence(schemaName, sequenceName);
createSequence(schemaName, sequenceName, restartWith, cache, incrementBy);
}

@Override
public void alterTableColumnIdentityCache(String schemaName, String tableName, String columnName, int cache) {
// Not supported by Derby

final String qname = DataDefinitionUtil.getQualifiedName(schemaName, tableName);
DataDefinitionUtil.assertValidName(columnName);

// modify the CACHE property of the identity column
final String ddl = "ALTER TABLE " + qname + " ALTER COLUMN " + columnName + " SET CACHE " + cache;

Expand Down Expand Up @@ -354,7 +355,7 @@ public void setIntegrityUnchecked(String schemaName, String tableName) {
// not expecting this to be called for this adapter
throw new UnsupportedOperationException("Set integrity unchecked not supported for this adapter.");
}

@Override
public void createOrReplaceView(String schemaName, String viewName, String selectClause) {
// Derby doesn't support CREATE OR REPLACE VIEW, so we have to try and drop the view first
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,10 @@ public void visit(DataModelVisitor v, final String tagGroup, final String tag) {
.forEach(obj -> obj.visit(v));
}

/**
* Visits all objects in the data model
* @param v
*/
public void visit(DataModelVisitor v) {
// visit every object
this.allObjects.forEach(obj -> obj.visit(v));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ public class Table extends BaseObject {
// The column to use when making this table multi-tenant (if supported by the the target)
private final String tenantColumnName;

// The With parameters on the table
private final List<With> withs;

/**
* Public constructor
*
Expand All @@ -68,7 +71,7 @@ public class Table extends BaseObject {
public Table(String schemaName, String name, int version, String tenantColumnName, Collection<ColumnBase> columns, PrimaryKeyDef pk,
IdentityDef identity, Collection<IndexDef> indexes, Collection<ForeignKeyConstraint> fkConstraints,
SessionVariableDef accessControlVar, Tablespace tablespace, List<IDatabaseObject> dependencies, Map<String,String> tags,
Collection<GroupPrivilege> privileges, List<Migration> migrations) {
Collection<GroupPrivilege> privileges, List<Migration> migrations, List<With> withs) {
super(schemaName, name, DatabaseObjectType.TABLE, version, migrations);
this.tenantColumnName = tenantColumnName;
this.columns.addAll(columns);
Expand All @@ -78,6 +81,7 @@ public Table(String schemaName, String name, int version, String tenantColumnNam
this.fkConstraints.addAll(fkConstraints);
this.accessControlVar = accessControlVar;
this.tablespace = tablespace;
this.withs = withs;

// Adds all dependencies which aren't null.
// The only circumstances where it is null is when it is self referencial (an FK on itself).
Expand Down Expand Up @@ -114,7 +118,7 @@ public String getTenantColumnName() {
@Override
public void apply(IDatabaseAdapter target) {
final String tsName = this.tablespace == null ? null : this.tablespace.getName();
target.createTable(getSchemaName(), getObjectName(), this.tenantColumnName, this.columns, this.primaryKey, this.identity, tsName);
target.createTable(getSchemaName(), getObjectName(), this.tenantColumnName, this.columns, this.primaryKey, this.identity, tsName, this.withs);

// Now add any indexes associated with this table
for (IndexDef idx: this.indexes) {
Expand Down Expand Up @@ -224,6 +228,9 @@ public static class Builder extends VersionedSchemaObject {
// Privileges to be granted on this table
private List<GroupPrivilege> privileges = new ArrayList<>();

// With metadata on the Table
private List<With> withs = new ArrayList<>();

/**
* Private constructor to force creation through factory method
* @param schemaName
Expand Down Expand Up @@ -685,7 +692,7 @@ public Table build(IDataModel dataModel) {
// Our schema objects are immutable by design, so all initialization takes place
// through the constructor
return new Table(getSchemaName(), getObjectName(), this.version, this.tenantColumnName, buildColumns(), this.primaryKey, this.identity, this.indexes.values(),
this.fkConstraints.values(), this.accessControlVar, this.tablespace, allDependencies, tags, privileges, migrations);
this.fkConstraints.values(), this.accessControlVar, this.tablespace, allDependencies, tags, privileges, migrations, withs);

}

Expand Down Expand Up @@ -803,6 +810,15 @@ public Builder addMigration(Migration... migration) {
super.addMigration(migration);
return this;
}

/**
* adds with parameters (key-values) to the table definition.
* @param withs
*/
public Builder addWiths(List<With> withs) {
this.withs.addAll(withs);
return this;
}
}

/**
Expand All @@ -814,24 +830,16 @@ public boolean exists(IDatabaseAdapter target) {
return target.doesTableExist(getSchemaName(), getObjectName());
}

/* (non-Javadoc)
* @see com.ibm.fhir.database.utils.model.IDatabaseObject#visit(com.ibm.fhir.database.utils.model.DataModelVisitor)
*/
@Override
public void visit(DataModelVisitor v) {
v.visited(this);

this.fkConstraints.forEach(fk -> v.visited(this, fk));
}

/* (non-Javadoc)
* @see com.ibm.fhir.database.utils.model.IDatabaseObject#visitReverse(com.ibm.fhir.database.utils.model.DataModelVisitor)
*/
@Override
public void visitReverse(DataModelVisitor v) {
// visit the child objects first when going in reverse
this.fkConstraints.forEach(fk -> v.visited(this, fk));

v.visited(this);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* (C) Copyright IBM Corp. 2021
*
* SPDX-License-Identifier: Apache-2.0
*/

package com.ibm.fhir.database.utils.model;

import java.util.Collections;
import java.util.List;

/**
* WITH to set metadata on the table: WITH (fillfactor=70)
*/
public class With {

public static final List<With> EMPTY = Collections.emptyList();
private String name = null;
private String value = null;

/**
* @param name
* @param value
*/
public With(String name, String value) {
this.name = name;
this.value = value;
}

public String getValue() {
return value;
}

public void setValue(String value) {
this.value = value;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

/**
* builds the sql component 'WITH'
* @return
*/
public String buildWithComponent() {
return name + "=" + value;
}

/**
* creates a with statement
* @param key
* @param value
*/
public static With with(String key, String value) {
return new With(key, value);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import com.ibm.fhir.database.utils.model.PrimaryKeyDef;
import com.ibm.fhir.database.utils.model.Privilege;
import com.ibm.fhir.database.utils.model.Table;
import com.ibm.fhir.database.utils.model.With;

/**
* A PostgreSql database target
Expand Down Expand Up @@ -93,15 +94,15 @@ public void warnOnce(MessageKey messageKey, String msg) {

@Override
public void createTable(String schemaName, String name, String tenantColumnName, List<ColumnBase> columns, PrimaryKeyDef primaryKey,
IdentityDef identity, String tablespaceName) {
IdentityDef identity, String tablespaceName, List<With> withs) {

// PostgreSql doesn't support partitioning, so we ignore tenantColumnName
if (tenantColumnName != null) {
warnOnce(MessageKey.MULTITENANCY, "PostgreSql does not support multi-tenancy: " + name);
}

// We also ignore tablespace for PostgreSql
String ddl = buildCreateTableStatement(schemaName, name, columns, primaryKey, identity, null);
String ddl = buildCreateTableStatement(schemaName, name, columns, primaryKey, identity, null, withs);
runStatement(ddl);
}

Expand Down
Loading