Add presto-sqlparser module for alternative SQLParser implementation (requires java 8+)

This commit is contained in:
Travis Burtrum 2017-05-28 22:14:30 -04:00
parent 849a85f1be
commit 5960341297
13 changed files with 306 additions and 16 deletions

View File

@ -44,7 +44,6 @@
<plugins> <plugins>
<plugin> <plugin>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration> <configuration>
<source>1.6</source> <source>1.6</source>
<target>1.6</target> <target>1.6</target>
@ -66,6 +65,20 @@
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>test-jar</goal>
</goals>
<phase>test-compile</phase>
</execution>
</executions>
<configuration>
<outputDirectory>${basedir}/target</outputDirectory>
</configuration>
</plugin>
</plugins> </plugins>
</build> </build>
</project> </project>

View File

@ -1,6 +1,6 @@
package com.moparisthebest.jdbc.codegen; package com.moparisthebest.jdbc.codegen;
import com.moparisthebest.jdbc.codegen.SQLParser; import java.util.Arrays;
/** /**
* Created by mopar on 5/25/17. * Created by mopar on 5/25/17.
@ -25,4 +25,11 @@ public abstract class AbstractSQLParser implements SQLParser {
return isSelect; return isSelect;
} }
@Override
public String toString() {
return this.getClass().getCanonicalName()+"{" +
"columnNames=" + Arrays.toString(columnNames) +
", isSelect=" + isSelect +
'}';
}
} }

View File

@ -3,6 +3,7 @@ package com.moparisthebest.jdbc.codegen;
import javax.annotation.processing.*; import javax.annotation.processing.*;
import javax.lang.model.SourceVersion; import javax.lang.model.SourceVersion;
import javax.lang.model.element.*; import javax.lang.model.element.*;
import javax.lang.model.type.MirroredTypeException;
import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror; import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements; import javax.lang.model.util.Elements;
@ -82,7 +83,11 @@ public class JdbcMapperProcessor extends AbstractProcessor {
} }
final TypeElement genClass = (TypeElement) element; final TypeElement genClass = (TypeElement) element;
final JdbcMapper.Mapper mapper = genClass.getAnnotation(JdbcMapper.Mapper.class); final JdbcMapper.Mapper mapper = genClass.getAnnotation(JdbcMapper.Mapper.class);
final SQLParser parser = new SimpleSQLParser();//(SQLParser)Class.forName(mapper.sqlParser().getCanonicalName()).newInstance(); final String sqlParserMirror = getSqlParser(mapper).toString();
//final SQLParser parser = new SimpleSQLParser();//(SQLParser)Class.forName(mapper.sqlParser().getCanonicalName()).newInstance();
//final SQLParser parser = mapper.sqlParser().equals(SQLParser.class) ? new SimpleSQLParser() : mapper.sqlParser().newInstance();
final SQLParser parser = sqlParserMirror.equals("com.moparisthebest.jdbc.codegen.SQLParser") ?
new SimpleSQLParser() : (SQLParser) Class.forName(sqlParserMirror).newInstance();
final String qualifiedName = genClass.getQualifiedName().toString(); final String qualifiedName = genClass.getQualifiedName().toString();
final boolean isInterface = genClass.getKind().isInterface(); final boolean isInterface = genClass.getKind().isInterface();
final boolean doJndi = !mapper.jndiName().isEmpty(); final boolean doJndi = !mapper.jndiName().isEmpty();
@ -305,7 +310,10 @@ public class JdbcMapperProcessor extends AbstractProcessor {
tryClose(w); tryClose(w);
} }
} catch (Exception e) { } catch (Exception e) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, e.getMessage(), element); final StringWriter sw = new StringWriter();
sw.write('\n');
e.printStackTrace(new PrintWriter(sw));
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, e.getMessage() + sw.toString(), element);
return false; return false;
} }
return true; return true;
@ -368,6 +376,16 @@ public class JdbcMapperProcessor extends AbstractProcessor {
w.write(");\n"); w.write(");\n");
} }
private static TypeMirror getSqlParser(final JdbcMapper.Mapper mapper) {
// ridiculous isn't it?
try {
mapper.sqlParser();
} catch (MirroredTypeException mte) {
return mte.getTypeMirror();
}
return null;
}
public static Class<?> typeMirrorToClass(final TypeMirror tm) throws ClassNotFoundException { public static Class<?> typeMirrorToClass(final TypeMirror tm) throws ClassNotFoundException {
switch (tm.getKind()) { switch (tm.getKind()) {
case BOOLEAN: case BOOLEAN:

View File

@ -27,8 +27,12 @@ public class JdbcMapperTest {
tryClose(dao); tryClose(dao);
} }
public PersonDAO getDao() {
return dao;
}
@Test @Test
public void testName() throws Throwable { public void testName() throws Throwable {
assertEquals(fieldPerson1.getFirstName(), dao.getFirstName(fieldPerson1.getPersonNo())); assertEquals(fieldPerson1.getFirstName(), getDao().getFirstName(fieldPerson1.getPersonNo()));
} }
} }

View File

@ -14,6 +14,7 @@ import java.util.Map;
@JdbcMapper.Mapper( @JdbcMapper.Mapper(
// jndiName = "bob", // jndiName = "bob",
cachePreparedStatements = false cachePreparedStatements = false
// , sqlParser = SimpleSQLParser.class
) )
public interface PersonDAO extends JdbcMapper { public interface PersonDAO extends JdbcMapper {

View File

@ -7,13 +7,17 @@ import static org.junit.Assert.*;
/** /**
* Created by mopar on 5/30/17. * Created by mopar on 5/30/17.
*/ */
public class SqlParserTest { public class SimpleSQLParserTest {
private final SQLParser factory = new SimpleSQLParser(); private final SQLParser factory = new SimpleSQLParser();
public SQLParser getFactory() {
return factory;
}
@Test @Test
public void testSingleSelect() { public void testSingleSelect() {
final SQLParser ret = factory.parse("select bob from tom"); final SQLParser ret = getFactory().parse("select bob from tom");
assertTrue(ret.isSelect()); assertTrue(ret.isSelect());
assertArrayEquals(new String[]{null, "BOB"}, ret.columnNames()); assertArrayEquals(new String[]{null, "BOB"}, ret.columnNames());
} }
@ -26,7 +30,7 @@ public class SqlParserTest {
, "select some_bob bob, some_tom as tom from tom" , "select some_bob bob, some_tom as tom from tom"
, "select tom.bob, some_tom as tom from tom" , "select tom.bob, some_tom as tom from tom"
}) { }) {
final SQLParser ret = factory.parse(sql); final SQLParser ret = getFactory().parse(sql);
assertTrue(ret.isSelect()); assertTrue(ret.isSelect());
assertArrayEquals(expected, ret.columnNames()); assertArrayEquals(expected, ret.columnNames());
} }
@ -39,7 +43,7 @@ public class SqlParserTest {
, "INSERT INTO bob (bob_no, bob) VALUES (1, 'bob')" , "INSERT INTO bob (bob_no, bob) VALUES (1, 'bob')"
, "MERGE INTO bob bla bla bla" , "MERGE INTO bob bla bla bla"
}) { }) {
final SQLParser ret = factory.parse(sql); final SQLParser ret = getFactory().parse(sql);
assertFalse(ret.isSelect()); assertFalse(ret.isSelect());
} }
} }

