Skip to content

Commit 8c84dd8

Browse files
author
Andrew Or
committed
Implement tests for functions
1 parent 3da16fb commit 8c84dd8

File tree

2 files changed

+206
-1
lines changed

2 files changed

+206
-1
lines changed

sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/catalog/SessionCatalog.scala

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -465,7 +465,18 @@ class SessionCatalog(externalCatalog: ExternalCatalog) {
465465
val functionsInCurrentDb = externalCatalog.listFunctions(currentDb, pattern).map { f =>
466466
FunctionIdentifier(f, Some(currentDb))
467467
}
468-
functionsInCurrentDb ++ tempFunctions.keys.asScala.map { f => FunctionIdentifier(f) }
468+
val regex = pattern.replaceAll("\\*", ".*").r
469+
val _tempFunctions = tempFunctions.keys().asScala
470+
.filter { f => regex.pattern.matcher(f).matches() }
471+
.map { f => FunctionIdentifier(f) }
472+
functionsInCurrentDb ++ _tempFunctions
473+
}
474+
475+
/**
476+
* Return a temporary function. For testing only.
477+
*/
478+
private[catalog] def getTempFunction(name: String): Option[CatalogFunction] = {
479+
Option(tempFunctions.get(name))
469480
}
470481

471482
}

sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/catalog/SessionCatalogSuite.scala

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,4 +528,198 @@ class SessionCatalogSuite extends SparkFunSuite {
528528
}
529529
}
530530

531+
// --------------------------------------------------------------------------
532+
// Functions
533+
// --------------------------------------------------------------------------
534+
535+
test("basic create and list functions") {
536+
val externalCatalog = newEmptyCatalog()
537+
val sessionCatalog = new SessionCatalog(externalCatalog)
538+
sessionCatalog.createDatabase(newDb("mydb"), ignoreIfExists = false)
539+
sessionCatalog.createFunction("mydb", newFunc("myfunc"))
540+
assert(externalCatalog.listFunctions("mydb", "*").toSet == Set("myfunc"))
541+
}
542+
543+
test("create function when database does not exist") {
544+
val catalog = new SessionCatalog(newBasicCatalog())
545+
intercept[AnalysisException] {
546+
catalog.createFunction("does_not_exist", newFunc())
547+
}
548+
}
549+
550+
test("create function that already exists") {
551+
val catalog = new SessionCatalog(newBasicCatalog())
552+
intercept[AnalysisException] {
553+
catalog.createFunction("db2", newFunc("func1"))
554+
}
555+
}
556+
557+
test("create temp function") {
558+
val catalog = new SessionCatalog(newBasicCatalog())
559+
val tempFunc1 = newFunc("temp1")
560+
val tempFunc2 = newFunc("temp2")
561+
catalog.createTempFunction(tempFunc1, ignoreIfExists = false)
562+
catalog.createTempFunction(tempFunc2, ignoreIfExists = false)
563+
assert(catalog.getTempFunction("temp1") == Some(tempFunc1))
564+
assert(catalog.getTempFunction("temp2") == Some(tempFunc2))
565+
assert(catalog.getTempFunction("temp3") == None)
566+
// Temporary function already exists
567+
intercept[AnalysisException] {
568+
catalog.createTempFunction(tempFunc1, ignoreIfExists = false)
569+
}
570+
// Temporary function is overridden
571+
val tempFunc3 = tempFunc1.copy(className = "something else")
572+
catalog.createTempFunction(tempFunc3, ignoreIfExists = true)
573+
assert(catalog.getTempFunction("temp1") == Some(tempFunc3))
574+
}
575+
576+
test("drop function") {
577+
val externalCatalog = newBasicCatalog()
578+
val sessionCatalog = new SessionCatalog(externalCatalog)
579+
assert(externalCatalog.listFunctions("db2", "*").toSet == Set("func1"))
580+
sessionCatalog.dropFunction("db2", FunctionIdentifier("func1"))
581+
assert(externalCatalog.listFunctions("db2", "*").isEmpty)
582+
}
583+
584+
test("drop function when database does not exist") {
585+
val catalog = new SessionCatalog(newBasicCatalog())
586+
intercept[AnalysisException] {
587+
catalog.dropFunction("does_not_exist", FunctionIdentifier("something"))
588+
}
589+
}
590+
591+
test("drop function that does not exist") {
592+
val catalog = new SessionCatalog(newBasicCatalog())
593+
intercept[AnalysisException] {
594+
catalog.dropFunction("db2", FunctionIdentifier("does_not_exist"))
595+
}
596+
}
597+
598+
test("drop temp function") {
599+
val catalog = new SessionCatalog(newBasicCatalog())
600+
val tempFunc = newFunc("func1")
601+
catalog.createTempFunction(tempFunc, ignoreIfExists = false)
602+
assert(catalog.getTempFunction("func1") == Some(tempFunc))
603+
catalog.dropTempFunction("func1", ignoreIfNotExists = false)
604+
assert(catalog.getTempFunction("func1") == None)
605+
intercept[AnalysisException] {
606+
catalog.dropTempFunction("func1", ignoreIfNotExists = false)
607+
}
608+
catalog.dropTempFunction("func1", ignoreIfNotExists = true)
609+
}
610+
611+
test("get function") {
612+
val catalog = new SessionCatalog(newBasicCatalog())
613+
assert(catalog.getFunction("db2", FunctionIdentifier("func1")) ==
614+
CatalogFunction(FunctionIdentifier("func1", Some("db2")), funcClass))
615+
intercept[AnalysisException] {
616+
catalog.getFunction("db2", FunctionIdentifier("does_not_exist"))
617+
}
618+
}
619+
620+
test("get function when database does not exist") {
621+
val catalog = new SessionCatalog(newBasicCatalog())
622+
intercept[AnalysisException] {
623+
catalog.getFunction("does_not_exist", FunctionIdentifier("func1"))
624+
}
625+
}
626+
627+
test("get temp function") {
628+
val externalCatalog = newBasicCatalog()
629+
val sessionCatalog = new SessionCatalog(externalCatalog)
630+
val metastoreFunc = externalCatalog.getFunction("db2", "func1")
631+
val tempFunc = newFunc("func1").copy(className = "something weird")
632+
sessionCatalog.createTempFunction(tempFunc, ignoreIfExists = false)
633+
// If a database is specified, we'll always return the function in that database
634+
assert(sessionCatalog.getFunction("db2", FunctionIdentifier("func1", Some("db2")))
635+
== metastoreFunc)
636+
// If no database is specified, we'll first return temporary functions
637+
assert(sessionCatalog.getFunction("db2", FunctionIdentifier("func1")) == tempFunc)
638+
// Then, if no such temporary function exist, check the current database
639+
sessionCatalog.dropTempFunction("func1", ignoreIfNotExists = false)
640+
assert(sessionCatalog.getFunction("db2", FunctionIdentifier("func1")) == metastoreFunc)
641+
}
642+
643+
test("rename function") {
644+
val catalog = new SessionCatalog(newBasicCatalog())
645+
val newName = "funcky"
646+
assert(catalog.getFunction("db2", FunctionIdentifier("func1")).className == funcClass)
647+
catalog.renameFunction("db2", FunctionIdentifier("func1"), FunctionIdentifier(newName))
648+
intercept[AnalysisException] { catalog.getFunction("db2", FunctionIdentifier("func1")) }
649+
assert(catalog.getFunction("db2", FunctionIdentifier(newName)).name.funcName == newName)
650+
assert(catalog.getFunction("db2", FunctionIdentifier(newName)).className == funcClass)
651+
intercept[AnalysisException] {
652+
catalog.renameFunction("db2", FunctionIdentifier("does_not_exist"), FunctionIdentifier("x"))
653+
}
654+
}
655+
656+
test("rename function when database does not exist") {
657+
val catalog = new SessionCatalog(newBasicCatalog())
658+
intercept[AnalysisException] {
659+
catalog.renameFunction(
660+
"does_not_exist", FunctionIdentifier("func1"), FunctionIdentifier("func5"))
661+
}
662+
}
663+
664+
test("rename temp function") {
665+
val externalCatalog = newBasicCatalog()
666+
val sessionCatalog = new SessionCatalog(externalCatalog)
667+
val tempFunc = newFunc("func1").copy(className = "something weird")
668+
sessionCatalog.createTempFunction(tempFunc, ignoreIfExists = false)
669+
// If a database is specified, we'll always rename the function in that database
670+
sessionCatalog.renameFunction(
671+
"db2", FunctionIdentifier("func1", Some("db2")), FunctionIdentifier("func3", Some("db2")))
672+
assert(sessionCatalog.getTempFunction("func1") == Some(tempFunc))
673+
assert(sessionCatalog.getTempFunction("func3") == None)
674+
assert(externalCatalog.listFunctions("db2", "*").toSet == Set("func3"))
675+
sessionCatalog.createFunction("db2", newFunc("func1", Some("db2")))
676+
// If no database is specified, we'll first rename temporary functions
677+
sessionCatalog.renameFunction("db2", FunctionIdentifier("func1"), FunctionIdentifier("func4"))
678+
assert(sessionCatalog.getTempFunction("func4") ==
679+
Some(tempFunc.copy(name = FunctionIdentifier("func4"))))
680+
assert(sessionCatalog.getTempFunction("func1") == None)
681+
assert(externalCatalog.listFunctions("db2", "*").toSet == Set("func1", "func3"))
682+
// Then, if no such temporary function exist, rename the function in the current database
683+
sessionCatalog.renameFunction("db2", FunctionIdentifier("func1"), FunctionIdentifier("func5"))
684+
assert(sessionCatalog.getTempFunction("func5") == None)
685+
assert(externalCatalog.listFunctions("db2", "*").toSet == Set("func3", "func5"))
686+
}
687+
688+
test("alter function") {
689+
val catalog = new SessionCatalog(newBasicCatalog())
690+
assert(catalog.getFunction("db2", FunctionIdentifier("func1")).className == funcClass)
691+
catalog.alterFunction("db2", newFunc("func1").copy(className = "muhaha"))
692+
assert(catalog.getFunction("db2", FunctionIdentifier("func1")).className == "muhaha")
693+
intercept[AnalysisException] { catalog.alterFunction("db2", newFunc("funcky")) }
694+
}
695+
696+
test("alter function when database does not exist") {
697+
val catalog = new SessionCatalog(newBasicCatalog())
698+
intercept[AnalysisException] {
699+
catalog.alterFunction("does_not_exist", newFunc())
700+
}
701+
}
702+
703+
test("list functions") {
704+
val catalog = new SessionCatalog(newBasicCatalog())
705+
val tempFunc1 = newFunc("func1").copy(className = "march")
706+
val tempFunc2 = newFunc("yes_me").copy(className = "april")
707+
catalog.createFunction("db2", newFunc("func2"))
708+
catalog.createFunction("db2", newFunc("not_me"))
709+
catalog.createTempFunction(tempFunc1, ignoreIfExists = false)
710+
catalog.createTempFunction(tempFunc2, ignoreIfExists = false)
711+
assert(catalog.listFunctions("db1", "*").toSet ==
712+
Set(FunctionIdentifier("func1"), FunctionIdentifier("yes_me")))
713+
assert(catalog.listFunctions("db2", "*").toSet ==
714+
Set(FunctionIdentifier("func1"),
715+
FunctionIdentifier("yes_me"),
716+
FunctionIdentifier("func1", Some("db2")),
717+
FunctionIdentifier("func2", Some("db2")),
718+
FunctionIdentifier("not_me", Some("db2"))))
719+
assert(catalog.listFunctions("db2", "func*").toSet ==
720+
Set(FunctionIdentifier("func1"),
721+
FunctionIdentifier("func1", Some("db2")),
722+
FunctionIdentifier("func2", Some("db2"))))
723+
}
724+
531725
}

0 commit comments

Comments
 (0)