Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support of timestamp/date/time using curly brackets #297

Merged
merged 8 commits into from
Jul 21, 2023
11 changes: 10 additions & 1 deletion docs/user/dql/expressions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ A literal is a symbol that represents a value. The most common literal values in
1. Numeric literals: specify numeric values such as integer and floating-point numbers.
2. String literals: specify a string enclosed by single or double quotes.
3. Boolean literals: ``true`` or ``false``.
4. Date and Time literals: DATE 'YYYY-MM-DD' represent the date, TIME 'hh:mm:ss' represent the time, TIMESTAMP 'YYYY-MM-DD hh:mm:ss' represent the timestamp.
4. Date and Time literals: DATE 'YYYY-MM-DD' represent the date, TIME 'hh:mm:ss' represent the time, TIMESTAMP 'YYYY-MM-DD hh:mm:ss' represent the timestamp. You can also surround the literals with curly brackets, if you do, you can replace date with d, time with t, and timestamp with ts

Examples
--------
Expand All @@ -49,6 +49,15 @@ Here is an example for different type of literals::
| Hello | Hello | It"s | It's | It's | "Its" | It's | It\'s | \I\t\s |
+-----------+-----------+-----------+-----------+----------+-----------+-----------+-------------+------------+


os> SELECT {DATE '2020-07-07'}, {D '2020-07-07'}, {TIME '01:01:01'}, {T '01:01:01'}, {TIMESTAMP '2020-07-07 01:01:01'}, {TS '2020-07-07 01:01:01'}
fetched rows / total rows = 1/1
+-----------------------+--------------------+---------------------+------------------+-------------------------------------+------------------------------+
| {DATE '2020-07-07'} | {D '2020-07-07'} | {TIME '01:01:01'} | {T '01:01:01'} | {TIMESTAMP '2020-07-07 01:01:01'} | {TS '2020-07-07 01:01:01'} |
|-----------------------+--------------------+---------------------+------------------+-------------------------------------+------------------------------|
| 2020-07-07 | 2020-07-07 | 01:01:01 | 01:01:01 | 2020-07-07 01:01:01 | 2020-07-07 01:01:01 |
+-----------------------+--------------------+---------------------+------------------+-------------------------------------+------------------------------+

Limitations
-----------

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1288,4 +1288,103 @@ protected JSONObject executeQuery(String query) throws IOException {
Response response = client().performRequest(request);
return new JSONObject(getResponseBody(response));
}

@Test
public void testTimestampBracket() throws IOException {
matthewryanwells marked this conversation as resolved.
Show resolved Hide resolved
JSONObject result = executeQuery("select {timestamp '2020-09-16 17:30:00'}");
verifySchema(result, schema("{timestamp '2020-09-16 17:30:00'}", null, "timestamp"));
verifyDataRows(result, rows("2020-09-16 17:30:00"));

result = executeQuery("select {ts '2020-09-16 17:30:00'}");
verifySchema(result, schema("{ts '2020-09-16 17:30:00'}", null, "timestamp"));
verifyDataRows(result, rows("2020-09-16 17:30:00"));

result = executeQuery("select {timestamp '2020-09-16 17:30:00.123'}");
verifySchema(result, schema("{timestamp '2020-09-16 17:30:00.123'}", null, "timestamp"));
verifyDataRows(result, rows("2020-09-16 17:30:00.123"));

result = executeQuery("select {ts '2020-09-16 17:30:00.123'}");
verifySchema(result, schema("{ts '2020-09-16 17:30:00.123'}", null, "timestamp"));
verifyDataRows(result, rows("2020-09-16 17:30:00.123"));
}

@Test
public void testTimeBracket() throws IOException {
JSONObject result = executeQuery("select {time '17:30:00'}");
matthewryanwells marked this conversation as resolved.
Show resolved Hide resolved
verifySchema(result, schema("{time '17:30:00'}", null, "time"));
verifyDataRows(result, rows("17:30:00"));

result = executeQuery("select {t '17:30:00'}");
verifySchema(result, schema("{t '17:30:00'}", null, "time"));
verifyDataRows(result, rows("17:30:00"));

result = executeQuery("select {time '17:30:00'}");
verifySchema(result, schema("{time '17:30:00'}", null, "time"));
verifyDataRows(result, rows("17:30:00"));

result = executeQuery("select {t '17:30:00'}");
verifySchema(result, schema("{t '17:30:00'}", null, "time"));
verifyDataRows(result, rows("17:30:00"));
}

