Skip to content

Commit

Permalink
#2677 Parsers need to be able to relate specific special characters t…
Browse files Browse the repository at this point in the history
…o types of statement (eg SPOOL)
  • Loading branch information
juliahayward committed Feb 19, 2020
1 parent 4cd946f commit 12bddbe
Show file tree
Hide file tree
Showing 8 changed files with 107 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ public class OracleParser extends Parser {











/**
* Delimiter of PL/SQL blocks and statements.
*/
Expand Down Expand Up @@ -171,6 +179,9 @@ private static String toRegexPattern(String... commands) {









Expand Down Expand Up @@ -262,6 +273,10 @@ protected ParsedSqlStatement createStatement(PeekingReader reader, Recorder reco










Expand Down Expand Up @@ -336,6 +351,9 @@ protected StatementType detectStatementType(String simplifiedStatement) {









Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ protected boolean isDelimiter(String peek, ParserContext context, int col) {
}

@Override
protected String readKeyword(PeekingReader reader, Delimiter delimiter) throws IOException {
protected String readKeyword(PeekingReader reader, Delimiter delimiter, ParserContext context) throws IOException {
// #2414: Ignore delimiter as GO (unlike ;) can be part of a regular keyword
return "" + (char) reader.read() + reader.readKeywordPart(null);
return "" + (char) reader.read() + reader.readKeywordPart(null, context);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,28 @@
*/
package org.flywaydb.core.internal.database.sybasease;

import org.flywaydb.core.api.FlywayException;
import org.flywaydb.core.api.configuration.Configuration;
import org.flywaydb.core.api.logging.Log;
import org.flywaydb.core.api.logging.LogFactory;
import org.flywaydb.core.internal.database.base.Database;
import org.flywaydb.core.internal.database.base.Table;
import org.flywaydb.core.internal.jdbc.JdbcConnectionFactory;
import org.flywaydb.core.internal.jdbc.Results;
import org.flywaydb.core.internal.sqlscript.Delimiter;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;

/**
* Sybase ASE database.
*/
public class SybaseASEDatabase extends Database<SybaseASEConnection> {
private static final Log LOG = LogFactory.getLog(SybaseASEDatabase.class);

private String databaseName = null;

/**
* Creates a new Sybase ASE database.
*
Expand Down Expand Up @@ -137,4 +146,44 @@ public boolean catalogIsSchema() {
return false;
}


boolean getDdlInTranOption() {
try {
// http://infocenter.sybase.com/help/index.jsp?topic=/com.sybase.infocenter.dc36273.1600/doc/html/san1393052037182.html
String databaseName = getDatabaseName();
// The Sybase driver (v7.07) concatenates "null" to this query and we can't see why. By adding a one-line
// comment marker we can at least prevent this causing us problems until we get a resolution.
String getDatabaseMetadataQuery = "sp_helpdb " + databaseName + " -- ";
Results results = getMainConnection().getJdbcTemplate().executeStatement(getDatabaseMetadataQuery);
for (int resultsIndex = 0; resultsIndex < results.getResults().size(); resultsIndex++) {
List<String> columns = results.getResults().get(resultsIndex).getColumns();
if (columns != null) {
int statusIndex = getStatusIndex(columns);
if (statusIndex > -1) {
String options = results.getResults().get(resultsIndex).getData().get(0).get(statusIndex);
return (options.contains("ddl in tran"));
}
}
}
return false;
} catch (Exception e) {
throw new FlywayException(e);
}
}

private int getStatusIndex(List<String> columns) {
for (int statusIndex = 0; statusIndex < columns.size(); statusIndex++) {
if ("status".equals(columns.get(statusIndex))) {
return statusIndex;
}
}
return -1;
}

String getDatabaseName() throws SQLException {
if (databaseName == null) {
databaseName = getMainConnection().getJdbcTemplate().queryForString("select db_name()");
}
return databaseName;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ protected boolean isDelimiter(String peek, ParserContext context, int col) {
}

@Override
protected String readKeyword(PeekingReader reader, Delimiter delimiter) throws IOException {
protected String readKeyword(PeekingReader reader, Delimiter delimiter, ParserContext context) throws IOException {
// #2414: Ignore delimiter as GO (unlike ;) can be part of a regular keyword
return "" + (char) reader.read() + reader.readKeywordPart(null);
return "" + (char) reader.read() + reader.readKeywordPart(null, context);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,7 @@ private Token readToken(PeekingReader reader, PositionTracker tracker, ParserCon
reader.swallow();
String text = reader.readUntilExcludingWithEscape(c, true);
if (reader.peek('.')) {
text = readAdditionalIdentifierParts(reader, c, context.getDelimiter());
text = readAdditionalIdentifierParts(reader, c, context.getDelimiter(), context);
}
return new Token(TokenType.IDENTIFIER, pos, line, col, text, text, context.getParensDepth());
}
Expand Down Expand Up @@ -522,10 +522,10 @@ private Token readToken(PeekingReader reader, PositionTracker tracker, ParserCon
if (isDelimiter(peek, context, col)) {
return handleDelimiter(reader, context, pos, line, col);
}
if (c == '_' || Character.isLetter(c)) {
String text = readKeyword(reader, context.getDelimiter());
if (c == '_' || context.isLetter(c)) {
String text = readKeyword(reader, context.getDelimiter(), context);
if (reader.peek('.')) {
text += readAdditionalIdentifierParts(reader, identifierQuote, context.getDelimiter());
text += readAdditionalIdentifierParts(reader, identifierQuote, context.getDelimiter(), context);
}
if (!isKeyword(text)) {
return new Token(TokenType.IDENTIFIER, pos, line, col, text, text, context.getParensDepth());
Expand All @@ -550,8 +550,8 @@ private Token readToken(PeekingReader reader, PositionTracker tracker, ParserCon
throw new FlywayException("Unknown char " + (char) reader.read() + " encountered on line " + line + " at column " + col);
}

protected String readKeyword(PeekingReader reader, Delimiter delimiter) throws IOException {
return "" + (char) reader.read() + reader.readKeywordPart(delimiter);
protected String readKeyword(PeekingReader reader, Delimiter delimiter, ParserContext context) throws IOException {
return "" + (char) reader.read() + reader.readKeywordPart(delimiter, context);
}

protected Token handleDelimiter(PeekingReader reader, ParserContext context, int pos, int line, int col) throws IOException {
Expand Down Expand Up @@ -594,15 +594,15 @@ protected boolean isKeyword(String text) {
}

@SuppressWarnings("Duplicates")
private String readAdditionalIdentifierParts(PeekingReader reader, char quote, Delimiter delimiter) throws IOException {
private String readAdditionalIdentifierParts(PeekingReader reader, char quote, Delimiter delimiter, ParserContext context) throws IOException {
String result = "";
reader.swallow();
result += ".";
if (reader.peek(quote)) {
reader.swallow();
result += reader.readUntilExcludingWithEscape(quote, true);
} else {
result += reader.readKeywordPart(delimiter);
result += reader.readKeywordPart(delimiter, context);
}
if (reader.peek('.')) {
reader.swallow();
Expand All @@ -611,7 +611,7 @@ private String readAdditionalIdentifierParts(PeekingReader reader, char quote, D
reader.swallow();
result += reader.readUntilExcludingWithEscape(quote, true);
} else {
result += reader.readKeywordPart(delimiter);
result += reader.readKeywordPart(delimiter, context);
}
}
return result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,15 @@ public StatementType getStatementType() {
public void setStatementType(StatementType statementType) {
this.statementType = statementType;
}

public boolean isLetter(char c) {
if (Character.isLetter(c)) {
return true;
}
// Some statement types admit other characters as letters
if (getStatementType() != null) {
return statementType.treatAsIfLetter(c);
}
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -134,13 +134,13 @@ private boolean isWhitespace(int r) {
*
* @return {@code true} if it is, {@code false} if not.
*/
public boolean peekKeywordPart() throws IOException {
public boolean peekKeywordPart(ParserContext context) throws IOException {
int r = peek();
return isKeywordPart(r);
return isKeywordPart(r, context);
}

private boolean isKeywordPart(int r) {
return r != -1 && ((char) r == '_' || (char) r == '$' || Character.isLetterOrDigit((char) r));
private boolean isKeywordPart(int r, ParserContext context) {
return r != -1 && ((char) r == '_' || (char) r == '$' || Character.isLetterOrDigit((char) r) || context.isLetter((char)r));
}

/**
Expand Down Expand Up @@ -411,10 +411,10 @@ public String readUntilIncluding(String delimiterSequence) throws IOException {
* @param delimiter The current delimiter.
* @return The string read.
*/
public String readKeywordPart(Delimiter delimiter) throws IOException {
public String readKeywordPart(Delimiter delimiter, ParserContext context) throws IOException {
StringBuilder result = new StringBuilder();
do {
if ((delimiter == null || !peek(delimiter.getDelimiter())) && peekKeywordPart()) {
if ((delimiter == null || !peek(delimiter.getDelimiter())) && peekKeywordPart(context)) {
result.append((char) read());
} else {
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,14 @@

public class StatementType {
public static final StatementType GENERIC = new StatementType();

/**
* Whether the character should be treated as if it is a letter; this allows statement types to handle
* characters that appear in specific contexts
* @param c
* @return
*/
public boolean treatAsIfLetter(char c) {
return false;
}
}

0 comments on commit 12bddbe

Please sign in to comment.