Simplify DCL for creating quotas.

This commit is contained in:
Vitaly Baranov 2020-04-08 06:09:40 +03:00
parent 23ac1ee87c
commit d548c7e381
9 changed files with 61 additions and 71 deletions

View File

@ -34,7 +34,7 @@ void updateQuotaFromQueryImpl(Quota & quota, const ASTCreateQuotaQuery & query,
auto duration = query_limits.duration; auto duration = query_limits.duration;
auto it = boost::range::find_if(quota_all_limits, [&](const Quota::Limits & x) { return x.duration == duration; }); auto it = boost::range::find_if(quota_all_limits, [&](const Quota::Limits & x) { return x.duration == duration; });
if (query_limits.unset_tracking) if (query_limits.drop)
{ {
if (it != quota_all_limits.end()) if (it != quota_all_limits.end())
quota_all_limits.erase(it); quota_all_limits.erase(it);
@ -59,6 +59,8 @@ void updateQuotaFromQueryImpl(Quota & quota, const ASTCreateQuotaQuery & query,
{ {
if (query_limits.max[resource_type]) if (query_limits.max[resource_type])
quota_limits.max[resource_type] = *query_limits.max[resource_type]; quota_limits.max[resource_type] = *query_limits.max[resource_type];
else
quota_limits.max[resource_type] = Quota::UNLIMITED;
} }
} }

View File

@ -136,7 +136,7 @@ namespace
create_query_limits.duration = limits.duration; create_query_limits.duration = limits.duration;
create_query_limits.randomize_interval = limits.randomize_interval; create_query_limits.randomize_interval = limits.randomize_interval;
for (auto resource_type : ext::range(Quota::MAX_RESOURCE_TYPE)) for (auto resource_type : ext::range(Quota::MAX_RESOURCE_TYPE))
if (limits.max[resource_type]) if (limits.max[resource_type] != Quota::UNLIMITED)
create_query_limits.max[resource_type] = limits.max[resource_type]; create_query_limits.max[resource_type] = limits.max[resource_type];
query->all_limits.push_back(create_query_limits); query->all_limits.push_back(create_query_limits);
} }

View File

@ -28,16 +28,17 @@ namespace
} }
void formatLimit(ResourceType resource_type, ResourceAmount max, const IAST::FormatSettings & settings) void formatLimit(ResourceType resource_type, ResourceAmount max, bool first, const IAST::FormatSettings & settings)
{ {
settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " MAX " << Quota::resourceTypeToKeyword(resource_type) if (first)
<< (settings.hilite ? IAST::hilite_none : ""); settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " MAX" << (settings.hilite ? IAST::hilite_none : "");
else
settings.ostr << ",";
settings.ostr << (settings.hilite ? IAST::hilite_operator : "") << " = " << (settings.hilite ? IAST::hilite_none : ""); settings.ostr << " " << (settings.hilite ? IAST::hilite_keyword : "") << Quota::resourceTypeToKeyword(resource_type)
<< (settings.hilite ? IAST::hilite_none : "") << " ";
if (max == Quota::UNLIMITED) if (resource_type == Quota::EXECUTION_TIME)
settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << "ANY" << (settings.hilite ? IAST::hilite_none : "");
else if (resource_type == Quota::EXECUTION_TIME)
settings.ostr << Quota::executionTimeToSeconds(max); settings.ostr << Quota::executionTimeToSeconds(max);
else else
settings.ostr << max; settings.ostr << max;
@ -59,9 +60,9 @@ namespace
<< interval_kind.toKeyword() << interval_kind.toKeyword()
<< (settings.hilite ? IAST::hilite_none : ""); << (settings.hilite ? IAST::hilite_none : "");
if (limits.unset_tracking) if (limits.drop)
{ {
settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " UNSET TRACKING" << (settings.hilite ? IAST::hilite_none : ""); settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " NO LIMITS" << (settings.hilite ? IAST::hilite_none : "");
} }
else else
{ {
@ -70,14 +71,12 @@ namespace
{ {
if (limits.max[resource_type]) if (limits.max[resource_type])
{ {
if (limit_found) formatLimit(resource_type, *limits.max[resource_type], !limit_found, settings);
settings.ostr << ",";
limit_found = true; limit_found = true;
formatLimit(resource_type, *limits.max[resource_type], settings);
} }
} }
if (!limit_found) if (!limit_found)
settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " TRACKING" << (settings.hilite ? IAST::hilite_none : ""); settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " TRACKING ONLY" << (settings.hilite ? IAST::hilite_none : "");
} }
} }

