Skip to content

Commit

Permalink
Merge 'cql3:statements:describe_statement: include UDT/UDF/UDA in gen…
Browse files Browse the repository at this point in the history
…eric describe' from Michał Jadwiszczak

So far generic describe (`DESC <name>`) followed Cassandra implementation and it only described keyspace/table/view/index.

This commit adds UDT/UDF/UDA to generic describe.

Fixes: #14170

Closes #14334

* github.com:scylladb/scylladb:
  docs:cql: add information  about generic describe
  cql-pytest:test_describe: add test for generic UDT/UDF/UDA desc
  cql3:statements:describe_statement: include UDT/UDF/UDA in generic describe
  • Loading branch information
nyh committed Sep 24, 2023
2 parents 762ca61 + 2071ade commit 4e1e756
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 1 deletion.
33 changes: 33 additions & 0 deletions cql3/statements/describe_statement.cc
Expand Up @@ -659,6 +659,7 @@ std::vector<lw_shared_ptr<column_specification>> generic_describe_statement::get

future<std::vector<std::vector<bytes_opt>>> generic_describe_statement::describe(cql3::query_processor& qp, const service::client_state& client_state) const {
auto db = qp.db();
auto& replica_db = db.real_database();
auto raw_ks = client_state.get_raw_keyspace();
auto ks_name = (_keyspace) ? *_keyspace : raw_ks;

Expand All @@ -671,6 +672,12 @@ future<std::vector<std::vector<bytes_opt>>> generic_describe_statement::describe
throw exceptions::invalid_request_exception(format("'{}' not found in keyspaces", _name));
}
}

auto ks = db.try_find_keyspace(ks_name);
if (!ks) {
throw exceptions::invalid_request_exception(format("'{}' not found in keyspaces", _name));
}
auto ks_meta = ks->metadata();

auto tbl = db.try_find_table(ks_name, _name);
if (tbl) {
Expand All @@ -686,6 +693,32 @@ future<std::vector<std::vector<bytes_opt>>> generic_describe_statement::describe
co_return serialize_descriptions({index(db, ks_name, _name, _with_internals)});
}

auto udt_meta = ks_meta->user_types();
if (udt_meta.has_type(to_bytes(_name))) {
co_return serialize_descriptions({type(replica_db, ks_meta, _name)});
}

auto uf = functions::functions::find(functions::function_name(ks_name, _name));
if (!uf.empty()) {
auto udfs = boost::copy_range<std::vector<shared_ptr<const keyspace_element>>>(uf | boost::adaptors::transformed([] (const auto& f) {
return dynamic_pointer_cast<const functions::user_function>(f.second);
}) | boost::adaptors::filtered([] (const auto& f) {
return f != nullptr;
}));
if (!udfs.empty()) {
co_return serialize_descriptions(co_await generate_descriptions(replica_db, udfs, true));
}

auto udas = boost::copy_range<std::vector<shared_ptr<const keyspace_element>>>(uf | boost::adaptors::transformed([] (const auto& f) {
return dynamic_pointer_cast<const functions::user_aggregate>(f.second);
}) | boost::adaptors::filtered([] (const auto& f) {
return f != nullptr;
}));
if (!udas.empty()) {
co_return serialize_descriptions(co_await generate_descriptions(replica_db, udas, true));
}
}

throw exceptions::invalid_request_exception(format("'{}' not found in keyspace '{}'", _name, ks_name));
}

Expand Down
3 changes: 3 additions & 0 deletions docs/cql/cqlsh.rst
Expand Up @@ -380,6 +380,9 @@ dumping all or portions of the schema.
In any of the commands, ``DESC`` may be used in place of ``DESCRIBE``.

You may also omit what you want to describe and just simply use ``DESCRIBE <name>``. This will look for the object
in a specific order: keyspace, table, view, index, user-defined type, user-defined function, user-defined aggregate.

The ``DESCRIBE CLUSTER`` command prints the cluster name and partitioner::


Expand Down
32 changes: 31 additions & 1 deletion test/cql-pytest/test_describe.py
Expand Up @@ -439,7 +439,16 @@ def test_index_desc_in_table_desc(cql, test_keyspace):
assert create_idx_c in desc
assert f"CREATE INDEX {tbl_name}_b_idx_1 ON {tbl}((a), b)" in desc

# Test that generic 'DESC' works properly. It should be able to describe keyspace, table.
# -----------------------------------------------------------------------------
# "Generic describe" is a describe statement without specifying what kind of object
# you want to describe, so it only requires keyspace name(optionally) and object name.
# Genric describe should be exactly the same as normal describe, so for instannce:
# `DESC TABLE <table_name> == DESC <table_name>`.
#
# ScyllaDB looks for describing object in a following order:
# keyspace, table, view, index, UDT, UDF, UDA

# Cassandra compatibility require us to be able generic describe: keyspace, table, view, index.
def test_generic_desc(cql, random_seed):
with new_random_keyspace(cql) as ks:
with new_random_table(cql, ks) as t1, new_test_table(cql, ks, "a int primary key, b int, c int") as tbl:
Expand All @@ -460,6 +469,27 @@ def test_generic_desc(cql, random_seed):
assert generic_tbl == desc_tbl
assert generic_idx == desc_idx

# We've extended generic describe to include user-defined objects: UDTs, UDFs and UDAs.
# Since Cassandra doesn't generic description of support user-defined objects,
# the test is `scylla_only`.
# Reproduces #14170
def test_generic_desc_user_defined(scylla_only, cql, test_keyspace):
with new_random_type(cql, test_keyspace) as udt:
assert cql.execute(f"DESC {udt}") == cql.execute(f"DESC TYPE {udt}")

with new_function(cql, test_keyspace, """
(val1 int, val2 int)
RETURNS NULL ON NULL INPUT
RETURNS int
LANGUAGE lua
AS 'return val1 + val2'
""") as fn:
assert cql.execute(f"DESC {test_keyspace}.{fn}") == cql.execute(f"DESC FUNCTION {test_keyspace}.{fn}")

with new_aggregate(cql, test_keyspace, f"(int) SFUNC {fn} STYPE int INITCOND 0") as aggr:
assert cql.execute(f"DESC {test_keyspace}.{aggr}") == cql.execute(f"DESC AGGREGATE {test_keyspace}.{aggr}")


# Test that 'DESC FUNCTION'/'DESC AGGREGATE' doesn't show UDA/UDF and doesn't crash Scylla
def test_desc_udf_uda(cql, test_keyspace):
with new_function(cql, test_keyspace, "(a int, b int) RETURNS NULL ON NULL INPUT RETURNS int LANGUAGE LUA AS 'return a+b'") as fn:
Expand Down

0 comments on commit 4e1e756

Please sign in to comment.