cdc.util.rdb.tools.RdbStats Maven / Gradle / Ivy
package cdc.util.rdb.tools;
import java.io.File;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashSet;
import java.util.Set;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import cdc.util.cli.AbstractMainSupport;
import cdc.util.cli.FeatureMask;
import cdc.util.cli.OptionEnum;
import cdc.util.csv.CsvWriter;
/**
* Basic utility used to produce statistics on a database.
*
* @author Damien Carbonne
*
*/
public final class RdbStats {
protected static final Logger LOGGER = LogManager.getLogger(RdbStats.class);
private final MainArgs margs;
protected final Connection connection;
private final DatabaseMetaData metadata;
protected final String catalogSeparator;
protected final String identifierQuoteString;
public static class MainArgs {
public enum Feature implements OptionEnum {
;
private final String name;
private final String description;
private Feature(String name,
String description) {
this.name = name;
this.description = description;
}
@Override
public final String getName() {
return name;
}
@Override
public final String getDescription() {
return description;
}
}
/** Database url. */
public String url;
/** User name. */
public String user;
/** User password. */
public String password;
/** JDBC driver. */
public String driver;
/** Set of schemas for which data must be collected. */
public final Set schemas = new HashSet<>();
/** Output file. */
public File outputFile;
protected final FeatureMask features = new FeatureMask<>();
public final void setEnabled(Feature feature,
boolean enabled) {
features.setEnabled(feature, enabled);
}
public final boolean isEnabled(Feature feature) {
return features.isEnabled(feature);
}
}
private RdbStats(MainArgs margs) throws SQLException {
LOGGER.info("Connect to: " + margs.url + " as: " + margs.user);
this.margs = margs;
if (margs.driver != null) {
try {
LOGGER.info("Load driver: " + margs.driver);
Class.forName(margs.driver);
} catch (final ClassNotFoundException e) {
LOGGER.error("Failed to load driver class: " + margs.driver, e);
}
}
this.connection = DriverManager.getConnection(margs.url, margs.user, margs.password);
metadata = connection.getMetaData();
catalogSeparator = metadata.getCatalogSeparator();
identifierQuoteString = metadata.getIdentifierQuoteString();
}
private void execute() throws SQLException, IOException {
try (final CsvWriter csvWriter = new CsvWriter(margs.outputFile);
final ResultSet rs = metadata.getTables(null, null, null, null)) {
csvWriter.writeln("Schema", "Catalog", "Table", "Count");
while (rs.next()) {
// 1: table catalog (string, may be null)
// 2: table schema (string, may be null)
// 3: table name (string)
final String schemaName = rs.getString(2); // May be null
if (acceptsSchema(schemaName)) {
final String catalogName = rs.getString(1); // May be null
final String tableName = rs.getString(3);
count(csvWriter, schemaName, catalogName, tableName);
}
}
csvWriter.flush();
} catch (final SQLException e) {
LOGGER.catching(e);
}
connection.close();
LOGGER.info("generated '" + margs.outputFile + "'");
}
private boolean acceptsSchema(String schemaName) {
return margs.schemas.isEmpty() || margs.schemas.contains(schemaName);
}
private void count(CsvWriter csvWiter,
String schemaName,
String catalogName,
String tableName) {
LOGGER.info("count(" + schemaName + ", " + catalogName + ", " + tableName + ")");
final String queryTableName = schemaName == null ? tableName : schemaName + catalogSeparator + tableName;
try (final Statement statement = connection.createStatement();
final ResultSet rs = statement.executeQuery("SELECT COUNT(*) FROM " + identifierQuoteString + queryTableName + identifierQuoteString)) {
rs.next();
csvWiter.write(schemaName, catalogName, tableName);
csvWiter.write(rs.getInt(1));
csvWiter.writeln();
} catch (final Exception e) {
LOGGER.error("Failed to count: " + catalogName + ", " + schemaName + ", " + queryTableName, e);
}
}
public static void execute(MainArgs margs) throws SQLException, IOException {
final RdbStats instance = new RdbStats(margs);
instance.execute();
}
public static void main(String[] args) {
final MainSupport support = new MainSupport();
support.main(args);
}
private static class MainSupport extends AbstractMainSupport {
private static final String SCHEMA = "schema";
public MainSupport() {
super(RdbStats.class, LOGGER);
}
@Override
protected String getVersion() {
return cdc.util.Config.VERSION;
}
@Override
protected void addSpecificOptions(Options options) {
options.addOption(Option.builder()
.longOpt(URL)
.desc("URL to access database.")
.hasArg()
.required()
.build());
options.addOption(Option.builder()
.longOpt(DRIVER)
.desc("Optional JDBC Driver class.")
.hasArg()
.build());
options.addOption(Option.builder()
.longOpt(USER)
.desc("Optional user name.")
.hasArg()
.build());
options.addOption(Option.builder("pwd")
.longOpt(PASSWORD)
.desc("Optional user password.")
.hasArg()
.build());
options.addOption(Option.builder()
.longOpt(SCHEMA)
.desc("Optional set of schemas that must be analysed. When empty, all schemas are analysed.")
.hasArgs()
.build());
options.addOption(Option.builder()
.longOpt(OUTPUT)
.desc("Output file.")
.hasArg()
.required()
.build());
addNoArgOptions(options, MainArgs.Feature.class);
}
@Override
protected MainArgs analyze(CommandLine cl) throws ParseException {
final MainArgs margs = new MainArgs();
margs.url = cl.getOptionValue(URL);
margs.user = cl.getOptionValue(USER);
margs.password = cl.getOptionValue(PASSWORD);
margs.driver = cl.getOptionValue(DRIVER);
if (cl.hasOption(SCHEMA)) {
for (final String s : cl.getOptionValues(SCHEMA)) {
margs.schemas.add(s);
}
}
margs.outputFile = getValueAsFile(cl, OUTPUT, null);
setMask(cl, MainArgs.Feature.class, margs.features::setEnabled);
return margs;
}
@Override
protected Void execute(MainArgs margs) throws Exception {
RdbStats.execute(margs);
return null;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy