mirror of
https://github.com/python/cpython
synced 2024-09-05 08:17:45 +00:00
gh-95273: Improve sqlite3.complete_statement docs (#95840)
Co-authored-by: Ezio Melotti <ezio.melotti@gmail.com> Co-authored-by: CAM Gerlach <CAM.Gerlach@Gerlach.CAM>
This commit is contained in:
parent
6f6a4e6cc5
commit
e6623e7083
|
@ -1,33 +0,0 @@
|
|||
# A minimal SQLite shell for experiments
|
||||
|
||||
import sqlite3
|
||||
|
||||
con = sqlite3.connect(":memory:")
|
||||
con.isolation_level = None
|
||||
cur = con.cursor()
|
||||
|
||||
buffer = ""
|
||||
|
||||
print("Enter your SQL commands to execute in sqlite3.")
|
||||
print("Enter a blank line to exit.")
|
||||
|
||||
while True:
|
||||
line = input()
|
||||
if line == "":
|
||||
break
|
||||
buffer += line
|
||||
if sqlite3.complete_statement(buffer):
|
||||
try:
|
||||
buffer = buffer.strip()
|
||||
cur.execute(buffer)
|
||||
|
||||
if buffer.lstrip().upper().startswith("SELECT"):
|
||||
print(cur.fetchall())
|
||||
except sqlite3.Error as e:
|
||||
err_msg = str(e)
|
||||
err_code = e.sqlite_errorcode
|
||||
err_name = e.sqlite_errorname
|
||||
print(f"{err_name} ({err_code}): {err_msg}")
|
||||
buffer = ""
|
||||
|
||||
con.close()
|
|
@ -222,14 +222,25 @@ Module functions
|
|||
|
||||
.. function:: complete_statement(statement)
|
||||
|
||||
Returns ``True`` if the string *statement* contains one or more complete SQL
|
||||
statements terminated by semicolons. It does not verify that the SQL is
|
||||
syntactically correct, only that there are no unclosed string literals and the
|
||||
statement is terminated by a semicolon.
|
||||
Return ``True`` if the string *statement* appears to contain
|
||||
one or more complete SQL statements.
|
||||
No syntactic verification or parsing of any kind is performed,
|
||||
other than checking that there are no unclosed string literals
|
||||
and the statement is terminated by a semicolon.
|
||||
|
||||
This can be used to build a shell for SQLite, as in the following example:
|
||||
For example::
|
||||
|
||||
.. literalinclude:: ../includes/sqlite3/complete_statement.py
|
||||
>>> sqlite3.complete_statement("SELECT foo FROM bar;")
|
||||
True
|
||||
>>> sqlite3.complete_statement("SELECT foo")
|
||||
False
|
||||
|
||||
This function may be useful during command-line input
|
||||
to determine if the entered text seems to form a complete SQL statement,
|
||||
or if additional input is needed before calling :meth:`~Cursor.execute`.
|
||||
|
||||
See :func:`!runsource` in :source:`Lib/sqlite3/__main__.py`
|
||||
for real-world use.
|
||||
|
||||
.. function:: enable_callback_tracebacks(flag, /)
|
||||
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
"""A simple SQLite CLI for the sqlite3 module.
|
||||
|
||||
Apart from using 'argparse' for the command-line interface,
|
||||
this module implements the REPL as a thin wrapper around
|
||||
the InteractiveConsole class from the 'code' stdlib module.
|
||||
"""
|
||||
import sqlite3
|
||||
import sys
|
||||
|
||||
|
@ -7,6 +13,14 @@
|
|||
|
||||
|
||||
def execute(c, sql, suppress_errors=True):
|
||||
"""Helper that wraps execution of SQL code.
|
||||
|
||||
This is used both by the REPL and by direct execution from the CLI.
|
||||
|
||||
'c' may be a cursor or a connection.
|
||||
'sql' is the SQL string to execute.
|
||||
"""
|
||||
|
||||
try:
|
||||
for row in c.execute(sql):
|
||||
print(row)
|
||||
|
@ -21,6 +35,7 @@ def execute(c, sql, suppress_errors=True):
|
|||
|
||||
|
||||
class SqliteInteractiveConsole(InteractiveConsole):
|
||||
"""A simple SQLite REPL."""
|
||||
|
||||
def __init__(self, connection):
|
||||
super().__init__()
|
||||
|
@ -28,6 +43,11 @@ def __init__(self, connection):
|
|||
self._cur = connection.cursor()
|
||||
|
||||
def runsource(self, source, filename="<input>", symbol="single"):
|
||||
"""Override runsource, the core of the InteractiveConsole REPL.
|
||||
|
||||
Return True if more input is needed; buffering is done automatically.
|
||||
Return False is input is a complete statement ready for execution.
|
||||
"""
|
||||
match source:
|
||||
case ".version":
|
||||
print(f"{sqlite3.sqlite_version}")
|
||||
|
@ -73,6 +93,7 @@ def main():
|
|||
else:
|
||||
db_name = repr(args.filename)
|
||||
|
||||
# Prepare REPL banner and prompts.
|
||||
banner = dedent(f"""
|
||||
sqlite3 shell, running on SQLite version {sqlite3.sqlite_version}
|
||||
Connected to {db_name}
|
||||
|
@ -86,8 +107,10 @@ def main():
|
|||
con = sqlite3.connect(args.filename, isolation_level=None)
|
||||
try:
|
||||
if args.sql:
|
||||
# SQL statement provided on the command-line; execute it directly.
|
||||
execute(con, args.sql, suppress_errors=False)
|
||||
else:
|
||||
# No SQL provided; start the REPL.
|
||||
console = SqliteInteractiveConsole(con)
|
||||
console.interact(banner, exitmsg="")
|
||||
finally:
|
||||
|
|
Loading…
Reference in a new issue