https://github.com/python/cpython/commit/beb8a50ca1e93fcb339cbd6291f8a91ecdcb171f
commit: beb8a50ca1e93fcb339cbd6291f8a91ecdcb171f
branch: 3.14
author: Miss Islington (bot) <31488909+miss-isling...@users.noreply.github.com>
committer: serhiy-storchaka <storch...@gmail.com>
date: 2025-05-09T15:17:24+03:00
summary:

[3.14] gh-133439: Fix dot commands with trailing spaces are mistaken for 
multi-line sqlite statements in the sqlite3 command-line interface (GH-133440) 
(GH-133738)

(cherry picked from commit ebd4881db2e8448b238d8ca2f6fcf331826132dd)

Co-authored-by: Tan Long <tanlo...@foxmail.com>

files:
A Misc/NEWS.d/next/Library/2025-05-05-22-11-24.gh-issue-133439.LpmyFz.rst
M Lib/sqlite3/__main__.py
M Lib/test/test_sqlite3/test_cli.py

diff --git a/Lib/sqlite3/__main__.py b/Lib/sqlite3/__main__.py
index 002f1986cddb89..4ccf292ddf211c 100644
--- a/Lib/sqlite3/__main__.py
+++ b/Lib/sqlite3/__main__.py
@@ -48,17 +48,25 @@ def runsource(self, source, filename="<input>", 
symbol="single"):
         Return True if more input is needed; buffering is done automatically.
         Return False if input is a complete statement ready for execution.
         """
-        match source:
-            case ".version":
-                print(f"{sqlite3.sqlite_version}")
-            case ".help":
-                print("Enter SQL code and press enter.")
-            case ".quit":
-                sys.exit(0)
-            case _:
-                if not sqlite3.complete_statement(source):
-                    return True
-                execute(self._cur, source)
+        if not source or source.isspace():
+            return False
+        if source[0] == ".":
+            match source[1:].strip():
+                case "version":
+                    print(f"{sqlite3.sqlite_version}")
+                case "help":
+                    print("Enter SQL code and press enter.")
+                case "quit":
+                    sys.exit(0)
+                case "":
+                    pass
+                case _ as unknown:
+                    self.write("Error: unknown command or invalid arguments:"
+                               f'  "{unknown}".\n')
+        else:
+            if not sqlite3.complete_statement(source):
+                return True
+            execute(self._cur, source)
         return False
 
 
diff --git a/Lib/test/test_sqlite3/test_cli.py 
b/Lib/test/test_sqlite3/test_cli.py
index ad0dcb3cccb5da..a03d7cbe16ba84 100644
--- a/Lib/test/test_sqlite3/test_cli.py
+++ b/Lib/test/test_sqlite3/test_cli.py
@@ -116,6 +116,38 @@ def test_interact_version(self):
         self.assertEqual(out.count(self.PS2), 0)
         self.assertIn(sqlite3.sqlite_version, out)
 
+    def test_interact_empty_source(self):
+        out, err = self.run_cli(commands=("", " "))
+        self.assertIn(self.MEMORY_DB_MSG, err)
+        self.assertEndsWith(out, self.PS1)
+        self.assertEqual(out.count(self.PS1), 3)
+        self.assertEqual(out.count(self.PS2), 0)
+
+    def test_interact_dot_commands_unknown(self):
+        out, err = self.run_cli(commands=(".unknown_command", ))
+        self.assertIn(self.MEMORY_DB_MSG, err)
+        self.assertEndsWith(out, self.PS1)
+        self.assertEqual(out.count(self.PS1), 2)
+        self.assertEqual(out.count(self.PS2), 0)
+        self.assertIn("Error", err)
+        # test "unknown_command" is pointed out in the error message
+        self.assertIn("unknown_command", err)
+
+    def test_interact_dot_commands_empty(self):
+        out, err = self.run_cli(commands=("."))
+        self.assertIn(self.MEMORY_DB_MSG, err)
+        self.assertEndsWith(out, self.PS1)
+        self.assertEqual(out.count(self.PS1), 2)
+        self.assertEqual(out.count(self.PS2), 0)
+
+    def test_interact_dot_commands_with_whitespaces(self):
+        out, err = self.run_cli(commands=(".version ", ". version"))
+        self.assertIn(self.MEMORY_DB_MSG, err)
+        self.assertEqual(out.count(sqlite3.sqlite_version + "\n"), 2)
+        self.assertEndsWith(out, self.PS1)
+        self.assertEqual(out.count(self.PS1), 3)
+        self.assertEqual(out.count(self.PS2), 0)
+
     def test_interact_valid_sql(self):
         out, err = self.run_cli(commands=("SELECT 1;",))
         self.assertIn(self.MEMORY_DB_MSG, err)
diff --git 
a/Misc/NEWS.d/next/Library/2025-05-05-22-11-24.gh-issue-133439.LpmyFz.rst 
b/Misc/NEWS.d/next/Library/2025-05-05-22-11-24.gh-issue-133439.LpmyFz.rst
new file mode 100644
index 00000000000000..e0a3ce98bf7158
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2025-05-05-22-11-24.gh-issue-133439.LpmyFz.rst
@@ -0,0 +1,2 @@
+Fix dot commands with trailing spaces are mistaken for multi-line SQL
+statements in the sqlite3 command-line interface.

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: arch...@mail-archive.com

Reply via email to