Skip to main content

SQL and Python Modes

Switch between SQL and Python mode, enter multi-line statements and stored program bodies, and run SQL from Python with session.run_sql and result objects.

MariaDB Shell has two input modes. In SQL mode, everything you type goes to the server as SQL, much like the mariadb command-line client. In Python mode, you type Python code that runs in the shell's embedded Python interpreter, with global objects such as session, util, and shell ready to use. Shell commands such as \use or \option work in both.

The prompt shows the active mode:

MariaDB localhost:3306 ssl shop SQL >
MariaDB localhost:3306 ssl shop Py >

Choosing the Mode​

The shell starts in SQL mode unless you choose otherwise. You can change the starting mode on the command line, or persist another default:

MethodEffect
--sqlStarts in SQL mode.
--py or --pythonStarts in Python mode.
-f <file>Chooses the mode from the file extension: .sql for SQL, .py for Python. See Batch Execution.
defaultMode optionSets the starting mode when no command line option chooses one. For example, \option --persist defaultMode py.
mariadb-shell --py mariadb://dba@localhost/shop

Switching Modes​

At the prompt, \sql switches to SQL mode and \py switches to Python mode. The global session stays open, so the connection, the default schema, and any open transaction carry over.

MariaDB localhost:3306 ssl shop SQL > \py
Switching to Python mode...
MariaDB localhost:3306 ssl shop Py > \sql
Switching to SQL mode... Commands end with ;
MariaDB localhost:3306 ssl shop SQL >

Each mode keeps its own command history. See Editing and History.

Running One SQL Statement from Python Mode​

\sql followed by a statement runs that statement and stays in Python mode. The result is printed as in SQL mode. Use it for a quick look at the data while you work on a Python script:

MariaDB localhost:3306 ssl shop Py > \sql SELECT COUNT(*) FROM product
+----------+
| COUNT(*) |
+----------+
| 3 |
+----------+
1 row in set (0.0001 sec)

No terminator is needed after the statement.

SQL Mode​

Statement Terminators​

A statement runs when the shell reads a terminator. Until then, the shell collects lines, and the prompt changes to -> to show that a statement is pending:

MariaDB localhost:3306 ssl shop SQL > SELECT name, price
-> FROM product
-> WHERE price > 20;
TerminatorEffect
;Runs the statement and prints the result in the current result format. You can change it with DELIMITER.
\gRuns the statement like ;.
\GRuns the statement and prints the result vertically, one column: value line per column, regardless of the current result format.
\Gj, \GJ, \GT, \GtRuns the statement and prints the result as a JSON array, as JSON with result metadata, as tab-separated values with a header, or as tab-separated values without a header. See Output Formats.
MariaDB localhost:3306 ssl shop SQL > SELECT * FROM product WHERE id = 1\G
*************************** 1. row ***************************
id: 1
name: Desk lamp
price: 24.90
in_stock: 1
1 row in set (0.0001 sec)

You can put several statements on one line. Each runs in turn and prints its own result:

MariaDB localhost:3306 ssl shop SQL > SELECT COUNT(*) FROM product; SELECT COUNT(*) FROM customer;

To abandon a pending statement, press Ctrl+C.

Stored Programs and DELIMITER​

The body of a stored procedure, function, trigger, or event contains semicolons that must not end the outer statement. Change the terminator with DELIMITER, write the statement, and change it back:

MariaDB localhost:3306 ssl shop SQL > DELIMITER //
MariaDB localhost:3306 ssl shop SQL > CREATE PROCEDURE cheap_products()
-> BEGIN
-> SELECT name FROM product WHERE price < 10;
-> END//
Query OK, 0 rows affected (0.0125 sec)
MariaDB localhost:3306 ssl shop SQL > DELIMITER ;
MariaDB localhost:3306 ssl shop SQL > CALL cheap_products();
+----------+
| name |
+----------+
| Notebook |
+----------+
1 row in set (0.0003 sec)

Query OK, 0 rows affected (0.0003 sec)

DELIMITER must start a new statement: type it at the main prompt, not in the middle of a pending statement. The current delimiter is shown by \status. SQL files that you run with -f or \source can use DELIMITER in the same way.

Multi-Line Input​

The \ command, alone on a line, starts a block. In a block, the shell collects every line you type, including complete statements, without running anything. An empty line ends the block, and the shell then runs the statements in it:

MariaDB localhost:3306 ssl shop SQL > \
> UPDATE product SET price = price * 1.05 WHERE in_stock;
> SELECT name, price FROM product;
>

Use a block when you paste several statements and want to look at them before any of them runs. Each statement in the block still needs a terminator: a statement without one stays pending after the empty line, as at the normal prompt.

Warnings​

By default, the shell prints the warnings that a statement raises right after its result. \nowarnings (\w) turns this off and \warnings (\W) turns it back on. To start without warnings, use --show-warnings=false, or persist showWarnings as false. See Shell Commands.

