2

I am using JDBC to get columns from query results.

For example:

String query = "SELECT foo, bar AS barAlias FROM table";
PreparedStatement preparedStatement = connection.prepareStatement(query);
ResultSet resultSet = preparedStatement.executeQuery();

//Show my "foo" column results
while (resultSet.next()) {
    log.debug(resultSet.getString("foo"));
}

I would like to parse my queries BEFORE running them. Essentially, I want to create an array for column labels that will match the value expected by the resultSet.get** method. For illustration purpose, I would like to replace the loop above by this and get the same results:

//Show my "foo" column results
while (resultSet.next()) {
    log.debug(resultSet.getString(arrayOfColumns.get(0)));
}

This seems easy. I could parse my statement with a simple regex that takes the string between SELECT and FROM, creating groups using the column delimiter, and building arrayOfColumns from the groups. But JDBC has specific ways to deal with aliases for example. For the second column, this naive parser would return the entire "bar AS barAlias" where I believe that resultSet.get** expects "barAlias". It will tell me "The column name bar As barAlias is not valid."

Essentially, I would like to understand the JBDC column label parsing behavior in order to replicate it.

NOTE, I am aware that I can get columns by index from the resultSet object. That is not the objective here. Also, I do not want to use any JDBC related method (I understand that the preparedStatement metadata is available). Think of this as a theoretical questions where do not have a JDBC library and MUST use regular expressions.

4 Answers 4

3

The best way of obtaining the columns of the result set is to ask JDBC to do it for you. You do not need a ResultSet object for it - ResultSetMetaData would be enough.

PreparedStatement preparedStatement = connection.prepareStatement(query);
ResultSetMetaData metaData = preparedStatement.getMetaData();

for (int i = 1 ; i <= metaData.getColumnCount() ; i++) {
    listOfColumns.add(metaData.getColumnLabel(i));
}
Sign up to request clarification or add additional context in comments.

7 Comments

Thanks! I know that this answer is accurate. I added clarification to my question. What I am interested in is how JDBC arrives to those labels. I am trying to reverse engineer the behavior, not use an existing method.
@FredericFortier JDBC driver usually passes the statement to RDBMS server, which uses its own SQL parser to parse the statement. It may have its own parser as well. Parsing SQL is not a simple task. Consider getting an existing parser (here is one). This is way to hard for a regex, unless your SQL has a very specific format. At the very least you should roll your own recursive descent parser; using ANTRL or some other parser gives you an even better chance to get it right.
This might work based on the description. Have you used this particular parser yourself? The key is that I do not want to use the JDBC drivers but yet arrive to the same column labels. I will give it a try.
Okay :-) So you feel confident that it is aligned with JDBC in the way that it parses column labels?
@FredericFortier Moreover, SQL-92 parser lacks access to metadata from your database, so SELECT * will tell you only that there is an asterisk *; unlike the metadata that you get from your JDBC driver, it wouldn't expand to a list of columns.
|
1

To get the column names that are associated with your ResultSet, you should consult its ResultSetMetaData. That's going to be both easier and more reliable than parsing the query text.

1 Comment

Of course it would be... however, it does not answer the question.
0

So, after having split on the delimiter (comma) to get column names between SELECT and FROM, check each one to see if it contains the string " AS " (you may need to account for upper and lowercase), then if present, split on that, and use the rightmost value.

1 Comment

Not all dbms use AS to represent aliases.
0

While I agree with others you should probably use ResultSetMetaData in "ordinary" use-cases, you seem to insist that the query string itself should be parsed. Parsing SQL with regular expressions is brittle, and you should avoid doing that. Better use an off-the-shelf SQL parser, which can do the parsing for you. There are several, including:

With jOOQ, you could just write this:

ctx.parser()
   .parseSelect("SELECT a, b ...")
   .getSelect()
   .stream()
   .forEach(f -> System.out.println(f.getName()));

Disclaimer: I work for the company behind jOOQ

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.