org.finos.legend.engine.postgres.QueryStringSplitter Maven / Gradle / Ivy
/*
* Licensed to Crate.io GmbH ("Crate") under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership. Crate licenses
* this file to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may
* obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* However, if you have executed another commercial license agreement
* with Crate these terms will supersede the license and you may use the
* software solely pursuant to the terms of the relevant commercial agreement.
*/
package org.finos.legend.engine.postgres;
import java.util.ArrayList;
import java.util.List;
import static org.finos.legend.engine.postgres.QueryStringSplitter.CommentType.LINE;
import static org.finos.legend.engine.postgres.QueryStringSplitter.CommentType.MULTI_LINE;
import static org.finos.legend.engine.postgres.QueryStringSplitter.CommentType.NO;
import static org.finos.legend.engine.postgres.QueryStringSplitter.QuoteType.DOUBLE;
import static org.finos.legend.engine.postgres.QueryStringSplitter.QuoteType.NONE;
import static org.finos.legend.engine.postgres.QueryStringSplitter.QuoteType.SINGLE;
/**
* Splits a query string by semicolon into multiple statements.
*/
class QueryStringSplitter
{
enum CommentType
{
NO,
LINE,
MULTI_LINE
}
enum QuoteType
{
NONE,
SINGLE,
DOUBLE
}
public static List splitQuery(String query)
{
final List queries = new ArrayList<>(2);
CommentType commentType = NO;
QuoteType quoteType = QuoteType.NONE;
boolean restoreSingleQuoteIfEscaped = false;
char[] chars = query.toCharArray();
boolean isCurrentlyEmpty = true;
int offset = 0;
char lastChar = ' ';
for (int i = 0; i < chars.length; i++)
{
char aChar = chars[i];
if (isCurrentlyEmpty && !Character.isWhitespace(aChar))
{
isCurrentlyEmpty = false;
}
switch (aChar)
{
case '\'':
if (commentType == NO && quoteType != DOUBLE)
{
if (lastChar == '\'')
{
// Escaping of ' via '', e.g.: 'hello ''Joe''!'
// When we set single quotes state to NONE,
// but we find out this was due to an escaped single quote (''),
// we restore the previous single quote state here.
quoteType = restoreSingleQuoteIfEscaped ? SINGLE : NONE;
restoreSingleQuoteIfEscaped = false;
}
else
{
restoreSingleQuoteIfEscaped = quoteType == SINGLE;
quoteType = quoteType == SINGLE ? NONE : SINGLE;
}
}
break;
case '"':
if (commentType == NO && quoteType != SINGLE)
{
quoteType = quoteType == DOUBLE ? NONE : DOUBLE;
}
break;
case '-':
if (commentType == NO && quoteType == NONE && lastChar == '-')
{
commentType = LINE;
}
break;
case '*':
if (commentType == NO && quoteType == NONE && lastChar == '/')
{
commentType = MULTI_LINE;
}
break;
case '/':
if (commentType == MULTI_LINE && lastChar == '*')
{
commentType = NO;
offset = i + 1;
}
break;
case '\n':
if (commentType == LINE)
{
commentType = NO;
offset = i + 1;
}
break;
case ';':
if (commentType == NO && quoteType == NONE)
{
queries.add(new String(chars, offset, i - offset + 1));
offset = i + 1;
isCurrentlyEmpty = true;
}
break;
default:
}
lastChar = aChar;
}
// statement might not be terminated by semicolon
if (!isCurrentlyEmpty && offset < chars.length && commentType == NO)
{
queries.add(new String(chars, offset, chars.length - offset));
}
if (queries.isEmpty())
{
queries.add("");
}
return queries;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy