8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-22 14:03:03 +01:00

Merge pull request #8358 from FirebirdSQL/work/isql-frontend-parser

Refactor ISQL creating FrontendParser class
This commit is contained in:
Adriano dos Santos Fernandes 2024-12-30 13:54:54 -03:00 committed by GitHub
commit 797781da66
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 2942 additions and 1696 deletions

View File

@ -24,6 +24,7 @@
<ClCompile Include="..\..\..\gen\isql\extract.cpp" />
<ClCompile Include="..\..\..\src\common\fb_exception.cpp" />
<ClCompile Include="..\..\..\src\isql\FrontendLexer.cpp" />
<ClCompile Include="..\..\..\src\isql\FrontendParser.cpp" />
<ClCompile Include="..\..\..\src\isql\InputDevices.cpp" />
<ClCompile Include="..\..\..\gen\isql\isql.cpp" />
<ClCompile Include="..\..\..\src\isql\iutils.cpp" />
@ -40,6 +41,7 @@
<ClInclude Include="..\..\..\src\isql\Extender.h" />
<ClInclude Include="..\..\..\src\isql\extra_proto.h" />
<ClInclude Include="..\..\..\src\isql\FrontendLexer.h" />
<ClInclude Include="..\..\..\src\isql\FrontendParser.h" />
<ClInclude Include="..\..\..\src\isql\InputDevices.h" />
<ClInclude Include="..\..\..\src\isql\isql.h" />
<ClInclude Include="..\..\..\src\isql\isql_proto.h" />

View File

@ -30,6 +30,9 @@
<ClCompile Include="..\..\..\src\isql\FrontendLexer.cpp">
<Filter>ISQL files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\isql\FrontendParser.cpp">
<Filter>ISQL files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\isql\InputDevices.cpp">
<Filter>ISQL files</Filter>
</ClCompile>
@ -73,6 +76,9 @@
<ClInclude Include="..\..\..\src\isql\FrontendLexer.h">
<Filter>Header files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\isql\FrontendParser.h">
<Filter>Header files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\isql\InputDevices.h">
<Filter>Header files</Filter>
</ClInclude>

View File

@ -177,6 +177,7 @@
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\src\isql\tests\FrontendLexerTest.cpp" />
<ClCompile Include="..\..\..\src\isql\tests\FrontendParserTest.cpp" />
<ClCompile Include="..\..\..\src\isql\tests\ISqlTest.cpp" />
</ItemGroup>
<ItemGroup>

View File

@ -10,6 +10,9 @@
<ClCompile Include="..\..\..\src\isql\tests\FrontendLexerTest.cpp">
<Filter>source</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\isql\tests\FrontendParserTest.cpp">
<Filter>source</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\isql\tests\ISqlTest.cpp">
<Filter>source</Filter>
</ClCompile>

42
src/common/StdHelper.h Normal file
View File

@ -0,0 +1,42 @@
/*
* The contents of this file are subject to the Initial
* Developer's Public License Version 1.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.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
*
* Software distributed under the License is distributed AS IS,
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
* See the License for the specific language governing rights
* and limitations under the License.
*
* The Original Code was created by Adriano dos Santos Fernandes
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2024 Adriano dos Santos Fernandes <adrianosf at gmail.com>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*
*/
#ifndef FB_COMMON_STD_HELPER_H
#define FB_COMMON_STD_HELPER_H
namespace Firebird {
// To be used with std::visit
template <typename... Ts>
struct StdVisitOverloads : Ts...
{
using Ts::operator()...;
};
template <typename... Ts>
StdVisitOverloads(Ts...) -> StdVisitOverloads<Ts...>;
} // namespace Firebird
#endif // FB_COMMON_STD_HELPER_H

View File

@ -93,6 +93,30 @@ public:
int compare(const AbstractString& s) const { return compare(s.c_str(), s.length()); }
int compare(const MetaString& m) const { return memcmp(data, m.data, MAX_SQL_IDENTIFIER_SIZE); }
string toQuotedString() const
{
string s;
if (hasData())
{
s.reserve(count + 2);
s.append("\"");
for (const auto c : *this)
{
if (c == '"')
s.append("\"");
s.append(&c, 1);
}
s.append("\"");
}
return s;
}
bool operator==(const char* s) const { return compare(s) == 0; }
bool operator!=(const char* s) const { return compare(s) != 0; }
bool operator==(const AbstractString& s) const { return compare(s) == 0; }

View File

