Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
192c6e7
Option to migrate SQL Server hard tables to PostgreSQL
labkey-adam Jul 23, 2025
dade229
migrateDataSource argument. Improve sequence handling.
labkey-adam Jul 24, 2025
06aea27
Skip views in source tables. Skip SQL-Server-only column csPath. Log …
labkey-adam Jul 24, 2025
c129a96
Clarify constant name
labkey-adam Jul 25, 2025
589b01e
Fix TableSorter handling of self-referencing FKs
labkey-adam Jul 25, 2025
527f04e
Move migration code to a separate class
labkey-adam Jul 25, 2025
c5b8580
Register handlers for schema-specific functionality
labkey-adam Jul 25, 2025
4bcb9d5
Inspect target table to determine columns to select from source table
labkey-adam Jul 26, 2025
7d200d7
Support skip annotations in comments for convenience
labkey-adam Jul 26, 2025
4e619bd
Provide line number for unexpected annotation
labkey-adam Jul 27, 2025
f2971a9
Remove special handling for Deleted columns
labkey-adam Jul 27, 2025
c1b2c92
Exit in the empty schemas case as well
labkey-adam Jul 27, 2025
63a1877
Don't redirect to a string
labkey-adam Jul 28, 2025
f143790
Merge remote-tracking branch 'origin/develop' into fb_migrate_ss_to_pg
labkey-adam Jul 29, 2025
e349fa0
Migrate provisioned schemas as well!
labkey-adam Jul 29, 2025
df2a02b
Merge remote-tracking branch 'origin/develop' into fb_migrate_ss_to_pg
labkey-adam Jul 30, 2025
0ae3ab8
Merge remote-tracking branch 'origin/develop' into fb_migrate_ss_to_pg
labkey-adam Jul 30, 2025
8a4fbf5
Code review feedback
labkey-adam Jul 31, 2025
eae0109
Work around exp FK cycle
labkey-adam Aug 1, 2025
83d84aa
Run in synchronous mode when migrating
labkey-adam Aug 1, 2025
5f5f180
Merge remote-tracking branch 'origin/develop' into fb_migrate_ss_to_pg
labkey-adam Aug 1, 2025
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
6 changes: 3 additions & 3 deletions api/src/org/labkey/api/data/ContainerManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -801,7 +801,7 @@ public static void updateDescription(Container container, String description, Us
{
ColumnValidators.validate(CORE.getTableInfoContainers().getColumn("Title"), null, 1, description);

//For some reason there is no primary key defined on core.containers
//For some reason, there is no primary key defined on core.containers
//so we can't use Table.update here
SQLFragment sql = new SQLFragment("UPDATE ");
sql.append(CORE.getTableInfoContainers());
Expand All @@ -817,7 +817,7 @@ public static void updateDescription(Container container, String description, Us

public static void updateSearchable(Container container, boolean searchable, User user)
{
//For some reason there is no primary key defined on core.containers
//For some reason, there is no primary key defined on core.containers
//so we can't use Table.update here
SQLFragment sql = new SQLFragment("UPDATE ");
sql.append(CORE.getTableInfoContainers());
Expand Down Expand Up @@ -2715,7 +2715,7 @@ public static int updateContainer(TableInfo dataTable, String idField, Collectio
}

/**
* If a container at the given path does not exist create one and set permissions. If the container does exist,
* If a container at the given path does not exist, create one and set permissions. If the container does exist,
* permissions are only set if there is no explicit ACL for the container. This prevents us from resetting
* permissions if all users are dropped. Implicitly done as an admin-level service user.
*/
Expand Down
2 changes: 1 addition & 1 deletion api/src/org/labkey/api/data/DbSchema.java
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ public static Pair<DbScope, String> getDbScopeAndSchemaName(String fullyQualifie
}
}

Module getModule()
public Module getModule()
{
return _module;
}
Expand Down
2 changes: 1 addition & 1 deletion api/src/org/labkey/api/data/ForeignKey.java
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ default String getLookupSchemaName()
return Objects.toString(getLookupSchemaKey(),null);
}

/* Schema path relative to the DefaultSchema (e.g. container) */
/* Schema path relative to the DefaultSchema (e.g., container) */
SchemaKey getLookupSchemaKey();

/**
Expand Down
59 changes: 52 additions & 7 deletions api/src/org/labkey/api/data/SqlScriptExecutor.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
*/
package org.labkey.api.data;

import org.apache.commons.lang3.mutable.MutableBoolean;
import org.apache.commons.lang3.mutable.MutableInt;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.NotNull;
Expand All @@ -31,6 +33,7 @@
import java.util.Collections;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
* Executes a single module upgrade SQL script, including finding calls into Java code that are embedded using
Expand All @@ -51,13 +54,14 @@ public class SqlScriptExecutor
/**
* Splits a SQL string into blocks and executes each block, one at a time. Blocks are determined in a dialect-specific
* way, using splitPattern and procPattern.
* @param scriptName Name of the SQL script for logging purposes
* @param sql The SQL string to split and execute
* @param splitPattern Dialect-specific regex pattern for splitting normal SQL statements into blocks. Null means no need to split.
* @param procPattern Dialect-specific regex pattern for finding executeJavaCode procedure calls in the SQL. See SqlDialect.getSqlScriptProcPattern() for details.
* @param schema Current schema. Null is allowed for testing purposes.
*
* @param scriptName Name of the SQL script for logging purposes
* @param sql The SQL string to split and execute
* @param splitPattern Dialect-specific regex pattern for splitting normal SQL statements into blocks. Null means no need to split.
* @param procPattern Dialect-specific regex pattern for finding executeJavaCode procedure calls in the SQL. See SqlDialect.getSqlScriptProcPattern() for details.
* @param schema Current schema. Null is allowed for testing purposes.
* @param moduleContext Current ModuleContext
* @param conn Connection to use, if non-null
* @param conn Connection to use, if non-null
*/
public SqlScriptExecutor(String scriptName, String sql, @Nullable Pattern splitPattern, @NotNull Pattern procPattern, @Nullable DbSchema schema, ModuleContext moduleContext, @Nullable Connection conn)
{
Expand All @@ -79,10 +83,51 @@ public void execute()
}
}

private static final String START_ANNOTATION = "@SkipOnEmptySchemasBegin";
private static final String END_ANNOTATION = "@SkipOnEmptySchemasEnd";

private Collection<Block> getBlocks()
{
String sql;

if (ModuleLoader.getInstance().shouldInsertData())
{
sql = _sql;
}
else
{
// Strip all statements (typically inserts) between the empty-schema START and END annotations, inclusive
MutableBoolean skipping = new MutableBoolean(false);
MutableInt lineCount = new MutableInt(0);
sql = _sql.lines()
.filter(line -> {
lineCount.increment();
if (line.contains(START_ANNOTATION))
{
if (skipping.booleanValue())
throw new IllegalStateException("Unexpected " + START_ANNOTATION + " at line " + lineCount.intValue());

skipping.setValue(true);
}

boolean ret = !skipping.booleanValue();

if (line.contains(END_ANNOTATION))
{
if (!skipping.booleanValue())
throw new IllegalStateException("Unexpected " + END_ANNOTATION + " at line " + lineCount.intValue());

skipping.setValue(false);
}

return ret;
}
)
.collect(Collectors.joining("\n"));
}

// Strip all comments from the script -- PostgreSQL JDBC driver goes berserk if it sees ; or ? inside a comment
StringBuilder stripped = new SqlScanner(_sql).stripComments();
StringBuilder stripped = new SqlScanner(sql).stripComments();

Collection<String> sqlBlocks;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -931,13 +931,6 @@ public DatabaseIdentifier makeDatabaseIdentifier(String alias)

private static final Pattern PROC_PATTERN = Pattern.compile("^\\s*SELECT\\s+core\\.(executeJava(?:Upgrade|Initialization)Code\\s*\\(\\s*'(.+)'\\s*\\))\\s*;\\s*$", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);

@Override
// No need to split up PostgreSQL scripts; execute all statements in a single block (unless we have a special stored proc call).
protected Pattern getSQLScriptSplitPattern()
{
return null;
}

@NotNull
@Override
protected Pattern getSQLScriptProcPattern()
Expand Down
1 change: 0 additions & 1 deletion api/src/org/labkey/api/exp/api/ProvisionedDbSchema.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
/**
* A schema in the underlying database that is populated by tables created (provisioned) dynamically
* based on administrator or other input into what columns/fields should be tracked.
* Created by klum on 2/23/14.
*/
public class ProvisionedDbSchema extends DbSchema
{
Expand Down
6 changes: 6 additions & 0 deletions api/src/org/labkey/api/exp/api/StorageProvisioner.java
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,12 @@ static TableInfo createTableInfo(@NotNull Domain domain)
*/
String ensureStorageTable(Domain domain, DomainKind<?> kind, DbScope scope);

/**
* Used by DatabaseMigration only. Creates the storage table associated with this domain, using the storage table
* name provided by the domain.
*/
void createStorageTable(Domain domain, DomainKind<?> kind, DbScope scope);

void dropNotRequiredIndices(Domain domain);
void addMissingRequiredIndices(Domain domain);
void addTableIndices(Domain domain, Set<PropertyStorageSpec.Index> indices, TableChange.IndexSizeMode sizeMode);
Expand Down
Loading