Skip to content

Instantly share code, notes, and snippets.

@nathanlws
Last active August 29, 2015 14:01
Show Gist options
  • Save nathanlws/3d6d546697810805edc6 to your computer and use it in GitHub Desktop.
Save nathanlws/3d6d546697810805edc6 to your computer and use it in GitHub Desktop.
Query Splitter
$ java -cp fdb-sql-parser-1.2.0.jar:. QuerySplitter "select * from a,b where (a.name='xyz' or a.id>5 ) and (b.name='abc' or b.id=5)"
original: select * from a,b where (a.name='xyz' or a.id>5 ) and (b.name='abc' or b.id=5)
unparsed: SELECT * FROM a, b WHERE ((a.name = 'xyz') OR (a.id > 5)) AND ((b.name = 'abc') OR (b.id = 5))
table a: SELECT * FROM a WHERE ((a.name = 'xyz') OR (a.id > 5)) AND (TRUE OR TRUE)
table b: SELECT * FROM b WHERE (TRUE OR TRUE) AND ((b.name = 'abc') OR (b.id = 5))
import com.foundationdb.sql.*;
import com.foundationdb.sql.parser.*;
import com.foundationdb.sql.unparser.*;
import java.util.*;
public class QuerySplitter
{
public static void main(String[] args) throws Exception {
SQLParser parser = new SQLParser();
NodeToString nodeToString = new NodeToString();
for(String s : args) {
StatementNode stmt = parser.parseStatement(s);
System.out.println("original: " + s);
System.out.println("unparsed: " + nodeToString.toString(stmt));
TableFinder finder = new TableFinder();
stmt.accept(finder);
for(TableName tn : finder.tableNames) {
QueryTreeNode copy = parser.getNodeFactory().copyNode(stmt, parser);
copy.accept(new TableKeeper(tn));
System.out.println("table " + tn + ": " + nodeToString.toString(copy));
}
}
}
private static class TableFinder implements Visitor
{
public List<TableName> tableNames = new ArrayList<>();
public Visitable visit(Visitable node) throws StandardException {
if(node instanceof FromList) {
FromList fl = (FromList)node;
for(int i = 0; i < fl.size(); ++i) {
tableNames.add(fl.get(i).getTableName());
}
}
return node;
}
public boolean visitChildrenFirst(Visitable node) {
return false;
}
public boolean stopTraversal() {
return false;
}
public boolean skipChildren(Visitable node) throws StandardException {
return false;
}
}
private static class TableKeeper implements Visitor
{
private final TableName keepTable;
public TableKeeper(TableName keepTable) {
this.keepTable = keepTable;
}
private boolean eliminate(ValueNode valueNode) {
if(valueNode instanceof ColumnReference) {
return !keepTable.equals(((ColumnReference)valueNode).getTableNameNode());
}
return false;
}
private ValueNode newTrueNode() throws StandardException {
BooleanConstantNode boolNode = new BooleanConstantNode();
boolNode.setNodeType(NodeTypes.BOOLEAN_CONSTANT_NODE);
boolNode.init(Boolean.TRUE);
return boolNode;
}
public Visitable visit(Visitable node) throws StandardException {
if(node instanceof FromList) {
FromList fl = (FromList)node;
Iterator<FromTable> it = fl.iterator();
while(it.hasNext()) {
FromTable ft = it.next();
if(!keepTable.equals(ft.getTableName())) {
it.remove();
}
}
}
else if(node instanceof BinaryRelationalOperatorNode) {
BinaryRelationalOperatorNode relNode = (BinaryRelationalOperatorNode)node;
if(eliminate(relNode.getLeftOperand()) || eliminate(relNode.getRightOperand())) {
node = newTrueNode();
}
}
return node;
}
public boolean visitChildrenFirst(Visitable node) {
return false;
}
public boolean stopTraversal() {
return false;
}
public boolean skipChildren(Visitable node) throws StandardException {
return false;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment