Skip to content
Snippets Groups Projects
Commit 331825f8 authored by Julien Lopez's avatar Julien Lopez
Browse files

Fix queries cross databases

parent 30429e60
No related branches found
No related tags found
No related merge requests found
......@@ -30,8 +30,8 @@ public abstract class DBDriver<DBRepr> {
}
/**
* Returns a {@link DBDriver} of a database using a configuration file. This function uses a
* cache for the drivers.
* Returns a {@link DBDriver} of a database using a configuration file. This function uses a cache
* for the drivers.
*
* @param dbName The name of the targeted database
* @param fileName The name of the configuration file
......@@ -44,16 +44,16 @@ public abstract class DBDriver<DBRepr> {
if (result != null)
return result;
switch (dbName) {
case "Oracle":
case OracleDriver.dbName:
result = new OracleDriver(fileName);
break;
case "PostgreSQL":
case PostgreSQLDriver.dbName:
result = new PostgreSQLDriver(fileName);
break;
case "Hive":
case QIRHiveDriver.dbName:
result = new QIRHiveDriver(fileName);
break;
case "HBase":
case HBaseDriver.dbName:
result = new HBaseDriver(fileName);
break;
default:
......@@ -81,8 +81,8 @@ public abstract class DBDriver<DBRepr> {
}
/**
* Opens a connection to the targeted database using the given {@link #newConfigFile} and stores
* it as {@link #configFile}.
* Opens a connection to the targeted database using the given {@link #newConfigFile} and stores it
* as {@link #configFile}.
*
* @throws QIRException Connection could not be established.
*/
......
......@@ -15,14 +15,15 @@ import qir.ast.QIRVariable;
public class QIRDriver {
/**
* Executes a QIR query. First, the query is normalized using the {@link QIRGreedyReduceVisitor}
* module, then the query is translated by the {@link QIRCompileVisitor} module into a query
* written in the different languages understandable by the different data providers, finally it
* is run by the {@link QIREvaluationVisitor} module.
* module, then the query is translated by the {@link QIRCompileVisitor} module into a query written
* in the different languages understandable by the different data providers, finally it is run by
* the {@link QIREvaluationVisitor} module.
*
* @param query The QIR query to execute
* @return The results of the query
*/
public static final QIRNode run(final QIRNode query) {
System.out.println(query.accept(new QIRGreedyReduceVisitor()).accept(QIRCompileVisitor.instance));
return query.accept(new QIRGreedyReduceVisitor()).accept(QIRCompileVisitor.instance).executeGeneric(Truffle.getRuntime().createVirtualFrame(new Object[]{}, new FrameDescriptor()));
}
......
......@@ -34,6 +34,7 @@ import qir.util.QIRException;
* @param DBRepr The type of representation of a query for the database.
*/
public final class HBaseDriver extends DBDriver<HBaseQuery> {
public static final String dbName = "HBase";
protected Connection conn;
private Configuration conf;
......@@ -77,7 +78,7 @@ public final class HBaseDriver extends DBDriver<HBaseQuery> {
@Override
public HBaseQuery translate(final QIRNode root) {
return root.accept(new QIRHBaseQueryVisitor(conf));
return root.accept(new QIRHBaseQueryVisitor(conf, dbName, configFile));
}
@Override
......
......@@ -24,9 +24,13 @@ import qir.util.QIRException;
*/
final class QIRHBaseQueryVisitor implements IQIRVisitor<HBaseQuery> {
private final Configuration conf;
private final String dbName;
private final String dbConfig;
QIRHBaseQueryVisitor(final Configuration conf) {
QIRHBaseQueryVisitor(final Configuration conf, final String dbName, final String dbConfig) {
this.conf = conf;
this.dbName = dbName;
this.dbConfig = dbConfig;
}
@Override
......@@ -42,7 +46,13 @@ final class QIRHBaseQueryVisitor implements IQIRVisitor<HBaseQuery> {
@Override
public final HBaseQuery visit(QIRScan qirScan) {
return new HBaseQuery(new Scan(), (String) ((QIRBaseValue<?>) ((QIRTable) qirScan.table).schemaName).value + ":" + (String) ((QIRBaseValue<?>) ((QIRTable) qirScan.table).tableName).value);
if (qirScan.table instanceof QIRTable && ((QIRTable) qirScan.table).dbName instanceof QIRString && ((QIRTable) qirScan.table).configFile instanceof QIRString) {
final QIRTable table = (QIRTable) qirScan.table;
if (!((QIRString) table.dbName).value.equals(dbName) || !((QIRString) table.configFile).value.equals(dbConfig))
throw new QIRException("Subquery for another database detected.");
return new HBaseQuery(new Scan(), (String) ((QIRBaseValue<?>) ((QIRTable) qirScan.table).schemaName).value + ":" + (String) ((QIRBaseValue<?>) ((QIRTable) qirScan.table).tableName).value);
}
throw new QIRException("QIR HBase Scan not implemented for table type: " + qirScan.table.getClass());
}
@Override
......
......@@ -4,6 +4,7 @@ import java.sql.*;
import java.util.Map.Entry;
import oracle.jdbc.pool.*;
import qir.ast.QIRNode;
import qir.ast.data.*;
import qir.util.QIRException;
......@@ -11,6 +12,8 @@ import qir.util.QIRException;
* {@link OracleDriver} is an intermediate between QIR and a Oracle database.
*/
public final class OracleDriver extends SQLStringDriver {
public static final String dbName = "Oracle";
public OracleDriver(final String configFile) {
super(configFile);
}
......@@ -32,11 +35,16 @@ public final class OracleDriver extends SQLStringDriver {
}
}
@Override
public String translate(final QIRNode root) {
return root.accept(new QIRSQLStringVisitor(dbName, configFile));
}
@Override
public final QIRList run(final String query) throws QIRException {
try {
enableWalnut();
for (Entry<String, String> f : new QIRSQLStringVisitor().popProlog().entrySet())
for (Entry<String, String> f : new QIRSQLStringVisitor(dbName, configFile).popProlog().entrySet())
addSLSQLFunction(f.getValue(), functionExists(f.getKey()));
return super.run(query);
} catch (final SQLException e) {
......
......@@ -3,16 +3,24 @@ package qir.driver.sql;
import java.sql.*;
import java.util.*;
import qir.ast.QIRNode;
import qir.util.QIRException;
/**
* {@link PostgreSQLDriver} is an intermediate between QIR and a PostgreSQL database.
*/
public final class PostgreSQLDriver extends SQLStringDriver {
public static final String dbName = "PostgreSQL";
public PostgreSQLDriver(final String newConfigFile) {
super(newConfigFile);
}
@Override
public String translate(final QIRNode root) {
return root.accept(new QIRSQLStringVisitor(dbName, configFile));
}
@Override
public final void openConnection(final String newConfigFile) throws QIRException {
try {
......
......@@ -6,16 +6,18 @@ import qir.ast.QIRNode;
import qir.util.QIRException;
/**
* {@link QIRHiveDriver} is an intermediate between QIR and a PostgreSQL database.
* {@link QIRHiveDriver} is an intermediate between QIR and a Hive database.
*/
public final class QIRHiveDriver extends SQLStringDriver {
public static final String dbName = "Hive";
public QIRHiveDriver(final String newConfigFile) {
super(newConfigFile);
}
@Override
public String translate(final QIRNode root) {
return root.accept(new QIRHiveStringVisitor());
return root.accept(new QIRHiveStringVisitor(dbName, configFile));
}
@Override
......
......@@ -15,6 +15,10 @@ import qir.ast.QIRVariable;
import qir.ast.data.QIRTdestr;
public class QIRHiveStringVisitor extends QIRSQLStringVisitor {
public QIRHiveStringVisitor(final String dbName, final String dbConfig) {
super(dbName, dbConfig);
}
@Override
public final String visit(final QIRApply qirApply) {
// TODO: Improve implementation
......
......@@ -34,6 +34,20 @@ class QIRSQLStringVisitor implements IQIRVisitor<String> {
* The functions to send to the database before the query can be executed.
*/
private Map<String, String> prolog = new HashMap<>();
/**
* The name of the database the query will be sent to.
*/
private final String dbName;
/**
* The configuration file of the database the query will be sent to.
*/
private final String dbConfig;
public QIRSQLStringVisitor(final String dbName, final String dbConfig) {
this.dbName = dbName;
this.dbConfig = dbConfig;
}
public final Map<String, String> popProlog() {
final Map<String, String> res = prolog;
......@@ -50,9 +64,13 @@ class QIRSQLStringVisitor implements IQIRVisitor<String> {
@Override
public final String visit(final QIRScan qirScan) {
if (qirScan.table instanceof QIRTable)
if (qirScan.table instanceof QIRTable && ((QIRTable) qirScan.table).dbName instanceof QIRString && ((QIRTable) qirScan.table).configFile instanceof QIRString) {
final QIRTable table = (QIRTable) qirScan.table;
if (!((QIRString) table.dbName).value.equals(dbName) || !((QIRString) table.configFile).value.equals(dbConfig))
throw new QIRException("Subquery for another database detected.");
return "select * from " + qirScan.table.accept(this);
return "select * from (" + qirScan.table.accept(this) + ") as " + genFreshId();
}
throw new QIRException("QIR SQL Scan not implemented for table type: " + qirScan.table.getClass());
}
@Override
......
......@@ -31,11 +31,6 @@ abstract class SQLStringDriver extends SQLDriver<String> {
super(configFile);
}
@Override
public String translate(final QIRNode root) {
return root.accept(new QIRSQLStringVisitor());
}
@Override
public QIRList run(final String query) throws QIRException {
try {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment