All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cdc.util.rdb.tools.RdbStats Maven / Gradle / Ivy

There is a newer version: 0.9.0
Show newest version
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