mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-22 16:43:03 +01:00
Merge pull request #8358 from FirebirdSQL/work/isql-frontend-parser
Refactor ISQL creating FrontendParser class
This commit is contained in:
commit
797781da66
@ -24,6 +24,7 @@
|
|||||||
<ClCompile Include="..\..\..\gen\isql\extract.cpp" />
|
<ClCompile Include="..\..\..\gen\isql\extract.cpp" />
|
||||||
<ClCompile Include="..\..\..\src\common\fb_exception.cpp" />
|
<ClCompile Include="..\..\..\src\common\fb_exception.cpp" />
|
||||||
<ClCompile Include="..\..\..\src\isql\FrontendLexer.cpp" />
|
<ClCompile Include="..\..\..\src\isql\FrontendLexer.cpp" />
|
||||||
|
<ClCompile Include="..\..\..\src\isql\FrontendParser.cpp" />
|
||||||
<ClCompile Include="..\..\..\src\isql\InputDevices.cpp" />
|
<ClCompile Include="..\..\..\src\isql\InputDevices.cpp" />
|
||||||
<ClCompile Include="..\..\..\gen\isql\isql.cpp" />
|
<ClCompile Include="..\..\..\gen\isql\isql.cpp" />
|
||||||
<ClCompile Include="..\..\..\src\isql\iutils.cpp" />
|
<ClCompile Include="..\..\..\src\isql\iutils.cpp" />
|
||||||
@ -40,6 +41,7 @@
|
|||||||
<ClInclude Include="..\..\..\src\isql\Extender.h" />
|
<ClInclude Include="..\..\..\src\isql\Extender.h" />
|
||||||
<ClInclude Include="..\..\..\src\isql\extra_proto.h" />
|
<ClInclude Include="..\..\..\src\isql\extra_proto.h" />
|
||||||
<ClInclude Include="..\..\..\src\isql\FrontendLexer.h" />
|
<ClInclude Include="..\..\..\src\isql\FrontendLexer.h" />
|
||||||
|
<ClInclude Include="..\..\..\src\isql\FrontendParser.h" />
|
||||||
<ClInclude Include="..\..\..\src\isql\InputDevices.h" />
|
<ClInclude Include="..\..\..\src\isql\InputDevices.h" />
|
||||||
<ClInclude Include="..\..\..\src\isql\isql.h" />
|
<ClInclude Include="..\..\..\src\isql\isql.h" />
|
||||||
<ClInclude Include="..\..\..\src\isql\isql_proto.h" />
|
<ClInclude Include="..\..\..\src\isql\isql_proto.h" />
|
||||||
|
@ -30,6 +30,9 @@
|
|||||||
<ClCompile Include="..\..\..\src\isql\FrontendLexer.cpp">
|
<ClCompile Include="..\..\..\src\isql\FrontendLexer.cpp">
|
||||||
<Filter>ISQL files</Filter>
|
<Filter>ISQL files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\..\src\isql\FrontendParser.cpp">
|
||||||
|
<Filter>ISQL files</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\..\src\isql\InputDevices.cpp">
|
<ClCompile Include="..\..\..\src\isql\InputDevices.cpp">
|
||||||
<Filter>ISQL files</Filter>
|
<Filter>ISQL files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@ -73,6 +76,9 @@
|
|||||||
<ClInclude Include="..\..\..\src\isql\FrontendLexer.h">
|
<ClInclude Include="..\..\..\src\isql\FrontendLexer.h">
|
||||||
<Filter>Header files</Filter>
|
<Filter>Header files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\..\src\isql\FrontendParser.h">
|
||||||
|
<Filter>Header files</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\..\src\isql\InputDevices.h">
|
<ClInclude Include="..\..\..\src\isql\InputDevices.h">
|
||||||
<Filter>Header files</Filter>
|
<Filter>Header files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
@ -177,6 +177,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="..\..\..\src\isql\tests\FrontendLexerTest.cpp" />
|
<ClCompile Include="..\..\..\src\isql\tests\FrontendLexerTest.cpp" />
|
||||||
|
<ClCompile Include="..\..\..\src\isql\tests\FrontendParserTest.cpp" />
|
||||||
<ClCompile Include="..\..\..\src\isql\tests\ISqlTest.cpp" />
|
<ClCompile Include="..\..\..\src\isql\tests\ISqlTest.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -10,6 +10,9 @@
|
|||||||
<ClCompile Include="..\..\..\src\isql\tests\FrontendLexerTest.cpp">
|
<ClCompile Include="..\..\..\src\isql\tests\FrontendLexerTest.cpp">
|
||||||
<Filter>source</Filter>
|
<Filter>source</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\..\src\isql\tests\FrontendParserTest.cpp">
|
||||||
|
<Filter>source</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\..\src\isql\tests\ISqlTest.cpp">
|
<ClCompile Include="..\..\..\src\isql\tests\ISqlTest.cpp">
|
||||||
<Filter>source</Filter>
|
<Filter>source</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
42
src/common/StdHelper.h
Normal file
42
src/common/StdHelper.h
Normal 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
|
@ -93,6 +93,30 @@ public:
|
|||||||
int compare(const AbstractString& s) const { return compare(s.c_str(), s.length()); }
|
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); }
|
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 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; }
|
bool operator==(const AbstractString& s) const { return compare(s) == 0; }
|
||||||
|
@ -28,9 +28,7 @@
|
|||||||
#include <cctype>
|
#include <cctype>
|
||||||
|
|
||||||
|
|
||||||
static std::string trim(std::string_view str);
|
std::string FrontendLexer::trim(std::string_view str)
|
||||||
|
|
||||||
static std::string trim(std::string_view str)
|
|
||||||
{
|
{
|
||||||
auto finish = str.end();
|
auto finish = str.end();
|
||||||
auto start = str.begin();
|
auto start = str.begin();
|
||||||
@ -142,7 +140,7 @@ std::variant<FrontendLexer::SingleStatement, FrontendLexer::IncompleteTokenError
|
|||||||
|
|
||||||
while (pos < end)
|
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);
|
const auto initialStatement = std::string(buffer.cbegin(), pos);
|
||||||
pos += term.length();
|
pos += term.length();
|
||||||
@ -189,22 +187,8 @@ FrontendLexer::Token FrontendLexer::getToken()
|
|||||||
|
|
||||||
switch (toupper(*pos))
|
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 ';':
|
||||||
|
case '.':
|
||||||
token.type = Token::TYPE_OTHER;
|
token.type = Token::TYPE_OTHER;
|
||||||
token.processedText = *pos++;
|
token.processedText = *pos++;
|
||||||
break;
|
break;
|
||||||
@ -224,13 +208,83 @@ FrontendLexer::Token FrontendLexer::getToken()
|
|||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<FrontendLexer::Token> FrontendLexer::getStringToken()
|
FrontendLexer::Token FrontendLexer::getNameToken()
|
||||||
{
|
{
|
||||||
|
skipSpacesAndComments();
|
||||||
|
|
||||||
Token token;
|
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)
|
if (pos >= end)
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
|
|
||||||
|
Token token;
|
||||||
const auto start = pos;
|
const auto start = pos;
|
||||||
|
|
||||||
switch (toupper(*pos))
|
switch (toupper(*pos))
|
||||||
|
@ -39,15 +39,18 @@ public:
|
|||||||
TYPE_EOF,
|
TYPE_EOF,
|
||||||
TYPE_STRING,
|
TYPE_STRING,
|
||||||
TYPE_META_STRING,
|
TYPE_META_STRING,
|
||||||
TYPE_OPEN_PAREN,
|
|
||||||
TYPE_CLOSE_PAREN,
|
|
||||||
TYPE_COMMA,
|
|
||||||
TYPE_OTHER
|
TYPE_OTHER
|
||||||
};
|
};
|
||||||
|
|
||||||
Type type = TYPE_OTHER;
|
Type type = TYPE_OTHER;
|
||||||
std::string rawText;
|
std::string rawText;
|
||||||
std::string processedText;
|
std::string processedText;
|
||||||
|
|
||||||
|
std::string getProcessedString() const
|
||||||
|
{
|
||||||
|
return type == FrontendLexer::Token::TYPE_STRING || type == FrontendLexer::Token::TYPE_META_STRING ?
|
||||||
|
processedText : rawText;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SingleStatement
|
struct SingleStatement
|
||||||
@ -74,6 +77,7 @@ public:
|
|||||||
FrontendLexer& operator=(const FrontendLexer&) = delete;
|
FrontendLexer& operator=(const FrontendLexer&) = delete;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
static std::string trim(std::string_view str);
|
||||||
static std::string stripComments(std::string_view statement);
|
static std::string stripComments(std::string_view statement);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -87,6 +91,11 @@ public:
|
|||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setPos(std::string::const_iterator newPos)
|
||||||
|
{
|
||||||
|
pos = newPos;
|
||||||
|
}
|
||||||
|
|
||||||
void rewind()
|
void rewind()
|
||||||
{
|
{
|
||||||
deletePos = buffer.begin();
|
deletePos = buffer.begin();
|
||||||
@ -97,7 +106,9 @@ public:
|
|||||||
void appendBuffer(std::string_view newBuffer);
|
void appendBuffer(std::string_view newBuffer);
|
||||||
void reset();
|
void reset();
|
||||||
std::variant<SingleStatement, FrontendLexer::IncompleteTokenError> getSingleStatement(std::string_view term);
|
std::variant<SingleStatement, FrontendLexer::IncompleteTokenError> getSingleStatement(std::string_view term);
|
||||||
|
|
||||||
Token getToken();
|
Token getToken();
|
||||||
|
Token getNameToken();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::optional<Token> getStringToken();
|
std::optional<Token> getStringToken();
|
||||||
|
732
src/isql/FrontendParser.cpp
Normal file
732
src/isql/FrontendParser.cpp
Normal 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
285
src/isql/FrontendParser.h
Normal 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
|
1268
src/isql/isql.epp
1268
src/isql/isql.epp
File diff suppressed because it is too large
Load Diff
@ -37,6 +37,7 @@
|
|||||||
#include "../common/utils_proto.h"
|
#include "../common/utils_proto.h"
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
using namespace Firebird;
|
||||||
using MsgFormat::SafeArg;
|
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);
|
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)
|
void IUTILS_printf(FILE* fp, const char* buffer)
|
||||||
{
|
{
|
||||||
/**************************************
|
/**************************************
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#ifndef ISQL_IUTILS_PROTO_H
|
#ifndef ISQL_IUTILS_PROTO_H
|
||||||
#define ISQL_IUTILS_PROTO_H
|
#define ISQL_IUTILS_PROTO_H
|
||||||
|
|
||||||
|
#include "../common/classes/MetaString.h"
|
||||||
#include "../common/classes/SafeArg.h"
|
#include "../common/classes/SafeArg.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
@ -33,6 +34,7 @@ void IUTILS_msg_get(USHORT number, TEXT* msg,
|
|||||||
const MsgFormat::SafeArg& args = MsgFormat::SafeArg());
|
const MsgFormat::SafeArg& args = MsgFormat::SafeArg());
|
||||||
void IUTILS_msg_get(USHORT number, USHORT size, TEXT* msg,
|
void IUTILS_msg_get(USHORT number, USHORT size, TEXT* msg,
|
||||||
const MsgFormat::SafeArg& args = MsgFormat::SafeArg());
|
const MsgFormat::SafeArg& args = MsgFormat::SafeArg());
|
||||||
|
Firebird::string IUTILS_name_to_string(const Firebird::MetaString& name);
|
||||||
void IUTILS_printf(FILE*, const char*);
|
void IUTILS_printf(FILE*, const char*);
|
||||||
void IUTILS_printf2(FILE*, const char*, ...);
|
void IUTILS_printf2(FILE*, const char*, ...);
|
||||||
void IUTILS_put_errmsg(USHORT number, const MsgFormat::SafeArg& args);
|
void IUTILS_put_errmsg(USHORT number, const MsgFormat::SafeArg& args);
|
||||||
|
1317
src/isql/show.epp
1317
src/isql/show.epp
File diff suppressed because it is too large
Load Diff
@ -26,6 +26,7 @@
|
|||||||
|
|
||||||
#include "../common/classes/fb_string.h"
|
#include "../common/classes/fb_string.h"
|
||||||
#include <firebird/Interface.h>
|
#include <firebird/Interface.h>
|
||||||
|
#include "../isql/FrontendParser.h"
|
||||||
#include "../jrd/obj.h"
|
#include "../jrd/obj.h"
|
||||||
|
|
||||||
void SHOW_comments(bool force);
|
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_grant_roles2 (const SCHAR*, bool*, const TEXT*, bool);
|
||||||
void SHOW_print_metadata_text_blob(FILE*, ISC_QUAD*, bool escape_squote = false,
|
void SHOW_print_metadata_text_blob(FILE*, ISC_QUAD*, bool escape_squote = false,
|
||||||
bool avoid_end_in_single_line_comment = 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();
|
void SHOW_read_owner();
|
||||||
const Firebird::string SHOW_trigger_action(SINT64);
|
const Firebird::string SHOW_trigger_action(SINT64);
|
||||||
processing_state SHOW_maps(bool extract, const SCHAR* map_name);
|
processing_state SHOW_maps(bool extract, const SCHAR* map_name);
|
||||||
|
621
src/isql/tests/FrontendParserTest.cpp
Normal file
621
src/isql/tests/FrontendParserTest.cpp
Normal 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
|
@ -4,16 +4,3 @@
|
|||||||
|
|
||||||
#define BOOST_TEST_MODULE ISqlTest
|
#define BOOST_TEST_MODULE ISqlTest
|
||||||
#include "boost/test/included/unit_test.hpp"
|
#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
|
|
||||||
|
@ -24,6 +24,8 @@
|
|||||||
#ifndef JRD_OBJ_H
|
#ifndef JRD_OBJ_H
|
||||||
#define 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.
|
// Object types used in RDB$DEPENDENCIES and RDB$USER_PRIVILEGES and stored in backup.
|
||||||
// Note: some values are hard coded in grant.gdl
|
// Note: some values are hard coded in grant.gdl
|
||||||
// Keep existing constants unchanged.
|
// Keep existing constants unchanged.
|
||||||
@ -76,10 +78,11 @@ const ObjectType obj_index_condition = 37;
|
|||||||
|
|
||||||
const ObjectType obj_type_MAX = 38;
|
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_user_or_role= 100;
|
||||||
const ObjectType obj_parameter = 101;
|
const ObjectType obj_parameter = 101;
|
||||||
const ObjectType obj_column = 102;
|
const ObjectType obj_column = 102;
|
||||||
|
const ObjectType obj_publication = 103;
|
||||||
|
|
||||||
const ObjectType obj_any = 255;
|
const ObjectType obj_any = 255;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user