Commit ade0302b authored by Grégory Mantelet's avatar Grégory Mantelet
Browse files

[ADQL] Remove column definition list in `WITH` clause (according to the recent

modifications of ADQL-2.1-PR)
+ Complete and fix case-sensitivity tests.
parent b2ed98ca
Loading
Loading
Loading
Loading
+1 −10
Original line number Diff line number Diff line
@@ -108,7 +108,7 @@ import adql.search.SimpleSearchHandler;
 * </i></p>
 *
 * @author Gr&eacute;gory Mantelet (CDS;ARI)
 * @version 2.0 (09/2019)
 * @version 2.0 (11/2019)
 */
public class DBChecker implements QueryChecker {

@@ -464,15 +464,6 @@ public class DBChecker implements QueryChecker {

			// Update the context:
			context.cteTables.add(adqlTable.getDBLink());

			// Check the number of columns:
			if (withItem.getColumnLabels() != null) {
				DBColumn[] columns = withItem.getResultingColumns();
				if (withItem.getColumnLabels().size() > columns.length)
					errors.addException(new ParseException("The WITH query \"" + withItem.getLabel() + "\" specifies MORE columns (" + withItem.getColumnLabels().size() + ") than available (" + columns.length + ")!", withItem.getPosition()));
				else if (withItem.getColumnLabels().size() < columns.length)
					errors.addException(new ParseException("The WITH query \"" + withItem.getLabel() + "\" specifies LESS columns (" + withItem.getColumnLabels().size() + ") than available (" + columns.length + ")!", withItem.getPosition()));
			}
		}

		// Check the existence of all tables in the FROM clause:
+2 −2
Original line number Diff line number Diff line
@@ -208,8 +208,8 @@ public class ADQLQueryFactory {
	}

