Skip to content

Commit

Permalink
[ADQL] Fix escaping of double quotes in delimited identifiers.
Browse files Browse the repository at this point in the history
A delimited identifier is any sequence of characters between a pair of
double quotes. For instance: "123 I am a delimited identifier!".

It is of course possible to have double quotes inside this kind of identifier,
but they have to be doubled in order to not be mistaken with the end of the
identifier. For instance: "Cool ""identifier""".

However, this escape option was not taken into account by the ADQL library,
though the same mechanism was already in place for string contants.
  • Loading branch information
gmantele committed Nov 10, 2017
1 parent 6ad03a8 commit 239c717
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 31 deletions.
66 changes: 35 additions & 31 deletions src/adql/parser/IdentifierItems.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,63 +2,67 @@

/*
* 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 - UDS/Centre de Données astronomiques de Strasbourg (CDS)
*
* Copyright 2012-2017 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
* Astronomisches Rechen Institut (ARI)
*/

import adql.query.IdentifierField;
import adql.query.TextPosition;

/**
* <p><b><u>Important:</u> This class is designed to be filled ONLY by {@link ADQLParser} !</b></p>
*
* <b><u>Important:</u> This class is designed to be filled ONLY by
* {@link ADQLParser}!</b>
*
* <p>This class is an array of maximum 4 {@link IdentifierItem}.</p>
* <p>
* The goal is to represent complex ADQL identifiers (column, table, ...)
* which may be composed of more than only one identifier.
* </p>
* <p>
* For instance, a table can be referenced either by only its name or by the name of its schema and its name.
* So, in this last case there are 2 identifiers.
* For instance, a table can be referenced either by only its name or by the
* name of its schema and its name. So, in this last case there are 2
* identifiers.
* </p>
* <p>
* It is possible to get one by one each identifier item (by using the getters),
* or the concatenation of all (thanks to {@link #join(String)}).
* It is possible to get one by one each identifier item (by using the
* getters), or the concatenation of all (thanks to {@link #join(String)}).
* </p>
*
* @author Gr&eacute;gory Mantelet (CDS)
* @version 01/2012
*
* see IdentifierItem
*
* @author Gr&eacute;gory Mantelet (CDS;ARI)
* @version 1.4 (11/2017)
*
* @see IdentifierItem
*/
public class IdentifierItems {

/**
* Represent any ADQL identifier (column name, table name or table/column alias).
*
* @author Gr&eacute;gory Mantelet (CDS)
* @version 01/2012
* Represent any ADQL identifier (column name, table name or table/column
* alias).
*
* @author Gr&eacute;gory Mantelet (CDS;ARI)
* @version 1.4 (11/2017)
*/
public static class IdentifierItem {
public String identifier = null;
public boolean caseSensitivity = false;
public TextPosition position = null;

public IdentifierItem(final Token token, final boolean caseSensitive){
identifier = token.image;
identifier = token.image.replaceAll("\"\"", "\"");
caseSensitivity = caseSensitive;
position = new TextPosition(token);
}
Expand All @@ -81,7 +85,7 @@ public String toString(){

/**
* Builds an IdentifierItems by specifying it is a table or a column identifier.
*
*
* @param tableIdentifier <i>true</i> if this IdentifierItems is a table identifier, <i>false</i> otherwise.
*/
public IdentifierItems(final boolean tableIdentifier){
Expand All @@ -90,9 +94,9 @@ public IdentifierItems(final boolean tableIdentifier){

/**
* <p>Apppends a simple identifier, that's to say an additional field (catalog, schema, table, column).</p>
*
*
* <p><i><u>Note:</u> This function has no effect if there are already 4 identifiers.</i></p>
*
*
* @param item Additional item (may be null).
*/
public void append(final IdentifierItem item){
Expand All @@ -103,7 +107,7 @@ public void append(final IdentifierItem item){

/**
* Gets the number of fields/identifiers stored in this {@link IdentifierItems}.
*
*
* @return The number of identifiers.
*/
public int size(){
Expand All @@ -112,9 +116,9 @@ public int size(){

/**
* Gets the whole ind-th identifier/field.
*
*
* @param ind Index of the identifier/field to get.
*
*
* @return The wanted identifier/field.
*/
public IdentifierItem get(final int ind){
Expand All @@ -123,9 +127,9 @@ public IdentifierItem get(final int ind){

/**
* Gets the value of the ind-th identifier/field.
*
*
* @param ind Index of the identifier/field to get.
*
*
* @return The value of the wanted identifier/field.
*/
public String getIdentifier(final int ind){
Expand Down Expand Up @@ -212,9 +216,9 @@ public boolean getColumnCaseSensitivity(){

/**
* Joins all identifiers with the given delimiter.
*
*
* @param delim The string which must separate the identifiers (if <i>null</i>, the delimiter will be an empty string).
*
*
* @return The joint complex identifier.
*/
public String join(String delim){
Expand Down
34 changes: 34 additions & 0 deletions test/adql/parser/TestIdentifierItem.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package adql.parser;

import static adql.parser.ADQLParserConstants.DELIMITED_IDENTIFIER;
import static adql.parser.ADQLParserConstants.REGULAR_IDENTIFIER;
import static org.junit.Assert.assertEquals;

import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import adql.parser.IdentifierItems.IdentifierItem;

public class TestIdentifierItem {

@BeforeClass
public static void setUpBeforeClass() throws Exception{}

@Before
public void setUp() throws Exception{}

@Test
public void testIdentifierItem(){
/* A regular identifier (with no special characters) should be returned
* as provided: */
IdentifierItem identifier = new IdentifierItem(new Token(REGULAR_IDENTIFIER, "m50"), false);
assertEquals("m50", identifier.toString());

/* Ensure doubled double quotes are escaped
* (i.e. considered as a single double quote): */
identifier = new IdentifierItem(new Token(DELIMITED_IDENTIFIER, "m50\"\""), true);
assertEquals("m50\"", identifier.toString());
}

}

0 comments on commit 239c717

Please sign in to comment.