@Test
public void testDateBracket() throws IOException {
JSONObject result = executeQuery("select {date '2020-09-16'}");
verifySchema(result, schema("{date '2020-09-16'}", null, "date"));
verifyDataRows(result, rows("2020-09-16"));

result = executeQuery("select {d '2020-09-16'}");
verifySchema(result, schema("{d '2020-09-16'}", null, "date"));
verifyDataRows(result, rows("2020-09-16"));
}

private void compareBrackets(String query1, String query2, String datetime) throws IOException {
JSONObject result1 = executeQuery("select " + query1 + " '" + datetime + "'");
JSONObject result2 = executeQuery("select {" + query2 + " '" + datetime + "'}");

verifyDataRows(result1, rows(datetime));
verifyDataRows(result2, rows(datetime));
}

@Test
public void testBracketedEquivalent() throws IOException {
compareBrackets("timestamp", "timestamp", "2020-09-16 17:30:00");
compareBrackets("timestamp", "ts", "2020-09-16 17:30:00");
compareBrackets("timestamp", "timestamp", "2020-09-16 17:30:00.123");
compareBrackets("timestamp", "ts", "2020-09-16 17:30:00.123");
compareBrackets("date", "date", "2020-09-16");
compareBrackets("date", "d", "2020-09-16");
compareBrackets("time", "time", "17:30:00");
compareBrackets("time", "t", "17:30:00");
}

private void queryFails(String query) {
Request request = new Request("POST", QUERY_API_ENDPOINT);
matthewryanwells marked this conversation as resolved.
Show resolved Hide resolved
request.setJsonEntity(String.format(Locale.ROOT, "{\n" + " \"query\": \"%s\"\n" + "}", query));

RequestOptions.Builder restOptionsBuilder = RequestOptions.DEFAULT.toBuilder();
restOptionsBuilder.addHeader("Content-Type", "application/json");
request.setOptions(restOptionsBuilder);

boolean fails = false;

try {
client().performRequest(request);
} catch(Exception ignored) {
fails = true;
}

assertTrue(fails);
matthewryanwells marked this conversation as resolved.
Show resolved Hide resolved
}

@Test
public void testBracketFails() {
queryFails("select {time 'failure'}");
queryFails("select {t 'failure'}");
queryFails("select {date 'failure'}");
queryFails("select {d 'failure'}");
queryFails("select {timestamp 'failure'}");
queryFails("select {ts 'failure'}");

}
}
4 changes: 3 additions & 1 deletion sql/src/main/antlr/OpenSearchSQLParser.g4
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,6 @@ constant
// Doesn't support the following types for now
//| BIT_STRING
//| NOT? nullLiteral=(NULL_LITERAL | NULL_SPEC_LITERAL)
//| LEFT_BRACE dateType=(D | T | TS | DATE | TIME | TIMESTAMP) stringLiteral RIGHT_BRACE
;

decimalLiteral
Expand Down Expand Up @@ -227,14 +226,17 @@ datetimeLiteral

dateLiteral
: DATE date=stringLiteral
| LEFT_BRACE (DATE | D) date=stringLiteral RIGHT_BRACE
;

timeLiteral
: TIME time=stringLiteral
| LEFT_BRACE (TIME | T) time=stringLiteral RIGHT_BRACE
;

timestampLiteral
: TIMESTAMP timestamp=stringLiteral
| LEFT_BRACE (TIMESTAMP | TS) timestamp=stringLiteral RIGHT_BRACE
;

// Actually, these constants are shortcuts to the corresponding functions
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
package org.opensearch.sql.common.antlr;

import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;

import lombok.AccessLevel;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.opensearch.sql.sql.antlr.SQLSyntaxParser;

/**
* A base class for tests for SQL or PPL parser.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package org.opensearch.sql.sql.antlr;

import org.junit.jupiter.api.Test;

public class BracketedTimestampTest extends SQLParserTest {
@Test
void date_shortened_test() {
acceptQuery("SELECT {d '2001-05-07'}");
}

@Test
void date_test() {
acceptQuery("SELECT {date '2001-05-07'}");
}

@Test
void time_shortened_test() {
acceptQuery("SELECT {t '10:11:12'}");
}

@Test
void time_test() {
acceptQuery("SELECT {time '10:11:12'}");
}

@Test
void timestamp_shortened_test() {
acceptQuery("SELECT {ts '2001-05-07 10:11:12'}");
}

@Test
void timestamp_test() {
acceptQuery("SELECT {timestamp '2001-05-07 10:11:12'}");
}
}