	/** @since 2.0 */
	public WithItem createWithItem(final IdentifierItem queryLabel, final ADQLQuery query, final Collection<ADQLColumn> colLabels) throws Exception {
		WithItem item = new WithItem(queryLabel.identifier, query, colLabels);
	public WithItem createWithItem(final IdentifierItem queryLabel, final ADQLQuery query) throws Exception {
		WithItem item = new WithItem(queryLabel.identifier, query);
		item.setLabelCaseSensitive(queryLabel.caseSensitivity);
		return item;
	}
+9 −11
Original line number Diff line number Diff line
@@ -14,7 +14,7 @@
 * 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 2019 - UDS/Centre de Données astronomiques de Strasbourg (CDS)
 * Copyright 2020 - UDS/Centre de Données astronomiques de Strasbourg (CDS)
 */

/*
@@ -31,7 +31,7 @@
* ParseException is thrown.
*
* Author:  Gr&eacute;gory Mantelet (CDS)
* Version: 2.0 (11/2019)
* Version: 2.0 (03/2020)
*/

							/* ########### */
@@ -68,7 +68,7 @@ package adql.parser.grammar;
 * 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 2019 - UDS/Centre de Données astronomiques de Strasbourg (CDS)
 * Copyright 2020 - UDS/Centre de Données astronomiques de Strasbourg (CDS)
 */

import java.util.Vector;
@@ -107,7 +107,7 @@ import adql.query.operand.function.geometry.GeometryFunction.GeometryValue;
 * @see ADQLParser
 *
 * @author Gr&eacute;gory Mantelet (CDS)
 * @version 2.0 (11/2019)
 * @version 2.0 (03/2020)
 * @since 2.0
 */
public class ADQLGrammar201 extends ADQLGrammarBase {
@@ -476,22 +476,20 @@ ADQLQuery SubQueryExpression(): {ADQLQuery q = null; Token start, end;} {
	}
}

ClauseADQL<WithItem> With(): { ClauseADQL<WithItem> withClause = query.getWith(); WithItem withItem; Token start,end; IdentifierItem id, colId; ArrayList<ADQLColumn> colLabels = new ArrayList<ADQLColumn>(10); ADQLQuery query; } {
ClauseADQL<WithItem> With(): { ClauseADQL<WithItem> withClause = query.getWith(); WithItem withItem; Token start,end; IdentifierItem id, colId; ADQLQuery query; } {
	try {
		start=<WITH> id=Identifier() [<LEFT_PAR> colId=Identifier() { colLabels.add(queryFactory.createColumn(colId)); } (<COMMA> colId=Identifier() { colLabels.add(queryFactory.createColumn(colId)); })* <RIGHT_PAR>] <AS> <LEFT_PAR> query=QueryExpression() end=<RIGHT_PAR>
		start=<WITH> id=Identifier() <AS> <LEFT_PAR> query=QueryExpression() end=<RIGHT_PAR>
		{
			withItem = queryFactory.createWithItem(id, query, colLabels);
			withItem = queryFactory.createWithItem(id, query);
			withItem.setPosition(new TextPosition(id.position, new TextPosition(end)));
			withClause.add(withItem);
			colLabels.clear();
		}
		(
			<COMMA> id=Identifier() [<LEFT_PAR> colId=Identifier() { colLabels.add(queryFactory.createColumn(colId)); } (<COMMA> colId=Identifier() { colLabels.add(queryFactory.createColumn(colId)); })* <RIGHT_PAR>] <AS> <LEFT_PAR> query=QueryExpression() end=<RIGHT_PAR>
			<COMMA> id=Identifier() <AS> <LEFT_PAR> query=QueryExpression() end=<RIGHT_PAR>
			{
				withItem = queryFactory.createWithItem(id, query, colLabels);
				withItem = queryFactory.createWithItem(id, query);
				withItem.setPosition(new TextPosition(id.position, new TextPosition(end)));
				withClause.add(withItem);
				colLabels.clear();
			}
		)*
		{
+4 −1
Original line number Diff line number Diff line
@@ -486,7 +486,10 @@ public class ADQLQuery implements ADQLObject {
					if (operand instanceof ADQLColumn && ((ADQLColumn)operand).getDBLink() != null) {
						DBColumn formerCol = ((ADQLColumn)operand).getDBLink();
						// keep the same ADQL and DB name ; just change the table:
						col = formerCol.copy(formerCol.getDBName(), (formerCol.isCaseSensitive() ? DBIdentifier.denormalize(formerCol.getADQLName(), true) : formerCol.getADQLName().toLowerCase()), formerCol.getTable());
						if (formerCol.isCaseSensitive())
							col = formerCol.copy(formerCol.getADQLName(), DBIdentifier.denormalize(formerCol.getADQLName(), true), formerCol.getTable());
						else
							col = formerCol.copy(formerCol.getADQLName().toLowerCase(), formerCol.getADQLName().toLowerCase(), formerCol.getTable());
					} else
						col = new DefaultDBColumn((item.isCaseSensitive() ? DBIdentifier.denormalize(item.getName(), true) : item.getName().toLowerCase()), null);
				}
+3 −122
Original line number Diff line number Diff line
package adql.query;

/*
 * This file is part of ADQLLibrary.
 *
 * ADQLLibrary is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * ADQLLibrary 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 Lesser General Public License for more details.
 *
 * 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 2019 - UDS/Centre de Données astronomiques de Strasbourg (CDS)
 */

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.NoSuchElementException;

import adql.db.DBColumn;
import adql.db.DBIdentifier;
import adql.db.DBTable;
import adql.parser.feature.LanguageFeature;
import adql.query.operand.ADQLColumn;

/**
 * Object representation of the definition of a Common Table Expression (CTE).
@@ -54,12 +31,6 @@ public class WithItem implements ADQLObject {
	/** Flag indicating whether the table name is case sensitive or not. */
	protected boolean caseSensitive = false;

	/** Labels of the resulting columns.
	 * <p><i><b>Note:</b>
	 * 	If NULL or empty, the default output column names must be used.
	 * </i></p> */
	protected List<ADQLColumn> columnLabels = null;

	/** ADQL query providing the CTE's content. */
	protected ADQLQuery query;

@@ -70,29 +41,12 @@ public class WithItem implements ADQLObject {
	protected DBTable dbLink = null;

	/**
	 * Create a WITH item with the minimum mandatory information.
	 * Create a WITH item.
	 *
	 * @param label	Name of the resulting table/CTE.
	 * @param query	ADQL query returning the content of this CTE.
	 */
	public WithItem(final String label, final ADQLQuery query) {
		this(label, query, null);
	}

	/**
	 * Create a WITH item with column labels.
	 *
	 * <p><i><b>Warning:</b>
	 * 	If the given list is NULL or empty, the default output column names will
	 * 	be used. However, if not NULL, the given list should contain as many
	 * 	elements as columns returned by the given query.
	 * </i></p>
	 *
	 * @param label			Name of the resulting table/CTE.
	 * @param query			ADQL query returning the content of this CTE.
	 * @param columnLabels	Labels of the output columns.
	 */
	public WithItem(final String label, final ADQLQuery query, final Collection<ADQLColumn> columnLabels) {
		if (label == null || label.trim().isEmpty())
			throw new NullPointerException("Missing label of the WITH item!");

@@ -101,7 +55,6 @@ public class WithItem implements ADQLObject {

		setLabel(label);
		this.query = query;
		this.columnLabels = (columnLabels == null || columnLabels.isEmpty()) ? null : new ArrayList<>(columnLabels);

	}

@@ -114,11 +67,6 @@ public class WithItem implements ADQLObject {
		label = toCopy.label;
		query = toCopy.query;
		position = toCopy.position;
		if (columnLabels != null) {
			columnLabels = new ArrayList<>(toCopy.columnLabels.size());
			for(ADQLColumn colLabel : toCopy.columnLabels)
				columnLabels.add(colLabel);
		}
	}

	@Override
@@ -184,27 +132,6 @@ public class WithItem implements ADQLObject {
		this.caseSensitive = caseSensitive;
	}

	/**
	 * Get the specified labels of the output columns of this CTE.
	 *
	 * @return	CTE's columns labels,
	 *        	or NULL if none is specified.
	 */
	public final List<ADQLColumn> getColumnLabels() {
		return columnLabels;
	}

	/**
	 * Specify the tables of all the output columns.
	 *
	 * @param newColumnLabels	New labels of the CTE's output columns,
	 *                       	or NULL (or an empty list) to use the default
	 *                       	column names instead.
	 */
	public final void setColumnLabels(final Collection<ADQLColumn> newColumnLabels) {
		columnLabels = (newColumnLabels == null || newColumnLabels.isEmpty()) ? null : new ArrayList<>(newColumnLabels);
	}

	/**
	 * Get the query corresponding to this CTE.
	 *
@@ -292,62 +219,16 @@ public class WithItem implements ADQLObject {

	@Override
	public String toADQL() {
		// Serialize the list of output columns:
		StringBuffer bufOutColumns = new StringBuffer();
		if (columnLabels != null && !columnLabels.isEmpty()) {
			for(ADQLColumn col : columnLabels) {
				bufOutColumns.append(bufOutColumns.length() == 0 ? '(' : ',');
				bufOutColumns.append(DBIdentifier.denormalize(col.getColumnName(), col.isCaseSensitive(IdentifierField.COLUMN)));
			}
			bufOutColumns.append(')');
		}
		// And now serialize the whole WithItem:
		return DBIdentifier.denormalize(label, caseSensitive) + bufOutColumns.toString() + " AS (\n" + query.toADQL() + "\n)";
		return DBIdentifier.denormalize(label, caseSensitive) + " AS (\n" + query.toADQL() + "\n)";
	}

	/**
	 * Get the description of all output columns.
	 *
	 * <p><i><b>Note 1:</b>
	 * 	All resulting columns are returned, even if no column's label is
	 * 	provided.
	 * </i></p>
	 *
	 * <p><i><b>Note 2:</b>
	 * 	List generated on the fly!
	 * </i></p>
	 *
	 * @return	List and description of all output columns.
	 */
	public DBColumn[] getResultingColumns() {
		// Fetch all resulting columns from the query:
		DBColumn[] dbColumns = query.getResultingColumns();

		// Force the writing of the column names:
		boolean caseSensitive;
		String newColLabel;
		for(int i = 0; i < dbColumns.length; i++) {
			// fetch the default column name and case sensitivity:
			caseSensitive = dbColumns[i].isCaseSensitive();
			newColLabel = dbColumns[i].getADQLName();

			// if an explicit label is given, use it instead:
			if (columnLabels != null && i < columnLabels.size()) {
				caseSensitive = columnLabels.get(i).isCaseSensitive(IdentifierField.COLUMN);
				newColLabel = columnLabels.get(i).getColumnName();
			}

			// reformat the column label in function of its case sensitivity:
			if (caseSensitive)
				newColLabel = DBIdentifier.denormalize(newColLabel, true);
			else
				newColLabel = newColLabel.toLowerCase();

			// finally, copy the original column with this new name:
			dbColumns[i] = dbColumns[i].copy(newColLabel, newColLabel, dbColumns[i].getTable());
		}

		return dbColumns;
		return query.getResultingColumns();
	}

}
Loading