@ -28,9 +28,7 @@
#include <cctype>
static std::string trim(std::string_view str);
static std::string trim(std::string_view str)
std::string FrontendLexer::trim(std::string_view str)
{
auto finish = str.end();
auto start = str.begin();
@ -142,7 +140,7 @@ std::variant<FrontendLexer::SingleStatement, FrontendLexer::IncompleteTokenError
while (pos < end)
{
if (end - pos >= term.length() && std::equal(term.begin(), term.end(), pos))
if (std::size_t(end - pos) >= term.length() && std::equal(term.begin(), term.end(), pos))
{
const auto initialStatement = std::string(buffer.cbegin(), pos);
pos += term.length();
@ -189,22 +187,8 @@ FrontendLexer::Token FrontendLexer::getToken()
switch (toupper(*pos))
{
case '(':
token.type = Token::TYPE_OPEN_PAREN;
token.processedText = *pos++;
break;
case ')':
token.type = Token::TYPE_CLOSE_PAREN;
token.processedText = *pos++;
break;
case ',':
token.type = Token::TYPE_COMMA;
token.processedText = *pos++;
break;
case ';':
case '.':
token.type = Token::TYPE_OTHER;
token.processedText = *pos++;
break;
@ -224,13 +208,83 @@ FrontendLexer::Token FrontendLexer::getToken()
return token;
}
std::optional<FrontendLexer::Token> FrontendLexer::getStringToken()
FrontendLexer::Token FrontendLexer::getNameToken()
{
skipSpacesAndComments();
Token token;
if (pos >= end)
{
token.type = Token::TYPE_EOF;
return token;
}
if (const auto optStringToken = getStringToken(); optStringToken.has_value())
return optStringToken.value();
/*** Revert to strict parsing with schemas support branch.
const auto start = pos;
bool first = true;
while (pos < end)
{
const auto c = *pos++;
if (!((c >= 'A' && c <= 'Z') ||
(c >= 'a' && c <= 'z') ||
c == '{' ||
c == '}' ||
(!first && c >= '0' && c <= '9') ||
(!first && c == '$') ||
(!first && c == '_')))
{
if (!first)
--pos;
break;
}
first = false;
}
token.processedText = token.rawText = std::string(start, pos);
std::transform(token.processedText.begin(), token.processedText.end(),
token.processedText.begin(), toupper);
return token;
***/
const auto start = pos;
switch (toupper(*pos))
{
case ';':
token.type = Token::TYPE_OTHER;
token.processedText = *pos++;
break;
default:
while (pos != end && !fb_utils::isspace(*pos) && *pos != '.')
++pos;
token.processedText = std::string(start, pos);
std::transform(token.processedText.begin(), token.processedText.end(),
token.processedText.begin(), toupper);
break;
}
token.rawText = std::string(start, pos);
return token;
}
std::optional<FrontendLexer::Token> FrontendLexer::getStringToken()
{
if (pos >= end)
return std::nullopt;
Token token;
const auto start = pos;
switch (toupper(*pos))

View File

@ -39,15 +39,18 @@ public:
TYPE_EOF,
TYPE_STRING,
TYPE_META_STRING,
TYPE_OPEN_PAREN,
TYPE_CLOSE_PAREN,
TYPE_COMMA,
TYPE_OTHER
};
Type type = TYPE_OTHER;
std::string rawText;
std::string processedText;
std::string getProcessedString() const
{
return type == FrontendLexer::Token::TYPE_STRING || type == FrontendLexer::Token::TYPE_META_STRING ?
processedText : rawText;
}
};
struct SingleStatement
@ -74,6 +77,7 @@ public:
FrontendLexer& operator=(const FrontendLexer&) = delete;
public:
static std::string trim(std::string_view str);
static std::string stripComments(std::string_view statement);
public:
@ -87,6 +91,11 @@ public:
return pos;
}
void setPos(std::string::const_iterator newPos)
{
pos = newPos;
}
void rewind()
{
deletePos = buffer.begin();
@ -97,7 +106,9 @@ public:
void appendBuffer(std::string_view newBuffer);
void reset();
std::variant<SingleStatement, FrontendLexer::IncompleteTokenError> getSingleStatement(std::string_view term);
Token getToken();
Token getNameToken();
private:
std::optional<Token> getStringToken();

732
src/isql/FrontendParser.cpp Normal file
View File

@ -0,0 +1,732 @@
/*
* The contents of this file are subject to the Initial
* Developer's Public License Version 1.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.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
*
* Software distributed under the License is distributed AS IS,
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
* See the License for the specific language governing rights
* and limitations under the License.
*
* The Original Code was created by Adriano dos Santos Fernandes
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2024 Adriano dos Santos Fernandes <adrianosf at gmail.com>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*
*/
#include "firebird.h"
#include "../isql/FrontendParser.h"
#include <cctype>
FrontendParser::AnyNode FrontendParser::internalParse()
{
static constexpr std::string_view TOKEN_ADD("ADD");
static constexpr std::string_view TOKEN_BLOBDUMP("BLOBDUMP");
static constexpr std::string_view TOKEN_BLOBVIEW("BLOBVIEW");
static constexpr std::string_view TOKEN_CONNECT("CONNECT");
static constexpr std::string_view TOKEN_COPY("COPY");
static constexpr std::string_view TOKEN_CREATE("CREATE");
static constexpr std::string_view TOKEN_DROP("DROP");
static constexpr std::string_view TOKEN_EDIT("EDIT");
static constexpr std::string_view TOKEN_EXIT("EXIT");
static constexpr std::string_view TOKEN_EXPLAIN("EXPLAIN");
static constexpr std::string_view TOKEN_HELP("HELP");
static constexpr std::string_view TOKEN_INPUT("INPUT");
static constexpr std::string_view TOKEN_OUTPUT("OUTPUT");
static constexpr std::string_view TOKEN_QUIT("QUIT");
static constexpr std::string_view TOKEN_SET("SET");
static constexpr std::string_view TOKEN_SHELL("SHELL");
static constexpr std::string_view TOKEN_SHOW("SHOW");
const auto commandToken = lexer.getToken();
if (commandToken.type == Token::TYPE_OTHER)
{
const auto& command = commandToken.processedText;
if (command == TOKEN_ADD)
{
if (const auto tableName = parseName())
{
AddNode node;
node.tableName = std::move(tableName.value());
if (parseEof())
return node;
}
}
else if (command == TOKEN_BLOBDUMP || command == TOKEN_BLOBVIEW)
{
if (const auto blobId = lexer.getToken(); blobId.type != Token::TYPE_EOF)
{
BlobDumpViewNode node;
// Find the high and low values of the blob id
if (blobId.processedText.empty())
return InvalidNode();
sscanf(blobId.processedText.c_str(), "%" xLONGFORMAT":%" xLONGFORMAT,
&node.blobId.gds_quad_high, &node.blobId.gds_quad_low);
if (command == TOKEN_BLOBDUMP)
{
if (const auto file = parseFileName())
{
node.file = std::move(file.value());
if (parseEof())
return node;
}
}
else
{
if (parseEof())
return node;
}
}
}
else if (command == TOKEN_CONNECT)
{
ConnectNode node;
do
{
const auto token = lexer.getToken();
if (token.type == Token::TYPE_EOF)
{
if (node.args.empty())
break;
else
return node;
}
else if (token.type != Token::TYPE_OTHER &&
token.type != Token::TYPE_STRING &&
token.type != Token::TYPE_META_STRING)
{
return InvalidNode();
}
node.args.push_back(std::move(token));
} while(true);
}
else if (command == TOKEN_COPY)
{
CopyNode node;
if (const auto source = parseName())
node.source = std::move(source.value());
else
return InvalidNode();
if (const auto destination = parseName())
node.destination = std::move(destination.value());
else
return InvalidNode();
if (const auto database = parseFileName())
node.database = std::move(database.value());
else
return InvalidNode();
if (parseEof())
return node;
}
else if (command == TOKEN_CREATE)
{
if (const auto createWhat = lexer.getToken();
createWhat.type == Token::TYPE_OTHER &&
(createWhat.processedText == "DATABASE" ||
(options.schemaAsDatabase && createWhat.processedText == "SCHEMA")))
{
CreateDatabaseNode node;
do
{
const auto token = lexer.getToken();
if (token.type == Token::TYPE_EOF)
{
if (node.args.empty())
break;
else
return node;
}
else if (token.type != Token::TYPE_OTHER &&
token.type != Token::TYPE_STRING &&
token.type != Token::TYPE_META_STRING)
{
return InvalidNode();
}
node.args.push_back(std::move(token));
} while(true);
}
}
else if (command == TOKEN_DROP)
{
if (const auto dropWhat = lexer.getToken();
dropWhat.type == Token::TYPE_OTHER &&
(dropWhat.processedText == "DATABASE" ||
(options.schemaAsDatabase && dropWhat.processedText == "SCHEMA")))
{
if (parseEof())
return DropDatabaseNode();
}
}
else if (command == TOKEN_EDIT)
{
EditNode node;
node.file = parseFileName();
if (parseEof())
return node;
}
else if (command == TOKEN_EXIT)
{
if (parseEof())
return ExitNode();
}
else if (command == TOKEN_EXPLAIN)
{
ExplainNode node;
if (const auto query = parseUtilEof())
{
node.query = std::move(query.value());
return node;
}
}
else if (command == TOKEN_HELP || command == "?")
{
HelpNode node;
if (const auto token = lexer.getToken(); token.type == Token::TYPE_EOF)
return node;
else if (token.type == Token::TYPE_OTHER)
{
node.command = token.processedText;
if (parseEof())
return node;
}
}
else if (command.length() >= 2 && TOKEN_INPUT.find(command) == 0)
{
if (const auto file = parseFileName())
{
InputNode node;
node.file = std::move(file.value());
if (parseEof())
return node;
}
}
else if (command.length() >= 3 && TOKEN_OUTPUT.find(command) == 0)
{
OutputNode node;
node.file = parseFileName();
if (parseEof())
return node;
}
else if (command == TOKEN_QUIT)
{
if (parseEof())
return QuitNode();
}
else if (command == TOKEN_SET)
{
if (const auto setNode = parseSet(); !std::holds_alternative<InvalidNode>(setNode))
return setNode;
}
else if (command == TOKEN_SHELL)
{
ShellNode node;
node.command = parseUtilEof();
return node;
}
else if (command == TOKEN_SHOW)
{
if (const auto showNode = parseShow(); !std::holds_alternative<InvalidNode>(showNode))
return showNode;
}
}
return InvalidNode();
}
FrontendParser::AnySetNode FrontendParser::parseSet()
{
static constexpr std::string_view TOKEN_AUTODDL("AUTODDL");
static constexpr std::string_view TOKEN_AUTOTERM("AUTOTERM");
static constexpr std::string_view TOKEN_BAIL("BAIL");
static constexpr std::string_view TOKEN_BLOBDISPLAY("BLOBDISPLAY");
static constexpr std::string_view TOKEN_BULK_INSERT("BULK_INSERT");
static constexpr std::string_view TOKEN_COUNT("COUNT");
static constexpr std::string_view TOKEN_ECHO("ECHO");
static constexpr std::string_view TOKEN_EXEC_PATH_DISPLAY("EXEC_PATH_DISPLAY");
static constexpr std::string_view TOKEN_EXPLAIN("EXPLAIN");
static constexpr std::string_view TOKEN_HEADING("HEADING");
static constexpr std::string_view TOKEN_KEEP_TRAN_PARAMS("KEEP_TRAN_PARAMS");
static constexpr std::string_view TOKEN_LIST("LIST");
static constexpr std::string_view TOKEN_LOCAL_TIMEOUT("LOCAL_TIMEOUT");
static constexpr std::string_view TOKEN_MAXROWS("MAXROWS");
static constexpr std::string_view TOKEN_NAMES("NAMES");
static constexpr std::string_view TOKEN_PER_TABLE_STATS("PER_TABLE_STATS");
static constexpr std::string_view TOKEN_PLAN("PLAN");
static constexpr std::string_view TOKEN_PLANONLY("PLANONLY");
static constexpr std::string_view TOKEN_ROWCOUNT("ROWCOUNT");
static constexpr std::string_view TOKEN_SQL("SQL");
static constexpr std::string_view TOKEN_SQLDA_DISPLAY("SQLDA_DISPLAY");
static constexpr std::string_view TOKEN_STATS("STATS");
static constexpr std::string_view TOKEN_TERMINATOR("TERMINATOR");
static constexpr std::string_view TOKEN_TIME("TIME");
static constexpr std::string_view TOKEN_TRANSACTION("TRANSACTION");
static constexpr std::string_view TOKEN_WARNINGS("WARNINGS");
static constexpr std::string_view TOKEN_WIDTH("WIDTH");
static constexpr std::string_view TOKEN_WNG("WNG");
static constexpr std::string_view TOKEN_WIRE_STATS("WIRE_STATS");
switch (const auto setCommandToken = lexer.getToken(); setCommandToken.type)
{
case Token::TYPE_EOF:
return SetNode();
case Token::TYPE_OTHER:
{
const auto& text = setCommandToken.processedText;
if (const auto parsed = parseSet<SetAutoDdlNode>(text, TOKEN_AUTODDL, 4))
return parsed.value();
else if (const auto parsed = parseSet<SetAutoTermNode>(text, TOKEN_AUTOTERM))
return parsed.value();
else if (const auto parsed = parseSet<SetBailNode>(text, TOKEN_BAIL))
return parsed.value();
else if (const auto parsed = parseSet<SetBlobDisplayNode>(text, TOKEN_BLOBDISPLAY, 4))
return parsed.value();
else if (text == TOKEN_BULK_INSERT)
{
SetBulkInsertNode node;
if (const auto statement = parseUtilEof())
{
node.statement = statement.value();
return node;
}
}
else if (const auto parsed = parseSet<SetCountNode>(text, TOKEN_COUNT))
return parsed.value();
else if (const auto parsed = parseSet<SetEchoNode>(text, TOKEN_ECHO))
return parsed.value();
else if (const auto parsed = parseSet<SetExecPathDisplayNode>(text, TOKEN_EXEC_PATH_DISPLAY))
return parsed.value();
else if (const auto parsed = parseSet<SetExplainNode>(text, TOKEN_EXPLAIN))
return parsed.value();
else if (const auto parsed = parseSet<SetHeadingNode>(text, TOKEN_HEADING))
return parsed.value();
else if (const auto parsed = parseSet<SetKeepTranParamsNode>(text, TOKEN_KEEP_TRAN_PARAMS, 9))
return parsed.value();
else if (const auto parsed = parseSet<SetListNode>(text, TOKEN_LIST))
return parsed.value();
else if (const auto parsed = parseSet<SetLocalTimeoutNode>(text, TOKEN_LOCAL_TIMEOUT))
return parsed.value();
else if (const auto parsed = parseSet<SetMaxRowsNode>(text, TOKEN_MAXROWS))
return parsed.value();
else if (text == TOKEN_NAMES)
{
SetNamesNode node;
node.name = parseName();
if (parseEof())
return node;
}
else if (const auto parsed = parseSet<SetPerTableStatsNode>(text, TOKEN_PER_TABLE_STATS, 7))
return parsed.value();
else if (const auto parsed = parseSet<SetPlanNode>(text, TOKEN_PLAN))
return parsed.value();
else if (const auto parsed = parseSet<SetPlanOnlyNode>(text, TOKEN_PLANONLY))
return parsed.value();
else if (const auto parsed = parseSet<SetMaxRowsNode>(text, TOKEN_ROWCOUNT))
return parsed.value();
else if (text == TOKEN_SQL)
{
SetSqlDialectNode node;
if (const auto dialectToken = lexer.getToken();
dialectToken.type == Token::TYPE_OTHER && dialectToken.processedText == "DIALECT")
{
if (const auto arg = lexer.getToken(); arg.type != Token::TYPE_EOF)
{
node.arg = arg.processedText;
if (parseEof())
return node;
}
}
}
else if (const auto parsed = parseSet<SetSqldaDisplayNode>(text, TOKEN_SQLDA_DISPLAY))
return parsed.value();
else if (const auto parsed = parseSet<SetStatsNode>(text, TOKEN_STATS, 4))
return parsed.value();
else if (const auto parsed = parseSet<SetTermNode>(text, TOKEN_TERMINATOR, 4, false))
return parsed.value();
else if (const auto parsed = parseSet<SetTimeNode>(text, TOKEN_TIME))
{
if (const auto setTimeNode = std::get_if<SetTimeNode>(&parsed.value());
setTimeNode && setTimeNode->arg == "ZONE")
{
return InvalidNode();
}
return parsed.value();
}
else if (text.length() >= 5 && std::string(TOKEN_TRANSACTION).find(text) == 0)
{
SetTransactionNode node;
node.statement = lexer.getBuffer();
return node;
}
else if (const auto parsed = parseSet<SetWarningsNode>(text, TOKEN_WARNINGS, 7))
return parsed.value();
else if (const auto parsed = parseSet<SetWarningsNode>(text, TOKEN_WNG))
return parsed.value();
else if (text == TOKEN_WIDTH)
{
SetWidthNode node;
if (const auto column = lexer.getToken(); column.type != Token::TYPE_EOF)
{
node.column = column.processedText;
if (const auto width = lexer.getToken(); width.type != Token::TYPE_EOF)
{
node.width = width.processedText;
if (!parseEof())
return InvalidNode();
}
return node;
}
}
else if (const auto parsed = parseSet<SetWireStatsNode>(text, TOKEN_WIRE_STATS, 4))
return parsed.value();
break;
}
}
return InvalidNode();
}
template <typename Node>
std::optional<FrontendParser::AnySetNode> FrontendParser::parseSet(std::string_view setCommand,
std::string_view testCommand, unsigned testCommandMinLen, bool useProcessedText)
{
if (setCommand == testCommand ||
(testCommandMinLen && setCommand.length() >= testCommandMinLen &&
std::string(testCommand).find(setCommand) == 0))
{
Node node;
if (const auto arg = lexer.getToken(); arg.type != Token::TYPE_EOF)
{
node.arg = useProcessedText ? arg.processedText : arg.rawText;
if (!parseEof())
return InvalidNode();
}
return node;
}
return std::nullopt;
}
FrontendParser::AnyShowNode FrontendParser::parseShow()
{
static constexpr std::string_view TOKEN_CHECKS("CHECKS");
static constexpr std::string_view TOKEN_COLLATES("COLLATES");
static constexpr std::string_view TOKEN_COLLATIONS("COLLATIONS");
static constexpr std::string_view TOKEN_COMMENTS("COMMENTS");
static constexpr std::string_view TOKEN_DATABASE("DATABASE");
static constexpr std::string_view TOKEN_DEPENDENCIES("DEPENDENCIES");
static constexpr std::string_view TOKEN_DEPENDENCY("DEPENDENCY");
static constexpr std::string_view TOKEN_DOMAINS("DOMAINS");
static constexpr std::string_view TOKEN_EXCEPTIONS("EXCEPTIONS");
static constexpr std::string_view TOKEN_FILTERS("FILTERS");
static constexpr std::string_view TOKEN_FUNCTIONS("FUNCTIONS");
static constexpr std::string_view TOKEN_INDEXES("INDEXES");
static constexpr std::string_view TOKEN_INDICES("INDICES");
static constexpr std::string_view TOKEN_GENERATORS("GENERATORS");
static constexpr std::string_view TOKEN_GRANTS("GRANTS");
static constexpr std::string_view TOKEN_MAPPINGS("MAPPINGS");
static constexpr std::string_view TOKEN_PACKAGES("PACKAGES");
static constexpr std::string_view TOKEN_PROCEDURES("PROCEDURES");
static constexpr std::string_view TOKEN_PUBLICATIONS("PUBLICATIONS");
static constexpr std::string_view TOKEN_ROLES("ROLES");
static constexpr std::string_view TOKEN_SECCLASSES("SECCLASSES");
static constexpr std::string_view TOKEN_SEQUENCES("SEQUENCES");
static constexpr std::string_view TOKEN_SQL("SQL");
static constexpr std::string_view TOKEN_SYSTEM("SYSTEM");
static constexpr std::string_view TOKEN_TABLES("TABLES");
static constexpr std::string_view TOKEN_TRIGGERS("TRIGGERS");
static constexpr std::string_view TOKEN_USERS("USERS");
static constexpr std::string_view TOKEN_VER("VER");
static constexpr std::string_view TOKEN_VERSION("VERSION");
static constexpr std::string_view TOKEN_VIEWS("VIEWS");
static constexpr std::string_view TOKEN_WIRE_STATISTICS("WIRE_STATISTICS");
static constexpr std::string_view TOKEN_WIRE_STATS("WIRE_STATS");
switch (const auto showCommandToken = lexer.getToken(); showCommandToken.type)
{
case Token::TYPE_EOF:
return ShowNode();
case Token::TYPE_OTHER:
{
const auto& text = showCommandToken.processedText;
if (const auto parsed = parseShowOptName<ShowChecksNode>(text, TOKEN_CHECKS, 5))
return parsed.value();
else if (const auto parsed = parseShowOptName<ShowCollationsNode>(text, TOKEN_COLLATES, 7))
return parsed.value();
else if (const auto parsed = parseShowOptName<ShowCollationsNode>(text, TOKEN_COLLATIONS, 9))
return parsed.value();
else if (text.length() >= 7 && std::string(TOKEN_COMMENTS).find(text) == 0)
{
if (parseEof())
return ShowCommentsNode();
}
else if (text == TOKEN_DATABASE)
{
if (parseEof())
return ShowDatabaseNode();
}
else if (const auto parsed = parseShowOptName<ShowDependenciesNode>(text, TOKEN_DEPENDENCIES, 5))
return parsed.value();
else if (const auto parsed = parseShowOptName<ShowDependenciesNode>(text, TOKEN_DEPENDENCY, 5))
return parsed.value();
else if (const auto parsed = parseShowOptName<ShowDomainsNode>(text, TOKEN_DOMAINS, 6))
return parsed.value();
else if (const auto parsed = parseShowOptName<ShowExceptionsNode>(text, TOKEN_EXCEPTIONS, 5))
return parsed.value();
else if (const auto parsed = parseShowOptName<ShowFiltersNode>(text, TOKEN_FILTERS, 6))
return parsed.value();
else if (text.length() >= 4 && std::string(TOKEN_FUNCTIONS).find(text) == 0)
{
ShowFunctionsNode node;
node.name = parseName();
if (node.name)
{
if (const auto token = lexer.getToken();
token.type == Token::TYPE_OTHER && token.rawText == ".")
{
node.package = node.name;
node.name = parseName();
if (parseEof())
return node;
}
else if (token.type == Token::TYPE_EOF)
{
return node;
}
}
else
return node;
}
else if (const auto parsed = parseShowOptName<ShowIndexesNode>(text, TOKEN_INDEXES, 3))
return parsed.value();
else if (const auto parsed = parseShowOptName<ShowIndexesNode>(text, TOKEN_INDICES, 0))
return parsed.value();
else if (const auto parsed = parseShowOptName<ShowGeneratorsNode>(text, TOKEN_GENERATORS, 3))
return parsed.value();
else if (const auto parsed = parseShowOptName<ShowGrantsNode>(text, TOKEN_GRANTS, 5))
return parsed.value();
else if (const auto parsed = parseShowOptName<ShowMappingsNode>(text, TOKEN_MAPPINGS, 3))
return parsed.value();
else if (const auto parsed = parseShowOptName<ShowPackagesNode>(text, TOKEN_PACKAGES, 4))
return parsed.value();
else if (text.length() >= 4 && std::string(TOKEN_PROCEDURES).find(text) == 0)
{
ShowProceduresNode node;
node.name = parseName();
if (node.name)
{
if (const auto token = lexer.getToken();
token.type == Token::TYPE_OTHER && token.rawText == ".")
{
node.package = node.name;
node.name = parseName();
if (parseEof())
return node;
}
else if (token.type == Token::TYPE_EOF)
{
return node;
}
}
else
return node;
}
else if (const auto parsed = parseShowOptName<ShowPublicationsNode>(text, TOKEN_PUBLICATIONS, 3))
return parsed.value();
else if (const auto parsed = parseShowOptName<ShowRolesNode>(text, TOKEN_ROLES, 4))
return parsed.value();
else if (text.length() >= 6 && std::string(TOKEN_SECCLASSES).find(text) == 0)
{
const auto lexerPos = lexer.getPos();
const auto token = lexer.getNameToken();
ShowSecClassesNode node;
if (!(token.type == Token::TYPE_OTHER && token.rawText == "*"))
{
lexer.setPos(lexerPos);
node.name = parseName();
if (!node.name)
return InvalidNode();
}
const auto optDetail = parseName();
node.detail = optDetail == "DET" || optDetail == "DETAIL";
if (!node.detail && optDetail)
return InvalidNode();
if (parseEof())
return node;
}
else if (const auto parsed = parseShowOptName<ShowGeneratorsNode>(text, TOKEN_SEQUENCES, 3))
return parsed.value();
else if (text == TOKEN_SQL)
{
if (const auto dialectToken = lexer.getToken();
dialectToken.type == Token::TYPE_OTHER && dialectToken.processedText == "DIALECT")
{
if (parseEof())
return ShowSqlDialectNode();
}
}
else if (text.length() >= 3 && std::string(TOKEN_SYSTEM).find(text) == 0)
{
ShowSystemNode node;
if (const auto objectType = parseName())
{
const auto objectTypeText = std::string(objectType->c_str());
if ((objectTypeText.length() >= 7 && std::string(TOKEN_COLLATES).find(objectTypeText) == 0) ||
(objectTypeText.length() >= 9 && std::string(TOKEN_COLLATIONS).find(objectTypeText) == 0))
{
node.objType = obj_collation;
}
else if (objectTypeText.length() >= 4 && std::string(TOKEN_FUNCTIONS).find(objectTypeText) == 0)
node.objType = obj_udf;
else if (objectTypeText.length() >= 5 && std::string(TOKEN_TABLES).find(objectTypeText) == 0)
node.objType = obj_relation;
else if (objectTypeText.length() >= 4 && std::string(TOKEN_ROLES).find(objectTypeText) == 0)
node.objType = obj_sql_role;
else if (objectTypeText.length() >= 4 && std::string(TOKEN_PROCEDURES).find(objectTypeText) == 0)
node.objType = obj_procedure;
else if (objectTypeText.length() >= 4 && std::string(TOKEN_PACKAGES).find(objectTypeText) == 0)
node.objType = obj_package_header;
else if (objectTypeText.length() >= 3 && std::string(TOKEN_PUBLICATIONS).find(objectTypeText) == 0)
node.objType = obj_publication;
else
return InvalidNode();
if (!parseEof())
return InvalidNode();
}
return node;
}
else if (const auto parsed = parseShowOptName<ShowTablesNode>(text, TOKEN_TABLES, 5))
return parsed.value();
else if (const auto parsed = parseShowOptName<ShowTriggersNode>(text, TOKEN_TRIGGERS, 4))
return parsed.value();
else if (text == TOKEN_USERS)
{
if (parseEof())
return ShowUsersNode();
}
else if (text == TOKEN_VER || text == TOKEN_VERSION)
{
if (parseEof())
return ShowVersionNode();
}
else if (const auto parsed = parseShowOptName<ShowViewsNode>(text, TOKEN_VIEWS, 4))
return parsed.value();
else if (text.length() >= 9 && std::string(TOKEN_WIRE_STATISTICS).find(text) == 0 ||
text == TOKEN_WIRE_STATS)
{
if (parseEof())
return ShowWireStatsNode();
}
break;
}
}
return InvalidNode();
}
template <typename Node>
std::optional<FrontendParser::AnyShowNode> FrontendParser::parseShowOptName(std::string_view showCommand,
std::string_view testCommand, unsigned testCommandMinLen)
{
if (showCommand == testCommand ||
(testCommandMinLen && showCommand.length() >= testCommandMinLen &&
std::string(testCommand).find(showCommand) == 0))
{
Node node;
node.name = parseName();
if (!parseEof())
return InvalidNode();
return node;
}
return std::nullopt;
}
std::optional<std::string> FrontendParser::parseUtilEof()
{
const auto startPos = lexer.getPos();
auto lastPos = startPos;
bool first = true;
do
{
const auto token = lexer.getToken();
if (token.type == Token::TYPE_EOF)
{
if (first)
return std::nullopt;
return FrontendLexer::trim(std::string(startPos, lastPos));
}
lastPos = lexer.getPos();
first = false;
} while (true);
return std::nullopt;
}

285
src/isql/FrontendParser.h Normal file
View File

@ -0,0 +1,285 @@
/*
* The contents of this file are subject to the Initial
* Developer's Public License Version 1.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.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
*
* Software distributed under the License is distributed AS IS,
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
* See the License for the specific language governing rights
* and limitations under the License.
*
* The Original Code was created by Adriano dos Santos Fernandes
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2024 Adriano dos Santos Fernandes <adrianosf at gmail.com>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*
*/
#ifndef FB_ISQL_FRONTEND_PARSER_H
#define FB_ISQL_FRONTEND_PARSER_H
#include "../isql/FrontendLexer.h"
#include "../jrd/obj.h"
#include "../common/classes/MetaString.h"
#include <optional>
#include <string>
#include <string_view>
#include <variant>
#include <vector>
class FrontendParser
{
private:
using Token = FrontendLexer::Token;
public:
struct Options
{
bool schemaAsDatabase = false;
};
struct InvalidNode {};
struct AddNode { Firebird::MetaString tableName; };
struct BlobDumpViewNode { ISC_QUAD blobId; std::optional<std::string> file; };
struct ConnectNode { std::vector<Token> args; };
struct CopyNode { Firebird::MetaString source; Firebird::MetaString destination; std::string database; };
struct CreateDatabaseNode { std::vector<Token> args; };
struct DropDatabaseNode {};
struct EditNode { std::optional<std::string> file; };
struct ExitNode {};
struct ExplainNode { std::string query; };
struct HelpNode { std::optional<std::string> command; };
struct InputNode { std::string file; };
struct OutputNode { std::optional<std::string> file; };
struct QuitNode {};
struct ShellNode { std::optional<std::string> command; };
struct SetNode {};
struct SetAutoDdlNode { std::string arg; };
struct SetAutoTermNode { std::string arg; };
struct SetBailNode { std::string arg; };
struct SetBlobDisplayNode { std::string arg; };
struct SetBulkInsertNode { std::string statement; };
struct SetCountNode { std::string arg; };
struct SetEchoNode { std::string arg; };
struct SetExecPathDisplayNode { std::string arg; };
struct SetExplainNode { std::string arg; };
struct SetHeadingNode { std::string arg; };
struct SetKeepTranParamsNode { std::string arg; };
struct SetListNode { std::string arg; };
struct SetLocalTimeoutNode { std::string arg; };
struct SetMaxRowsNode { std::string arg; };
struct SetNamesNode { std::optional<Firebird::MetaString> name; };
struct SetPerTableStatsNode { std::string arg; };
struct SetPlanNode { std::string arg; };
struct SetPlanOnlyNode { std::string arg; };
struct SetSqldaDisplayNode { std::string arg; };
struct SetSqlDialectNode { std::string arg; };
struct SetStatsNode { std::string arg; };
struct SetTermNode { std::string arg; };
struct SetTimeNode { std::string arg; };
struct SetTransactionNode { std::string statement; };
struct SetWarningsNode { std::string arg; };
struct SetWidthNode { std::string column; std::string width; };
struct SetWireStatsNode { std::string arg; };
struct ShowNode {};
struct ShowChecksNode { std::optional<Firebird::MetaString> name; };
struct ShowCollationsNode { std::optional<Firebird::MetaString> name; };
struct ShowCommentsNode {};
struct ShowDatabaseNode {};
struct ShowDomainsNode { std::optional<Firebird::MetaString> name; };
struct ShowDependenciesNode { std::optional<Firebird::MetaString> name; };
struct ShowExceptionsNode { std::optional<Firebird::MetaString> name; };
struct ShowFiltersNode { std::optional<Firebird::MetaString> name; };
struct ShowFunctionsNode { std::optional<Firebird::MetaString> name; std::optional<Firebird::MetaString> package; };
struct ShowGeneratorsNode { std::optional<Firebird::MetaString> name; };
struct ShowGrantsNode { std::optional<Firebird::MetaString> name; };
struct ShowIndexesNode { std::optional<Firebird::MetaString> name; };
struct ShowMappingsNode { std::optional<Firebird::MetaString> name; };
struct ShowPackagesNode { std::optional<Firebird::MetaString> name; };
struct ShowProceduresNode { std::optional<Firebird::MetaString> name; std::optional<Firebird::MetaString> package; };
struct ShowPublicationsNode { std::optional<Firebird::MetaString> name; };
struct ShowRolesNode { std::optional<Firebird::MetaString> name; };
struct ShowSecClassesNode { std::optional<Firebird::MetaString> name; bool detail = false; };
struct ShowSqlDialectNode {};
struct ShowSystemNode { std::optional<ObjectType> objType; };
struct ShowTablesNode { std::optional<Firebird::MetaString> name; };
struct ShowTriggersNode { std::optional<Firebird::MetaString> name; };
struct ShowUsersNode {};
struct ShowVersionNode {};
struct ShowViewsNode { std::optional<Firebird::MetaString> name; };
struct ShowWireStatsNode {};
using AnySetNode = std::variant<
SetNode,
SetAutoDdlNode,
SetAutoTermNode,
SetBailNode,
SetBlobDisplayNode,
SetBulkInsertNode,
SetCountNode,
SetEchoNode,
SetExecPathDisplayNode,
SetExplainNode,
SetHeadingNode,
SetKeepTranParamsNode,
SetListNode,
SetLocalTimeoutNode,
SetMaxRowsNode,
SetNamesNode,
SetPerTableStatsNode,
SetPlanNode,
SetPlanOnlyNode,
SetSqldaDisplayNode,
SetSqlDialectNode,
SetStatsNode,
SetTermNode,
SetTimeNode,
SetTransactionNode,
SetWarningsNode,
SetWidthNode,
SetWireStatsNode,
InvalidNode
>;
using AnyShowNode = std::variant<
ShowNode,
ShowChecksNode,
ShowCollationsNode,
ShowCommentsNode,
ShowDatabaseNode,
ShowDomainsNode,
ShowDependenciesNode,
ShowExceptionsNode,
ShowFiltersNode,
ShowFunctionsNode,
ShowGeneratorsNode,
ShowGrantsNode,
ShowIndexesNode,
ShowMappingsNode,
ShowPackagesNode,
ShowProceduresNode,
ShowPublicationsNode,
ShowRolesNode,
ShowSecClassesNode,
ShowSqlDialectNode,
ShowSystemNode,
ShowTablesNode,
ShowTriggersNode,
ShowUsersNode,
ShowVersionNode,
ShowViewsNode,
ShowWireStatsNode,
InvalidNode
>;
using AnyNode = std::variant<
AddNode,
BlobDumpViewNode,
ConnectNode,
CopyNode,
CreateDatabaseNode,
DropDatabaseNode,
EditNode,
ExitNode,
ExplainNode,
HelpNode,
InputNode,
OutputNode,
QuitNode,
ShellNode,
AnySetNode,
AnyShowNode,
InvalidNode
>;
template <typename>
static inline constexpr bool AlwaysFalseV = false;
public:
FrontendParser(std::string_view statement, const Options& aOptions)
: lexer(statement),
options(aOptions)
{
}
FrontendParser(const FrontendParser&) = delete;
FrontendParser& operator=(const FrontendParser&) = delete;
public:
static AnyNode parse(std::string_view statement, const Options& options)
{
try
{
FrontendParser parser(statement, options);
return parser.internalParse();
}
catch (const FrontendLexer::IncompleteTokenError&)
{
return InvalidNode();
}
}
private:
AnyNode internalParse();
AnySetNode parseSet();
template <typename Node>
std::optional<AnySetNode> parseSet(std::string_view setCommand,
std::string_view testCommand, unsigned testCommandMinLen = 0, bool useProcessedText = true);
AnyShowNode parseShow();
template <typename Node>
std::optional<AnyShowNode> parseShowOptName(std::string_view showCommand,
std::string_view testCommand, unsigned testCommandMinLen = 0);
bool parseEof()
{
return lexer.getToken().type == Token::TYPE_EOF;
}
std::optional<Firebird::MetaString> parseName()
{
const auto token = lexer.getNameToken();
if (token.type != Token::TYPE_EOF)
return Firebird::MetaString(token.processedText.c_str());
return std::nullopt;
}
std::optional<std::string> parseFileName()
{
const auto token = lexer.getToken();
if (token.type == Token::TYPE_STRING || token.type == Token::TYPE_META_STRING)
return token.processedText;
else if (token.type != Token::TYPE_EOF)
return token.rawText;
return std::nullopt;
}
std::optional<std::string> parseUtilEof();
private:
FrontendLexer lexer;
const Options options;
};
#endif // FB_ISQL_FRONTEND_PARSER_H

File diff suppressed because it is too large Load Diff

View File

@ -37,6 +37,7 @@
#include "../common/utils_proto.h"
#include <stdarg.h>
using namespace Firebird;
using MsgFormat::SafeArg;
@ -148,6 +149,16 @@ void IUTILS_msg_get(USHORT number, USHORT size, TEXT* msg, const SafeArg& args)
fb_msg_format(NULL, ISQL_MSG_FAC, number, size, msg, args);
}
string IUTILS_name_to_string(const MetaString& name)
{
if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION)
return name.toQuotedString();
else
return name.c_str();
}
void IUTILS_printf(FILE* fp, const char* buffer)
{
/**************************************

View File

@ -24,6 +24,7 @@
#ifndef ISQL_IUTILS_PROTO_H
#define ISQL_IUTILS_PROTO_H
#include "../common/classes/MetaString.h"
#include "../common/classes/SafeArg.h"
#include <stdio.h>
@ -33,6 +34,7 @@ void IUTILS_msg_get(USHORT number, TEXT* msg,
const MsgFormat::SafeArg& args = MsgFormat::SafeArg());
void IUTILS_msg_get(USHORT number, USHORT size, TEXT* msg,
const MsgFormat::SafeArg& args = MsgFormat::SafeArg());
Firebird::string IUTILS_name_to_string(const Firebird::MetaString& name);
void IUTILS_printf(FILE*, const char*);
void IUTILS_printf2(FILE*, const char*, ...);
void IUTILS_put_errmsg(USHORT number, const MsgFormat::SafeArg& args);

File diff suppressed because it is too large Load Diff

View File

@ -26,6 +26,7 @@
#include "../common/classes/fb_string.h"
#include <firebird/Interface.h>
#include "../isql/FrontendParser.h"
#include "../jrd/obj.h"
void SHOW_comments(bool force);
@ -36,7 +37,7 @@ void SHOW_grant_roles (const SCHAR*, bool*);
void SHOW_grant_roles2 (const SCHAR*, bool*, const TEXT*, bool);
void SHOW_print_metadata_text_blob(FILE*, ISC_QUAD*, bool escape_squote = false,
bool avoid_end_in_single_line_comment = false);
processing_state SHOW_metadata(const SCHAR* const*, SCHAR**);
processing_state SHOW_metadata(const FrontendParser::AnyShowNode& node);
void SHOW_read_owner();
const Firebird::string SHOW_trigger_action(SINT64);
processing_state SHOW_maps(bool extract, const SCHAR* map_name);

View File

@ -0,0 +1,621 @@
/*
* The contents of this file are subject to the Initial
* Developer's Public License Version 1.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.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
*
* Software distributed under the License is distributed AS IS,
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
* See the License for the specific language governing rights
* and limitations under the License.
*
* The Original Code was created by Adriano dos Santos Fernandes
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2024 Adriano dos Santos Fernandes <adrianosf at gmail.com>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*
*/
#include "firebird.h"
#include "boost/test/unit_test.hpp"
#include "../FrontendParser.h"
#include <variant>
using namespace Firebird;
BOOST_AUTO_TEST_SUITE(ISqlSuite)
BOOST_AUTO_TEST_SUITE(FrontendParserSuite)
BOOST_AUTO_TEST_SUITE(FrontendParserTests)
BOOST_AUTO_TEST_CASE(ParseCommandTest)
{
const FrontendParser::Options parserOptions;
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"add", parserOptions)));
BOOST_TEST((std::get<FrontendParser::AddNode>(FrontendParser::parse(
"add table1", parserOptions)).tableName == "TABLE1"));
BOOST_TEST((std::get<FrontendParser::AddNode>(FrontendParser::parse(
"add \"table2\"", parserOptions)).tableName == "table2"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"blobdump", parserOptions)));
{
const auto blobDump1 = std::get<FrontendParser::BlobDumpViewNode>(FrontendParser::parse(
"blobdump 1:2 /tmp/blob.txt", parserOptions));
BOOST_TEST(blobDump1.blobId.gds_quad_high == 1);
BOOST_TEST(blobDump1.blobId.gds_quad_low == 2u);
BOOST_TEST(blobDump1.file.value() == "/tmp/blob.txt");
const auto blobDump2 = std::get<FrontendParser::BlobDumpViewNode>(FrontendParser::parse(
"blobdump 1:2 'C:\\A dir\\blob.txt'", parserOptions));
BOOST_TEST((blobDump2.file.value() == "C:\\A dir\\blob.txt"));
}
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"blobview", parserOptions)));
{
const auto blobView1 = std::get<FrontendParser::BlobDumpViewNode>(FrontendParser::parse(
"blobview 1:2", parserOptions));
BOOST_TEST(blobView1.blobId.gds_quad_high == 1);
BOOST_TEST(blobView1.blobId.gds_quad_low == 2u);
BOOST_TEST(!blobView1.file);
}
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"connect", parserOptions)));
{
const auto connect1 = std::get<FrontendParser::ConnectNode>(FrontendParser::parse(
"connect 'test.fdb'", parserOptions));
BOOST_TEST(connect1.args[0].getProcessedString() == "test.fdb");
const auto connect2 = std::get<FrontendParser::ConnectNode>(FrontendParser::parse(
"connect 'test.fdb' user user", parserOptions));
BOOST_TEST(connect2.args.size() == 3u);
}
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"copy", parserOptions)));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"copy source destination", parserOptions)));
{
const auto copy1 = std::get<FrontendParser::CopyNode>(FrontendParser::parse(
"copy source \"destination\" localhost:/tmp/database.fdb", parserOptions));
BOOST_TEST((copy1.source == "SOURCE"));
BOOST_TEST((copy1.destination == "destination"));
BOOST_TEST(copy1.database == "localhost:/tmp/database.fdb");
}
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"create", parserOptions)));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"create database", parserOptions)));
{
const auto createDatabase1 = std::get<FrontendParser::CreateDatabaseNode>(FrontendParser::parse(
"create database 'test.fdb'", parserOptions));
BOOST_TEST(createDatabase1.args[0].getProcessedString() == "test.fdb");
const auto createDatabase2 = std::get<FrontendParser::CreateDatabaseNode>(FrontendParser::parse(
"create database 'test.fdb' user user", parserOptions));
BOOST_TEST(createDatabase2.args.size() == 3u);
}
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"drop database x", parserOptions)));
BOOST_TEST(std::holds_alternative<FrontendParser::DropDatabaseNode>(FrontendParser::parse(
"drop database", parserOptions)));
BOOST_TEST(!std::get<FrontendParser::EditNode>(FrontendParser::parse(
"edit", parserOptions)).file);
BOOST_TEST(std::get<FrontendParser::EditNode>(FrontendParser::parse(
"edit /tmp/file.sql", parserOptions)).file.value() == "/tmp/file.sql");
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"exit x", parserOptions)));
BOOST_TEST(std::holds_alternative<FrontendParser::ExitNode>(FrontendParser::parse(
"exit", parserOptions)));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"explain", parserOptions)));
BOOST_TEST(std::get<FrontendParser::ExplainNode>(FrontendParser::parse(
"explain select 1 from rdb$database", parserOptions)).query == "select 1 from rdb$database");
BOOST_TEST(!std::get<FrontendParser::HelpNode>(FrontendParser::parse(
"help", parserOptions)).command.has_value());
BOOST_TEST(std::get<FrontendParser::HelpNode>(FrontendParser::parse(
"help set", parserOptions)).command.value() == "SET");
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"help set x", parserOptions)));
BOOST_TEST(!std::get<FrontendParser::HelpNode>(FrontendParser::parse(
"?", parserOptions)).command.has_value());
BOOST_TEST(std::get<FrontendParser::HelpNode>(FrontendParser::parse(
"? set", parserOptions)).command.value() == "SET");
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"? set x", parserOptions)));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"input", parserOptions)));
BOOST_TEST(std::get<FrontendParser::InputNode>(FrontendParser::parse(
"input /tmp/file.sql", parserOptions)).file == "/tmp/file.sql");
BOOST_TEST(!std::get<FrontendParser::OutputNode>(FrontendParser::parse(
"output", parserOptions)).file);
BOOST_TEST(std::get<FrontendParser::OutputNode>(FrontendParser::parse(
"output /tmp/file.txt", parserOptions)).file.value() == "/tmp/file.txt");
BOOST_TEST(std::holds_alternative<FrontendParser::QuitNode>(FrontendParser::parse(
"quit", parserOptions)));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"quit x", parserOptions)));
BOOST_TEST(!std::get<FrontendParser::ShellNode>(FrontendParser::parse(
"shell", parserOptions)).command);
BOOST_TEST(std::get<FrontendParser::ShellNode>(FrontendParser::parse(
"shell ls -l /tmp", parserOptions)).command.value() == "ls -l /tmp");
}
BOOST_AUTO_TEST_CASE(ParseSetTest)
{
const FrontendParser::Options parserOptions;
const auto parseSet = [&](const std::string_view text) {
return std::get<FrontendParser::AnySetNode>(FrontendParser::parse(text, parserOptions));
};
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"\"set\"", parserOptions)));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set x", parserOptions)));
BOOST_TEST(std::holds_alternative<FrontendParser::SetNode>(parseSet("set")));
BOOST_TEST(std::get<FrontendParser::SetAutoDdlNode>(parseSet(
"set auto")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetAutoDdlNode>(parseSet(
"set auto on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set auto off x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetAutoDdlNode>(parseSet(
"set autoddl")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetAutoDdlNode>(parseSet(
"set autoddl on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set autoddl off x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetAutoTermNode>(parseSet(
"set autoterm")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetAutoTermNode>(parseSet(
"set autoterm on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set autoterm off x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetBailNode>(parseSet(
"set bail")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetBailNode>(parseSet(
"set bail on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set bail off x", parserOptions)));
BOOST_TEST((std::get<FrontendParser::SetBulkInsertNode>(parseSet(
"set bulk_insert insert into mytable (a, b) values (1, ?)")).statement ==
"insert into mytable (a, b) values (1, ?)"));
BOOST_TEST(std::get<FrontendParser::SetBlobDisplayNode>(parseSet(
"set blob")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetBlobDisplayNode>(parseSet(
"set blob on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set blob off x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetBlobDisplayNode>(parseSet(
"set blobdisplay")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetBlobDisplayNode>(parseSet(
"set blobdisplay on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set blobdisplay off x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetCountNode>(parseSet(
"set count")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetCountNode>(parseSet(
"set count on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set count off x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetEchoNode>(parseSet(
"set echo")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetEchoNode>(parseSet(
"set echo on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set echo off x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetExecPathDisplayNode>(parseSet(
"set exec_path_display")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetExecPathDisplayNode>(parseSet(
"set exec_path_display blr")).arg == "BLR"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set exec_path_display off x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetExplainNode>(parseSet(
"set explain")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetExplainNode>(parseSet(
"set explain on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set explain off x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetHeadingNode>(parseSet(
"set heading")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetHeadingNode>(parseSet(
"set heading on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set heading off x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetKeepTranParamsNode>(parseSet(
"set keep_tran")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetKeepTranParamsNode>(parseSet(
"set keep_tran on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set keep_tran off x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetKeepTranParamsNode>(parseSet(
"set keep_tran_params")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetKeepTranParamsNode>(parseSet(
"set keep_tran_params on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set keep_tran_params off x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetListNode>(parseSet(
"set list")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetListNode>(parseSet(
"set list on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set list off x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetLocalTimeoutNode>(parseSet(
"set local_timeout")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetLocalTimeoutNode>(parseSet(
"set local_timeout 80")).arg == "80"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set local_timeout 90 x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetMaxRowsNode>(parseSet(
"set maxrows")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetMaxRowsNode>(parseSet(
"set maxrows 80")).arg == "80"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set maxrows 90 x", parserOptions)));
BOOST_TEST(!std::get<FrontendParser::SetNamesNode>(parseSet(
"set names")).name.has_value());
BOOST_TEST((std::get<FrontendParser::SetNamesNode>(parseSet(
"set names utf8")).name == "UTF8"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set names utf8 x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetPerTableStatsNode>(parseSet(
"set per_tab")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetPerTableStatsNode>(parseSet(
"set per_tab on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set per_tab off x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetPerTableStatsNode>(parseSet(
"set per_table_stats")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetPerTableStatsNode>(parseSet(
"set per_table_stats on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set per_table_stats off x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetPlanNode>(parseSet(
"set plan")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetPlanNode>(parseSet(
"set plan on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set plan off x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetPlanOnlyNode>(parseSet(
"set planonly")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetPlanOnlyNode>(parseSet(
"set planonly on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set planonly off x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetMaxRowsNode>(parseSet(
"set rowcount")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetMaxRowsNode>(parseSet(
"set rowcount 80")).arg == "80"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set rowcount 90 x", parserOptions)));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set sql", parserOptions)));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set sql dialect", parserOptions)));
BOOST_TEST((std::get<FrontendParser::SetSqlDialectNode>(parseSet(
"set sql dialect 3")).arg == "3"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set sql dialect 3 x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetSqldaDisplayNode>(parseSet(
"set sqlda_display")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetSqldaDisplayNode>(parseSet(
"set sqlda_display on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set sqlda_display off x", parserOptions)));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set sta", parserOptions)));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set sta on", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetStatsNode>(parseSet(
"set stat")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetStatsNode>(parseSet(
"set stat on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set stat off x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetStatsNode>(parseSet(
"set stats")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetStatsNode>(parseSet(
"set stats on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set stats off x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetTermNode>(parseSet(
"set term")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetTermNode>(parseSet(
"set term !")).arg == "!"));
BOOST_TEST((std::get<FrontendParser::SetTermNode>(parseSet(
"set term Go")).arg == "Go"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set term a b", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetTermNode>(parseSet(
"set terminator")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetTermNode>(parseSet(
"set terminator !")).arg == "!"));
BOOST_TEST((std::get<FrontendParser::SetTermNode>(parseSet(
"set terminator Go")).arg == "Go"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set terminator a b", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetTimeNode>(parseSet(
"set time")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetTimeNode>(parseSet(
"set time on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set time off x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetTransactionNode>(parseSet(
"set transaction")).statement == "set transaction");
BOOST_TEST(std::get<FrontendParser::SetTransactionNode>(parseSet(
"set transaction read committed")).statement == "set transaction read committed");
BOOST_TEST(std::get<FrontendParser::SetWarningsNode>(parseSet(
"set warning")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetWarningsNode>(parseSet(
"set warning on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set warning off x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetWarningsNode>(parseSet(
"set warnings")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetWarningsNode>(parseSet(
"set warnings on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set warnings off x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetWarningsNode>(parseSet(
"set wng")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetWarningsNode>(parseSet(
"set wng on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set wng off x", parserOptions)));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set width", parserOptions)));
BOOST_TEST((std::get<FrontendParser::SetWidthNode>(parseSet(
"set width x")).column == "X"));
BOOST_TEST(std::get<FrontendParser::SetWidthNode>(parseSet(
"set width x")).width.empty());
BOOST_TEST((std::get<FrontendParser::SetWidthNode>(parseSet(
"set width x 80")).column == "X"));
BOOST_TEST((std::get<FrontendParser::SetWidthNode>(parseSet(
"set width x 90")).width == "90"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set width x 90 y", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetWireStatsNode>(parseSet(
"set wire")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetWireStatsNode>(parseSet(
"set wire on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set wire off x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetWireStatsNode>(parseSet(
"set wire_stats")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetWireStatsNode>(parseSet(
"set wire_stats on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set wire_stats off x", parserOptions)));
// Engine commands.
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set decfloat", parserOptions)));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set decfloat x", parserOptions)));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set generator", parserOptions)));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set generator x", parserOptions)));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set role", parserOptions)));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set role x", parserOptions)));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set statistics", parserOptions)));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set statistics x", parserOptions)));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set time zone", parserOptions)));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set trusted", parserOptions)));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set trusted x", parserOptions)));
}
BOOST_AUTO_TEST_CASE(ParseShowTest)
{
const FrontendParser::Options parserOptions;
const auto parseShow = [&](const std::string_view text) {
return std::get<FrontendParser::AnyShowNode>(FrontendParser::parse(text, parserOptions));
};
BOOST_TEST((std::holds_alternative<FrontendParser::ShowNode>(parseShow("show"))));
BOOST_TEST(!std::get<FrontendParser::ShowChecksNode>(parseShow(
"show check")).name);
BOOST_TEST((std::get<FrontendParser::ShowChecksNode>(parseShow(
"show check name")).name == "NAME"));
BOOST_TEST(!std::get<FrontendParser::ShowCollationsNode>(parseShow(
"show collate")).name);
BOOST_TEST((std::get<FrontendParser::ShowCollationsNode>(parseShow(
"show collate name")).name == "NAME"));
BOOST_TEST(!std::get<FrontendParser::ShowCollationsNode>(parseShow(
"show collation")).name);
BOOST_TEST((std::get<FrontendParser::ShowCollationsNode>(parseShow(
"show collation name")).name == "NAME"));
BOOST_TEST(std::holds_alternative<FrontendParser::ShowCommentsNode>(parseShow(
"show comments")));
BOOST_TEST(!std::get<FrontendParser::ShowDependenciesNode>(parseShow(
"show depen")).name);
BOOST_TEST((std::get<FrontendParser::ShowDependenciesNode>(parseShow(
"show depen name")).name == "NAME"));
BOOST_TEST(!std::get<FrontendParser::ShowDomainsNode>(parseShow(
"show domain")).name);
BOOST_TEST((std::get<FrontendParser::ShowDomainsNode>(parseShow(
"show domain name")).name == "NAME"));
BOOST_TEST(!std::get<FrontendParser::ShowExceptionsNode>(parseShow(
"show excep")).name);
BOOST_TEST((std::get<FrontendParser::ShowExceptionsNode>(parseShow(
"show excep name")).name == "NAME"));
BOOST_TEST(!std::get<FrontendParser::ShowFiltersNode>(parseShow(
"show filter")).name);
BOOST_TEST((std::get<FrontendParser::ShowFiltersNode>(parseShow(
"show filter name")).name == "NAME"));
BOOST_TEST(!std::get<FrontendParser::ShowFunctionsNode>(parseShow(
"show func")).name);
BOOST_TEST((std::get<FrontendParser::ShowFunctionsNode>(parseShow(
"show func name")).name == "NAME"));
BOOST_TEST((std::get<FrontendParser::ShowFunctionsNode>(parseShow(
"show func package.name")).package == "PACKAGE"));
BOOST_TEST((std::get<FrontendParser::ShowFunctionsNode>(parseShow(
"show func package.name")).name == "NAME"));
BOOST_TEST(!std::get<FrontendParser::ShowIndexesNode>(parseShow(
"show ind")).name);
BOOST_TEST((std::get<FrontendParser::ShowIndexesNode>(parseShow(
"show index name")).name == "NAME"));
BOOST_TEST((std::get<FrontendParser::ShowIndexesNode>(parseShow(
"show indices name")).name == "NAME"));
BOOST_TEST(!std::get<FrontendParser::ShowGeneratorsNode>(parseShow(
"show gen")).name);
BOOST_TEST((std::get<FrontendParser::ShowGeneratorsNode>(parseShow(
"show generator name")).name == "NAME"));
BOOST_TEST(!std::get<FrontendParser::ShowMappingsNode>(parseShow(
"show map")).name);
BOOST_TEST((std::get<FrontendParser::ShowMappingsNode>(parseShow(
"show mapping name")).name == "NAME"));
BOOST_TEST(!std::get<FrontendParser::ShowPackagesNode>(parseShow(
"show pack")).name);
BOOST_TEST((std::get<FrontendParser::ShowPackagesNode>(parseShow(
"show package name")).name == "NAME"));
BOOST_TEST(!std::get<FrontendParser::ShowProceduresNode>(parseShow(
"show proc")).name);
BOOST_TEST((std::get<FrontendParser::ShowProceduresNode>(parseShow(
"show proc name")).name == "NAME"));
BOOST_TEST((std::get<FrontendParser::ShowProceduresNode>(parseShow(
"show proc package.name")).package == "PACKAGE"));
BOOST_TEST((std::get<FrontendParser::ShowProceduresNode>(parseShow(
"show proc package.name")).name == "NAME"));
BOOST_TEST(!std::get<FrontendParser::ShowPublicationsNode>(parseShow(
"show pub")).name);
BOOST_TEST((std::get<FrontendParser::ShowPublicationsNode>(parseShow(
"show publication name")).name == "NAME"));
BOOST_TEST(!std::get<FrontendParser::ShowRolesNode>(parseShow(
"show role")).name);
BOOST_TEST((std::get<FrontendParser::ShowRolesNode>(parseShow(
"show roles name")).name == "NAME"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"show seccla", parserOptions)));
BOOST_TEST(!std::get<FrontendParser::ShowSecClassesNode>(parseShow(
"show seccla *")).detail);
BOOST_TEST(std::get<FrontendParser::ShowSecClassesNode>(parseShow(
"show seccla * detail")).detail);
BOOST_TEST(!std::get<FrontendParser::ShowSecClassesNode>(parseShow(
"show seccla * detail")).name);
BOOST_TEST((std::get<FrontendParser::ShowSecClassesNode>(parseShow(
"show secclasses name")).name == "NAME"));
BOOST_TEST((!std::get<FrontendParser::ShowSystemNode>(parseShow(
"show system")).objType.has_value()));
BOOST_TEST((!std::get<FrontendParser::ShowSystemNode>(parseShow(
"show system table")).objType == obj_relation));
BOOST_TEST((std::get<FrontendParser::ShowTablesNode>(parseShow(
"show table \"test\"")).name == "test"));
BOOST_TEST((std::get<FrontendParser::ShowTablesNode>(parseShow(
"show table \"te\"\"st\"")).name == "te\"st"));
BOOST_TEST(!std::get<FrontendParser::ShowTablesNode>(parseShow(
"show table")).name);
BOOST_TEST((std::get<FrontendParser::ShowTablesNode>(parseShow(
"show tables name")).name == "NAME"));
BOOST_TEST(!std::get<FrontendParser::ShowTriggersNode>(parseShow(
"show trig")).name);
BOOST_TEST((std::get<FrontendParser::ShowTriggersNode>(parseShow(
"show triggers name")).name == "NAME"));
BOOST_TEST(!std::get<FrontendParser::ShowViewsNode>(parseShow(
"show view")).name);
BOOST_TEST((std::get<FrontendParser::ShowViewsNode>(parseShow(
"show views name")).name == "NAME"));
BOOST_TEST(std::holds_alternative<FrontendParser::ShowWireStatsNode>(parseShow(
"show wire_stat")));
BOOST_TEST(std::holds_alternative<FrontendParser::ShowWireStatsNode>(parseShow(
"show wire_statistics")));
}
BOOST_AUTO_TEST_SUITE_END() // FrontendParserTests
BOOST_AUTO_TEST_SUITE_END() // FrontendParserSuite
BOOST_AUTO_TEST_SUITE_END() // ISqlSuite

View File

@ -4,16 +4,3 @@
#define BOOST_TEST_MODULE ISqlTest
#include "boost/test/included/unit_test.hpp"
// TODO: Remove.
BOOST_AUTO_TEST_SUITE(IsqlSuite)
BOOST_AUTO_TEST_SUITE(DummySuite)
BOOST_AUTO_TEST_CASE(DummyTest)
{
}
BOOST_AUTO_TEST_SUITE_END() // DummySuite
BOOST_AUTO_TEST_SUITE_END() // IsqlSuite

View File

@ -24,6 +24,8 @@
#ifndef JRD_OBJ_H
#define JRD_OBJ_H
#include "../common/gdsassert.h"
// Object types used in RDB$DEPENDENCIES and RDB$USER_PRIVILEGES and stored in backup.
// Note: some values are hard coded in grant.gdl
// Keep existing constants unchanged.
@ -76,10 +78,11 @@ const ObjectType obj_index_condition = 37;
const ObjectType obj_type_MAX = 38;
// used in the parser only / no relation with obj_type_MAX (should be greater)
// not used in metadata / no relation with obj_type_MAX (should be greater)
const ObjectType obj_user_or_role= 100;
const ObjectType obj_parameter = 101;
const ObjectType obj_column = 102;
const ObjectType obj_publication = 103;
const ObjectType obj_any = 255;