package adql.parser; /* * 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 2012-2017 - UDS/Centre de DonnĂ©es astronomiques de Strasbourg (CDS), * Astronomisches Rechen Institut (ARI) */ import java.util.Collection; import adql.db.FunctionDef; import adql.parser.IdentifierItems.IdentifierItem; import adql.query.ADQLOrder; import adql.query.ADQLQuery; import adql.query.ClauseConstraints; import adql.query.ColumnReference; import adql.query.IdentifierField; import adql.query.SelectItem; import adql.query.TextPosition; import adql.query.constraint.ADQLConstraint; import adql.query.constraint.Between; import adql.query.constraint.Comparison; import adql.query.constraint.ComparisonOperator; import adql.query.constraint.ConstraintsGroup; import adql.query.constraint.Exists; import adql.query.constraint.In; import adql.query.constraint.IsNull; import adql.query.constraint.NotConstraint; import adql.query.from.ADQLJoin; import adql.query.from.ADQLTable; import adql.query.from.CrossJoin; import adql.query.from.FromContent; import adql.query.from.InnerJoin; import adql.query.from.OuterJoin; import adql.query.from.OuterJoin.OuterType; import adql.query.operand.ADQLColumn; import adql.query.operand.ADQLOperand; import adql.query.operand.Concatenation; import adql.query.operand.NegativeOperand; import adql.query.operand.NumericConstant; import adql.query.operand.Operation; import adql.query.operand.OperationType; import adql.query.operand.StringConstant; import adql.query.operand.WrappedOperand; import adql.query.operand.function.DefaultUDF; import adql.query.operand.function.MathFunction; import adql.query.operand.function.MathFunctionType; import adql.query.operand.function.SQLFunction; import adql.query.operand.function.SQLFunctionType; import adql.query.operand.function.UserDefinedFunction; import adql.query.operand.function.geometry.AreaFunction; import adql.query.operand.function.geometry.BoxFunction; import adql.query.operand.function.geometry.CentroidFunction; import adql.query.operand.function.geometry.CircleFunction; import adql.query.operand.function.geometry.ContainsFunction; import adql.query.operand.function.geometry.DistanceFunction; import adql.query.operand.function.geometry.ExtractCoord; import adql.query.operand.function.geometry.ExtractCoordSys; import adql.query.operand.function.geometry.GeometryFunction; import adql.query.operand.function.geometry.GeometryFunction.GeometryValue; import adql.query.operand.function.geometry.IntersectsFunction; import adql.query.operand.function.geometry.PointFunction; import adql.query.operand.function.geometry.PolygonFunction; import adql.query.operand.function.geometry.RegionFunction; /** * <p>This class lets the {@link ADQLParser} to build an object representation of an ADQL query.</p> * * <p>To customize the object representation you merely have to extends the appropriate functions of this class.</p> * * @author Grégory Mantelet (CDS;ARI) * @version 1.4 (04/2017) * * @see ADQLParser */ public class ADQLQueryFactory { /** * Type of table JOIN. * * @author Grégory Mantelet (CDS) * @version 1.0 (08/2011) */ public static enum JoinType{ CROSS, INNER, OUTER_LEFT, OUTER_RIGHT, OUTER_FULL; } /** * Create a query factory. */ public ADQLQueryFactory(){ ; } public ADQLQuery createQuery() throws Exception{ return new ADQLQuery(); } public ADQLTable createTable(final IdentifierItems idItems, final IdentifierItem alias) throws Exception{ ADQLTable t = new ADQLTable(idItems.getCatalog(), idItems.getSchema(), idItems.getTable()); // Set the table alias: if (alias != null) t.setAlias(alias.identifier); // Set the case sensitivity on the table name parts: byte caseSensitivity = idItems.getCaseSensitivity(); if (alias != null) caseSensitivity = IdentifierField.ALIAS.setCaseSensitive(caseSensitivity, alias.caseSensitivity); t.setCaseSensitive(caseSensitivity); return t; } public ADQLTable createTable(ADQLQuery query, IdentifierItem alias) throws Exception{ ADQLTable t = new ADQLTable(query); if (alias != null){ // Set the table alias: t.setAlias(alias.identifier); // Set the case sensitivity: t.setCaseSensitive(IdentifierField.ALIAS, alias.caseSensitivity); } return t; } public ADQLJoin createJoin(JoinType type, FromContent leftTable, FromContent rightTable) throws Exception{ switch(type){ case CROSS: return new CrossJoin(leftTable, rightTable); case INNER: return new InnerJoin(leftTable, rightTable); case OUTER_LEFT: return new OuterJoin(leftTable, rightTable, OuterType.LEFT); case OUTER_RIGHT: return new OuterJoin(leftTable, rightTable, OuterType.RIGHT); case OUTER_FULL: return new OuterJoin(leftTable, rightTable, OuterType.FULL); default: throw new Exception("Unknown join type: " + type); } } public ADQLJoin createJoin(JoinType type, FromContent leftTable, FromContent rightTable, ClauseConstraints condition) throws Exception{ switch(type){ case CROSS: throw new Exception("A cross join must have no condition (that's to say: no part ON) !"); default: ADQLJoin join = createJoin(type, leftTable, rightTable); join.setJoinCondition(condition); return join; } } public ADQLJoin createJoin(JoinType type, FromContent leftTable, FromContent rightTable, Collection<ADQLColumn> lstColumns) throws Exception{ switch(type){ case CROSS: throw new Exception("A cross join must have no columns list (that's to say: no part USING) !"); default: ADQLJoin join = createJoin(type, leftTable, rightTable); join.setJoinedColumns(lstColumns); return join; } } public SelectItem createSelectItem(ADQLOperand operand, String alias) throws Exception{ return new SelectItem(operand, alias); } public ADQLColumn createColumn(final IdentifierItems idItems) throws Exception{ ADQLColumn col = new ADQLColumn(idItems.getCatalog(), idItems.getSchema(), idItems.getTable(), idItems.getColumn()); // Set the case sensitivity: col.setCaseSensitive(idItems.getCaseSensitivity()); // Set the position: col.setPosition(idItems.getPosition()); return col; } public ADQLColumn createColumn(final IdentifierItem columnName) throws Exception{ ADQLColumn col = new ADQLColumn(null, null, null, columnName.identifier); // Set the case sensitivity: col.setCaseSensitive(IdentifierField.COLUMN, columnName.caseSensitivity); // Set the position: col.setPosition(columnName.position); return col; } public NumericConstant createNumericConstant(String value) throws Exception{ return new NumericConstant(value, true); } public StringConstant createStringConstant(String value) throws Exception{ return new StringConstant(value); } public Operation createOperation(ADQLOperand leftOp, OperationType op, ADQLOperand rightOp) throws Exception{ return new Operation(leftOp, op, rightOp); } public NegativeOperand createNegativeOperand(ADQLOperand opToNegativate) throws Exception{ return new NegativeOperand(opToNegativate); } public Concatenation createConcatenation() throws Exception{ return new Concatenation(); } public WrappedOperand createWrappedOperand(ADQLOperand opToWrap) throws Exception{ return new WrappedOperand(opToWrap); } public ConstraintsGroup createGroupOfConstraints() throws Exception{ return new ConstraintsGroup(); } public NotConstraint createNot(ADQLConstraint constraintToNot) throws Exception{ return new NotConstraint(constraintToNot); } public Comparison createComparison(ADQLOperand leftOp, ComparisonOperator op, ADQLOperand rightOp) throws Exception{ return new Comparison(leftOp, op, rightOp); } public Between createBetween(boolean not, ADQLOperand value, ADQLOperand min, ADQLOperand max) throws Exception{ return new Between(value, min, max, not); } public IsNull createIsNull(boolean notNull, ADQLColumn column) throws Exception{ return new IsNull(column, notNull); } public Exists createExists(ADQLQuery query) throws Exception{ return new Exists(query); } public In createIn(ADQLOperand leftOp, ADQLQuery query, boolean notIn) throws Exception{ return new In(leftOp, query, notIn); } public In createIn(ADQLOperand leftOp, ADQLOperand[] valuesList, boolean notIn) throws Exception{ return new In(leftOp, valuesList, notIn); } public SQLFunction createSQLFunction(SQLFunctionType type, ADQLOperand op, boolean distinctValues) throws Exception{ return new SQLFunction(type, op, distinctValues); } public MathFunction createMathFunction(MathFunctionType type, ADQLOperand param1, ADQLOperand param2) throws Exception{ return new MathFunction(type, param1, param2); } /** * <p>Creates the user defined functions called as the given name and with the given parameters.</p> * * <p> * By default, this function returns a {@link DefaultUDF} instance. It is generic enough to cover every kind of functions. * But you can of course override this function in order to return your own instance of {@link UserDefinedFunction}. * In this case, you may not forget to call the super function (super.createUserDefinedFunction(name, params)) so that * all other unknown functions are still returned as {@link DefaultUDF} instances. * </p> * * <p><i><b>IMPORTANT:</b> * The tests done to check whether a user defined function is allowed/managed in this implementation, is done later by the parser. * Only declared UDF will pass the test of the parser. For that, you should give it a list of allowed UDFs (each UDF will be then * represented by a {@link FunctionDef} object). * </i></p> * * @param name Name of the user defined function to create. * @param params Parameters of the user defined function to create. * * @return The corresponding user defined function (by default an instance of {@link DefaultUDF}). * * @throws Exception If there is a problem while creating the function. */ public UserDefinedFunction createUserDefinedFunction(String name, ADQLOperand[] params) throws Exception{ return new DefaultUDF(name, params); } public DistanceFunction createDistance(PointFunction point1, PointFunction point2) throws Exception{ return new DistanceFunction(new GeometryValue<PointFunction>(point1), new GeometryValue<PointFunction>(point2)); } public DistanceFunction createDistance(GeometryValue<PointFunction> point1, GeometryValue<PointFunction> point2) throws Exception{ return new DistanceFunction(point1, point2); } public PointFunction createPoint(ADQLOperand coordSys, ADQLOperand coords, ADQLOperand coords2) throws Exception{ return new PointFunction(coordSys, coords, coords2); } public BoxFunction createBox(ADQLOperand coordinateSystem, ADQLOperand firstCoord, ADQLOperand secondCoord, ADQLOperand boxWidth, ADQLOperand boxHeight) throws Exception{ return new BoxFunction(coordinateSystem, firstCoord, secondCoord, boxWidth, boxHeight); } public CircleFunction createCircle(ADQLOperand coordSys, ADQLOperand coord1, ADQLOperand coord2, ADQLOperand radius) throws Exception{ return new CircleFunction(coordSys, coord1, coord2, radius); } public CentroidFunction createCentroid(GeometryFunction param) throws Exception{ return new CentroidFunction(new GeometryValue<GeometryFunction>(param)); } public CentroidFunction createCentroid(GeometryValue<GeometryFunction> param) throws Exception{ return new CentroidFunction(param); } public RegionFunction createRegion(ADQLOperand param) throws Exception{ return new RegionFunction(param); } public PolygonFunction createPolygon(ADQLOperand coordSys, Collection<? extends ADQLOperand> coords) throws Exception{ return new PolygonFunction(coordSys, coords); } public AreaFunction createArea(GeometryFunction param) throws Exception{ return new AreaFunction(new GeometryValue<GeometryFunction>(param)); } public AreaFunction createArea(GeometryValue<GeometryFunction> param) throws Exception{ return new AreaFunction(param); } public ExtractCoord createCoord1(PointFunction point) throws Exception{ return new ExtractCoord(1, new GeometryValue<PointFunction>(point)); } public ExtractCoord createCoord1(ADQLColumn point) throws Exception{ return new ExtractCoord(1, new GeometryValue<PointFunction>(point)); } public ExtractCoord createCoord2(PointFunction point) throws Exception{ return new ExtractCoord(2, new GeometryValue<PointFunction>(point)); } public ExtractCoord createCoord2(ADQLColumn point) throws Exception{ return new ExtractCoord(2, new GeometryValue<PointFunction>(point)); } public ExtractCoordSys createExtractCoordSys(GeometryFunction param) throws Exception{ return new ExtractCoordSys(new GeometryValue<GeometryFunction>(param)); } public ExtractCoordSys createExtractCoordSys(ADQLColumn param) throws Exception{ return new ExtractCoordSys(new GeometryValue<GeometryFunction>(param)); } public ExtractCoordSys createExtractCoordSys(GeometryValue<GeometryFunction> param) throws Exception{ return new ExtractCoordSys(new GeometryValue<GeometryFunction>(param)); } public ContainsFunction createContains(GeometryFunction left, GeometryFunction right) throws Exception{ return new ContainsFunction(new GeometryValue<GeometryFunction>(left), new GeometryValue<GeometryFunction>(right)); } public ContainsFunction createContains(GeometryValue<GeometryFunction> left, GeometryValue<GeometryFunction> right) throws Exception{ return new ContainsFunction(left, right); } public IntersectsFunction createIntersects(GeometryFunction left, GeometryFunction right) throws Exception{ return new IntersectsFunction(new GeometryValue<GeometryFunction>(left), new GeometryValue<GeometryFunction>(right)); } public IntersectsFunction createIntersects(GeometryValue<GeometryFunction> left, GeometryValue<GeometryFunction> right) throws Exception{ return new IntersectsFunction(left, right); } /** * Replace {@link #createOrder(int, boolean, TextPosition)}. * @since 1.4 */ public ADQLOrder createOrder(final int ind, final boolean desc) throws Exception{ return new ADQLOrder(ind, desc); } /** * @deprecated since 1.4 ; Replaced by {@link #createOrder(int, boolean)} */ @Deprecated public ADQLOrder createOrder(final int ind, final boolean desc, final TextPosition position) throws Exception{ ADQLOrder order = new ADQLOrder(ind, desc); if (order != null) order.setPosition(position); return order; } public ADQLOrder createOrder(final IdentifierItem colName, final boolean desc) throws Exception{ ADQLOrder order = new ADQLOrder(colName.identifier, desc); if (order != null) order.setCaseSensitive(colName.caseSensitivity); return order; } /** * @deprecated since 1.4 ; Former version's mistake: an ORDER BY item is either a regular/delimited column name or an integer, not a qualified column name ; Replaced by {@link #createOrder(adql.parser.IdentifierItems.IdentifierItem, boolean)} ; This function is no longer used by ADQLParser. */ @Deprecated public ADQLOrder createOrder(final IdentifierItems idItems, final boolean desc) throws Exception{ ADQLOrder order = new ADQLOrder(idItems.join("."), desc); if (order != null) order.setCaseSensitive(idItems.getColumnCaseSensitivity()); return order; } public ColumnReference createColRef(final IdentifierItem idItem) throws Exception{ ColumnReference colRef = new ColumnReference(idItem.identifier); if (colRef != null){ colRef.setPosition(idItem.position); colRef.setCaseSensitive(idItem.caseSensitivity); } return colRef; } public ColumnReference createColRef(final IdentifierItems idItems) throws Exception{ ColumnReference colRef = new ColumnReference(idItems.join(".")); if (colRef != null){ colRef.setPosition(idItems.getPosition()); colRef.setCaseSensitive(idItems.getColumnCaseSensitivity()); } return colRef; } public ColumnReference createColRef(final int index, final TextPosition position) throws Exception{ ColumnReference colRef = new ColumnReference(index); if (colRef != null) colRef.setPosition(position); return colRef; } }