8

Does anyone know whether there is a java library for parsing a MySQL schema? In code I want to be able to determine the tables and fields specified in a schema. Or will I need to write my own?

Thanks Richard.

Edit: Just want to avoid re-inventing the wheel unnecessarily :)

Richard H
  • 38,037
  • 37
  • 111
  • 138
  • Depending on what you need it for there may be a way of doing it in rather simple way. So what will be the application of this? Otherwise have a look at http://stackoverflow.com/questions/660609/sql-parser-library-for-java – bobah May 25 '10 at 10:10
  • @bobah - ok yes http://stackoverflow.com/questions/660609/sql-parser-library-for-java has the answer - jsqlparser. thanks – Richard H May 25 '10 at 10:27

3 Answers3

5

Answering my own question:

Am using jsqlparser http://jsqlparser.sourceforge.net/

This parses individual statements, not multiple statements such as found in a schema. So split the schema on ';'. It also doesn't like the '`' character, so these need to be stripped out. Code to get column names for a particular table:

public class BUDataColumnsFinder {

public static String[] readSql(String schema) throws IOException {
    BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(schema)));
    String mysql = "";
    String line;
    while ((line = br.readLine()) != null) {
        mysql = mysql + line;
    }
    br.close();
    mysql = mysql.replaceAll("`", "");
    return mysql.split(";");
}

public static List<String> getColumnNames(String tableName, String schemaFile) throws JSQLParserException, IOException {

    CCJSqlParserManager pm = new CCJSqlParserManager();
    List<String> columnNames = new ArrayList<String>();

    String[] sqlStatements = readSql(schemaFile);

    for (String sqlStatement : sqlStatements) {

        Statement statement = pm.parse(new StringReader(sqlStatement));

        if (statement instanceof CreateTable) {

            CreateTable create = (CreateTable) statement;
            String name = create.getTable().getName();

            if (name.equalsIgnoreCase(tableName)) {
                List<ColumnDefinition> columns = create.getColumnDefinitions();
                for (ColumnDefinition def : columns) {
                    columnNames.add(def.getColumnName());
                }
                break;
            }
        }
    }

    return columnNames;
}


public static void main(String[] args) throws Exception {

    String schemaFile = "/home/john/config/bu-schema.sql";

    String tableName = "records";

    List<String> columnNames = BUDataColumnsFinder.getColumnNames(tableName, schemaFile);

    for (String name : columnNames) {
        System.out.println("name: " + name);
    }

}

}
Richard H
  • 38,037
  • 37
  • 111
  • 138
  • it looks as though jsql parser is no longer maintained at that address. The version on github [https://github.com/JSQLParser/JSqlParser] is more up-to-date and is now published at https://oss.sonatype.org/content/groups/public/com/github/jsqlparser/jsqlparser/ – robert May 24 '18 at 08:59
3

You may want to consider using code from Alibaba's Druid project. Although designed as a sophisticated connection pooling library, this project supports a very advanced parser and AST for ANSI SQL and non-ANSI dialects such as MySQL, Oracle, SQL Server, etc. The project is open source and bears the very liberal Apache License Version 2.0.

The main entry points into this part of the library is SQLUtils.java. You can use values returned from SQLUtils.parseStatements to access a typed model of the statements:

List<SQLStatement> statements = SQLUtils.parseStatements(sql, JdbcConstants.MYSQL);
for (SQLStatement statement : statements) {
   if (statement instanceof MySqlCreateTableStatment) {
      MySqlCreateTableStatment createTable = (MySqlCreateTableStatment) statement;
      // Use methods like: createTable.getTableSource()
   }
}
btiernay
  • 7,873
  • 5
  • 42
  • 48
1

Why not just use DatabaseMetaData to find out the tables and columns? This presumes that the schema expressed in SQL has been run against the database you're connected to, but that's not a difficult assumption to satisfy.

MySQL might be able to simply import the data if you have the data in CSV format. I'd dig deeper into MySQL tools before I'd write Java code to do such a thing. If that doesn't work, I'd find an ETL tool to help me. Writing Java would be my solution of last resort.

duffymo
  • 305,152
  • 44
  • 369
  • 561
  • unfortunately this code is (currently) being run before the database is built. However, i could maybe change the order of stuff, so thanks for the tip – Richard H May 25 '10 at 09:59
  • 1
    Unless your Java code has to create the database (and it shouldn't), I don't believe you should parse the SQL DDL. – duffymo May 25 '10 at 10:02
  • no, it's not creating the db. what it is doing is creating a file for db import with the columns defined in the schema, the values taken from a source data file that contains these columns plus a whole bunch of others in non-static order. – Richard H May 25 '10 at 10:05