View File

@ -13,17 +13,16 @@ class ASTExtendedRoleSet;
/** CREATE QUOTA [IF NOT EXISTS | OR REPLACE] name /** CREATE QUOTA [IF NOT EXISTS | OR REPLACE] name
* [KEYED BY {'none' | 'user name' | 'ip address' | 'client key' | 'client key or user name' | 'client key or ip address'}] * [KEYED BY {'none' | 'user name' | 'ip address' | 'client key' | 'client key or user name' | 'client key or ip address'}]
* [FOR [RANDOMIZED] INTERVAL number {SECOND | MINUTE | HOUR | DAY} * [FOR [RANDOMIZED] INTERVAL number {SECOND | MINUTE | HOUR | DAY}
* {[SET] MAX {{QUERIES | ERRORS | RESULT ROWS | RESULT BYTES | READ ROWS | READ BYTES | EXECUTION TIME} = {number | ANY} } [,...] | * {MAX {{QUERIES | ERRORS | RESULT ROWS | RESULT BYTES | READ ROWS | READ BYTES | EXECUTION TIME} = number} [,...] |
* [SET] TRACKING} [,...]] * NO LIMITS | TRACKING ONLY} [,...]]
* [TO {role [,...] | ALL | ALL EXCEPT role [,...]}] * [TO {role [,...] | ALL | ALL EXCEPT role [,...]}]
* *
* ALTER QUOTA [IF EXISTS] name * ALTER QUOTA [IF EXISTS] name
* [RENAME TO new_name] * [RENAME TO new_name]
* [KEYED BY {'none' | 'user name' | 'ip address' | 'client key' | 'client key or user name' | 'client key or ip address'}] * [KEYED BY {'none' | 'user name' | 'ip address' | 'client key' | 'client key or user name' | 'client key or ip address'}]
* [FOR [RANDOMIZED] INTERVAL number {SECOND | MINUTE | HOUR | DAY} * [FOR [RANDOMIZED] INTERVAL number {SECOND | MINUTE | HOUR | DAY}
* {[SET] MAX {{QUERIES | ERRORS | RESULT ROWS | RESULT BYTES | READ ROWS | READ BYTES | EXECUTION TIME} = {number | ANY} } [,...] | * {MAX {{QUERIES | ERRORS | RESULT ROWS | RESULT BYTES | READ ROWS | READ BYTES | EXECUTION TIME} = number} [,...] |
* [SET] TRACKING | * NO LIMITS | TRACKING ONLY} [,...]]
* UNSET TRACKING} [,...]]
* [TO {role [,...] | ALL | ALL EXCEPT role [,...]}] * [TO {role [,...] | ALL | ALL EXCEPT role [,...]}]
*/ */
class ASTCreateQuotaQuery : public IAST, public ASTQueryWithOnCluster class ASTCreateQuotaQuery : public IAST, public ASTQueryWithOnCluster
@ -48,7 +47,7 @@ public:
struct Limits struct Limits
{ {
std::optional<ResourceAmount> max[MAX_RESOURCE_TYPE]; std::optional<ResourceAmount> max[MAX_RESOURCE_TYPE];
bool unset_tracking = false; bool drop = false;
std::chrono::seconds duration = std::chrono::seconds::zero(); std::chrono::seconds duration = std::chrono::seconds::zero();
bool randomize_interval = false; bool randomize_interval = false;
}; };

View File

