Skip to content

Commit

Permalink
0001913: DbFill now has the capability to print the sql to the comman…
Browse files Browse the repository at this point in the history
…d line and to the Sql Editor.
  • Loading branch information
adambailey- committed Aug 14, 2014
1 parent 3144199 commit b776283
Show file tree
Hide file tree
Showing 3 changed files with 232 additions and 12 deletions.
Expand Up @@ -28,6 +28,7 @@
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Options;
import org.apache.commons.lang.ArrayUtils;
import org.jumpmind.db.model.Table;
import org.jumpmind.symmetric.common.ParameterConstants;
import org.jumpmind.symmetric.io.data.DbFill;
import org.jumpmind.symmetric.service.IParameterService;
Expand All @@ -51,6 +52,8 @@ public class DbFillCommand extends AbstractCommandLauncher {
private static final String OPTION_WEIGHTS = "weights";

private static final String OPTION_CONTINUE = "continue";

private static final String OPTION_PRINT = "print";

public DbFillCommand() {
super("dbfill", "[tablename...]", "DbFill.Option.");
Expand Down Expand Up @@ -89,6 +92,7 @@ protected void buildOptions(Options options) {
addOption(options, null, OPTION_INTERVAL, true);
addOption(options, null, OPTION_WEIGHTS, true);
addOption(options, null, OPTION_CONTINUE, false);
addOption(options, null, OPTION_PRINT, false);
}

@Override
Expand Down Expand Up @@ -138,6 +142,9 @@ protected boolean executeWithOptions(CommandLine line) throws Exception {
if (line.hasOption(OPTION_CONTINUE)) {
dbFill.setContinueOnError(true);
}
if (line.hasOption(OPTION_PRINT)) {
dbFill.setPrint(true);
}
// Ignore the Symmetric config tables.
getSymmetricEngine();
IParameterService parameterService = engine.getParameterService();
Expand All @@ -154,8 +161,34 @@ protected boolean executeWithOptions(CommandLine line) throws Exception {
} else {
tableNames = line.getArgs();
}

dbFill.fillTables(tableNames, tableProperties);

if (!dbFill.getPrint()) {
dbFill.fillTables(tableNames, tableProperties);
} else {
for (String tableName : tableNames) {
Table table = platform.readTableFromDatabase(dbFill.getCatalogToUse(), dbFill.getSchemaToUse(),
tableName);
if (table != null) {
for (int i = 0; i < dbFill.getRecordCount(); i++) {
for (int j = 0; j < dbFill.getInsertWeight(); j++) {
dbFill.createInsertRandomRecord(table);
String sql = dbFill.getSql() + ";";
System.out.println(sql);
}
for (int j = 0; j < dbFill.getUpdateWeight(); j++) {
dbFill.createUpdateRandomRecord(table);
String sql = dbFill.getSql() + ";";
System.out.println(sql);
}
for (int j = 0; j < dbFill.getDeleteWeight(); j++) {
dbFill.createDeleteRandomRecord(table, null);
String sql = dbFill.getSql() + ";";
System.out.println(sql);
}
}
}
}
}

return true;
}
Expand Down
Expand Up @@ -150,5 +150,6 @@ DbFill.Option.ignore=One or more prefixes to identify tables to ignore. This arg
DbFill.Option.interval=The time to wait in milliseconds between each change made to the database.
DbFill.Option.weights=By default, an insert is performed for each count ('1,0,0'). To randomly select between an insert, update or delete on each table, weight can be applied so inserts can occur more than deletes. To make sure inserts happen twice as much as updates, and deletes are never performed use '2,1,0'.
DbFill.Option.continue=Ignore ANY errors and continue to modify the database.
DbFill.Option.print=Print out the SQL of the DbFill instead of of filling the table(s).

DbSql.Option.sql=Run this sql statement in the shell
206 changes: 196 additions & 10 deletions symmetric-io/src/main/java/org/jumpmind/symmetric/io/data/DbFill.java
Expand Up @@ -86,6 +86,10 @@ public class DbFill {
private boolean verbose = false;

private boolean continueOnError = false;

private boolean print = false;

private String sql;

// Weights given to insert, update, and delete commands when
// randomly selecting a command for any given table.
Expand Down Expand Up @@ -370,8 +374,8 @@ private void insertRandomRecord(Table table) {
int attempt = 0;
while (!success && attempt < 5) {
try {
platform.getSqlTemplate().update(statement.getSql(), statementValues,
statement.getTypes());
platform.getSqlTemplate().update(statement.getSql(),
statementValues,statement.getTypes());
success = true;
} catch (UniqueKeyException e) {
attempt++;
Expand All @@ -398,8 +402,12 @@ private void insertRandomRecord(Table table) {
}
}
}

private void deleteRandomRecord(Table table) {
deleteRandomRecord(table, null);
}

/**
/**
* Select a random row from the table and update all columns except for primary and foreign keys.
*
* @param sqlTemplate
Expand Down Expand Up @@ -444,10 +452,6 @@ private void updateRandomRecord(Table table) {
}
}

private void deleteRandomRecord(Table table) {
deleteRandomRecord(table, null);
}

/**
* Delete a random row in the given table or delete all rows matching selectColumns
* in the given table.
Expand Down Expand Up @@ -524,7 +528,7 @@ private void deleteRandomRecord(Table table, Map<Column, Object> selectColumns)
}
}
}

/**
* Generates a random row for the given table. If a fk dependency exists, it is assumed
* the foreign table has already been populated with random data. A runtime exception will
Expand Down Expand Up @@ -711,15 +715,15 @@ private String randomUUID() {
return UUID.randomUUID().toString();
}

protected String getSchemaToUse() {
public String getSchemaToUse() {
if (StringUtils.isBlank(schema)) {
return platform.getDefaultSchema();
} else {
return schema;
}
}

protected String getCatalogToUse() {
public String getCatalogToUse() {
if (StringUtils.isBlank(catalog)) {
return platform.getDefaultCatalog();
} else {
Expand Down Expand Up @@ -755,6 +759,164 @@ protected Table getDbTable(String tableName) {
}
return null;
}

private String createSqlStatement(String sql, Object[] statementValues, Column[] types) {
String statement = "";
int j = 0;
for (int i = 0; i < sql.length(); i++) {
if (sql.charAt(i) == '?') {
Object typeValue = types[j].getJdbcTypeName();
if (!typeValue.toString()
.equals("")) {
typeValue = getTypeValue(types[j]
.getJdbcTypeName(), statementValues[j].toString());
}
statement += typeValue;
j++;
} else {
statement += sql.charAt(i);
}
}
return statement;
}

public void createInsertRandomRecord(Table table) {

Table[] tables = null;
if (cascading) {
tables = addFkInsertDependentTables(table);
tables = Database.sortByForeignKeys(tables);
} else {
tables = new Table[] { table };
}

Map<String, Object> insertedColumns = new HashMap<String, Object>(
tables.length);

for (Table tbl : tables) {
DmlStatement statement = platform.createDmlStatement(
DmlType.INSERT, tbl);
generateRandomValues(insertedColumns, tbl);
Column[] statementColumns = statement.getMetaData();
Object[] statementValues = new Object[statementColumns.length];
for (int j = 0; j < statementColumns.length; j++) {
statementValues[j] = insertedColumns.get(tbl.getName() + "."
+ statementColumns[j].getName());
}

if (print) {
sql = createSqlStatement(statement.getSql(), statementValues, statement.getColumns());
}
}
}

public void createUpdateRandomRecord(Table table) {
Row row = selectRandomRow(table);
if (row == null) {
log.warn("Unable to update a random record in empty table '"
+ table.getName() + "'.");
return;
}
DmlStatement updStatement = platform.createDmlStatement(DmlType.UPDATE,
table.getCatalog(), table.getSchema(), table.getName(),
table.getPrimaryKeyColumns(), table.getNonPrimaryKeyColumns(),
null);
Column[] columns = updStatement.getMetaData();
Object[] values = new Object[columns.length];

// Get list of local fk reference columns
List<String> localFkRefColumns = getLocalFkRefColumns(table);
for (int i = 0; i < columns.length; i++) {
if (columns[i].isPrimaryKey()
|| localFkRefColumns.contains(columns[i].getName())) {
values[i] = row.getString(columns[i].getName());
} else {
values[i] = generateRandomValueForColumn(columns[i]);
}
}
if (print) {
sql = createSqlStatement(updStatement.getSql(), values, columns);
}
}

public void createDeleteRandomRecord(Table table, Map<Column, Object> selectColumns) {
List<Row> rows = null;
if (selectColumns != null) {
// Select dependent records to delete
Column[] selectColumnArray = selectColumns.keySet().toArray(new Column[0]);
String sqlSelect = platform.createDmlStatement(DmlType.SELECT, table.getCatalog(), table.getSchema(), table.getName(),
selectColumnArray, table.getColumns(), null).getSql();
Object[] values = new Object[selectColumnArray.length];
for (int i=0; i<selectColumnArray.length; i++) {
values[i] = selectColumns.get(selectColumnArray[i]);
}
rows = platform.getSqlTemplate().query(sqlSelect, values);
} else {
// Select new random row to delete
rows = new ArrayList<Row>(1);
Row row = selectRandomRow(table);
if (row == null) {
log.warn("Unable to delete a random record from empty table '" + table.getName() + "'.");
return;
}
rows.add(row);
}

for (Row row : rows) {
if (cascading) {
// Delete dependent tables
for (Table tbl : getAllDbTables()) {
if (tbl.getName().equals(table.getName()))
{
continue;
}
for (ForeignKey fk : tbl.getForeignKeys()) {
if (fk.getForeignTableName().equals(table.getName())) {
Map<Column, Object> selectValues = new HashMap<Column, Object>();
for (Reference ref : fk.getReferences()) {
// Create a column/value map for each column referenced by the foreign table.
selectValues.put(ref.getLocalColumn(), row.getString(ref.getForeignColumnName()));
}
// Delete all records in the foreign table that map this row.
deleteRandomRecord(tbl, selectValues);
}
}
}
}
DmlStatement statement = platform.createDmlStatement(DmlType.DELETE, table);
Column[] keys = statement.getMetaData();
Object[] keyValues = new Object[keys.length];
for (int i=0; i<keys.length; i++) {
keyValues[i] = row.get(keys[i].getName());
}
if (print) {
sql = createSqlStatement(statement.getSql(), keyValues, keys);
}
}
}

protected String getTypeValue(String type, String value) {
if (type.equalsIgnoreCase("CHAR")) {
value = "'" + value + "'";
} else if (type.equalsIgnoreCase("VARCHAR")) {
value = "'" + value + "'";
} else if (type.equalsIgnoreCase("LONGVARCHAR")) {
value = "'" + value + "'";
} else if (type.equalsIgnoreCase("DATE")) {
value = "'" + value + "'";
} else if (type.equalsIgnoreCase("TIME")) {
value = "'" + value + "'";
} else if (type.equalsIgnoreCase("TIMESTAMP")) {
value = "'" + value + "'";
} else if (type.equalsIgnoreCase("CLOB")) {
value = "'" + value + "'";
} else if (type.equalsIgnoreCase("BLOB")) {
value = "'" + value + "'";
} else if (type.equalsIgnoreCase("ARRAY")) {
value = "[" + value + "]";
}
return value;
}

public void setPlatform(IDatabasePlatform platform) {
this.platform = platform;
Expand Down Expand Up @@ -830,5 +992,29 @@ public void setDmlWeight(int[] dmlWeight) {
public void setContinueOnError(boolean continueOnError) {
this.continueOnError = continueOnError;
}

public void setPrint(boolean print) {
this.print = print;
}

public String getSql() {
return sql;
}

public boolean getPrint() {
return print;
}

public int getInsertWeight() {
return dmlWeight[0];
}

public int getUpdateWeight() {
return dmlWeight[1];
}

public int getDeleteWeight() {
return dmlWeight[2];
}

}

0 comments on commit b776283

Please sign in to comment.