Python Mode​

In Python mode, the shell runs Python 3 code. Compound statements such as for, if, and def continue on the next lines, and an empty line ends them:

MariaDB localhost:3306 ssl shop Py > for row in session.run_sql("SELECT id FROM product").fetch_all():
-> print(row.id)
->
1
2
3

The global session is available as session. To open additional sessions from Python, use mysql.get_session() or shell.open_session(). See Sessions and Global Objects.

Running SQL from Python​

session.run_sql(query[, args]) sends one statement to the server and returns a ClassicResult object. Use ? placeholders for values and pass them as a list in args. The shell quotes and escapes them, so values never become part of the SQL text:

res = session.run_sql(
"SELECT id, name, price FROM product WHERE price > ? ORDER BY price",
[10])

At the interactive prompt, a result object that you evaluate on its own is printed as a table, as in SQL mode. In a script, you read the rows yourself.

Reading Rows​

MethodReturns
fetch_one()The next row as a Row object, or None when no rows are left.
fetch_all()A list of all remaining rows.
fetch_one_object()The next row as a dictionary that maps column names to values, or None.
has_data()True if the statement produced a result set, also when it has no rows.
next_result()Moves to the next result set when a statement, such as a CALL, returns several. Returns False when there are no more.

A Row gives access to its fields in three ways: as an attribute (row.name), by position (row[1]), and by name with row.get_field("name"). Use get_field() for column names that aren't valid Python identifiers, such as COUNT(*) or order-date. len(row) and row.length return the number of fields.

res = session.run_sql("SELECT id, name, price FROM product WHERE price > ?", [10])
row = res.fetch_one()
print(row.name, row[2], row.get_field("price"))
# Desk lamp 24.90 24.90

remaining = res.fetch_all()
print(len(remaining))
# 1

obj = session.run_sql("SELECT name FROM product WHERE id = 1").fetch_one_object()
print(obj)
# {"name": "Desk lamp"}
info

DECIMAL values arrive in Python as strings, so no precision is lost. Convert them with decimal.Decimal(row.price) before you calculate with them. Integer columns arrive as int, and NULL as None.

Result Information​

PropertyDescription
affected_items_countRows inserted, updated, or deleted by the statement.
auto_increment_valueThe AUTO_INCREMENT value generated by the last INSERT.
warnings_countNumber of warnings the statement raised.
warningsThe warnings, as a list of [level, code, message] entries. Also available as get_warnings().
infoThe server's information string, such as Rows matched: 3 Changed: 0 Warnings: 0.
execution_timeThe execution time as a string, such as 0.0002 sec.
column_countNumber of columns in the result set.
column_namesList of column names.
columnsList of Column objects with column metadata. See Column Metadata.
statement_idThe ID of the statement that produced the result.

Every property also has a getter method, for example get_affected_items_count().

r = session.run_sql("INSERT INTO product (name, price) VALUES (?, ?)", ["Stapler", 7.25])
print(r.affected_items_count, r.auto_increment_value, r.warnings_count)
# 1 4 0

r = session.run_sql("SELECT CAST('abc' AS INT)")
r.fetch_all()
print(r.warnings_count, r.get_warnings())
# 1 [["Warning", 1292, "Truncated incorrect INTEGER value: 'abc'"]]

Column Metadata​

Each entry in columns is a Column object with these properties:

PropertyDescription
column_name, column_labelThe original column name and the name or alias in the result.
table_name, table_labelThe original table name and its alias.
schema_nameThe schema of the table.
typeThe column type, such as Type.INT, Type.STRING, or Type.DECIMAL.
lengthThe column length.
fractional_digitsThe number of decimal places.
number_signedWhether a numeric column is signed.
zero_fillWhether the column has the ZEROFILL attribute.
collation_name, character_set_nameThe collation and character set of a string column.
flagsOther column flags, such as NOT_NULL or PRI_KEY.
res = session.run_sql("SELECT id, name, price FROM product")
for col in res.columns:
print(col.column_name, col.type, col.length, col.fractional_digits)
# id <Type.INT> 11 0
# name <Type.STRING> 160 0
# price <Type.DECIMAL> 10 2

For the full list of members, type \? ClassicResult, \? Row, or \? Column at the prompt.

Transactions​

session.start_transaction(), session.commit(), and session.rollback() control transactions from Python. You can also send START TRANSACTION, COMMIT, and ROLLBACK with run_sql(). Autocommit follows the server setting, as in SQL mode.

session.start_transaction()
try:
session.run_sql("UPDATE product SET price = price * 0.9 WHERE in_stock = 0")
session.run_sql("INSERT INTO price_log (note) VALUES (?)", ["clearance"])
session.commit()
except Exception:
session.rollback()
raise

To print a result in one of the shell's output formats from Python, use shell.dump_rows(). See Output Formats.