@ -63,12 +63,22 @@ namespace
}); });
} }
bool parseLimit(IParserBase::Pos & pos, Expected & expected, ResourceType & resource_type, ResourceAmount & max) bool parseLimit(IParserBase::Pos & pos, Expected & expected, bool first, ResourceType & resource_type, ResourceAmount & max)
{ {
return IParserBase::wrapParseImpl(pos, [&] return IParserBase::wrapParseImpl(pos, [&]
{ {
if (!ParserKeyword{"MAX"}.ignore(pos, expected)) if (first)
return false; {
if (!ParserKeyword{"MAX"}.ignore(pos, expected))
return false;
}
else
{
if (!ParserToken{TokenType::Comma}.ignore(pos, expected))
return false;
ParserKeyword{"MAX"}.ignore(pos, expected);
}
bool resource_type_set = false; bool resource_type_set = false;
for (auto rt : ext::range_with_static_cast<Quota::ResourceType>(Quota::MAX_RESOURCE_TYPE)) for (auto rt : ext::range_with_static_cast<Quota::ResourceType>(Quota::MAX_RESOURCE_TYPE))
@ -83,9 +93,6 @@ namespace
if (!resource_type_set) if (!resource_type_set)
return false; return false;
if (!ParserToken{TokenType::Equals}.ignore(pos, expected))
return false;
ASTPtr max_ast; ASTPtr max_ast;
if (ParserNumber{}.parse(pos, max_ast, expected)) if (ParserNumber{}.parse(pos, max_ast, expected))
{ {
@ -95,10 +102,6 @@ namespace
else else
max = applyVisitor(FieldVisitorConvertToNumber<ResourceAmount>(), max_field); max = applyVisitor(FieldVisitorConvertToNumber<ResourceAmount>(), max_field);
} }
else if (ParserKeyword{"ANY"}.ignore(pos, expected))
{
max = Quota::UNLIMITED;
}
else else
return false; return false;
@ -106,18 +109,7 @@ namespace
}); });
} }
bool parseCommaAndLimit(IParserBase::Pos & pos, Expected & expected, ResourceType & resource_type, ResourceAmount & max) bool parseLimits(IParserBase::Pos & pos, Expected & expected, ASTCreateQuotaQuery::Limits & limits)
{
return IParserBase::wrapParseImpl(pos, [&]
{
if (!ParserToken{TokenType::Comma}.ignore(pos, expected))
return false;
return parseLimit(pos, expected, resource_type, max);
});
}
bool parseLimits(IParserBase::Pos & pos, Expected & expected, bool alter, ASTCreateQuotaQuery::Limits & limits)
{ {
return IParserBase::wrapParseImpl(pos, [&] return IParserBase::wrapParseImpl(pos, [&]
{ {
@ -142,23 +134,22 @@ namespace
new_limits.duration = std::chrono::seconds(static_cast<UInt64>(num_intervals * interval_kind.toAvgSeconds())); new_limits.duration = std::chrono::seconds(static_cast<UInt64>(num_intervals * interval_kind.toAvgSeconds()));
if (alter && ParserKeyword{"UNSET TRACKING"}.ignore(pos, expected)) if (ParserKeyword{"NO LIMITS"}.ignore(pos, expected))
{ {
new_limits.unset_tracking = true; new_limits.drop = true;
} }
else if (ParserKeyword{"SET TRACKING"}.ignore(pos, expected) || ParserKeyword{"TRACKING"}.ignore(pos, expected)) else if (ParserKeyword{"TRACKING ONLY"}.ignore(pos, expected))
{ {
} }
else else
{ {
ParserKeyword{"SET"}.ignore(pos, expected);
ResourceType resource_type; ResourceType resource_type;
ResourceAmount max; ResourceAmount max;
if (!parseLimit(pos, expected, resource_type, max)) if (!parseLimit(pos, expected, true, resource_type, max))
return false; return false;
new_limits.max[resource_type] = max; new_limits.max[resource_type] = max;
while (parseCommaAndLimit(pos, expected, resource_type, max)) while (parseLimit(pos, expected, false, resource_type, max))
new_limits.max[resource_type] = max; new_limits.max[resource_type] = max;
} }
@ -167,7 +158,7 @@ namespace
}); });
} }
bool parseAllLimits(IParserBase::Pos & pos, Expected & expected, bool alter, std::vector<ASTCreateQuotaQuery::Limits> & all_limits) bool parseAllLimits(IParserBase::Pos & pos, Expected & expected, std::vector<ASTCreateQuotaQuery::Limits> & all_limits)
{ {
return IParserBase::wrapParseImpl(pos, [&] return IParserBase::wrapParseImpl(pos, [&]
{ {
@ -175,7 +166,7 @@ namespace
do do
{ {
ASTCreateQuotaQuery::Limits limits; ASTCreateQuotaQuery::Limits limits;
if (!parseLimits(pos, expected, alter, limits)) if (!parseLimits(pos, expected, limits))
{ {
all_limits.resize(old_size); all_limits.resize(old_size);
return false; return false;
@ -257,7 +248,7 @@ bool ParserCreateQuotaQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expe
if (!key_type && parseKeyType(pos, expected, key_type)) if (!key_type && parseKeyType(pos, expected, key_type))
continue; continue;
if (parseAllLimits(pos, expected, alter, all_limits)) if (parseAllLimits(pos, expected, all_limits))
continue; continue;
break; break;

View File

@ -9,17 +9,16 @@ namespace DB
* CREATE QUOTA [IF NOT EXISTS | OR REPLACE] name * CREATE QUOTA [IF NOT EXISTS | OR REPLACE] name
* [KEYED BY {'none' | 'user name' | 'ip address' | 'client key' | 'client key or user name' | 'client key or ip address'}] * [KEYED BY {'none' | 'user name' | 'ip address' | 'client key' | 'client key or user name' | 'client key or ip address'}]
* [FOR [RANDOMIZED] INTERVAL number {SECOND | MINUTE | HOUR | DAY} * [FOR [RANDOMIZED] INTERVAL number {SECOND | MINUTE | HOUR | DAY}
* {[SET] MAX {{QUERIES | ERRORS | RESULT ROWS | RESULT BYTES | READ ROWS | READ BYTES | EXECUTION TIME} = {number | ANY} } [,...] | * {MAX {{QUERIES | ERRORS | RESULT ROWS | RESULT BYTES | READ ROWS | READ BYTES | EXECUTION TIME} = number} [,...] |
* [SET] TRACKING} [,...]] * NO LIMITS | TRACKING ONLY} [,...]]
* [TO {role [,...] | ALL | ALL EXCEPT role [,...]}] * [TO {role [,...] | ALL | ALL EXCEPT role [,...]}]
* *
* ALTER QUOTA [IF EXISTS] name * ALTER QUOTA [IF EXISTS] name
* [RENAME TO new_name] * [RENAME TO new_name]
* [KEYED BY {'none' | 'user name' | 'ip address' | 'client key' | 'client key or user name' | 'client key or ip address'}] * [KEYED BY {'none' | 'user name' | 'ip address' | 'client key' | 'client key or user name' | 'client key or ip address'}]
* [FOR [RANDOMIZED] INTERVAL number {SECOND | MINUTE | HOUR | DAY} * [FOR [RANDOMIZED] INTERVAL number {SECOND | MINUTE | HOUR | DAY}
* {[SET] MAX {{QUERIES | ERRORS | RESULT ROWS | RESULT BYTES | READ ROWS | READ BYTES | EXECUTION TIME} = {number | ANY} } [,...] | * {MAX {{QUERIES | ERRORS | RESULT ROWS | RESULT BYTES | READ ROWS | READ BYTES | EXECUTION TIME} = number} } [,...] |
* [SET] TRACKING | * NO LIMITS | TRACKING ONLY} [,...]]
* UNSET TRACKING} [,...]]
* [TO {role [,...] | ALL | ALL EXCEPT role [,...]}] * [TO {role [,...] | ALL | ALL EXCEPT role [,...]}]
*/ */
class ParserCreateQuotaQuery : public IParserBase class ParserCreateQuotaQuery : public IParserBase

View File

@ -22,7 +22,7 @@ def create_entities():
instance.query("CREATE USER u2 IDENTIFIED BY 'qwerty' HOST LOCAL DEFAULT ROLE rx") instance.query("CREATE USER u2 IDENTIFIED BY 'qwerty' HOST LOCAL DEFAULT ROLE rx")
instance.query("CREATE SETTINGS PROFILE s2 SETTINGS PROFILE s1 TO u2") instance.query("CREATE SETTINGS PROFILE s2 SETTINGS PROFILE s1 TO u2")
instance.query("CREATE ROW POLICY p ON mydb.mytable FOR SELECT USING a<1000 TO u1, u2") instance.query("CREATE ROW POLICY p ON mydb.mytable FOR SELECT USING a<1000 TO u1, u2")
instance.query("CREATE QUOTA q FOR INTERVAL 1 HOUR SET MAX QUERIES = 100 TO ALL EXCEPT rx") instance.query("CREATE QUOTA q FOR INTERVAL 1 HOUR MAX QUERIES 100 TO ALL EXCEPT rx")
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
@ -41,7 +41,7 @@ def test_create():
assert instance.query("SHOW CREATE USER u1") == "CREATE USER u1 SETTINGS PROFILE s1\n" assert instance.query("SHOW CREATE USER u1") == "CREATE USER u1 SETTINGS PROFILE s1\n"
assert instance.query("SHOW CREATE USER u2") == "CREATE USER u2 HOST LOCAL DEFAULT ROLE rx\n" assert instance.query("SHOW CREATE USER u2") == "CREATE USER u2 HOST LOCAL DEFAULT ROLE rx\n"
assert instance.query("SHOW CREATE ROW POLICY p ON mydb.mytable") == "CREATE ROW POLICY p ON mydb.mytable FOR SELECT USING a < 1000 TO u1, u2\n" assert instance.query("SHOW CREATE ROW POLICY p ON mydb.mytable") == "CREATE ROW POLICY p ON mydb.mytable FOR SELECT USING a < 1000 TO u1, u2\n"
assert instance.query("SHOW CREATE QUOTA q") == "CREATE QUOTA q KEYED BY \\'none\\' FOR INTERVAL 1 HOUR MAX QUERIES = 100 TO ALL EXCEPT rx\n" assert instance.query("SHOW CREATE QUOTA q") == "CREATE QUOTA q KEYED BY \\'none\\' FOR INTERVAL 1 HOUR MAX QUERIES 100 TO ALL EXCEPT rx\n"
assert instance.query("SHOW GRANTS FOR u1") == "" assert instance.query("SHOW GRANTS FOR u1") == ""
assert instance.query("SHOW GRANTS FOR u2") == "GRANT rx TO u2\n" assert instance.query("SHOW GRANTS FOR u2") == "GRANT rx TO u2\n"
assert instance.query("SHOW CREATE ROLE rx") == "CREATE ROLE rx SETTINGS PROFILE s1\n" assert instance.query("SHOW CREATE ROLE rx") == "CREATE ROLE rx SETTINGS PROFILE s1\n"

View File

@ -180,7 +180,7 @@ def test_reload_users_xml_by_timer():
def test_dcl_introspection(): def test_dcl_introspection():
assert instance.query("SHOW QUOTAS") == "myQuota\n" assert instance.query("SHOW QUOTAS") == "myQuota\n"
assert instance.query("SHOW CREATE QUOTA myQuota") == "CREATE QUOTA myQuota KEYED BY \\'user name\\' FOR INTERVAL 1 YEAR MAX QUERIES = 1000, MAX READ ROWS = 1000 TO default\n" assert instance.query("SHOW CREATE QUOTA myQuota") == "CREATE QUOTA myQuota KEYED BY \\'user name\\' FOR INTERVAL 1 YEAR MAX QUERIES 1000, READ ROWS 1000 TO default\n"
expected_usage = "myQuota key=\\\\'default\\\\' interval=\[.*\] queries=0/1000 errors=0 result_rows=0 result_bytes=0 read_rows=0/1000 read_bytes=0 execution_time=0" expected_usage = "myQuota key=\\\\'default\\\\' interval=\[.*\] queries=0/1000 errors=0 result_rows=0 result_bytes=0 read_rows=0/1000 read_bytes=0 execution_time=0"
assert re.match(expected_usage, instance.query("SHOW QUOTA USAGE")) assert re.match(expected_usage, instance.query("SHOW QUOTA USAGE"))
assert re.match(expected_usage, instance.query("SHOW QUOTA USAGE CURRENT")) assert re.match(expected_usage, instance.query("SHOW QUOTA USAGE CURRENT"))
@ -193,7 +193,7 @@ def test_dcl_introspection():
# Add interval. # Add interval.
copy_quota_xml('two_intervals.xml') copy_quota_xml('two_intervals.xml')
assert instance.query("SHOW QUOTAS") == "myQuota\n" assert instance.query("SHOW QUOTAS") == "myQuota\n"
assert instance.query("SHOW CREATE QUOTA myQuota") == "CREATE QUOTA myQuota KEYED BY \\'user name\\' FOR INTERVAL 1 YEAR MAX QUERIES = 1000, MAX READ ROWS = 1000, FOR RANDOMIZED INTERVAL 2 YEAR MAX RESULT BYTES = 30000, MAX READ BYTES = 20000, MAX EXECUTION TIME = 120 TO default\n" assert instance.query("SHOW CREATE QUOTA myQuota") == "CREATE QUOTA myQuota KEYED BY \\'user name\\' FOR INTERVAL 1 YEAR MAX QUERIES 1000, READ ROWS 1000, FOR RANDOMIZED INTERVAL 2 YEAR MAX RESULT BYTES 30000, READ BYTES 20000, EXECUTION TIME 120 TO default\n"
expected_usage = "myQuota key=\\\\'default\\\\' interval=\[.*\] queries=1/1000 errors=0 result_rows=50 result_bytes=200 read_rows=50/1000 read_bytes=200 execution_time=.*\n"\ expected_usage = "myQuota key=\\\\'default\\\\' interval=\[.*\] queries=1/1000 errors=0 result_rows=50 result_bytes=200 read_rows=50/1000 read_bytes=200 execution_time=.*\n"\
"myQuota key=\\\\'default\\\\' interval=\[.*\] queries=0 errors=0 result_rows=0 result_bytes=0/30000 read_rows=0 read_bytes=0/20000 execution_time=0/120" "myQuota key=\\\\'default\\\\' interval=\[.*\] queries=0 errors=0 result_rows=0 result_bytes=0/30000 read_rows=0 read_bytes=0/20000 execution_time=0/120"
assert re.match(expected_usage, instance.query("SHOW QUOTA USAGE")) assert re.match(expected_usage, instance.query("SHOW QUOTA USAGE"))
@ -201,8 +201,8 @@ def test_dcl_introspection():
# Drop interval, add quota. # Drop interval, add quota.
copy_quota_xml('two_quotas.xml') copy_quota_xml('two_quotas.xml')
assert instance.query("SHOW QUOTAS") == "myQuota\nmyQuota2\n" assert instance.query("SHOW QUOTAS") == "myQuota\nmyQuota2\n"
assert instance.query("SHOW CREATE QUOTA myQuota") == "CREATE QUOTA myQuota KEYED BY \\'user name\\' FOR INTERVAL 1 YEAR MAX QUERIES = 1000, MAX READ ROWS = 1000 TO default\n" assert instance.query("SHOW CREATE QUOTA myQuota") == "CREATE QUOTA myQuota KEYED BY \\'user name\\' FOR INTERVAL 1 YEAR MAX QUERIES 1000, READ ROWS 1000 TO default\n"
assert instance.query("SHOW CREATE QUOTA myQuota2") == "CREATE QUOTA myQuota2 KEYED BY \\'client key or user name\\' FOR RANDOMIZED INTERVAL 1 HOUR MAX RESULT ROWS = 4000, MAX RESULT BYTES = 400000, MAX READ ROWS = 4000, MAX READ BYTES = 400000, MAX EXECUTION TIME = 60, FOR INTERVAL 1 MONTH MAX EXECUTION TIME = 1800\n" assert instance.query("SHOW CREATE QUOTA myQuota2") == "CREATE QUOTA myQuota2 KEYED BY \\'client key or user name\\' FOR RANDOMIZED INTERVAL 1 HOUR MAX RESULT ROWS 4000, RESULT BYTES 400000, READ ROWS 4000, READ BYTES 400000, EXECUTION TIME 60, FOR INTERVAL 1 MONTH MAX EXECUTION TIME 1800\n"
expected_usage = "myQuota key=\\\\'default\\\\' interval=\[.*\] queries=1/1000 errors=0 result_rows=50 result_bytes=200 read_rows=50/1000 read_bytes=200 execution_time=.*" expected_usage = "myQuota key=\\\\'default\\\\' interval=\[.*\] queries=1/1000 errors=0 result_rows=50 result_bytes=200 read_rows=50/1000 read_bytes=200 execution_time=.*"
assert re.match(expected_usage, instance.query("SHOW QUOTA USAGE")) assert re.match(expected_usage, instance.query("SHOW QUOTA USAGE"))
@ -212,9 +212,9 @@ def test_dcl_management():
assert instance.query("SHOW QUOTAS") == "" assert instance.query("SHOW QUOTAS") == ""
assert instance.query("SHOW QUOTA USAGE") == "" assert instance.query("SHOW QUOTA USAGE") == ""
instance.query("CREATE QUOTA qA FOR INTERVAL 15 MONTH SET MAX QUERIES = 123 TO CURRENT_USER") instance.query("CREATE QUOTA qA FOR INTERVAL 15 MONTH MAX QUERIES 123 TO CURRENT_USER")
assert instance.query("SHOW QUOTAS") == "qA\n" assert instance.query("SHOW QUOTAS") == "qA\n"
assert instance.query("SHOW CREATE QUOTA qA") == "CREATE QUOTA qA KEYED BY \\'none\\' FOR INTERVAL 5 QUARTER MAX QUERIES = 123 TO default\n" assert instance.query("SHOW CREATE QUOTA qA") == "CREATE QUOTA qA KEYED BY \\'none\\' FOR INTERVAL 5 QUARTER MAX QUERIES 123 TO default\n"
expected_usage = "qA key=\\\\'\\\\' interval=\[.*\] queries=0/123 errors=0 result_rows=0 result_bytes=0 read_rows=0 read_bytes=0 execution_time=.*" expected_usage = "qA key=\\\\'\\\\' interval=\[.*\] queries=0/123 errors=0 result_rows=0 result_bytes=0 read_rows=0 read_bytes=0 execution_time=.*"
assert re.match(expected_usage, instance.query("SHOW QUOTA USAGE")) assert re.match(expected_usage, instance.query("SHOW QUOTA USAGE"))
@ -222,14 +222,14 @@ def test_dcl_management():
expected_usage = "qA key=\\\\'\\\\' interval=\[.*\] queries=1/123 errors=0 result_rows=50 result_bytes=200 read_rows=50 read_bytes=200 execution_time=.*" expected_usage = "qA key=\\\\'\\\\' interval=\[.*\] queries=1/123 errors=0 result_rows=50 result_bytes=200 read_rows=50 read_bytes=200 execution_time=.*"
assert re.match(expected_usage, instance.query("SHOW QUOTA USAGE")) assert re.match(expected_usage, instance.query("SHOW QUOTA USAGE"))
instance.query("ALTER QUOTA qA FOR INTERVAL 15 MONTH MAX QUERIES = 321, MAX ERRORS = 10, FOR INTERVAL 0.5 HOUR MAX EXECUTION TIME = 0.5") instance.query("ALTER QUOTA qA FOR INTERVAL 15 MONTH MAX QUERIES 321, MAX ERRORS 10, FOR INTERVAL 0.5 HOUR MAX EXECUTION TIME 0.5")
assert instance.query("SHOW CREATE QUOTA qA") == "CREATE QUOTA qA KEYED BY \\'none\\' FOR INTERVAL 30 MINUTE MAX EXECUTION TIME = 0.5, FOR INTERVAL 5 QUARTER MAX QUERIES = 321, MAX ERRORS = 10 TO default\n" assert instance.query("SHOW CREATE QUOTA qA") == "CREATE QUOTA qA KEYED BY \\'none\\' FOR INTERVAL 30 MINUTE MAX EXECUTION TIME 0.5, FOR INTERVAL 5 QUARTER MAX QUERIES 321, ERRORS 10 TO default\n"
expected_usage = "qA key=\\\\'\\\\' interval=\[.*\] queries=0 errors=0 result_rows=0 result_bytes=0 read_rows=0 read_bytes=0 execution_time=.*/0.5\n"\ expected_usage = "qA key=\\\\'\\\\' interval=\[.*\] queries=0 errors=0 result_rows=0 result_bytes=0 read_rows=0 read_bytes=0 execution_time=.*/0.5\n"\
"qA key=\\\\'\\\\' interval=\[.*\] queries=1/321 errors=0/10 result_rows=50 result_bytes=200 read_rows=50 read_bytes=200 execution_time=.*" "qA key=\\\\'\\\\' interval=\[.*\] queries=1/321 errors=0/10 result_rows=50 result_bytes=200 read_rows=50 read_bytes=200 execution_time=.*"
assert re.match(expected_usage, instance.query("SHOW QUOTA USAGE")) assert re.match(expected_usage, instance.query("SHOW QUOTA USAGE"))
instance.query("ALTER QUOTA qA FOR INTERVAL 15 MONTH UNSET TRACKING, FOR RANDOMIZED INTERVAL 16 MONTH SET TRACKING, FOR INTERVAL 1800 SECOND UNSET TRACKING") instance.query("ALTER QUOTA qA FOR INTERVAL 15 MONTH NO LIMITS, FOR RANDOMIZED INTERVAL 16 MONTH TRACKING ONLY, FOR INTERVAL 1800 SECOND NO LIMITS")
assert instance.query("SHOW CREATE QUOTA qA") == "CREATE QUOTA qA KEYED BY \\'none\\' FOR RANDOMIZED INTERVAL 16 MONTH TRACKING TO default\n" assert instance.query("SHOW CREATE QUOTA qA") == "CREATE QUOTA qA KEYED BY \\'none\\' FOR RANDOMIZED INTERVAL 16 MONTH TRACKING ONLY TO default\n"
expected_usage = "qA key=\\\\'\\\\' interval=\[.*\] queries=0 errors=0 result_rows=0 result_bytes=0 read_rows=0 read_bytes=0 execution_time=.*" expected_usage = "qA key=\\\\'\\\\' interval=\[.*\] queries=0 errors=0 result_rows=0 result_bytes=0 read_rows=0 read_bytes=0 execution_time=.*"
assert re.match(expected_usage, instance.query("SHOW QUOTA USAGE")) assert re.match(expected_usage, instance.query("SHOW QUOTA USAGE"))
@ -238,7 +238,7 @@ def test_dcl_management():
assert re.match(expected_usage, instance.query("SHOW QUOTA USAGE")) assert re.match(expected_usage, instance.query("SHOW QUOTA USAGE"))
instance.query("ALTER QUOTA qA RENAME TO qB") instance.query("ALTER QUOTA qA RENAME TO qB")
assert instance.query("SHOW CREATE QUOTA qB") == "CREATE QUOTA qB KEYED BY \\'none\\' FOR RANDOMIZED INTERVAL 16 MONTH TRACKING TO default\n" assert instance.query("SHOW CREATE QUOTA qB") == "CREATE QUOTA qB KEYED BY \\'none\\' FOR RANDOMIZED INTERVAL 16 MONTH TRACKING ONLY TO default\n"
expected_usage = "qB key=\\\\'\\\\' interval=\[.*\] queries=1 errors=0 result_rows=50 result_bytes=200 read_rows=50 read_bytes=200 execution_time=.*" expected_usage = "qB key=\\\\'\\\\' interval=\[.*\] queries=1 errors=0 result_rows=50 result_bytes=200 read_rows=50 read_bytes=200 execution_time=.*"
assert re.match(expected_usage, instance.query("SHOW QUOTA USAGE")) assert re.match(expected_usage, instance.query("SHOW QUOTA USAGE"))

View File

@ -1,2 +1,2 @@
default default
CREATE QUOTA default KEYED BY \'user name\' FOR INTERVAL 1 HOUR TRACKING TO default, readonly CREATE QUOTA default KEYED BY \'user name\' FOR INTERVAL 1 HOUR TRACKING ONLY TO default, readonly