Skip to content
Snippets Groups Projects
Commit 04a00fe2 authored by gmantele's avatar gmantele
Browse files

[ADQL] Fix a sub-query bug. No DBTable was set on an ADQLTable having a

sub-query. Without this information, it was impossible to resolve columns makingreference to sub-queries of the clause FROM. See the JUnit test case for a
concrete example.
(error raised by Hendrik Heinl - ARI/GAVO)
parent 19026c1b
No related branches found
No related tags found
No related merge requests found
......@@ -16,7 +16,7 @@ package adql.query.from;
* You should have received a copy of the GNU Lesser General Public License
* along with ADQLLibrary. If not, see <http://www.gnu.org/licenses/>.
*
* Copyright 2012-2015 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
* Copyright 2012-2016 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
* Astronomisches Rechen Institut (ARI)
*/
......@@ -39,7 +39,7 @@ import adql.query.TextPosition;
* A table reference may have an alias (MUST if it is a sub-query).
*
* @author Gr&eacute;gory Mantelet (CDS;ARI)
* @version 06/2015
* @version 2.1 (07/2016)
*/
public class ADQLTable implements ADQLObject, FromContent {
......@@ -165,6 +165,7 @@ public class ADQLTable implements ADQLObject, FromContent {
*
* @return The position of this {@link ADQLTable}.
*/
@Override
public final TextPosition getPosition(){
return position;
}
......@@ -174,6 +175,7 @@ public class ADQLTable implements ADQLObject, FromContent {
*
* @param pos Position of this {@link ADQLTable}.
*/
@Override
public final void setPosition(final TextPosition pos){
position = pos;
}
......@@ -465,18 +467,15 @@ public class ADQLTable implements ADQLObject, FromContent {
}
/**
* <p>Sets the {@link DBTable} corresponding to this {@link ADQLTable}.</p>
* <p><i>
* <u>Note:</u> This function will do nothing if this {@link ADQLTable} is a sub query.
* </i></p>
* Sets the {@link DBTable} corresponding to this {@link ADQLTable}.
*
* @param dbLink Its corresponding {@link DBTable}.
*/
public final void setDBLink(DBTable dbLink){
if (!isSubQuery())
this.dbLink = dbLink;
this.dbLink = dbLink;
}
@Override
public SearchColumnList getDBColumns(){
SearchColumnList list = new SearchColumnList();
if (isSubQuery() && dbLink == null)
......@@ -488,12 +487,14 @@ public class ADQLTable implements ADQLObject, FromContent {
return list;
}
@Override
public ArrayList<ADQLTable> getTables(){
ArrayList<ADQLTable> tables = new ArrayList<ADQLTable>();
tables.add(this);
return tables;
}
@Override
public ArrayList<ADQLTable> getTablesByAlias(final String alias, final boolean caseSensitive){
ArrayList<ADQLTable> tables = new ArrayList<ADQLTable>();
......@@ -515,19 +516,23 @@ public class ADQLTable implements ADQLObject, FromContent {
return tables;
}
@Override
public ADQLObject getCopy() throws Exception{
return new ADQLTable(this);
}
@Override
public String getName(){
return hasAlias() ? alias : (isSubQuery() ? "{subquery}" : getTableName());
}
@Override
public ADQLIterator adqlIterator(){
return new ADQLIterator(){
private boolean subQueryGot = !isSubQuery();
@Override
public ADQLObject next(){
if (!subQueryGot){
subQueryGot = true;
......@@ -536,10 +541,12 @@ public class ADQLTable implements ADQLObject, FromContent {
throw new NoSuchElementException();
}
@Override
public boolean hasNext(){
return !subQueryGot;
}
@Override
public void replace(ADQLObject replacer) throws UnsupportedOperationException, IllegalStateException{
if (!subQueryGot)
throw new IllegalStateException("replace(ADQLObject) impossible: next() has not yet been called !");
......@@ -553,6 +560,7 @@ public class ADQLTable implements ADQLObject, FromContent {
throw new UnsupportedOperationException("Impossible to replace a sub-query (" + subQuery.toADQL() + ") by a " + replacer.getClass().getName() + " (" + replacer.toADQL() + ") !");
}
@Override
public void remove(){
if (!subQueryGot)
throw new IllegalStateException("remove() impossible: next() has not yet been called !");
......@@ -562,6 +570,7 @@ public class ADQLTable implements ADQLObject, FromContent {
};
}
@Override
public String toADQL(){
return (isSubQuery() ? ("(" + subQuery.toADQL() + ")") : getFullTableName()) + ((alias == null) ? "" : (" AS " + (isCaseSensitive(IdentifierField.ALIAS) ? ("\"" + alias + "\"") : alias)));
}
......
package adql.db;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import org.junit.Before;
import org.junit.Test;
import adql.parser.ADQLParser;
import adql.query.ADQLQuery;
import tap.metadata.TAPMetadata;
import tap.metadata.TAPTable;
import tap.metadata.TableSetParser;
public class TestSeveralSubQueries {
@Before
public void setUp() throws Exception{}
@Test
public void test(){
try{
TableSetParser tsParser = new TableSetParser();
TAPMetadata esaMetaData = tsParser.parse(new File("test/adql/db/subquery_test_tables.xml"));
ArrayList<DBTable> esaTables = new ArrayList<DBTable>(esaMetaData.getNbTables());
Iterator<TAPTable> itTables = esaMetaData.getTables();
while(itTables.hasNext())
esaTables.add(itTables.next());
ADQLParser adqlParser = new ADQLParser(new DBChecker(esaTables));
ADQLQuery query = adqlParser.parseQuery("SELECT sel2.*,t1.h_m, t1.j_m, t1.k_m\nFROM (\n SELECT sel1.*, t3.*\n FROM (\n SELECT *\n FROM table2 AS t2\n WHERE 1=CONTAINS(POINT('ICRS', t2.ra, t2.dec), CIRCLE('ICRS', 56.75, 24.1167, 15.))\n ) AS sel1 JOIN table3 AS t3 ON t3.oid2=sel1.oid2\n) AS sel2 JOIN table1 AS t1 ON sel2.oid=t1.oid");
assertEquals("SELECT sel2.* , t1.h_m , t1.j_m , t1.k_m\nFROM (SELECT sel1.* , t3.*\nFROM (SELECT *\nFROM table2 AS t2\nWHERE 1 = CONTAINS(POINT('ICRS', t2.ra, t2.dec), CIRCLE('ICRS', 56.75, 24.1167, 15.))) AS sel1 INNER JOIN table3 AS t3 ON ON t3.oid2 = sel1.oid2) AS sel2 INNER JOIN table1 AS t1 ON ON sel2.oid = t1.oid", query.toADQL());
}catch(Exception ex){
ex.printStackTrace(System.err);
fail("No error expected! (see console for more details)");
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<vod:tableset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:vod="http://www.ivoa.net/xml/VODataService/v1.1" xsi:type="vod:TableSet" xsi:schemaLocation="http://www.ivoa.net/xml/VODataService/v1.1 http://www.ivoa.net/xml/VODataService/v1.1">
<schema>
<name>public</name>
<table type="base_table">
<name>table1</name>
<column std="false">
<name>oid</name>
<unit></unit>
<ucd>meta.id;meta.main</ucd>
<utype></utype>
<dataType xsi:type="vod:TAPType">BIGINT</dataType>
<flag>indexed</flag>
</column>
<column std="false">
<name>ra</name>
<unit>deg</unit>
<ucd>pos.eq.ra;meta.main</ucd>
<utype></utype>
<dataType xsi:type="vod:TAPType">DOUBLE</dataType>
<flag>indexed</flag>
</column>
<column std="false">
<name>dec</name>
<unit>Angle[deg]</unit>
<ucd>pos.eq.dec;meta.main</ucd>
<utype></utype>
<dataType xsi:type="vod:TAPType">DOUBLE</dataType>
<flag>indexed</flag>
</column>
<column std="false">
<name>h_m</name>
<unit>mag</unit>
<ucd>phot.mag;em.IR.H</ucd>
<utype></utype>
<dataType xsi:type="vod:TAPType">REAL</dataType>
</column>
<column std="false">
<name>j_m</name>
<unit>mag</unit>
<ucd>phot.mag;em.IR.J</ucd>
<utype></utype>
<dataType xsi:type="vod:TAPType">REAL</dataType>
</column>
<column std="false">
<name>k_m</name>
<unit>mag</unit>
<ucd>phot.mag;em.IR.K</ucd>
<utype></utype>
<dataType xsi:type="vod:TAPType">REAL</dataType>
</column>
</table>
<table type="base_table">
<name>table2</name>
<column std="false">
<name>oid2</name>
<unit></unit>
<ucd>meta.id;meta.main</ucd>
<utype></utype>
<dataType xsi:type="vod:TAPType">BIGINT</dataType>
<flag>indexed</flag>
</column>
<column std="false">
<name>ra</name>
<unit>deg</unit>
<ucd>pos.eq.ra;meta.main</ucd>
<utype></utype>
<dataType xsi:type="vod:TAPType">DOUBLE</dataType>
<flag>indexed</flag>
</column>
<column std="false">
<name>ra_error</name>
<unit>mas</unit>
<ucd>stat.error;pos.eq.ra</ucd>
<utype></utype>
<dataType xsi:type="vod:TAPType">DOUBLE</dataType>
</column>
<column std="false">
<name>dec</name>
<unit>deg</unit>
<ucd>pos.eq.dec;meta.main</ucd>
<utype></utype>
<dataType xsi:type="vod:TAPType">DOUBLE</dataType>
<flag>indexed</flag>
</column>
<column std="false">
<name>dec_error</name>
<unit>mas</unit>
<ucd>stat.error;pos.eq.dec</ucd>
<utype></utype>
<dataType xsi:type="vod:TAPType">DOUBLE</dataType>
</column>
<column std="false">
<name>parallax</name>
<unit>mas</unit>
<ucd>pos.parallax</ucd>
<utype></utype>
<dataType xsi:type="vod:TAPType">DOUBLE</dataType>
<flag>indexed</flag>
</column>
<column std="false">
<name>parallax_error</name>
<unit>mas</unit>
<ucd>stat.error;pos.parallax</ucd>
<utype></utype>
<dataType xsi:type="vod:TAPType">DOUBLE</dataType>
<flag>indexed</flag>
</column>
<column std="false">
<name>magnitude</name>
<unit>mag</unit>
<ucd>phot.mag;stat.mean;em.opt</ucd>
<utype></utype>
<dataType xsi:type="vod:TAPType">DOUBLE</dataType>
<flag>indexed</flag>
</column>
<column std="false">
<name>pmdec</name>
<unit>mas/year</unit>
<ucd>pos.pm;pos.eq.dec</ucd>
<utype></utype>
<dataType xsi:type="vod:TAPType">DOUBLE</dataType>
<flag>indexed</flag>
</column>
<column std="false">
<name>pmdec_error</name>
<unit>mas/year</unit>
<ucd>stat.error;pos.pm;pos.eq.dec</ucd>
<utype></utype>
<dataType xsi:type="vod:TAPType">DOUBLE</dataType>
</column>
<column std="false">
<name>pmra</name>
<unit>mas/year</unit>
<ucd>pos.pm;pos.eq.ra</ucd>
<utype></utype>
<dataType xsi:type="vod:TAPType">DOUBLE</dataType>
<flag>indexed</flag>
</column>
<column std="false">
<name>pmra_error</name>
<unit>mas/year</unit>
<ucd>stat.error;pos.pm;pos.eq.ra</ucd>
<utype></utype>
<dataType xsi:type="vod:TAPType">DOUBLE</dataType>
</column>
</table>
<table type="base_table">
<name>table3</name>
<column std="false">
<name>oid</name>
<unit></unit>
<ucd>meta.id</ucd>
<utype></utype>
<dataType xsi:type="vod:TAPType">BIGINT</dataType>
</column>
<column std="false">
<name>oid2</name>
<description></description>
<unit></unit>
<ucd>meta.id</ucd>
<utype></utype>
<dataType xsi:type="vod:TAPType">BIGINT</dataType>
</column>
</table>
</schema>
<schema>
<name>tap_schema</name>
<table type="base_table">
<name>tables</name>
<column std="false">
<name>description</name>
<dataType xsi:type="vod:TAPType">VARCHAR</dataType>
</column>
<column std="false">
<name>schema_name</name>
<dataType xsi:type="vod:TAPType">VARCHAR</dataType>
</column>
<column std="false">
<name>size</name>
<dataType xsi:type="vod:TAPType">INTEGER</dataType>
</column>
<column std="false">
<name>table_name</name>
<dataType xsi:type="vod:TAPType">VARCHAR</dataType>
</column>
<column std="false">
<name>table_type</name>
<dataType xsi:type="vod:TAPType">VARCHAR</dataType>
</column>
<column std="false">
<name>utype</name>
<dataType xsi:type="vod:TAPType">VARCHAR</dataType>
</column>
</table>
<table type="base_table">
<name>columns</name>
<column std="false">
<name>column_name</name>
<dataType xsi:type="vod:TAPType">VARCHAR</dataType>
</column>
<column std="false">
<name>datatype</name>
<dataType xsi:type="vod:TAPType">VARCHAR</dataType>
</column>
<column std="false">
<name>description</name>
<dataType xsi:type="vod:TAPType">VARCHAR</dataType>
</column>
<column std="false">
<name>indexed</name>
<dataType xsi:type="vod:TAPType">INTEGER</dataType>
</column>
<column std="false">
<name>principal</name>
<dataType xsi:type="vod:TAPType">INTEGER</dataType>
</column>
<column std="false">
<name>schema_name</name>
<dataType xsi:type="vod:TAPType">VARCHAR</dataType>
</column>
<column std="false">
<name>size</name>
<dataType xsi:type="vod:TAPType">INTEGER</dataType>
</column>
<column std="false">
<name>std</name>
<dataType xsi:type="vod:TAPType">INTEGER</dataType>
</column>
<column std="false">
<name>table_name</name>
<dataType xsi:type="vod:TAPType">VARCHAR</dataType>
</column>
<column std="false">
<name>ucd</name>
<dataType xsi:type="vod:TAPType">VARCHAR</dataType>
</column>
<column std="false">
<name>unit</name>
<dataType xsi:type="vod:TAPType">VARCHAR</dataType>
</column>
<column std="false">
<name>utype</name>
<dataType xsi:type="vod:TAPType">VARCHAR</dataType>
</column>
</table>
<table type="base_table">
<name>keys</name>
<column std="false">
<name>description</name>
<dataType xsi:type="vod:TAPType">VARCHAR</dataType>
</column>
<column std="false">
<name>from_table</name>
<dataType xsi:type="vod:TAPType">VARCHAR</dataType>
</column>
<column std="false">
<name>key_id</name>
<dataType xsi:type="vod:TAPType">VARCHAR</dataType>
</column>
<column std="false">
<name>target_table</name>
<dataType xsi:type="vod:TAPType">VARCHAR</dataType>
</column>
<column std="false">
<name>utype</name>
<dataType xsi:type="vod:TAPType">VARCHAR</dataType>
</column>
</table>
<table type="base_table">
<name>schemas</name>
<column std="false">
<name>description</name>
<dataType xsi:type="vod:TAPType">VARCHAR</dataType>
</column>
<column std="false">
<name>schema_name</name>
<dataType xsi:type="vod:TAPType">VARCHAR</dataType>
</column>
<column std="false">
<name>utype</name>
<dataType xsi:type="vod:TAPType">VARCHAR</dataType>
</column>
</table>
<table type="base_table">
<name>key_columns</name>
<column std="false">
<name>from_column</name>
<dataType xsi:type="vod:TAPType">VARCHAR</dataType>
</column>
<column std="false">
<name>key_id</name>
<dataType xsi:type="vod:TAPType">VARCHAR</dataType>
</column>
<column std="false">
<name>target_column</name>
<dataType xsi:type="vod:TAPType">VARCHAR</dataType>
</column>
</table>
</schema>
</vod:tableset>
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