From 8be8e411103e5a0078a0c40277eddce203b15fb4 Mon Sep 17 00:00:00 2001
From: Jocelyne <jocelyne.abihaidar@jetbrains.com>
Date: Tue, 10 Dec 2024 14:36:13 +0100
Subject: [PATCH 1/5] fix: EXPOSED-662 SchemaUtils.listTables() closes
 connection to db

For some unclear reason, the changes made [here](https://github.com/JetBrains/Exposed/pull/2301/commits/008faf34f498b0481d6e2c71e96dbcf2cf199d5f) were causing the database connection to close. This fixes that by adding a new function `tableNamesForAllSchemas()` and invoking that in `allTablesNames()`.
---
 exposed-core/api/exposed-core.api             |  1 +
 .../statements/api/ExposedDatabaseMetadata.kt |  2 ++
 .../exposed/sql/vendors/VendorDialect.kt      |  8 +++-----
 exposed-jdbc/api/exposed-jdbc.api             |  1 +
 .../jdbc/JdbcDatabaseMetadataImpl.kt          |  3 +++
 .../sql/tests/shared/ddl/CreateTableTests.kt  | 20 +++++++++++++++++++
 6 files changed, 30 insertions(+), 5 deletions(-)

diff --git a/exposed-core/api/exposed-core.api b/exposed-core/api/exposed-core.api
index 30280279f2..1e56a5b9fd 100644
--- a/exposed-core/api/exposed-core.api
+++ b/exposed-core/api/exposed-core.api
@@ -3580,6 +3580,7 @@ public abstract class org/jetbrains/exposed/sql/statements/api/ExposedDatabaseMe
 	public abstract fun sequences ()Ljava/util/List;
 	public abstract fun tableConstraints (Ljava/util/List;)Ljava/util/Map;
 	public abstract fun tableNamesByCurrentSchema (Ljava/util/Map;)Lorg/jetbrains/exposed/sql/vendors/SchemaMetadata;
+	public abstract fun tableNamesForAllSchemas ()Ljava/util/List;
 }
 
 public abstract class org/jetbrains/exposed/sql/statements/api/ExposedSavepoint {
diff --git a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/statements/api/ExposedDatabaseMetadata.kt b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/statements/api/ExposedDatabaseMetadata.kt
index 78271a0e70..817eacb25a 100644
--- a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/statements/api/ExposedDatabaseMetadata.kt
+++ b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/statements/api/ExposedDatabaseMetadata.kt
@@ -55,6 +55,8 @@ abstract class ExposedDatabaseMetadata(val database: String) {
      */
     abstract fun tableNamesByCurrentSchema(tableNamesCache: Map<String, List<String>>?): SchemaMetadata
 
+    abstract fun tableNamesForAllSchemas(): List<String>
+
     /** Returns a map with the [ColumnMetadata] of all the defined columns in each of the specified [tables]. */
     abstract fun columns(vararg tables: Table): Map<Table, List<ColumnMetadata>>
 
diff --git a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/VendorDialect.kt b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/VendorDialect.kt
index 4d3c979a82..0fe4c3cbad 100644
--- a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/VendorDialect.kt
+++ b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/VendorDialect.kt
@@ -32,17 +32,15 @@ abstract class VendorDialect(
         }
 
     protected fun getAllTableNamesCache(): Map<String, List<String>> {
-        val connection = TransactionManager.current().connection
         if (_allTableNames == null) {
-            _allTableNames = connection.metadata { tableNames }
+            _allTableNames = TransactionManager.current().connection.metadata { tableNames }
         }
         return _allTableNames!!
     }
 
     private fun getAllSchemaNamesCache(): List<String> {
-        val connection = TransactionManager.current().connection
         if (_allSchemaNames == null) {
-            _allSchemaNames = connection.metadata { schemaNames }
+            _allSchemaNames = TransactionManager.current().connection.metadata { schemaNames }
         }
         return _allSchemaNames!!
     }
@@ -53,7 +51,7 @@ abstract class VendorDialect(
 
     /** Returns a list with the names of all the defined tables with schema prefixes if the database supports it. */
     override fun allTablesNames(): List<String> = TransactionManager.current().connection.metadata {
-        getAllTableNamesCache().flatMap { it.value }
+        tableNamesForAllSchemas()
     }
 
     override fun tableExists(table: Table): Boolean {
diff --git a/exposed-jdbc/api/exposed-jdbc.api b/exposed-jdbc/api/exposed-jdbc.api
index 5ee212d776..6724deac1c 100644
--- a/exposed-jdbc/api/exposed-jdbc.api
+++ b/exposed-jdbc/api/exposed-jdbc.api
@@ -55,6 +55,7 @@ public final class org/jetbrains/exposed/sql/statements/jdbc/JdbcDatabaseMetadat
 	public fun sequences ()Ljava/util/List;
 	public fun tableConstraints (Ljava/util/List;)Ljava/util/Map;
 	public fun tableNamesByCurrentSchema (Ljava/util/Map;)Lorg/jetbrains/exposed/sql/vendors/SchemaMetadata;
+	public fun tableNamesForAllSchemas ()Ljava/util/List;
 }
 
 public final class org/jetbrains/exposed/sql/statements/jdbc/JdbcDatabaseMetadataImpl$Companion {
diff --git a/exposed-jdbc/src/main/kotlin/org/jetbrains/exposed/sql/statements/jdbc/JdbcDatabaseMetadataImpl.kt b/exposed-jdbc/src/main/kotlin/org/jetbrains/exposed/sql/statements/jdbc/JdbcDatabaseMetadataImpl.kt
index e8d8a7d34b..6390dc6db9 100644
--- a/exposed-jdbc/src/main/kotlin/org/jetbrains/exposed/sql/statements/jdbc/JdbcDatabaseMetadataImpl.kt
+++ b/exposed-jdbc/src/main/kotlin/org/jetbrains/exposed/sql/statements/jdbc/JdbcDatabaseMetadataImpl.kt
@@ -131,6 +131,9 @@ class JdbcDatabaseMetadataImpl(database: String, val metadata: DatabaseMetaData)
         return SchemaMetadata(currentSchema!!, tablesInSchema)
     }
 
+    override fun tableNamesForAllSchemas(): List<String> =
+        schemaNames.flatMap { tableNamesFor(it) }
+
     private fun ResultSet.extractColumns(): List<ColumnMetadata> {
         val result = mutableListOf<ColumnMetadata>()
         while (next()) {
diff --git a/exposed-tests/src/test/kotlin/org/jetbrains/exposed/sql/tests/shared/ddl/CreateTableTests.kt b/exposed-tests/src/test/kotlin/org/jetbrains/exposed/sql/tests/shared/ddl/CreateTableTests.kt
index 80f1d5c9b0..12d27a13e0 100644
--- a/exposed-tests/src/test/kotlin/org/jetbrains/exposed/sql/tests/shared/ddl/CreateTableTests.kt
+++ b/exposed-tests/src/test/kotlin/org/jetbrains/exposed/sql/tests/shared/ddl/CreateTableTests.kt
@@ -13,6 +13,7 @@ import org.jetbrains.exposed.sql.tests.shared.Category
 import org.jetbrains.exposed.sql.tests.shared.Item
 import org.jetbrains.exposed.sql.tests.shared.assertEqualCollections
 import org.jetbrains.exposed.sql.tests.shared.assertEquals
+import org.jetbrains.exposed.sql.tests.shared.assertFalse
 import org.jetbrains.exposed.sql.tests.shared.assertTrue
 import org.jetbrains.exposed.sql.transactions.TransactionManager
 import org.jetbrains.exposed.sql.vendors.MysqlDialect
@@ -666,4 +667,23 @@ class CreateTableTests : DatabaseTestsBase() {
             }
         }
     }
+
+    @Test
+    fun testListTablesDoesNotCloseDatabaseConnection() {
+        val tester = object : IntIdTable("tester") {
+            val int = integer("intColumn")
+        }
+        withDb { testDb ->
+            val defaultSchemaName = when (currentDialectTest) {
+                is SQLServerDialect -> "dbo"
+                is OracleDialect -> testDb.user
+                is MysqlDialect -> testDb.db!!.name
+                else -> "public"
+            }
+            assertTrue(SchemaUtils.listTables().none { it.equals("$defaultSchemaName.${OneTable.tableName}", ignoreCase = true) })
+        }
+        withDb {
+            assertFalse(tester.exists())
+        }
+    }
 }

From bf6a070b49326c780a24334aacc17a8aaf4f6e40 Mon Sep 17 00:00:00 2001
From: Chantal Loncle <82039410+bog-walk@users.noreply.github.com>
Date: Thu, 9 Jan 2025 06:47:44 -0500
Subject: [PATCH 2/5] fix: EXPOSED-662 SchemaUtils.listTables() returns empty
 list & closes db connection

- Revert change to VendorDialect.allTablesNames() so that both it and SchemaUtils.listTables()
 has original behavior (only returns lists in current schema)
- Add new SchemaUtils method to alternatively return list of all table names in all
schemas.
- Adjust tests to invoke listTables() without prior call to exists().
---
 exposed-core/api/exposed-core.api             |  4 +-
 .../org/jetbrains/exposed/sql/SchemaUtils.kt  | 11 ++-
 .../statements/api/ExposedDatabaseMetadata.kt |  2 -
 .../exposed/sql/vendors/DatabaseDialect.kt    | 12 ++-
 .../exposed/sql/vendors/VendorDialect.kt      | 21 ++++-
 exposed-jdbc/api/exposed-jdbc.api             |  1 -
 .../jdbc/JdbcDatabaseMetadataImpl.kt          |  3 -
 .../sql/tests/shared/ddl/CreateTableTests.kt  | 82 +++++++++++++------
 8 files changed, 97 insertions(+), 39 deletions(-)

diff --git a/exposed-core/api/exposed-core.api b/exposed-core/api/exposed-core.api
index 1e56a5b9fd..8aeff76133 100644
--- a/exposed-core/api/exposed-core.api
+++ b/exposed-core/api/exposed-core.api
@@ -2202,6 +2202,7 @@ public final class org/jetbrains/exposed/sql/SchemaUtils {
 	public static synthetic fun dropSequence$default (Lorg/jetbrains/exposed/sql/SchemaUtils;[Lorg/jetbrains/exposed/sql/Sequence;ZILjava/lang/Object;)V
 	public final fun listDatabases ()Ljava/util/List;
 	public final fun listTables ()Ljava/util/List;
+	public final fun listTablesInAllSchemas ()Ljava/util/List;
 	public final fun setSchema (Lorg/jetbrains/exposed/sql/Schema;Z)V
 	public static synthetic fun setSchema$default (Lorg/jetbrains/exposed/sql/SchemaUtils;Lorg/jetbrains/exposed/sql/Schema;ZILjava/lang/Object;)V
 	public final fun sortTablesByReferences (Ljava/lang/Iterable;)Ljava/util/List;
@@ -3580,7 +3581,6 @@ public abstract class org/jetbrains/exposed/sql/statements/api/ExposedDatabaseMe
 	public abstract fun sequences ()Ljava/util/List;
 	public abstract fun tableConstraints (Ljava/util/List;)Ljava/util/Map;
 	public abstract fun tableNamesByCurrentSchema (Ljava/util/Map;)Lorg/jetbrains/exposed/sql/vendors/SchemaMetadata;
-	public abstract fun tableNamesForAllSchemas ()Ljava/util/List;
 }
 
 public abstract class org/jetbrains/exposed/sql/statements/api/ExposedSavepoint {
@@ -3825,6 +3825,7 @@ public abstract interface class org/jetbrains/exposed/sql/vendors/DatabaseDialec
 	public static final field Companion Lorg/jetbrains/exposed/sql/vendors/DatabaseDialect$Companion;
 	public abstract fun addPrimaryKey (Lorg/jetbrains/exposed/sql/Table;Ljava/lang/String;[Lorg/jetbrains/exposed/sql/Column;)Ljava/lang/String;
 	public abstract fun allTablesNames ()Ljava/util/List;
+	public abstract fun allTablesNamesInAllSchemas ()Ljava/util/List;
 	public abstract fun catalog (Lorg/jetbrains/exposed/sql/Transaction;)Ljava/lang/String;
 	public abstract fun checkTableMapping (Lorg/jetbrains/exposed/sql/Table;)Z
 	public abstract fun columnConstraints ([Lorg/jetbrains/exposed/sql/Table;)Ljava/util/Map;
@@ -4321,6 +4322,7 @@ public abstract class org/jetbrains/exposed/sql/vendors/VendorDialect : org/jetb
 	public fun <init> (Ljava/lang/String;Lorg/jetbrains/exposed/sql/vendors/DataTypeProvider;Lorg/jetbrains/exposed/sql/vendors/FunctionProvider;)V
 	public fun addPrimaryKey (Lorg/jetbrains/exposed/sql/Table;Ljava/lang/String;[Lorg/jetbrains/exposed/sql/Column;)Ljava/lang/String;
 	public fun allTablesNames ()Ljava/util/List;
+	public fun allTablesNamesInAllSchemas ()Ljava/util/List;
 	public fun catalog (Lorg/jetbrains/exposed/sql/Transaction;)Ljava/lang/String;
 	public fun checkTableMapping (Lorg/jetbrains/exposed/sql/Table;)Z
 	public fun columnConstraints ([Lorg/jetbrains/exposed/sql/Table;)Ljava/util/Map;
diff --git a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/SchemaUtils.kt b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/SchemaUtils.kt
index 5f9de60092..705c1c3dff 100644
--- a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/SchemaUtils.kt
+++ b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/SchemaUtils.kt
@@ -856,12 +856,21 @@ object SchemaUtils {
     }
 
     /**
-     * Retrieves a list of all table names in the current database.
+     * Retrieves a list of all table names in the current database schema.
+     * The names will be returned with schema prefixes if the database supports it.
      *
      * @return A list of table names as strings.
      */
     fun listTables(): List<String> = currentDialect.allTablesNames()
 
+    /**
+     * Retrieves a list of all table names in the current database schema.
+     * The names will be returned with schema prefixes if the database supports it.
+     *
+     * @return A list of table names as strings.
+     */
+    fun listTablesInAllSchemas(): List<String> = currentDialect.allTablesNamesInAllSchemas()
+
     /** Drops all [tables], using a batch execution if [inBatch] is set to `true`. */
     fun drop(vararg tables: Table, inBatch: Boolean = false) {
         if (tables.isEmpty()) return
diff --git a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/statements/api/ExposedDatabaseMetadata.kt b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/statements/api/ExposedDatabaseMetadata.kt
index 817eacb25a..78271a0e70 100644
--- a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/statements/api/ExposedDatabaseMetadata.kt
+++ b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/statements/api/ExposedDatabaseMetadata.kt
@@ -55,8 +55,6 @@ abstract class ExposedDatabaseMetadata(val database: String) {
      */
     abstract fun tableNamesByCurrentSchema(tableNamesCache: Map<String, List<String>>?): SchemaMetadata
 
-    abstract fun tableNamesForAllSchemas(): List<String>
-
     /** Returns a map with the [ColumnMetadata] of all the defined columns in each of the specified [tables]. */
     abstract fun columns(vararg tables: Table): Map<Table, List<ColumnMetadata>>
 
diff --git a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/DatabaseDialect.kt b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/DatabaseDialect.kt
index 407b302eae..f6ae982aa6 100644
--- a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/DatabaseDialect.kt
+++ b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/DatabaseDialect.kt
@@ -78,9 +78,19 @@ interface DatabaseDialect {
     /** Returns the name of the current database. */
     fun getDatabase(): String
 
-    /** Returns a list with the names of all the defined tables. */
+    /**
+     * Returns a list with the names of all the defined tables in the current database schema.
+     * The names will be returned with schema prefixes if the database supports it.
+     */
     fun allTablesNames(): List<String>
 
+    /**
+     * Returns a list with the names of all the tables in all database schemas.
+     * The names will be returned with schema prefixes, if the database supports it, and non-user defined tables,
+     * like system information table names, will be included.
+     */
+    fun allTablesNamesInAllSchemas(): List<String>
+
     /** Checks if the specified table exists in the database. */
     fun tableExists(table: Table): Boolean
 
diff --git a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/VendorDialect.kt b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/VendorDialect.kt
index 0fe4c3cbad..a66419c5a5 100644
--- a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/VendorDialect.kt
+++ b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/VendorDialect.kt
@@ -24,7 +24,7 @@ abstract class VendorDialect(
     private var _allTableNames: Map<String, List<String>>? = null
     private var _allSchemaNames: List<String>? = null
 
-    /** Returns a list with the names of all the defined tables within default scheme. */
+    /** Returns a list with the names of all the defined tables in the current schema. */
     val allTablesNames: List<String>
         get() {
             val connection = TransactionManager.current().connection
@@ -49,9 +49,24 @@ abstract class VendorDialect(
 
     override fun getDatabase(): String = catalog(TransactionManager.current())
 
-    /** Returns a list with the names of all the defined tables with schema prefixes if the database supports it. */
+    /**
+     * Returns a list with the names of all the defined tables in the current database schema.
+     * The names will be returned with schema prefixes if the database supports it.
+     *
+     * **Note:** This method always re-reads data from the database. Using `allTablesNames` field is
+     * the preferred way to avoid unnecessary metadata queries.
+     */
     override fun allTablesNames(): List<String> = TransactionManager.current().connection.metadata {
-        tableNamesForAllSchemas()
+        tableNamesByCurrentSchema(null).tableNames
+    }
+
+    /**
+     * Returns a list with the names of all the tables in all database schemas.
+     * The names will be returned with schema prefixes, if the database supports it, and non-user defined tables,
+     * like system information table names, will be included.
+     */
+    override fun allTablesNamesInAllSchemas(): List<String> = getAllSchemaNamesCache().flatMap { schema ->
+        getAllTableNamesCache().getValue(schema)
     }
 
     override fun tableExists(table: Table): Boolean {
diff --git a/exposed-jdbc/api/exposed-jdbc.api b/exposed-jdbc/api/exposed-jdbc.api
index 6724deac1c..5ee212d776 100644
--- a/exposed-jdbc/api/exposed-jdbc.api
+++ b/exposed-jdbc/api/exposed-jdbc.api
@@ -55,7 +55,6 @@ public final class org/jetbrains/exposed/sql/statements/jdbc/JdbcDatabaseMetadat
 	public fun sequences ()Ljava/util/List;
 	public fun tableConstraints (Ljava/util/List;)Ljava/util/Map;
 	public fun tableNamesByCurrentSchema (Ljava/util/Map;)Lorg/jetbrains/exposed/sql/vendors/SchemaMetadata;
-	public fun tableNamesForAllSchemas ()Ljava/util/List;
 }
 
 public final class org/jetbrains/exposed/sql/statements/jdbc/JdbcDatabaseMetadataImpl$Companion {
diff --git a/exposed-jdbc/src/main/kotlin/org/jetbrains/exposed/sql/statements/jdbc/JdbcDatabaseMetadataImpl.kt b/exposed-jdbc/src/main/kotlin/org/jetbrains/exposed/sql/statements/jdbc/JdbcDatabaseMetadataImpl.kt
index 6390dc6db9..e8d8a7d34b 100644
--- a/exposed-jdbc/src/main/kotlin/org/jetbrains/exposed/sql/statements/jdbc/JdbcDatabaseMetadataImpl.kt
+++ b/exposed-jdbc/src/main/kotlin/org/jetbrains/exposed/sql/statements/jdbc/JdbcDatabaseMetadataImpl.kt
@@ -131,9 +131,6 @@ class JdbcDatabaseMetadataImpl(database: String, val metadata: DatabaseMetaData)
         return SchemaMetadata(currentSchema!!, tablesInSchema)
     }
 
-    override fun tableNamesForAllSchemas(): List<String> =
-        schemaNames.flatMap { tableNamesFor(it) }
-
     private fun ResultSet.extractColumns(): List<ColumnMetadata> {
         val result = mutableListOf<ColumnMetadata>()
         while (next()) {
diff --git a/exposed-tests/src/test/kotlin/org/jetbrains/exposed/sql/tests/shared/ddl/CreateTableTests.kt b/exposed-tests/src/test/kotlin/org/jetbrains/exposed/sql/tests/shared/ddl/CreateTableTests.kt
index 12d27a13e0..b19da9bc77 100644
--- a/exposed-tests/src/test/kotlin/org/jetbrains/exposed/sql/tests/shared/ddl/CreateTableTests.kt
+++ b/exposed-tests/src/test/kotlin/org/jetbrains/exposed/sql/tests/shared/ddl/CreateTableTests.kt
@@ -19,6 +19,7 @@ import org.jetbrains.exposed.sql.transactions.TransactionManager
 import org.jetbrains.exposed.sql.vendors.MysqlDialect
 import org.jetbrains.exposed.sql.vendors.OracleDialect
 import org.jetbrains.exposed.sql.vendors.SQLServerDialect
+import org.jetbrains.exposed.sql.vendors.SQLiteDialect
 import org.junit.Test
 import java.util.*
 import kotlin.test.assertFails
@@ -596,20 +597,15 @@ class CreateTableTests : DatabaseTestsBase() {
                 assertEquals(true, OneTable.exists())
                 assertEquals(false, OneOneTable.exists())
 
-                val defaultSchemaName = when (currentDialectTest) {
-                    is SQLServerDialect -> "dbo"
-                    is OracleDialect -> testDb.user
-                    is MysqlDialect -> testDb.db!!.name
-                    else -> "public"
-                }
-                assertTrue(SchemaUtils.listTables().any { it.equals("$defaultSchemaName.${OneTable.tableName}", ignoreCase = true) })
+                val schemaPrefixedName = testDb.getDefaultSchemaPrefixedTableName(OneTable.tableName)
+                assertTrue(SchemaUtils.listTables().any { it.equals(schemaPrefixedName, ignoreCase = true) })
 
                 SchemaUtils.createSchema(one)
                 SchemaUtils.create(OneOneTable)
                 assertEquals(true, OneTable.exists())
                 assertEquals(true, OneOneTable.exists())
 
-                assertTrue(SchemaUtils.listTables().any { it.equals(OneOneTable.tableName, ignoreCase = true) })
+                assertTrue(SchemaUtils.listTablesInAllSchemas().any { it.equals(OneOneTable.tableName, ignoreCase = true) })
             } finally {
                 SchemaUtils.drop(OneTable, OneOneTable)
                 val cascade = testDb != TestDB.SQLSERVER
@@ -618,6 +614,57 @@ class CreateTableTests : DatabaseTestsBase() {
         }
     }
 
+    @Test
+    fun testListTablesInCurrentSchema() {
+        withDb { testDb ->
+            SchemaUtils.create(OneTable)
+
+            val schemaPrefixedName = testDb.getDefaultSchemaPrefixedTableName(OneTable.tableName)
+            assertTrue(SchemaUtils.listTables().any { it.equals(schemaPrefixedName, ignoreCase = true) })
+        }
+
+        withDb { testDb ->
+            // ensures that db connection has not been lost by calling listTables()
+            assertEquals(testDb != TestDB.SQLITE, OneTable.exists())
+
+            SchemaUtils.drop(OneTable)
+        }
+    }
+
+    private fun TestDB.getDefaultSchemaPrefixedTableName(tableName: String): String = when (currentDialectTest) {
+        is SQLServerDialect -> "dbo.$tableName"
+        is OracleDialect -> "${this.user}.$tableName"
+        is MysqlDialect -> "${this.db!!.name}.$tableName"
+        is SQLiteDialect -> tableName
+        else -> "public.$tableName"
+    }
+
+    @Test
+    fun testListTablesInAllSchemas() {
+        withDb { testDb ->
+            if (currentDialectTest.supportsCreateSchema) {
+                val one = prepareSchemaForTest("one")
+
+                try {
+                    SchemaUtils.createSchema(one)
+                    // table "one.one" is created in new schema by db because of name
+                    // even though current schema has not been set to the new one above
+                    SchemaUtils.create(OneOneTable)
+
+                    // so new table will not appear in list of tables in current schema
+                    assertFalse(SchemaUtils.listTables().any { it.equals(OneOneTable.tableName, ignoreCase = true) })
+                    // but new table appears in list of tables from all schema
+                    assertTrue(SchemaUtils.listTablesInAllSchemas().any { it.equals(OneOneTable.tableName, ignoreCase = true) })
+                    assertTrue(OneOneTable.exists())
+                } finally {
+                    SchemaUtils.drop(OneOneTable)
+                    val cascade = testDb != TestDB.SQLSERVER
+                    SchemaUtils.dropSchema(one, cascade = cascade)
+                }
+            }
+        }
+    }
+
     @Test
     fun `create table with quoted name with camel case`() {
         val testTable = object : IntIdTable("quotedTable") {
@@ -667,23 +714,4 @@ class CreateTableTests : DatabaseTestsBase() {
             }
         }
     }
-
-    @Test
-    fun testListTablesDoesNotCloseDatabaseConnection() {
-        val tester = object : IntIdTable("tester") {
-            val int = integer("intColumn")
-        }
-        withDb { testDb ->
-            val defaultSchemaName = when (currentDialectTest) {
-                is SQLServerDialect -> "dbo"
-                is OracleDialect -> testDb.user
-                is MysqlDialect -> testDb.db!!.name
-                else -> "public"
-            }
-            assertTrue(SchemaUtils.listTables().none { it.equals("$defaultSchemaName.${OneTable.tableName}", ignoreCase = true) })
-        }
-        withDb {
-            assertFalse(tester.exists())
-        }
-    }
 }

From 6c1d3fe15b6f47c60461904b21f2c8f358eb939f Mon Sep 17 00:00:00 2001
From: Chantal Loncle <82039410+bog-walk@users.noreply.github.com>
Date: Thu, 9 Jan 2025 07:27:54 -0500
Subject: [PATCH 3/5] fix: EXPOSED-662 SchemaUtils.listTables() returns empty
 list & closes db connection

- Fix KDocs for new SchemaUtils method
- Override CachableMapWithDefault properties to throw unsupported exception &
prevent future similar issues
---
 .../main/kotlin/org/jetbrains/exposed/sql/SchemaUtils.kt    | 5 +++--
 .../exposed/sql/statements/jdbc/JdbcDatabaseMetadataImpl.kt | 6 ++++++
 2 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/SchemaUtils.kt b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/SchemaUtils.kt
index 705c1c3dff..198c385770 100644
--- a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/SchemaUtils.kt
+++ b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/SchemaUtils.kt
@@ -864,8 +864,9 @@ object SchemaUtils {
     fun listTables(): List<String> = currentDialect.allTablesNames()
 
     /**
-     * Retrieves a list of all table names in the current database schema.
-     * The names will be returned with schema prefixes if the database supports it.
+     * Returns a list with the names of all the tables in all database schemas.
+     * The names will be returned with schema prefixes, if the database supports it, and non-user defined tables,
+     * like system information table names, will be included.
      *
      * @return A list of table names as strings.
      */
diff --git a/exposed-jdbc/src/main/kotlin/org/jetbrains/exposed/sql/statements/jdbc/JdbcDatabaseMetadataImpl.kt b/exposed-jdbc/src/main/kotlin/org/jetbrains/exposed/sql/statements/jdbc/JdbcDatabaseMetadataImpl.kt
index e8d8a7d34b..35dc062daf 100644
--- a/exposed-jdbc/src/main/kotlin/org/jetbrains/exposed/sql/statements/jdbc/JdbcDatabaseMetadataImpl.kt
+++ b/exposed-jdbc/src/main/kotlin/org/jetbrains/exposed/sql/statements/jdbc/JdbcDatabaseMetadataImpl.kt
@@ -87,6 +87,12 @@ class JdbcDatabaseMetadataImpl(database: String, val metadata: DatabaseMetaData)
         override fun get(key: K): V? = map.getOrPut(key) { default(key) }
         override fun containsKey(key: K): Boolean = true
         override fun isEmpty(): Boolean = false
+
+        override val entries: Set<Map.Entry<K, V>> = throw UnsupportedOperationException(
+            "Iteration is impossible because CachableMapWithDefault is filled in lazily"
+        )
+        override val keys: Set<K> = throw UnsupportedOperationException()
+        override val values: Collection<V> = throw UnsupportedOperationException()
     }
 
     override val tableNames: Map<String, List<String>>

From d51c95cc7b60562a5de8cecb2a2170e496faed62 Mon Sep 17 00:00:00 2001
From: Chantal Loncle <82039410+bog-walk@users.noreply.github.com>
Date: Thu, 9 Jan 2025 07:52:09 -0500
Subject: [PATCH 4/5] fix: EXPOSED-662 SchemaUtils.listTables() returns empty
 list & closes db connection

- Undo changes to CachableMapWithDefault
---
 .../exposed/sql/statements/jdbc/JdbcDatabaseMetadataImpl.kt | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/exposed-jdbc/src/main/kotlin/org/jetbrains/exposed/sql/statements/jdbc/JdbcDatabaseMetadataImpl.kt b/exposed-jdbc/src/main/kotlin/org/jetbrains/exposed/sql/statements/jdbc/JdbcDatabaseMetadataImpl.kt
index 35dc062daf..e8d8a7d34b 100644
--- a/exposed-jdbc/src/main/kotlin/org/jetbrains/exposed/sql/statements/jdbc/JdbcDatabaseMetadataImpl.kt
+++ b/exposed-jdbc/src/main/kotlin/org/jetbrains/exposed/sql/statements/jdbc/JdbcDatabaseMetadataImpl.kt
@@ -87,12 +87,6 @@ class JdbcDatabaseMetadataImpl(database: String, val metadata: DatabaseMetaData)
         override fun get(key: K): V? = map.getOrPut(key) { default(key) }
         override fun containsKey(key: K): Boolean = true
         override fun isEmpty(): Boolean = false
-
-        override val entries: Set<Map.Entry<K, V>> = throw UnsupportedOperationException(
-            "Iteration is impossible because CachableMapWithDefault is filled in lazily"
-        )
-        override val keys: Set<K> = throw UnsupportedOperationException()
-        override val values: Collection<V> = throw UnsupportedOperationException()
     }
 
     override val tableNames: Map<String, List<String>>

From 0e1c754e0fc5a852103570c9e1cd385c5132558e Mon Sep 17 00:00:00 2001
From: Oleg Babichev <oleg.babichev@jetbrains.com>
Date: Thu, 9 Jan 2025 14:38:26 +0100
Subject: [PATCH 5/5] Disallow `entries` and `keys` fields of
 CachableMapWithDefault

---
 .../sql/statements/jdbc/JdbcDatabaseMetadataImpl.kt  | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/exposed-jdbc/src/main/kotlin/org/jetbrains/exposed/sql/statements/jdbc/JdbcDatabaseMetadataImpl.kt b/exposed-jdbc/src/main/kotlin/org/jetbrains/exposed/sql/statements/jdbc/JdbcDatabaseMetadataImpl.kt
index e8d8a7d34b..c0ff258eae 100644
--- a/exposed-jdbc/src/main/kotlin/org/jetbrains/exposed/sql/statements/jdbc/JdbcDatabaseMetadataImpl.kt
+++ b/exposed-jdbc/src/main/kotlin/org/jetbrains/exposed/sql/statements/jdbc/JdbcDatabaseMetadataImpl.kt
@@ -87,6 +87,18 @@ class JdbcDatabaseMetadataImpl(database: String, val metadata: DatabaseMetaData)
         override fun get(key: K): V? = map.getOrPut(key) { default(key) }
         override fun containsKey(key: K): Boolean = true
         override fun isEmpty(): Boolean = false
+
+        override val entries: Set<Map.Entry<K, V>>
+            get() = throw UnsupportedOperationException(
+                "The entries field should not be used on CachableMapWithDefault because the lazy population of the collection for missing keys " +
+                    "and entries may lead to inconsistencies between calls."
+            )
+
+        override val keys: Set<K>
+            get() = throw UnsupportedOperationException(
+                "The keys field should not be used on CachableMapWithDefault because the lazy population of the collection for missing keys " +
+                    "and keys may lead to inconsistencies between calls."
+            )
     }
 
     override val tableNames: Map<String, List<String>>