Skip to content

Commit

Permalink
Support adding of multiple foreign keys with one ALTER-TABLE statement
Browse files Browse the repository at this point in the history
  • Loading branch information
sdbuehlmann committed Feb 19, 2024
1 parent 35be171 commit b209c10
Show file tree
Hide file tree
Showing 5 changed files with 206 additions and 83 deletions.
24 changes: 23 additions & 1 deletion src/main/java/ch/admin/bar/siard2/cmd/ArchiveMapping.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
import java.util.*;
import ch.admin.bar.siard2.api.*;
import ch.admin.bar.siard2.cmd.mapping.ColumnIdMapper;
import ch.admin.bar.siard2.cmd.mapping.TableIdMapper;
import ch.admin.bar.siard2.cmd.model.QualifiedColumnId;
import ch.admin.bar.siard2.cmd.model.QualifiedTableId;
import lombok.val;

public class ArchiveMapping implements ColumnIdMapper {
public class ArchiveMapping implements TableIdMapper, ColumnIdMapper {
private Map<String,SchemaMapping> _mapSchemas = new HashMap<String,SchemaMapping>();
public SchemaMapping getSchemaMapping(String sSchemaName) { return _mapSchemas.get(sSchemaName); }
public String getMappedSchemaName(String sSchemaName) { return getSchemaMapping(sSchemaName).getMappedSchemaName(); }
Expand Down Expand Up @@ -64,4 +66,24 @@ public QualifiedColumnId map(QualifiedColumnId origQualifiedColumnId) {
.column(mappedColumnName)
.build();
}

@Override
public QualifiedTableId map(QualifiedTableId orig) {
val sm = getSchemaMapping(orig.getSchema());
if (sm == null) {
return orig;
}

val builder = orig.toBuilder()
.schema(sm.getMappedSchemaName());

val tm = sm.getTableMapping(orig.getTable());
if (tm == null) {
return builder.build();
}

return builder
.table(tm.getMappedTableName())
.build();
}
} /* class ArchiveMapping */
4 changes: 4 additions & 0 deletions src/main/java/ch/admin/bar/siard2/cmd/MetaDataToDb.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import ch.enterag.sqlparser.identifier.*;
import ch.admin.bar.siard2.api.*;
import ch.admin.bar.siard2.api.generated.*;
import lombok.val;

/*====================================================================*/
/** Transfers meta data from databases to SIARD files and back.
Expand Down Expand Up @@ -372,6 +373,9 @@ private void createTable(MetaTable mt, SchemaMapping sm)
/* now execute it */
_il.event(sbSql.toString());

val sql = sbSql.toString();
System.out.println(sql);

try {
Statement stmt = _dmd.getConnection().createStatement();
stmt.setQueryTimeout(_iQueryTimeoutSeconds);
Expand Down
108 changes: 56 additions & 52 deletions src/main/java/ch/admin/bar/siard2/cmd/PrimaryDataToDb.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,12 @@
======================================================================*/
package ch.admin.bar.siard2.cmd;

import java.io.*;
import java.math.*;
import java.sql.*;
import java.util.*;

import ch.admin.bar.siard2.api.Archive;
import ch.admin.bar.siard2.api.Cell;
import ch.admin.bar.siard2.api.Field;
import ch.admin.bar.siard2.api.MetaColumn;
import ch.admin.bar.siard2.api.MetaData;
import ch.admin.bar.siard2.api.MetaField;
import ch.admin.bar.siard2.api.MetaForeignKey;
import ch.admin.bar.siard2.api.MetaSchema;
import ch.admin.bar.siard2.api.MetaTable;
import ch.admin.bar.siard2.api.MetaType;
Expand All @@ -29,12 +23,40 @@
import ch.admin.bar.siard2.api.Schema;
import ch.admin.bar.siard2.api.Table;
import ch.admin.bar.siard2.api.Value;
import ch.enterag.utils.*;
import ch.enterag.utils.background.*;
import ch.enterag.utils.logging.*;
import ch.enterag.sqlparser.*;
import ch.enterag.sqlparser.identifier.*;
import ch.admin.bar.siard2.api.generated.*;
import ch.admin.bar.siard2.api.generated.CategoryType;
import ch.admin.bar.siard2.cmd.model.QualifiedTableId;
import ch.admin.bar.siard2.cmd.sql.CreateForeignKeySqlGenerator;
import ch.admin.bar.siard2.cmd.sql.IdEncoder;
import ch.admin.bar.siard2.cmd.utils.ListAssembler;
import ch.enterag.sqlparser.SqlLiterals;
import ch.enterag.sqlparser.identifier.QualifiedId;
import ch.enterag.utils.EU;
import ch.enterag.utils.StopWatch;
import ch.enterag.utils.background.Progress;
import ch.enterag.utils.logging.IndentLogger;
import lombok.val;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.math.BigDecimal;
import java.sql.Array;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.NClob;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.SQLXML;
import java.sql.Statement;
import java.sql.Types;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

/*====================================================================*/
/** Transfers primary data from SIARD files to databases.
Expand Down Expand Up @@ -145,49 +167,31 @@ public void addCandidateKeys(Connection conn, MetaTable mt)
}
}
} /* addCandidateKeys */

public void addForeignKeys(Connection conn, MetaTable mt)
throws SQLException
{

public void addForeignKeys(Connection conn, MetaTable mt) throws SQLException {
_il.enter(mt.getName());
if (mt.getMetaForeignKeys() > 0)
{
SchemaMapping sm = _am.getSchemaMapping(mt.getParentMetaSchema().getName());
TableMapping tm = sm.getTableMapping(mt.getName());
QualifiedId qiTable = new QualifiedId(null,sm.getMappedSchemaName(),tm.getMappedTableName());
String sSql = "ALTER TABLE "+qiTable.format();
for (int iForeignKey = 0; iForeignKey < mt.getMetaForeignKeys(); iForeignKey++)
{
MetaForeignKey mfk = mt.getMetaForeignKey(iForeignKey);
StringBuilder sbSql = new StringBuilder(sSql + " ADD CONSTRAINT " + mfk.getName()+" FOREIGN KEY(");
SchemaMapping smReferenced = sm;
if (mfk.getReferencedSchema() != null)
smReferenced = _am.getSchemaMapping(mfk.getReferencedSchema());
TableMapping tmReferenced = smReferenced.getTableMapping(mfk.getReferencedTable());
QualifiedId qiReferenced = new QualifiedId(null,
smReferenced.getMappedSchemaName(),tmReferenced.getMappedTableName());
StringBuilder sbReferences = new StringBuilder(" REFERENCES "+qiReferenced.format()+"(");
for (int iReference = 0; iReference < mfk.getReferences(); iReference++)
{
if (iReference > 0)
{
sbSql.append(", ");
sbReferences.append(", ");
}
sbSql.append(tm.getMappedColumnName(mfk.getColumn(iReference)));
sbReferences.append(tmReferenced.getMappedColumnName(mfk.getReferenced(iReference)));
}
sbSql.append(")");
sbReferences.append(")");
sbSql.append(sbReferences.toString());
Statement stmt = conn.createStatement();
stmt.setQueryTimeout(_iQueryTimeoutSeconds);
stmt.execute(sbSql.toString());
stmt.close();
}

if (mt.getMetaForeignKeys() > 0) {
val sqlGenerator = CreateForeignKeySqlGenerator.builder()
.tableId(QualifiedTableId.builder()
.schema(mt.getParentMetaSchema().getName())
.table(mt.getName())
.build())
.idEncoder(new IdEncoder())
.columnIdMapper(_am)
.tableIdMapper(_am)
.build();

val sql = sqlGenerator.create(ListAssembler.assemble(mt.getMetaForeignKeys(), mt::getMetaForeignKey));

Statement stmt = conn.createStatement();
stmt.setQueryTimeout(_iQueryTimeoutSeconds);
stmt.execute(sql);
stmt.close();
}

_il.exit();
} /* addForeignKeys */
}

private void enableConstraints(MetaSchema ms)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,40 @@
@Builder
public class CreateForeignKeySqlGenerator {

@NonNull private final QualifiedTableId tableId;
@NonNull
private final QualifiedTableId tableId;

@NonNull
private final TableIdMapper tableIdMapper;
@NonNull
private final ColumnIdMapper columnIdMapper;
@NonNull
private final IdEncoder idEncoder;

public String create(final List<MetaForeignKey> foreignKeyMetaData) {
if (foreignKeyMetaData.isEmpty()) {
return "";
}

val mappedTableId = tableIdMapper.map(tableId);

val sb = new StringBuilder()
.append("ALTER TABLE ")
.append(idEncoder.encodeKeySensitive(mappedTableId));

val addConstraintStatements = foreignKeyMetaData.stream()
.map(this::addConstraintStatement)
.collect(Collectors.joining(", "));

@NonNull private final TableIdMapper tableIdMapper;
@NonNull private final ColumnIdMapper columnIdMapper;
@NonNull private final IdEncoder idEncoder;
sb.append(" ")
.append(addConstraintStatements);

public String create(final MetaForeignKey foreignKeyMetaData) {
log.debug("SQL statement for creating foreign-keys: {}", sb);

return sb.toString();
}

private String addConstraintStatement(final MetaForeignKey foreignKeyMetaData) {
if (foreignKeyMetaData.getReferences() == 0) {
log.error("SIARD metadata for foreign-key {} has no references and will be ignored.", foreignKeyMetaData.getName());
return "";
Expand All @@ -42,12 +69,8 @@ public String create(final MetaForeignKey foreignKeyMetaData) {
.findFirst()
.orElseThrow(() -> new IllegalStateException("No references found"));

val mappedTableId = tableIdMapper.map(tableId);

val sb = new StringBuilder()
.append("ALTER TABLE ")
.append(idEncoder.encodeKeySensitive(mappedTableId))
.append(" ADD CONSTRAINT ")
.append("ADD CONSTRAINT ")
.append(foreignKeyMetaData.getName())
.append(" FOREIGN KEY (")
.append(references.stream()
Expand Down

0 comments on commit b209c10

Please sign in to comment.