Skip to content

Commit

Permalink
[KYUUBI #4080] Support GetTables for Trino Fe
Browse files Browse the repository at this point in the history
### _Why are the changes needed?_

Close #4080, This pr aims to support `GetTables` for Trino Fe

### _How was this patch tested?_
- [x] Add some test cases that check the changes thoroughly including negative and positive cases if possible

- [ ] Add screenshots for manual tests if appropriate

- [x] [Run test](https://kyuubi.apache.org/docs/latest/develop_tools/testing.html#running-tests) locally before make a pull request

Closes #4081 from Yikf/getTables.

Closes #4080

c00564e [Yikf] Support GetTables for Trino Fe

Authored-by: Yikf <yikaifei1@gmail.com>
Signed-off-by: ulysses-you <ulyssesyou@apache.org>
  • Loading branch information
yikf authored and ulysses-you committed Jan 5, 2023
1 parent 8d3d9cc commit bed47ce
Show file tree
Hide file tree
Showing 6 changed files with 258 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,15 @@ GTE : '>=' | '!<';
LEFT_PAREN: '(';
RIGHT_PAREN: ')';
OR: 'OR';
SEARCH_STRING_ESCAPE: '\'' '\\' '\'';

DESC: 'DESC';
DESCRIBE: 'DESCRIBE';
FROM: 'FROM';

FALSE: 'FALSE';
LIKE: 'LIKE';
IN: 'IN';
WHERE: 'WHERE';

KYUUBI: 'KYUUBI';
KYUUBIADMIN: 'KYUUBIADMIN';
Expand All @@ -73,33 +76,41 @@ AUTO_INCREMENT: 'AUTO_INCREMENT';
CASE_SENSITIVE: 'CASE_SENSITIVE';
CREATE_PARAMS: 'CREATE_PARAMS';
DATA_TYPE: 'DATA_TYPE';
ESCAPE: 'ESCAPE';
FIXED_PREC_SCALE: 'FIXED_PREC_SCALE';
IS: 'IS';
LITERAL_PREFIX: 'LITERAL_PREFIX';
LITERAL_SUFFIX: 'LITERAL_SUFFIX';
LOCAL_TYPE_NAME: 'LOCAL_TYPE_NAME';
MAXIMUM_SCALE: 'MAXIMUM_SCALE';
MINIMUM_SCALE: 'MINIMUM_SCALE';
NULL: 'NULL';
NULLABLE: 'NULLABLE';
NUM_PREC_RADIX: 'NUM_PREC_RADIX';
ORDER: 'ORDER';
PRECISION: 'PRECISION';
REMARKS: 'REMARKS';
REF_GENERATION: 'REF_GENERATION';
SEARCHABLE: 'SEARCHABLE';
SELECT: 'SELECT';
SESSION: 'SESSION';
SQL_DATA_TYPE: 'SQL_DATA_TYPE';
SQL_DATETIME_SUB: 'SQL_DATETIME_SUB';
SYSTEM_JDBC_CATALOGS: 'SYSTEM.JDBC.CATALOGS';
SYSTEM_JDBC_SCHEMAS: 'SYSTEM.JDBC.SCHEMAS';
SYSTEM_JDBC_TABLES: 'SYSTEM.JDBC.TABLES';
SYSTEM_JDBC_TABLE_TYPES: 'SYSTEM.JDBC.TABLE_TYPES';
SYSTEM_JDBC_TYPES: 'SYSTEM.JDBC.TYPES';
SELF_REFERENCING_COL_NAME: 'SELF_REFERENCING_COL_NAME';
UNSIGNED_ATTRIBUTE: 'UNSIGNED_ATTRIBUTE';
TABLE_CAT: 'TABLE_CAT';
TABLE_CATALOG: 'TABLE_CATALOG';
TABLE_NAME: 'TABLE_NAME';
TABLE_SCHEM: 'TABLE_SCHEM';
TABLE_TYPE: 'TABLE_TYPE';
TYPE_CAT: 'TYPE_CAT';
TYPE_NAME: 'TYPE_NAME';

WHERE: 'WHERE';
TYPE_SCHEM: 'TYPE_SCHEM';

BACKQUOTED_IDENTIFIER
: '`' ( ~'`' | '``' )* '`'
Expand All @@ -118,7 +129,7 @@ IDENTIFIER
;

STRING
: '\'' ( ~('\''|'\\') | ('\\' .) )* '\''
: '\'' ( ~'\'' | '\'\'' )* '\''
| 'R\'' (~'\'')* '\''
| 'R"'(~'"')* '"'
;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,41 @@ singleStatement
statement
: SELECT TABLE_SCHEM COMMA TABLE_CATALOG FROM SYSTEM_JDBC_SCHEMAS
(WHERE (TABLE_CATALOG EQ catalog=STRING+)? AND? (TABLE_SCHEM LIKE schema=STRING+)?)?
ORDER BY TABLE_CATALOG COMMA TABLE_SCHEM #getSchemas
| SELECT TABLE_CAT FROM SYSTEM_JDBC_CATALOGS ORDER BY TABLE_CAT #getCatalogs
| SELECT TABLE_TYPE FROM SYSTEM_JDBC_TABLE_TYPES ORDER BY TABLE_TYPE #getTableTypes
ORDER BY TABLE_CATALOG COMMA TABLE_SCHEM #getSchemas
| SELECT TABLE_CAT FROM SYSTEM_JDBC_CATALOGS ORDER BY TABLE_CAT #getCatalogs
| SELECT TABLE_TYPE FROM SYSTEM_JDBC_TABLE_TYPES ORDER BY TABLE_TYPE #getTableTypes
| SELECT TYPE_NAME COMMA DATA_TYPE COMMA PRECISION COMMA LITERAL_PREFIX COMMA
LITERAL_SUFFIX COMMA CREATE_PARAMS COMMA NULLABLE COMMA CASE_SENSITIVE COMMA
SEARCHABLE COMMA UNSIGNED_ATTRIBUTE COMMA FIXED_PREC_SCALE COMMA AUTO_INCREMENT
COMMA LOCAL_TYPE_NAME COMMA MINIMUM_SCALE COMMA MAXIMUM_SCALE COMMA SQL_DATA_TYPE
COMMA SQL_DATETIME_SUB COMMA NUM_PREC_RADIX FROM SYSTEM_JDBC_TYPES ORDER BY DATA_TYPE #getTypeInfo
| .*? #passThrough
COMMA SQL_DATETIME_SUB COMMA NUM_PREC_RADIX FROM SYSTEM_JDBC_TYPES ORDER BY DATA_TYPE #getTypeInfo
| SELECT TABLE_CAT COMMA TABLE_SCHEM COMMA TABLE_NAME COMMA TABLE_TYPE COMMA REMARKS COMMA
TYPE_CAT COMMA TYPE_SCHEM COMMA TYPE_NAME COMMA SELF_REFERENCING_COL_NAME COMMA REF_GENERATION
FROM SYSTEM_JDBC_TABLES
(WHERE tableCatalogFilter? AND? tableSchemaFilter? AND? tableNameFilter? AND? tableTypeFilter?)?
ORDER BY TABLE_TYPE COMMA TABLE_CAT COMMA TABLE_SCHEM COMMA TABLE_NAME #getTables
| .*? #passThrough
;

tableCatalogFilter
: TABLE_CAT IS NULL #nullCatalog
| TABLE_CAT EQ catalog=STRING+ #catalogFilter
;

tableSchemaFilter
: TABLE_SCHEM IS NULL #nulTableSchema
| TABLE_SCHEM LIKE schemaPattern=STRING+ ESCAPE SEARCH_STRING_ESCAPE #schemaFilter
;

tableNameFilter
: TABLE_NAME LIKE tableNamePattern=STRING+ ESCAPE SEARCH_STRING_ESCAPE
;

tableTypeFilter
: FALSE #tableTypesAlwaysFalse
| TABLE_TYPE IN '(' stirngInValue (',' stirngInValue)* ')' #typesFilter
;

stirngInValue
: STRING+
;
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@

package org.apache.kyuubi.server.trino.api

import scala.collection.JavaConverters._

import org.apache.hive.service.rpc.thrift.TProtocolVersion

import org.apache.kyuubi.operation.OperationHandle
import org.apache.kyuubi.service.BackendService
import org.apache.kyuubi.sql.parser.trino.KyuubiTrinoFeParser
import org.apache.kyuubi.sql.plan.PassThroughNode
import org.apache.kyuubi.sql.plan.trino.{GetCatalogs, GetSchemas, GetTableTypes, GetTypeInfo}
import org.apache.kyuubi.sql.plan.trino.{GetCatalogs, GetSchemas, GetTables, GetTableTypes, GetTypeInfo}

class KyuubiTrinoOperationTranslator(backendService: BackendService) {
lazy val parser = new KyuubiTrinoFeParser()
Expand All @@ -50,6 +52,15 @@ class KyuubiTrinoOperationTranslator(backendService: BackendService) {
backendService.getTableTypes(sessionHandle)
case GetTypeInfo() =>
backendService.getTypeInfo(sessionHandle)
case GetTables(catalogName, schemaPattern, tableNamePattern, tableTypes, emptyResult) =>
val operationHandle = backendService.getTables(
sessionHandle,
catalogName,
schemaPattern,
tableNamePattern,
tableTypes.asJava)
operationHandle.setHasResultSet(!emptyResult)
operationHandle
case PassThroughNode() =>
backendService.executeStatement(sessionHandle, statement, configs, runAsync, queryTimeout)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,25 @@

package org.apache.kyuubi.sql.parser.trino

import scala.collection.JavaConverters._

import org.antlr.v4.runtime.tree.ParseTree

import org.apache.kyuubi.sql.KyuubiTrinoFeBaseParser._
import org.apache.kyuubi.sql.KyuubiTrinoFeBaseParserBaseVisitor
import org.apache.kyuubi.sql.parser.KyuubiParser
import org.apache.kyuubi.sql.parser.KyuubiParser.unescapeSQLString
import org.apache.kyuubi.sql.plan.{KyuubiTreeNode, PassThroughNode}
import org.apache.kyuubi.sql.plan.trino.{GetCatalogs, GetSchemas, GetTableTypes, GetTypeInfo}
import org.apache.kyuubi.sql.plan.trino.{GetCatalogs, GetSchemas, GetTables, GetTableTypes, GetTypeInfo}

class KyuubiTrinoFeAstBuilder extends KyuubiTrinoFeBaseParserBaseVisitor[AnyRef] {

override def visit(tree: ParseTree): AnyRef = {
Option(tree) match {
case Some(_) => super.visit(tree)
case _ => null
}

}
override def visitSingleStatement(
ctx: SingleStatementContext): KyuubiTreeNode = {
visit(ctx.statement).asInstanceOf[KyuubiTreeNode]
Expand All @@ -38,12 +49,12 @@ class KyuubiTrinoFeAstBuilder extends KyuubiTrinoFeBaseParserBaseVisitor[AnyRef]
val catalog = if (ctx.catalog == null) {
null
} else {
KyuubiParser.unescapeSQLString(ctx.catalog.getText)
unescapeSQLString(ctx.catalog.getText)
}
val schema = if (ctx.schema == null) {
null
} else {
KyuubiParser.unescapeSQLString(ctx.schema.getText)
unescapeSQLString(ctx.schema.getText)
}

GetSchemas(catalog, schema)
Expand All @@ -60,4 +71,47 @@ class KyuubiTrinoFeAstBuilder extends KyuubiTrinoFeBaseParserBaseVisitor[AnyRef]
override def visitGetTypeInfo(ctx: GetTypeInfoContext): KyuubiTreeNode = {
GetTypeInfo()
}

override def visitGetTables(ctx: GetTablesContext): KyuubiTreeNode = {
val catalog = visit(ctx.tableCatalogFilter()).asInstanceOf[String]
val schemaPattern = visit(ctx.tableSchemaFilter()).asInstanceOf[String]
val tableNamePattern = visit(ctx.tableNameFilter()).asInstanceOf[String]

var emptyResult = false
var tableTypes: List[String] = null

ctx.tableTypeFilter() match {
case _: TableTypesAlwaysFalseContext =>
emptyResult = true
case typesFilter: TypesFilterContext =>
tableTypes = visitTypesFilter(typesFilter)
case _ => // ctx.tableTypeFilter is null.
}

GetTables(catalog, schemaPattern, tableNamePattern, tableTypes, emptyResult)
}

override def visitNullCatalog(ctx: NullCatalogContext): AnyRef = {
null
}

override def visitCatalogFilter(ctx: CatalogFilterContext): String = {
unescapeSQLString(ctx.catalog.getText)
}

override def visitNulTableSchema(ctx: NulTableSchemaContext): AnyRef = {
null
}

override def visitSchemaFilter(ctx: SchemaFilterContext): String = {
unescapeSQLString(ctx.schemaPattern.getText)
}

override def visitTableNameFilter(ctx: TableNameFilterContext): String = {
unescapeSQLString(ctx.tableNamePattern.getText)
}

override def visitTypesFilter(ctx: TypesFilterContext): List[String] = {
ctx.stirngInValue().asScala.map(v => unescapeSQLString(v.getText)).toList
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,12 @@ case class GetTableTypes() extends KyuubiTreeNode {
case class GetTypeInfo() extends KyuubiTreeNode {
override def name(): String = "Get Type Info"
}

case class GetTables(
catalogName: String,
schemaPattern: String,
tableNamePattern: String,
tableTypes: List[String],
emptyResult: Boolean = false) extends KyuubiTreeNode {
override def name(): String = "Get Tables"
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ package org.apache.kyuubi.parser.trino
import org.apache.kyuubi.KyuubiFunSuite
import org.apache.kyuubi.sql.parser.trino.KyuubiTrinoFeParser
import org.apache.kyuubi.sql.plan.{KyuubiTreeNode, PassThroughNode}
import org.apache.kyuubi.sql.plan.trino.{GetCatalogs, GetSchemas, GetTableTypes, GetTypeInfo}
import org.apache.kyuubi.sql.plan.trino.{GetCatalogs, GetSchemas, GetTables, GetTableTypes, GetTypeInfo}

class KyuubiTrinoFeParserSuite extends KyuubiFunSuite {
val parser = new KyuubiTrinoFeParser()
Expand Down Expand Up @@ -108,4 +108,134 @@ class KyuubiTrinoFeParserSuite extends KyuubiFunSuite {

assert(kyuubiTreeNode.isInstanceOf[GetTypeInfo])
}

test("Support GetTables for Trino Fe") {
def check(
query: String,
catalog: String = null,
schema: String = null,
tableName: String = null,
types: List[String] = null,
emptyRes: Boolean = false): Unit = {
parse(query) match {
case GetTables(catalogName, schemaPattern, tableNamePattern, tableTypes, emptyResult) =>
assert(catalog == catalogName)
assert(schema == schemaPattern)
assert(tableName == tableNamePattern)
assert(types == tableTypes)
assert(emptyRes == emptyResult)
case _ => fail(s"Query $query parse failed. ")
}
}

check(
"""
| SELECT TABLE_CAT, TABLE_SCHEM, TABLE_NAME, TABLE_TYPE, REMARKS,
| TYPE_CAT, TYPE_SCHEM, TYPE_NAME,
| SELF_REFERENCING_COL_NAME, REF_GENERATION
| FROM system.jdbc.tables
| ORDER BY TABLE_TYPE, TABLE_CAT, TABLE_SCHEM, TABLE_NAME
|""".stripMargin)

check(
"""
| SELECT TABLE_CAT, TABLE_SCHEM, TABLE_NAME, TABLE_TYPE, REMARKS,
| TYPE_CAT, TYPE_SCHEM, TYPE_NAME,
| SELF_REFERENCING_COL_NAME, REF_GENERATION
| FROM system.jdbc.tables
| WHERE TABLE_CAT IS NULL
| ORDER BY TABLE_TYPE, TABLE_CAT, TABLE_SCHEM, TABLE_NAME
|""".stripMargin)

check(
"""
| SELECT TABLE_CAT, TABLE_SCHEM, TABLE_NAME, TABLE_TYPE, REMARKS,
| TYPE_CAT, TYPE_SCHEM, TYPE_NAME,
| SELF_REFERENCING_COL_NAME, REF_GENERATION
| FROM system.jdbc.tables
| WHERE TABLE_CAT = 'ykf_catalog'
| ORDER BY TABLE_TYPE, TABLE_CAT, TABLE_SCHEM, TABLE_NAME
|""".stripMargin,
catalog = "ykf_catalog")

check(
"""
| SELECT TABLE_CAT, TABLE_SCHEM, TABLE_NAME, TABLE_TYPE, REMARKS,
| TYPE_CAT, TYPE_SCHEM, TYPE_NAME,
| SELF_REFERENCING_COL_NAME, REF_GENERATION
| FROM system.jdbc.tables
| WHERE TABLE_CAT = 'ykf_catalog' AND TABLE_SCHEM IS NULL
| ORDER BY TABLE_TYPE, TABLE_CAT, TABLE_SCHEM, TABLE_NAME
|""".stripMargin,
catalog = "ykf_catalog")

check(
"""
| SELECT TABLE_CAT, TABLE_SCHEM, TABLE_NAME, TABLE_TYPE, REMARKS,
| TYPE_CAT, TYPE_SCHEM, TYPE_NAME,
| SELF_REFERENCING_COL_NAME, REF_GENERATION
| FROM system.jdbc.tables
| WHERE TABLE_CAT = 'ykf_catalog' AND TABLE_SCHEM LIKE '%aa' ESCAPE '\'
| ORDER BY TABLE_TYPE, TABLE_CAT, TABLE_SCHEM, TABLE_NAME
|""".stripMargin,
catalog = "ykf_catalog",
"%aa")

check(
"""
| SELECT TABLE_CAT, TABLE_SCHEM, TABLE_NAME, TABLE_TYPE, REMARKS,
| TYPE_CAT, TYPE_SCHEM, TYPE_NAME,
| SELF_REFERENCING_COL_NAME, REF_GENERATION
| FROM system.jdbc.tables
| WHERE TABLE_CAT = 'ykf_catalog' AND TABLE_NAME LIKE '%aa' ESCAPE '\'
| ORDER BY TABLE_TYPE, TABLE_CAT, TABLE_SCHEM, TABLE_NAME
|""".stripMargin,
catalog = "ykf_catalog",
tableName = "%aa")

check(
"""
| SELECT TABLE_CAT, TABLE_SCHEM, TABLE_NAME, TABLE_TYPE, REMARKS,
| TYPE_CAT, TYPE_SCHEM, TYPE_NAME,
| SELF_REFERENCING_COL_NAME, REF_GENERATION
| FROM system.jdbc.tables
| WHERE TABLE_CAT = 'ykf_catalog' AND TABLE_NAME LIKE '%aa' ESCAPE '\' AND FALSE
| ORDER BY TABLE_TYPE, TABLE_CAT, TABLE_SCHEM, TABLE_NAME
|""".stripMargin,
catalog = "ykf_catalog",
tableName = "%aa",
emptyRes = true)

check(
"""
| SELECT TABLE_CAT, TABLE_SCHEM, TABLE_NAME, TABLE_TYPE, REMARKS,
| TYPE_CAT, TYPE_SCHEM, TYPE_NAME,
| SELF_REFERENCING_COL_NAME, REF_GENERATION
| FROM system.jdbc.tables
| WHERE TABLE_CAT = 'ykf_catalog' AND TABLE_SCHEM LIKE '%aa' ESCAPE '\' AND
| TABLE_TYPE IN ('ykf_type', 'ykf2_type')
| ORDER BY TABLE_TYPE, TABLE_CAT, TABLE_SCHEM, TABLE_NAME
|""".stripMargin,
catalog = "ykf_catalog",
schema = "%aa",
types = List("ykf_type", "ykf2_type"))

check(
"""
| SELECT TABLE_CAT, TABLE_SCHEM, TABLE_NAME, TABLE_TYPE, REMARKS,
| TYPE_CAT, TYPE_SCHEM, TYPE_NAME,
| SELF_REFERENCING_COL_NAME, REF_GENERATION
| FROM system.jdbc.tables
| WHERE
| TABLE_CAT = 'ykf_catalog' AND
| TABLE_SCHEM LIKE '%aa' ESCAPE '\' AND
| TABLE_NAME LIKE 'bb%' ESCAPE '\' AND
| TABLE_TYPE IN ('ykf_type', 'ykf2_type')
| ORDER BY TABLE_TYPE, TABLE_CAT, TABLE_SCHEM, TABLE_NAME
|""".stripMargin,
catalog = "ykf_catalog",
schema = "%aa",
tableName = "bb%",
types = List("ykf_type", "ykf2_type"))
}
}

0 comments on commit bed47ce

Please sign in to comment.