10
pom.xml
View File

@ -69,6 +69,7 @@
<module>runtime-compiler</module> <module>runtime-compiler</module>
<module>querymapper</module> <module>querymapper</module>
<module>jdbcmapper</module> <module>jdbcmapper</module>
<module>presto-sqlparser</module>
</modules> </modules>
<dependencyManagement> <dependencyManagement>
<dependencies> <dependencies>
@ -161,13 +162,12 @@
<pluginManagement> <pluginManagement>
<plugins> <plugins>
<plugin> <plugin>
<groupId>org.codehaus.mojo</groupId> <artifactId>maven-compiler-plugin</artifactId>
<artifactId>build-helper-maven-plugin</artifactId> <version>3.1</version>
<version>1.8</version>
</plugin> </plugin>
<plugin> <plugin>
<artifactId>maven-antrun-plugin</artifactId> <artifactId>maven-jar-plugin</artifactId>
<version>1.7</version> <version>2.2</version>
</plugin> </plugin>
</plugins> </plugins>
</pluginManagement> </pluginManagement>

75
presto-sqlparser/pom.xml Normal file
View File

@ -0,0 +1,75 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.moparisthebest.jdbcmapper</groupId>
<artifactId>jdbcmapper-parent</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>presto-sqlparser</artifactId>
<name>${project.artifactId}</name>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>jdbcmapper</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.facebook.presto</groupId>
<artifactId>presto-parser</artifactId>
<version>0.177</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>jdbcmapper</artifactId>
<version>${project.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>querymapper</artifactId>
<version>${project.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derby</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<debug>true</debug>
<!--compilerArgument>-Xlint:unchecked</compilerArgument-->
</configuration>
<executions>
<execution>
<id>my-testCompile</id>
<phase>test-compile</phase>
<goals>
<goal>testCompile</goal>
</goals>
<configuration>
<annotationProcessors>
<annotationProcessor>com.moparisthebest.jdbc.codegen.JdbcMapperProcessor</annotationProcessor>
</annotationProcessors>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,62 @@
package com.moparisthebest.jdbc.codegen;
import com.facebook.presto.sql.parser.SqlParser;
import com.facebook.presto.sql.tree.*;
import java.util.Arrays;
import java.util.List;
/**
* Created by mopar on 5/31/17.
*/
public class PrestoSQLParser extends AbstractSQLParser {
private static final SqlParser SQL_PARSER = new SqlParser();
public PrestoSQLParser() {
super(null, false);
}
private PrestoSQLParser(final String[] columnNames, final boolean isSelect) {
super(columnNames, isSelect);
}
@Override
public SQLParser parse(final String sql) {
boolean isSelect = false;
String[] columnNames = null;
try {
//final Expression stmt = SQL_PARSER.createExpression(sql);
final Statement stmt = SQL_PARSER.createStatement(sql);
isSelect = stmt instanceof Query;
if (isSelect) {
final Query query = (Query) stmt;
final List<SelectItem> selectItems = ((QuerySpecification)query.getQueryBody()).getSelect().getSelectItems();
columnNames = new String[selectItems.size() + 1];
int x = 0;
for(final SelectItem selectItem : selectItems) {
final SingleColumn sc = (SingleColumn) selectItem;
if(sc.getAlias().isPresent()) {
columnNames[++x] = sc.getAlias().get().toUpperCase();
continue;
}
final Expression scExp = sc.getExpression();
//columnNames[++x] = selectItem.toString();
if(scExp instanceof Identifier) {
columnNames[++x] = ((Identifier)scExp).getName().toUpperCase();
} else if(scExp instanceof DereferenceExpression) {
columnNames[++x] = ((DereferenceExpression)scExp).getFieldName().toUpperCase();
} else {
throw new RuntimeException("unknown syntax");
}
}
}
} catch(com.facebook.presto.sql.parser.ParsingException e) {
// ignore
//e.printStackTrace();
//throw new RuntimeException(e);
}
return new PrestoSQLParser(columnNames, isSelect);
}
}

View File

@ -0,0 +1,56 @@
package com.moparisthebest.jdbc.codegen;
import com.moparisthebest.jdbc.dto.FieldPerson;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
/**
* Created by mopar on 5/24/17.
*/
@JdbcMapper.Mapper(
// jndiName = "bob",
cachePreparedStatements = false
, sqlParser = PrestoSQLParser.class
)
public interface PrestoPersonDAO extends PersonDAO {
@JdbcMapper.SQL("UPDATE person SET first_name = {firstName} WHERE last_name = {lastName}")
int setFirstName(String firstName, String lastName);
@JdbcMapper.SQL("UPDATE person SET first_name = {firstName} WHERE person_no = {personNo}")
void setFirstName(String firstName, long personNo) throws SQLException;
@JdbcMapper.SQL("UPDATE person SET first_name = {firstName} WHERE person_no = {personNo}")
void setFirstNameBlob(byte[] firstName, long personNo) throws SQLException;
@JdbcMapper.SQL("SELECT first_name FROM person WHERE person_no = {personNo}")
String getFirstName(long personNo) throws SQLException;
@JdbcMapper.SQL("SELECT first_name, last_name FROM person WHERE person_no = {personNo}")
FieldPerson getPerson(long personNo) throws SQLException;
@JdbcMapper.SQL("SELECT first_name, last_name FROM person WHERE last_name = {lastName}")
List<FieldPerson> getPeople(String lastName) throws SQLException;
@JdbcMapper.SQL("SELECT first_name, last_name FROM person WHERE last_name = {lastName}")
FieldPerson[] getPeopleArray(String lastName) throws SQLException;
@JdbcMapper.SQL("SELECT first_name, last_name FROM person WHERE last_name = {lastName}")
Iterator<FieldPerson> getPeopleIterator(String lastName) throws SQLException;
@JdbcMapper.SQL("SELECT first_name, last_name FROM person WHERE last_name = {lastName}")
ListIterator<FieldPerson> getPeopleListIterator(String lastName) throws SQLException;
@JdbcMapper.SQL("SELECT first_name, last_name, person_no FROM person WHERE last_name = {lastName}")
Map<String, FieldPerson> getPersonMap(String lastName) throws SQLException;
@JdbcMapper.SQL("SELECT first_name, last_name, person_no FROM person WHERE last_name = {lastName}")
Map<String, List<FieldPerson>> getPersonMapList(String lastName) throws SQLException;
@JdbcMapper.SQL("SELECT first_name FROM person WHERE person_no = {personNo} and last_name = {lastName}")
String getFirstName(long personNo, String lastName) throws SQLException;
}

View File

@ -0,0 +1,33 @@
package com.moparisthebest.jdbc.codegen;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import static com.moparisthebest.jdbc.QueryMapperTest.fieldPerson1;
import static com.moparisthebest.jdbc.QueryMapperTest.getConnection;
import static com.moparisthebest.jdbc.TryClose.tryClose;
import static org.junit.Assert.assertEquals;
/**
* Created by mopar on 5/24/17.
*/
public class PrestoPersonDAOTest extends JdbcMapperTest {
private static PersonDAO dao;
@BeforeClass
public static void setUp() throws Throwable {
dao = JdbcMapperFactory.create(PrestoPersonDAO.class, getConnection());
//dao = new com.moparisthebest.jdbc.codegen.PersonDAOBean(getConnection());
}
@AfterClass
public static void tearDown() throws Throwable {
tryClose(dao);
}
public PersonDAO getDao() {
return dao;
}
}

View File

@ -0,0 +1,18 @@
package com.moparisthebest.jdbc.codegen;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Created by mopar on 5/30/17.
*/
public class PrestoSQLParserTest extends SimpleSQLParserTest {
private final SQLParser factory = new PrestoSQLParser();
public SQLParser getFactory() {
return factory;
}
}

View File

@ -36,7 +36,6 @@
<plugins> <plugins>
<plugin> <plugin>
<artifactId>maven-jar-plugin</artifactId> <artifactId>maven-jar-plugin</artifactId>
<version>2.2</version>
<executions> <executions>
<execution> <execution>
<goals> <goals>