package com.tesora.dve.sql.parser;
/*
* #%L
* Tesora Inc.
* Database Virtualization Engine
* %%
* Copyright (C) 2011 - 2014 Tesora Inc.
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class PELogLineBuffer extends LogLineBuffer {
// so the format is:
// DEBUG MMM-DD HH:MM:SS [SSConnectionNNNN] (sql.parser.InvokeParser:89) - <sqlstmt>
// DEBUG MMM-DD HH:MM:SS [SSConnectionNNNN] (sql.parser.InvokeParser:120) =>
// errors look like
// ERROR MMM-DD HH:MM:SS ...
//
// So the begin stmt bit is the log header + InvokeParser:89) -
// And the end is either the log header + InvokeParser:120) - or the ERROR
private static final String logHeader = "DEBUG .+ \\[SSConnection" + "(\\" + "d+)\\] ";
private static final String ipHeader = "\\(sql\\.parser\\.InvokeParser:";
private enum Delimiter {
BEGINPARSE(logHeader + ipHeader + "89\\) - ",true),
PARSERESULT(logHeader + ipHeader + "120\\) - ",false),
ERROR("ERROR .+ \\(client\\.messages\\.ResponseMessage:94\\)",false);
private final Pattern regex;
private final boolean payload;
private final String in;
private Delimiter(String pattern, boolean usePayload) {
in = pattern;
regex = Pattern.compile(pattern);
payload = usePayload;
}
public Pattern getRegex() { return regex; }
public boolean usePayload() { return payload; }
@SuppressWarnings("unused")
public String getPattern() { return in; }
}
private static final Delimiter[] delimiters = Delimiter.values();
protected MatchResult[] matches = null;
private static class MatchResult {
protected int start;
protected int end;
protected Delimiter delimiter;
protected String connID;
public MatchResult(int startoff, int endoff, Delimiter d, String connectionID) {
start = startoff;
end = endoff;
delimiter = d;
connID = connectionID;
}
public Delimiter getDelimiter() {
return delimiter;
}
public int getStartOffset() {
return start;
}
public int getEndOffset() {
return end;
}
public String getConnectionID() {
return connID;
}
}
private MatchResult findMatch(String stmt, int suboff) {
int offset = -1;
int endoff = -1;
Delimiter delimiter = null;
Matcher matched = null;
for(int i = 0; i < delimiters.length; i++) {
Delimiter d = delimiters[i];
Matcher m = d.getRegex().matcher(stmt);
if (m.find(suboff)) {
int thisoffset = m.start();
if (offset == -1 || thisoffset < offset) {
offset = thisoffset;
endoff = m.end();
delimiter = delimiters[i];
if (delimiter.usePayload()) {
matched = m;
}
}
}
}
if (offset == -1)
return null;
return new MatchResult(offset, endoff, delimiter, (matched == null ? null : matched.group(1)));
}
@Override
protected boolean haveStatement() {
if (buffer == null)
return false;
String stmt = buffer.toString();
matches = new MatchResult[2];
MatchResult results = findMatch(stmt, 0);
if (results != null) {
matches[0] = results;
int sucoff = results.getEndOffset();
results = findMatch(stmt,sucoff);
if (results != null) {
matches[1] = results;
return true;
}
}
matches = null;
return false;
}
@Override
protected TaggedStatement getStatement() {
if (matches != null) {
// any statement is between the last match position of the first match and the first match position of the last match.
// well, there might be some extra cruft in there so search backwards from the start offset of the second match for
// a carriage return
String attempt = buffer.toString().substring(matches[0].getEndOffset(), matches[1].getStartOffset());
String stmt = attempt;
// the new buffer starts just before the second match
String newbuf = buffer.toString().substring(matches[1].getStartOffset());
buffer = new StringBuilder();
buffer.append(newbuf);
if (stmt.charAt(0) == '#' || stmt.indexOf("SHOW PROCESSLIST") > -1) {
// not using it
return null;
}
if (matches[0].getDelimiter().usePayload()) {
String connID = matches[0].getConnectionID();
int id = -1;
if (connID != null) try {
id = Integer.parseInt(connID);
} catch (NumberFormatException nfe) {
System.err.println("Unable to pick conn id out of " + connID);
id = -1;
}
return new TaggedStatement(stmt,id,null);
}
}
return null;
}
}