arrow-left

All pages
gitbookPowered by GitBook
1 of 6

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

API Reference

hashtag
API Reference

hashtag
Contents:

      • - Synchronous connection

      • - Asynchronous connection (New in 2.0)

  • (New in 2.0)

- Synchronous connection pool (New in 2.0)

  • - Asynchronous connection pool (New in 2.0)

  • The MariaDB Connector/Python module
    Constructors
    connect()
    asyncConnect()
    The connection class
    Connection
    Connection constructors
    The cursor class
    Cursor
    Cursor methods
    Async/Await Supportarrow-up-right
    AsyncConnectionarrow-up-right
    AsyncCursorarrow-up-right
    Connection Pooling
    Synchronous Pool
    Asynchronous Pool
    Constants
    CAPABILITY
    CLIENT
    create_pool()
    create_async_pool()
    Attributes
    Exceptions
    Connection methods
    Connection attributes
    Cursor attributes
    AsyncConnectionPoolarrow-up-right
    CURSOR
    ERR (Error)
    FIELD_FLAG
    FIELD_TYPE
    INDICATORS
    INFO
    TPC_STATE
    STATUS

    The ConnectionPool class

    hashtag
    class ConnectionPool(*args, **kwargs)

    Class defining a pool of database connections

    MariaDB Connector/Python supports simple connection pooling. A connection pool holds a number of open connections and handles thread safety when providing connections to threads.

    The size of a connection pool is configurable at creation time, but cannot be changed afterward. The maximum size of a connection pool is limited to 64 connections.

    Keyword Arguments:

    • `pool_name` (str) - Name of connection pool

    • `pool_size` (int) - Size of pool. The Maximum allowed number is 64. Default to 5

    • `pool_reset_connection` (bool

    hashtag
    ConnectionPool methods

    hashtag
    ConnectionPool.add_connection(connection=None)

    Adds a connection object to the connection pool.

    In case that the pool doesn’t have a free slot or is not configured, a PoolError exception will be raised.

    hashtag
    ConnectionPool.close()

    Closes connection pool and all connections.

    hashtag
    ConnectionPool.get_connection()

    Returns a connection from the connection pool or raises a PoolError exception if a connection is not available.

    hashtag
    ConnectionPool.set_config(**kwargs)

    Sets the connection configuration for the connection pool. For valid connection arguments, check the mariadb.connect() method.

    Note: This method doesn’t create connections in the pool. To fill the pool, one has to use add_connection() ḿethod.

    hashtag
    ConnectionPool attributes

    hashtag
    ConnectionPool.connection_count

    Returns the number of connections in connection pool.

    Since version 1.1.0

    hashtag
    ConnectionPool.max_size

    Returns the maximum size for connection pools.

    hashtag
    ConnectionPool.pool_size

    Returns the size of the connection pool.

    hashtag
    ConnectionPool.pool_name

    Returns the name of the connection pool.

    ) - Will reset the connection before returning it to the pool. Default to True.
  • `pool_validation_interval` (int) - Specifies the validation interval in milliseconds after which the status of a connection requested from the pool is checked. A value of 0 means that the status will always be checked. Default to 500 (Added in version 1.1.6)

  • **kwargs - Optional additional connection arguments, as described in mariadb.connect() method.

  • spinner
    spinner

    The MariaDB Connector/Python module

    MariaDB Connector/Python module enables python programs to access MariaDB and MySQL databases, using an API which is compliant with the Python DB API 2.0 (PEP-249).

    hashtag
    Constructors

    hashtag
    Connection

    hashtag
    connect(dsn=None, connectionclass=mariadb.connections.Connection, **kwargs)

    Creates a MariaDB Connection object.

    By default, the standard connectionclass mariadb.connections.Connection will be created.

    Parameter connectionclass specifies a subclass of mariadb.Connection object. If not specified, default will be used. This optional parameter was added in version 1.1.0.

    Since version 2.0: Connection can be established using a URI string or keyword arguments. Keyword arguments override URI values when both are provided.

    URI Connection (recommended):

    Keyword Arguments:

    Connection parameters can also be provided as keyword arguments:

    • `host` - The host name or IP address of the database server. If MariaDB Connector/Python was built with MariaDB Connector/C 3.3, it is also possible to provide a comma separated list of hosts for simple fail over in case of one or more hosts are not available.

    • `user`, `username` - The username used to authenticate with the database server

    • `password`, `passwd` - The password of the given user

    hashtag
    Removed Parameters in Version 2.0

    The following parameters have been removed:

    • `reconnect` / `auto_reconnect` - Automatic reconnection is no longer supported. Use connection pools or call conn.reconnect() manually.

    • `cursor_type` - Replaced by buffered=False parameter in cursor creation.

    For migration guidance, see the .

    hashtag
    NOTE

    For a description of configuration file handling and settings please read the chapter of the MariaDB Connector/C documentation.

    Examples:

    Output:

    hashtag
    Async Connection

    hashtag
    asyncConnect(dsn=None, **kwargs)

    Since version 2.0

    Creates an asynchronous MariaDB Connection object for use with async/await.

    Usage:

    For detailed async usage, see .

    hashtag
    Connection Pool

    hashtag
    create_pool(**kwargs)

    Since version 2.0

    Creates a synchronous connection pool.

    Note: Connection pooling requires the mariadb[pool] package to be installed:

    Usage:

    Keyword Arguments:

    • `min_size` (int) - Minimum number of connections in pool. Default: 5

    • `max_size` (int) - Maximum number of connections in pool. Default: 10

    • `ping_threshold` (float

    For detailed pooling documentation, see .

    hashtag
    create_async_pool(**kwargs)

    Since version 2.0

    Creates an asynchronous connection pool for use with async/await.

    Note: Requires mariadb[pool] package.

    Usage:

    For detailed async pooling, see .

    hashtag
    Type constructors

    hashtag
    Binary()

    Constructs an object capable of holding a binary value.

    hashtag
    Date(year, month, day)

    Constructs an object holding a date value.

    hashtag
    DateFromTicks(ticks)

    Constructs an object holding a date value from the given ticks value (number of seconds since the epoch). For more information see the documentation of the standard Python time module.

    hashtag
    Time(hour, minute, second)

    Constructs an object holding a time value.

    hashtag
    TimeFromTicks(ticks)

    Constructs an object holding a time value from the given ticks value (number of seconds since the epoch). For more information see the documentation of the standard Python time module.

    hashtag
    Timestamp(year, month, day, hour, minute, second)

    Constructs an object holding a datetime value.

    hashtag
    TimestampFromTicks(ticks)

    Constructs an object holding a datetime value from the given ticks value (number of seconds since the epoch). For more information see the documentation of the standard Python time module.

    hashtag
    Attributes

    hashtag
    apilevel

    String constant stating the supported DB API level. The value for mariadb is 2.0.

    hashtag
    threadsafety

    Integer constant stating the level of thread safety. For mariadb the value is 1, which means threads can share the module but not the connection.

    hashtag
    paramstyle

    String constant stating the type of parameter marker. For mariadb the value is qmark. For compatibility reasons mariadb also supports the format and pyformat paramstyles with the limitation that they can’t be mixed inside a SQL statement.

    hashtag
    mariadbapi_version

    String constant stating the version of the used MariaDB Connector/C library.

    hashtag
    client_version

    Since version 1.1.0

    Returns the version of MariaDB Connector/C library in use as an integer. The number has the following format: MAJOR_VERSION * 10000 + MINOR_VERSION * 1000 + PATCH_VERSION

    hashtag
    client_version_info

    Since version 1.1.0 Returns the version of MariaDB Connector/C library as a tuple in the following format: (MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION)

    hashtag
    Exceptions

    Compliant to DB API 2.0 MariaDB Connector/C provides information about errors through the following exceptions:

    hashtag
    exception DataError

    Exception raised for errors that are due to problems with the processed data like division by zero, numeric value out of range, etc.

    hashtag
    exception DatabaseError

    Exception raised for errors that are related to the database

    hashtag
    exception InterfaceError

    Exception raised for errors that are related to the database interface rather than the database itself

    hashtag
    exception Warning

    Exception raised for important warnings like data truncations while inserting, etc

    hashtag
    exception PoolError

    Exception raised for errors related to ConnectionPool class.

    hashtag
    exception OperationalError

    Exception raised for errors that are related to the database’s operation and not necessarily under the control of the programmer.

    hashtag
    exception IntegrityError

    Exception raised when the relational integrity of the database is affected, e.g. a foreign key check fails

    hashtag
    exception InternalError

    Exception raised when the database encounters an internal error, e.g. the cursor is not valid anymore

    hashtag
    exception ProgrammingError

    Exception raised for programming errors, e.g. table not found or already exists, syntax error in the SQL statement

    hashtag
    exception NotSupportedError

    Exception raised in case a method or database API was used which is not supported by the database

    hashtag
    Type objects

    MariaDB Connector/Python type objects are immutable sets for type settings and defined in DBAPI 2.0 (PEP-249).

    Example:

    Output:

    hashtag
    STRING

    This type object is used to describe columns in a database that are string-based (e.g. CHAR1).

    hashtag
    BINARY

    This type object is used to describe (long) binary columns in a database (e.g. LONG, RAW, BLOBs).

    hashtag
    NUMBER

    This type object is used to describe numeric columns in a database.

    hashtag
    DATETIME

    This type object is used to describe date/time columns in a database.

    hashtag
    ROWID

    This type object is not supported in MariaDB Connector/Python and represents an empty set.

    `database`, `db` - Database (schema) name to use when connecting with the database server

  • `unix_socket` - The location of the unix socket file to use instead of using an IP port to connect. If socket authentication is enabled, this can also be used in place of a password.

  • `port` - Port number of the database server. If not specified, the default value of 3306 will be used.

  • `connect_timeout` - Connect timeout in seconds

  • `read_timeout` - Read timeout in seconds

  • `write_timeout` - Write timeout in seconds

  • `local_infile` - Enables or disables the use of LOAD DATA LOCAL INFILE statements.

  • `compress` (default: False) - Uses the compressed protocol for client server communication. If the server doesn’t support compressed protocol, the default protocol will be used.

  • `init_command` - Command(s) which will be executed when connecting and reconnecting to the database server

  • `default_file` - Read options from the specified option file. If the file is an empty string, default configuration file(s) will be used

  • `default_group` - Read options from the specified group

  • `plugin_dir` - Directory which contains MariaDB client plugins (C extension only, not available in pure Python)

  • `binary` (default: False) - Since version 2.0 - When enabled at connection level, all cursors default to binary protocol (prepared statements). Can be overridden per cursor.

  • `cache_prep_stmts` (default: True) - Since version 2.0 - Enables or disables prepared statement caching. When enabled, prepared statements are reused across executions.

  • `prep_stmt_cache_size` (default: 100) - Since version 2.0 - Maximum number of cached prepared statements per connection. When the cache is full, the least recently used statement is evicted.

  • `pipeline` (default: False) - Since version 2.0 - Enables pipelining for batch operations

  • `ssl_key` - Defines a path to a private key file to use for TLS. This option requires that you use the absolute path, not a relative path. The specified key must be in PEM format

  • `ssl_cert` - Defines a path to the X509 certificate file to use for TLS. This option requires that you use the absolute path, not a relative path. The X609 certificate must be in PEM format.

  • `ssl_ca` - Defines a path to a PEM file that should contain one or more X509 certificates for trusted Certificate Authorities (CAs) to use for TLS. This option requires that you use the absolute path, not a relative path.

  • `ssl_capath` - Defines a path to a directory that contains one or more PEM files that contains one X509 certificate for a trusted Certificate Authority (CA)

  • `ssl_cipher` - Defines a list of permitted cipher suites to use for TLS

  • `ssl_crlpath` - Defines a path to a PEM file that should contain one or more revoked X509 certificates to use for TLS. This option requires that you use the absolute path, not a relative path.

  • `ssl_verify_cert` - Enables server certificate verification.

  • `ssl` - The connection must use TLS security, or it will fail.

  • `tls_version` - A comma-separated list (without whitespaces) of TLS versions. Valid versions are TLSv1.0, TLSv1.1,TLSv1.2 and TLSv1.3. Added in version 1.1.7.

  • `autocommit` (default: False) - Specifies the autocommit settings. True will enable autocommit, False will disable it (default).

  • `converter` - Specifies a conversion dictionary, where keys are FIELD_TYPE values and values are conversion functions

  • `prepared`
    - Replaced by
    binary=True
    parameter.
    ) - Ping connections idle for more than this many seconds. Default: 0.25
  • **kwargs - Connection arguments as described in mariadb.connect() method

  • Migration Guidearrow-up-right
    Configuration filesarrow-up-right
    Async/Await Supportarrow-up-right
    Connection Pooling
    Async/Await Supportarrow-up-right
    spinner
    import mariadb
    
    # Simple URI
    conn = mariadb.connect("mariadb://user:password@localhost:3306/mydb")
    
    # URI with query parameters
    conn = mariadb.connect("mariadb://user:password@localhost/mydb?autocommit=true&binary=true")
    
    # Keyword arguments override URI values
    conn = mariadb.connect("mariadb://user:password@localhost/mydb", database="otherdb")
    import mariadb
    
    # URI connection (recommended)
    with mariadb.connect("mariadb://example_user:GHbe_Su3B8@localhost/test") as connection:
        print(connection.character_set)
    
    # Keyword arguments (still supported)
    with mariadb.connect(user="example_user", host="localhost", database="test", password="GHbe_Su3B8") as connection:
        print(connection.character_set)
    
    # Binary protocol enabled at connection level
    with mariadb.connect("mariadb://localhost/test?binary=true") as connection:
        cursor = connection.cursor()  # Uses binary protocol by default
        cursor.execute("SELECT * FROM users WHERE id = ?", (1,))
    utf8mb4
    import asyncio
    import mariadb
    
    async def main():
        # URI connection
        conn = await mariadb.asyncConnect("mariadb://user:password@localhost/mydb")
        
        # Or with keyword arguments
        conn = await mariadb.asyncConnect(
            host="localhost",
            user="user",
            password="password",
            database="mydb"
        )
        
        cursor = await conn.cursor()
        await cursor.execute("SELECT * FROM users WHERE id = ?", (1,))
        row = await cursor.fetchone()
        
        await cursor.close()
        await conn.close()
    
    asyncio.run(main())
    pip install mariadb[pool]
    import mariadb
    
    pool = mariadb.create_pool(
        host="localhost",
        user="user",
        password="password",
        database="mydb",
        min_size=5,
        max_size=20
    )
    
    with pool.acquire() as conn:
        with conn.cursor() as cursor:
            cursor.execute("SELECT 1")
    import asyncio
    import mariadb
    
    async def main():
        pool = await mariadb.create_async_pool(
            host="localhost",
            user="user",
            password="password",
            database="mydb",
            min_size=10,
            max_size=50
        )
        
        async with await pool.acquire() as conn:
            async with conn.cursor() as cursor:
                await cursor.execute("SELECT 1")
        
        await pool.close()
    
    asyncio.run(main())
    import mariadb
    from mariadb.constants import FIELD_TYPE
    
    print(FIELD_TYPE.GEOMETRY == mariadb.BINARY)
    print(FIELD_TYPE.DATE == mariadb.DATE)
    print(FIELD_TYPE.VARCHAR == mariadb.BINARY)
    True
    True
    False

    Constants

    Constants are declared in mariadb.constants module.

    For using constants of various types, they have to be imported first:

    hashtag
    CAPABILITY

    MariaDB capability flags.

    These flags are used to check the capabilities both of a MariaDB server or the client applicaion.

    Capability flags are defined in module mariadb.constants.CAPABILIY

    Since version 1.1.4

    Output:

    hashtag
    CLIENT

    MariaDB capability flags.

    These flags are used to check the capabilities both of a MariaDB server or the client applicaion.

    Capability flags are defined in module mariadb.constants.CLIENT

    Since version 1.1.0, deprecated in 1.1.4

    hashtag
    CURSOR

    Cursor constants are used for server side cursors. Currently only read only cursor is supported.

    Cursor constants are defined in module mariadb.constants.CURSOR.

    Since version 1.1.0

    hashtag
    CURSOR.NONE

    This is the default setting (no cursor)

    hashtag
    CURSOR.READ_ONLY

    Will create a server side read only cursor. The cursor is a forward cursor, which means it is not possible to scroll back.

    hashtag
    ERR (Error)

    Using ERR constants instead of error numbers make the code more readable. Error constants are defined in constants.ERR module

    Since version 1.1.2

    Output:

    hashtag
    FIELD_FLAG

    MariaDB FIELD_FLAG Constants

    These constants represent the various field flags. As an addition to the DBAPI 2.0 standard (PEP-249) these flags are returned as eighth element of the cursor description attribute.

    Field flags are defined in module mariadb.constants.FIELD_FLAG

    Since version 1.1.0

    hashtag
    FIELD_FLAG.NOT_NULL

    column is defined as not NULL

    hashtag
    FIELD_FLAG.PRIMARY_KEY

    column is (part of) a primary key

    hashtag
    FIELD_FLAG.UNIQUE_KEY

    column is (part of) a unique key

    hashtag
    FIELD_FLAG.MULTIPLE_KEY

    column is (part of) a key

    hashtag
    FIELD_FLAG.BLOB

    column contains a binary object

    hashtag
    FIELD_FLAG.UNSIGNED

    numeric column is defined as unsigned

    hashtag
    FIELD_FLAG.ZEROFILL

    column has zerofill attribute

    hashtag
    FIELD_FLAG.BINARY

    column is a binary

    hashtag
    FIELD_FLAG.ENUM

    column is defined as enum

    hashtag
    FIELD_FLAG.AUTO_INCREMENT

    column is an auto_increment column

    hashtag
    FIELD_FLAG.TIMESTAMP

    column is defined as time stamp

    hashtag
    FIELD_FLAG.SET

    column is defined as SET

    hashtag
    FIELD_FLAG.NO_DEFAULT

    column hasn’t a default value

    hashtag
    FIELD_FLAG.ON_UPDATE_NOW

    column will be set to current timestamp on UPDATE

    hashtag
    FIELD_FLAG.NUMERIC

    column contains numeric value

    hashtag
    FIELD_FLAG.PART_OF_KEY

    column is part of a key

    hashtag
    FIELD_TYPE

    MariaDB FIELD_TYPE Constants

    These constants represent the field types supported by MariaDB. The field type is returned as second element of cursor description attribute.

    Field types are defined in module mariadb.constants.FIELD_TYPE

    hashtag
    FIELD_TYPE.TINY

    column type is TINYINT (1-byte integer)

    hashtag
    FIELD_TYPE.SHORT

    column type is SMALLINT (2-byte integer)

    hashtag
    FIELD_TYPE.LONG

    column tyoe is INT (4-byte integer)

    hashtag
    FIELD_TYPE.FLOAT

    column type is FLOAT (4-byte single precision)

    hashtag
    FIELD_TYPE.DOUBLE

    column type is DOUBLE (8-byte double precision)

    hashtag
    FIELD_TYPE.NULL

    column type is NULL

    hashtag
    FIELD_TYPE.TIMESTAMP

    column tyoe is TIMESTAMP

    hashtag
    FIELD_TYPE.LONGLONG

    column tyoe is BIGINT (8-byte Integer)

    hashtag
    FIELD_TYPE.INT24

    column type is MEDIUMINT (3-byte Integer)

    hashtag
    FIELD_TYPE.DATE

    column type is DATE

    hashtag
    FIELD_TYPE.TIME

    column type is TIME

    hashtag
    FIELD_TYPE.DATETIME

    column type is DATETIME

    hashtag
    FIELD_TYPE.YEAR

    column type is YEAR

    hashtag
    FIELD_TYPE.VARCHAR

    column type is VARCHAR

    hashtag
    FIELD_TYPE.BIT

    column type is BIT

    hashtag
    FIELD_TYPE.JSON

    column type is JSON

    hashtag
    FIELD_TYPE.NEWDECIMAL

    column type is DECIMAL

    hashtag
    FIELD_TYPE.ENUM

    column type is ENUM

    hashtag
    FIELD_TYPE.SET

    column type is SET

    hashtag
    FIELD_TYPE.TINY_BLOB

    column type is TINYBLOB (max. length of 255 bytes)

    hashtag
    FIELD_TYPE.MEDIUM_BLOB

    column type is MEDIUMBLOB (max. length of 16,777,215 bytes)

    hashtag
    FIELD_TYPE.LONG_BLOB

    column type is LONGBLOB (max. length 4GB bytes)

    hashtag
    FIELD_TYPE.BLOB

    column type is BLOB (max. length of 65.535 bytes)

    hashtag
    FIELD_TYPE.VAR_STRING

    column type is VARCHAR (variable length)

    hashtag
    FIELD_TYPE.STRING

    column type is CHAR (fixed length)

    hashtag
    FIELD_TYPE.GEOMETRY

    column type is GEOMETRY

    hashtag
    INDICATORS

    Indicator values are used in executemany() method of cursor class to indicate special values when connected to a MariaDB server 10.2 or newer.

    hashtag
    INDICATOR.NULL

    indicates a NULL value

    hashtag
    INDICATOR.DEFAULT

    indicates to use default value of column

    hashtag
    INDICATOR.IGNORE

    indicates to ignore value for column for UPDATE statements. If set, the column will not be updated.

    hashtag
    INDICATOR.IGNORE_ROW

    indicates not to update the entire row.

    hashtag
    INFO

    For internal use only

    hashtag
    TPC_STATE

    For internal use only

    hashtag
    STATUS

    The STATUS constants are used to check the server status of the current connection.

    Since version 1.1.0

    Example:

    if (connection.server_status & STATUS.SP_OUT_PARAMS): print("retrieving output parameters from store procedure") ... else: print("retrieving data from stored procedure") ....

    hashtag
    STATUS.IN_TRANS

    Pending transaction

    hashtag
    STATUS.AUTOCOMMIT

    Server operates in autocommit mode

    hashtag
    STATUS.MORE_RESULTS_EXIST

    The result from last executed statement contained two or more result sets which can be retrieved by cursors nextset() method.

    hashtag
    STATUS.QUERY_NO_GOOD_INDEX_USED

    The last executed statement didn’t use a good index.

    hashtag
    STATUS.QUERY_NO_INDEX_USED

    The last executed statement didn’t use an index.

    hashtag
    STATUS.CURSOR_EXISTS

    The last executed statement opened a server side cursor.

    hashtag
    STATUS.LAST_ROW_SENT

    For server side cursors this flag indicates end of a result set.

    hashtag
    STATUS.DB_DROPPED

    The current database in use was dropped and there is no default database for the connection anymore.

    hashtag
    STATUS.NO_BACKSLASH_ESCAPES

    Indicates that SQL mode NO_BACKSLASH_ESCAPE is active, which means that the backslash character ‘' becomes an ordinary character.

    hashtag
    STATUS.QUERY_WAS_SLOW

    The previously executed statement was slow (and needs to be optimized).

    hashtag
    STATUS.PS_OUT_PARAMS

    The current result set contains output parameters of a stored procedure.

    hashtag
    STATUS.SESSION_STATE_CHANGED

    The session status has been changed.

    hashtag
    STATUS.ANSI_QUOTES

    SQL mode ANSI_QUOTES is active.

    hashtag
    STATUS.METADATA_CHANGED

    Metadata has changed (e.g., table structure modified).

    hashtag
    STATUS.IN_TRANS_READONLY

    Pending read-only transaction.

    hashtag
    EXT_FIELD_TYPE

    MariaDB Extended FIELD_TYPE Constants

    These constants represent the extended field types supported by MariaDB. Extended field types provide additional type information beyond standard SQL types.

    Extended field types are defined in module mariadb.constants.EXT_FIELD_TYPE

    Since version 2.0

    hashtag
    EXT_FIELD_TYPE.NONE

    No extended type information (value: 0)

    hashtag
    EXT_FIELD_TYPE.JSON

    JSON data type (value: 1)

    hashtag
    EXT_FIELD_TYPE.UUID

    UUID data type (value: 2)

    hashtag
    EXT_FIELD_TYPE.INET4

    IPv4 address data type (value: 3)

    hashtag
    EXT_FIELD_TYPE.INET6

    IPv6 address data type (value: 4)

    hashtag
    EXT_FIELD_TYPE.POINT

    Geometry POINT type (value: 5)

    hashtag
    EXT_FIELD_TYPE.MULTIPOINT

    Geometry MULTIPOINT type (value: 6)

    hashtag
    EXT_FIELD_TYPE.LINESTRING

    Geometry LINESTRING type (value: 7)

    hashtag
    EXT_FIELD_TYPE.MULTILINESTRING

    Geometry MULTILINESTRING type (value: 8)

    hashtag
    EXT_FIELD_TYPE.POLYGON

    Geometry POLYGON type (value: 9)

    hashtag
    EXT_FIELD_TYPE.MULTIPOLYGON

    Geometry MULTIPOLYGON type (value: 10)

    hashtag
    EXT_FIELD_TYPE.GEOMETRYCOLLECTION

    Geometry GEOMETRYCOLLECTION type (value: 11)

    Example:

    hashtag
    SESSION_TRACK

    Session tracking constants for monitoring session state changes.

    Session tracking constants are defined in module mariadb.constants.SESSION_TRACK

    Since version 2.0

    from mariadb.constants import *
    spinner
    import mariadb
    from mariadb.constants import *
    
    # connection parameters
    conn_params= {
        "user" : "example_user",
        "password" : "GHbe_Su3B8",
        "host" : "localhost"
    }
    
    with mariadb.connect(**conn_params) as connection:
        # test if LOAD DATA LOCAL INFILE is supported
        if connection.server_capabilities & CAPABILITY.LOCAL_FILES:
            print("Server supports LOCAL INFILE")
    Server supports LOCAL INFILE
    import mariadb
    from mariadb.constants import *
    
    # connection parameters
    conn_params= {
        "user" : "example_user",
        "password" : "wrong_password",
        "host" : "localhost"
    }
    
    # try to establish a connection
    try:
        connection= mariadb.connect(**conn_params)
    except mariadb.OperationalError as Err:
        if Err.errno == ERR.ER_ACCESS_DENIED_ERROR:
            print("Access denied. Wrong password!")
    Access denied. Wrong password!
    cursor.callproc("my_storedprocedure", (1,"foo"))
    import mariadb
    from mariadb.constants import EXT_FIELD_TYPE
    
    conn = mariadb.connect("mariadb://user:password@localhost/mydb")
    cursor = conn.cursor()
    
    cursor.execute("SELECT id, data, location FROM test_table")
    metadata = cursor.metadata
    
    if metadata:
        for i, ext_type in enumerate(metadata['ext_type_or_format']):
            if ext_type == EXT_FIELD_TYPE.JSON:
                print(f"Column {i} is JSON type")
            elif ext_type == EXT_FIELD_TYPE.UUID:
                print(f"Column {i} is UUID type")
            elif ext_type == EXT_FIELD_TYPE.POINT:
                print(f"Column {i} is POINT geometry type")
    
    cursor.close()
    conn.close()

    The connection class

    hashtag
    class Connection(*args, **kwargs)

    MariaDB Connector/Python Connection Object

    Handles the connection to a MariaDB or MySQL database server. It encapsulates a database session.

    Connections are created using the method mariadb.connect()

    hashtag
    Connection Parameters

    The mariadb.connect() function accepts the following parameters:

    hashtag
    Basic Connection Parameters

    • host (str) - Hostname or IP address of the database server. Can be a comma-separated list for failover support. Default: 'localhost'

    • port (int) - Port number of the database server. Default: 3306

    hashtag
    Timeout Parameters

    • connect_timeout (float) - Timeout in seconds for establishing connection. Default: 10.0

    • socket_timeout (float) - Timeout in seconds for socket operations. Default: 30.0

    hashtag
    SSL/TLS Parameters

    • ssl, use_ssl (bool) - Enable SSL/TLS encryption. Default: False

    • ssl_ca (str) - Path to Certificate Authority (CA) certificate file in PEM format. Default:

    hashtag
    Connection Behavior Parameters

    • autocommit (bool) - Enable autocommit mode. Default: False

    • read_only (bool) - Set connection to read-only mode. Default: False

    hashtag
    Protocol and Performance Parameters

    • binary (bool) - Use binary protocol (prepared statements) by default. Default: False

    • max_allowed_packet (int) - Maximum packet size in bytes. Default: 16777216 (16MB)

    hashtag
    Character Encoding Parameters

    • character_encoding, charset (str) - Character set to use for the connection. Default: 'utf8mb4'

    hashtag
    Result Format Parameters

    • named_tuple (bool) - Return rows as named tuples instead of regular tuples. Default: False

    • dictionary (bool) - Return rows as dictionaries instead of tuples. Default: False

    hashtag
    Type Conversion Parameters

    • converter (dict) - Custom type converter dictionary mapping field types to conversion functions. Default: None

    hashtag
    Connection Examples

    Basic connection with dictionary parameters:

    Connection with SSL/TLS:

    Connection with URI (since version 2.0):

    Connection with timeouts and compression:

    Connection with result format options:

    Connection with failover hosts:

    hashtag
    Connection constructors

    hashtag
    Connection.xid(format_id: int, global_transaction_id: str, branch_qualifier: str) -> Xid

    Creates a transaction ID object suitable for passing to the .tpc_*() methods of this connection.

    Parameters:

    • format_id: Format id. Default to value 0.

    • global_transaction_id: Global transaction qualifier, which must be unique. The maximum length of the global transaction id is limited to 64 characters.

    • branch_qualifier: Branch qualifier which represents a local transaction identifier. The maximum length of the branch qualifier is limited to 64 characters.

    Since version 1.0.1.

    Example:

    hashtag
    Connection methods

    hashtag
    Connection.begin() -> None

    Start a new transaction which can be committed by .commit() method, or canceled by .rollback() method.

    Since version 1.1.0.

    Example:

    hashtag
    Connection.commit() -> None

    Commit any pending transaction to the database.

    Example:

    hashtag
    Connection.change_user(user: Optional[str], password: Optional[str], database: Optional[str] = None) -> None

    Changes the user and default database of the current connection

    Parameters: : - user: user name

    • password: password

    • database: name of default database

    In order to successfully change users a valid username and password parameters must be provided and that user must have sufficient permissions to access the desired database. If for any reason authorization fails an exception will be raised and the current user authentication will remain.

    Example:

    hashtag
    Connection.close() -> None

    Close the connection now (rather than whenever ._del_() is called).

    The connection will be unusable from this point forward; an Error (or subclass) exception will be raised if any operation is attempted with the connection. The same applies to all cursor objects trying to use the connection.

    Note that closing a connection without committing the changes first will cause an implicit rollback to be performed.

    Example:

    hashtag
    Connection.cursor(cursor_class: Optional[type] = None, **kwargs: Any) -> Cursor

    Create a new cursor for executing queries.

    Parameters:

    • cursor_class (Optional[type]) - Optional custom cursor class (advanced usage)

    • **kwargs (Any) - Additional cursor parameters:

    Returns:

    • Cursor object

    Raises:

    • ProgrammingError - If connection is closed

    By default, fetch methods return result set values as tuples. Use dictionary=True or named_tuple=True to change the return format.

    Removed in version 2.0:

    • cursor_type - Use buffered=True for buffered results

    • prepared - Use binary=True instead

    • cursorclass - No longer supported as a parameter

    Examples:

    hashtag
    Connection.dump_debug_info() -> None

    This function is designed to be executed by a user with the SUPER privilege and is used to dump server status information into the log for the MariaDB Server relating to the connection.

    Since version 1.1.2.

    Example:

    hashtag
    Connection.get_server_version() -> tuple[int, int, int]

    Returns a tuple representing the version of the connected server in the following format: (MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION)

    hashtag
    Connection.escape_string(escape_str: str) -> str

    Parameters: statement: string

    This function is used to create a legal SQL string that you can use in an SQL statement. The given string is encoded to an escaped SQL string.

    Since version 1.0.5.

    Output:

    hashtag
    Connection.kill(connection_id: int) -> None

    This function is used to ask the server to kill a database connection specified by the connection_id parameter.

    The connection id can be retrieved by SHOW PROCESSLIST SQL command.

    Note: This function requires the SUPER or CONNECTION ADMIN privilege.

    Example:

    hashtag
    Connection.ping() -> None

    Checks if the connection to the database server is still available.

    If auto reconnect was set to true, an attempt will be made to reconnect to the database server in case the connection was lost

    If the connection is not available an InterfaceError will be raised.

    Example:

    hashtag
    Connection.reconnect() -> None

    tries to reconnect to a server in case the connection died due to timeout or other errors. It uses the same credentials which were specified in connect() method.

    Example:

    hashtag
    Connection.reset() -> None

    Resets the current connection and clears session state and pending results. Open cursors will become invalid and cannot be used anymore.

    Example:

    hashtag
    Connection.rollback() -> None

    Causes the database to roll back to the start of any pending transaction

    Closing a connection without committing the changes first will cause an implicit rollback to be performed. Note that rollback() will not work as expected if autocommit mode was set to True or the storage engine does not support transactions.”

    hashtag
    Connection.select_db(new_db: str) -> None

    Gets the default database for the current connection.

    The default database can also be obtained or changed by database attribute.

    Since version 1.1.0.

    Example:

    hashtag
    Connection.show_warnings() -> Optional[List[tuple]]

    Shows error, warning and note messages from last executed command.

    Example:

    hashtag
    Connection.tpc_begin(xid: Xid) -> None

    Parameter: : xid: xid object which was created by .xid() method of connection : class

    Begins a TPC transaction with the given transaction ID xid.

    This method should be called outside a transaction (i.e., nothing may have been executed since the last .commit() or .rollback()). Furthermore, it is an error to call .commit() or .rollback() within the TPC transaction. A ProgrammingError is raised if the application calls .commit() or .rollback() during an active TPC transaction.

    Example:

    hashtag
    Connection.tpc_commit(xid: Optional[Xid] = None) -> None

    Optional parameter:

    • xid : xid object which was created by .xid() method of connection class.

    When called with no arguments, .tpc_commit() commits a TPC transaction previously prepared with .tpc_prepare().

    If .tpc_commit() is called prior to .tpc_prepare(), a single phase commit is performed. A transaction manager may choose to do this if only a single resource is participating in the global transaction. When called with a transaction ID xid, the database commits the given transaction. If an invalid transaction ID is provided, a ProgrammingError will be raised. This form should be called outside a transaction, and is intended for use in recovery.

    Example (Two-Phase Commit):

    hashtag
    Connection.tpc_prepare() -> None

    Performs the first phase of a transaction started with .tpc_begin(). A ProgrammingError will be raised if this method was called outside a TPC transaction.

    After calling .tpc_prepare(), no statements can be executed until .tpc_commit() or .tpc_rollback() have been called.

    Example:

    hashtag
    Connection.tpc_recover() -> List[tuple]

    Returns a list of pending transaction IDs suitable for use with tpc_commit(xid) or .tpc_rollback(xid).

    Example:

    hashtag
    Connection.tpc_rollback(xid: Optional[Xid] = None) -> None

    Parameter: : xid: xid object which was created by .xid() method of connection : class

    Performs the first phase of a transaction started with .tpc_begin(). A ProgrammingError will be raised if this method outside a TPC transaction.

    After calling .tpc_prepare(), no statements can be executed until .tpc_commit() or .tpc_rollback() have been called.

    Example:

    hashtag
    Connection attributes

    hashtag
    Connection.auto_reconnect: bool

    removed in version 2.0

    (read/write)

    Enable or disable automatic reconnection to the server if the connection is found to have been lost.

    When enabled, client tries to reconnect to a database server in case the connection to a database server died due to timeout or other errors.

    hashtag
    Connection.autocommit: bool

    (read/write)

    Toggles autocommit mode on or off for the current database connection.

    Autocommit mode only affects operations on transactional table types. Be aware that rollback() will not work if autocommit mode was switched on.

    By default, autocommit mode is set to False.

    hashtag
    Connection.character_set: str

    (read-only)

    Client character set.

    For MariaDB Connector/Python, it is always utf8mb4.

    hashtag
    Connection.client_capabilities: int

    (read-only)

    Client capability flags.

    Since version 1.1.0.

    hashtag
    Connection.collation: str

    (read-only)

    Client character set collation

    hashtag
    Connection.connection_id: int

    (read-only)

    Id of current connection

    hashtag
    Connection.database: Optional[str]

    (read-only)

    Returns or sets the default database for the current connection.

    The default database can also be obtained or changed by database attribute.

    Since version 1.1.0.

    hashtag
    Connection.open: bool

    (read-only)

    Returns true if the connection is alive.

    A ping command will be sent to the server for this purpose, which means this function might fail if there are still non-processed pending result sets.

    Since version 1.1.0.

    hashtag
    Connection.server_capabilities: int

    (read-only)

    Server capability flags.

    Since version 1.1.0.

    hashtag
    Connection.extended_server_capabilities: int

    (read-only)

    Extended server capability flags (only for MariaDB database servers).

    Since version 1.1.0.

    hashtag
    Connection.server_info: str

    (read-only)

    Server version in alphanumerical format (str)

    hashtag
    Connection.server_mariadb: bool

    (read-only)

    Returns True if the connected server is MariaDB, False if it's MySQL.

    This property is useful for detecting server type and implementing server-specific logic.

    Example:

    hashtag
    Connection.server_name: Optional[str]

    (read-only)

    Returns the server name.

    hashtag
    Connection.server_port: int

    (read-only)

    Database server TCP/IP port. This value will be 0 in case of an unix socket connection.

    hashtag
    Connection.server_status: int

    (read-only)

    Return server status flags

    Since version 1.1.0.

    hashtag
    Connection.server_version: int

    (read-only)

    Returns an integer representing the server version.

    The form of the version number is VERSION_MAJOR * 10000 + VERSION_MINOR * 100 + VERSION_PATCH

    hashtag
    Connection.server_version_info: tuple

    (read-only)

    Returns numeric version of connected database server in tuple format.

    hashtag
    Connection.tls_cipher: Optional[str]

    (read-only)

    Returns the TLS cipher suite in use.

    Since version 1.0.5.

    hashtag
    Connection.tls_version: Optional[str]

    (read-only)

    Returns the TLS protocol version.

    hashtag
    Connection.tls_peer_cert_info: Optional[dict]

    (read-only)

    Returns peer certificate information for TLS connections.

    Since version 1.1.11.

    hashtag
    Connection.unix_socket: Optional[str]

    (read-only)

    Returns the unix socket file name.

    hashtag
    Connection.user: Optional[str]

    (read-only)

    Returns the username for the current connection or empty string if it can’t be determined, e.g., when using socket authentication.

    hashtag
    Connection.warnings: int

    (read-only)

    Returns the number of warnings from the last executed statement., or zero if there are no warnings.

  • user, username (str) - Username for authentication. Default: None

  • password, passwd (str) - Password for authentication. Default: None

  • database, db (str) - Database (schema) name to use. Default: None

  • unix_socket (str) - Path to Unix socket file for local connections. Default: None

  • read_timeout (float) - Alias for socket_timeout. Default: 30.0

  • write_timeout (float) - Alias for socket_timeout. Default: 30.0

  • query_timeout (int) - Maximum query execution time in seconds (0 = no timeout). Default: 0

  • None
  • ssl_cert (str) - Path to client certificate file in PEM format. Default: None

  • ssl_key (str) - Path to client private key file in PEM format. Default: None

  • ssl_capath (str) - Path to directory containing CA certificates in PEM format. Default: None

  • ssl_cipher (str) - List of permitted cipher suites for SSL/TLS. Default: None

  • ssl_crl (str) - Path to certificate revocation list file. Default: None

  • ssl_crlpath (str) - Path to directory containing CRL files. Default: None

  • ssl_verify_cert (bool) - Enable server certificate verification. Default: False

  • tls_version (str) - TLS version(s) to use (e.g., 'TLSv1.2', 'TLSv1.3', 'TLSv1.2,TLSv1.3'). Automatically enables SSL. Default: None

  • compress (bool) - Enable protocol compression. Default: False

  • local_infile (bool) - Enable LOAD DATA LOCAL INFILE statements. Default: None

  • init_command (str) - SQL command to execute when connecting/reconnecting. Default: None

  • cache_prep_stmts (bool) - Enable prepared statement caching. Default: True

  • prep_stmt_cache_size (int) - Maximum number of cached prepared statements. Default: 100

  • pipeline (bool) - Enable pipelining for prepared statements. Default: True

  • client_flag (int) - Additional client capability flags. Default: 0

  • native_object (bool) - Return native Python objects for certain types. Default: False

    named_tuple
    (
    bool
    ) - Return rows as named tuples
  • dictionary (bool) - Return rows as dictionaries

  • buffered (bool) - Buffer all results immediately

  • binary (bool) - Use binary protocol (prepared statements)

  • spinner
    import mariadb
    
    conn = mariadb.connect(
        host='localhost',
        port=3306,
        user='myuser',
        password='mypassword',
        database='mydb'
    )
    conn = mariadb.connect(
        host='localhost',
        user='myuser',
        password='mypassword',
        database='mydb',
        ssl_ca='/path/to/ca-cert.pem',
        ssl_cert='/path/to/client-cert.pem',
        ssl_key='/path/to/client-key.pem',
        ssl_verify_cert=True
    )
    # Basic URI
    conn = mariadb.connect("mariadb://myuser:mypassword@localhost:3306/mydb")
    
    # URI with SSL parameters
    conn = mariadb.connect(
        "mariadb://myuser:mypassword@localhost/mydb",
        ssl_ca='/path/to/ca-cert.pem',
        ssl_verify_cert=True
    )
    conn = mariadb.connect(
        host='localhost',
        user='myuser',
        password='mypassword',
        database='mydb',
        connect_timeout=5.0,
        socket_timeout=60.0,
        compress=True
    )
    # Return rows as dictionaries
    conn = mariadb.connect(
        host='localhost',
        user='myuser',
        password='mypassword',
        database='mydb',
        dictionary=True
    )
    
    cursor = conn.cursor()
    cursor.execute("SELECT id, name FROM users LIMIT 1")
    row = cursor.fetchone()
    print(row['name'])  # Access by column name
    # Multiple hosts for automatic failover
    conn = mariadb.connect(
        host='primary.example.com,secondary.example.com,tertiary.example.com',
        port=3306,
        user='myuser',
        password='mypassword',
        database='mydb'
    )
    import mariadb
    
    conn = mariadb.connect("mariadb://user:password@localhost/mydb")
    
    # Create a transaction ID for distributed transaction
    xid = conn.xid(1, "global_tx_12345", "branch_001")
    print(f"XID: {xid}")  # Output: (1, 'global_tx_12345', 'branch_001')
    
    conn.close()
    import mariadb
    
    conn = mariadb.connect("mariadb://user:password@localhost/mydb")
    
    # Start explicit transaction
    conn.begin()
    
    cursor = conn.cursor()
    cursor.execute("INSERT INTO accounts (name, balance) VALUES (?, ?)", ("Alice", 1000))
    cursor.execute("UPDATE accounts SET balance = balance - 100 WHERE name = ?", ("Alice",))
    
    # Commit the transaction
    conn.commit()
    
    cursor.close()
    conn.close()
    import mariadb
    
    conn = mariadb.connect("mariadb://user:password@localhost/mydb")
    cursor = conn.cursor()
    
    try:
        cursor.execute("INSERT INTO users (name, email) VALUES (?, ?)", 
                       ("John Doe", "john@example.com"))
        cursor.execute("INSERT INTO logs (action) VALUES (?)", 
                       ("User created",))
        
        # Commit both inserts as a single transaction
        conn.commit()
        print("Transaction committed successfully")
    except mariadb.Error as e:
        # Rollback on error
        conn.rollback()
        print(f"Error: {e}")
    finally:
        cursor.close()
        conn.close()
    import mariadb
    
    conn = mariadb.connect("mariadb://user:password@localhost/mydb")
    
    print(f"Current user: {conn.user}")
    print(f"Current database: {conn.database}")
    
    # Switch to a different user and database
    try:
        conn.change_user("app_user", "app_pass", "app_db")
        print(f"Changed to user: {conn.user}")
        print(f"Changed to database: {conn.database}")
    except mariadb.Error as e:
        print(f"Failed to change user: {e}")
    finally:
        conn.close()
    import mariadb
    
    # Using context manager (recommended - auto-closes)
    with mariadb.connect("mariadb://user:password@localhost/mydb") as conn:
        cursor = conn.cursor()
        cursor.execute("SELECT * FROM users")
        users = cursor.fetchall()
        cursor.close()
    # Connection automatically closed here
    
    # Manual close
    conn = mariadb.connect("mariadb://user:password@localhost/mydb")
    try:
        cursor = conn.cursor()
        cursor.execute("SELECT COUNT(*) FROM users")
        count = cursor.fetchone()[0]
        print(f"Total users: {count}")
    finally:
        conn.close()  # Always close in finally block
    # Default cursor (unbuffered, text protocol, returns tuples)
    cursor = conn.cursor()
    
    # Buffered cursor (stores entire result set in memory)
    cursor = conn.cursor(buffered=True)
    
    # Binary protocol cursor (prepared statements)
    cursor = conn.cursor(binary=True)
    
    # Dictionary cursor (access columns by name)
    cursor = conn.cursor(dictionary=True)
    row = cursor.fetchone()
    print(row['column_name'])
    
    # Named tuple cursor (access columns as attributes)
    cursor = conn.cursor(named_tuple=True)
    row = cursor.fetchone()
    print(row.column_name)
    import mariadb
    
    conn = mariadb.connect("mariadb://user:password@localhost/mydb")
    
    try:
        # Dump debug information to server log
        # Requires SUPER privilege
        conn.dump_debug_info()
        print("Debug info dumped to server log")
    except mariadb.Error as e:
        print(f"Error: {e}")
        # Output: Error: Access denied; you need (at least one of) the SUPER privilege(s)
    
    conn.close()
    # connection parameters
    conn_params= {
        "user" : "example_user",
        "password" : "GHbe_Su3B8",
        "host" : "localhost"
    }
    
    with mariadb.connect(**conn_params) as connection:
        string = 'This string contains the following special characters: \\,"'
        print(connection.escape_string(string))
    This string contains the following special characters: \\,\"
    import mariadb
    import time
    
    conn = mariadb.connect("mariadb://user:password@localhost/mydb")
    
    cursor = conn.cursor()
    
    # Get list of active connections
    cursor.execute("SHOW PROCESSLIST")
    processes = cursor.fetchall()
    
    print("Active connections:")
    for proc in processes:
        conn_id, user, host, db, command, time_val, state, info = proc
        print(f"ID: {conn_id}, User: {user}, DB: {db}, Command: {command}")
    
    # Kill a specific connection (requires SUPER privilege)
    target_connection_id = 123
    try:
        conn.kill(target_connection_id)
        print(f"Connection {target_connection_id} killed successfully")
    except mariadb.Error as e:
        print(f"Error killing connection: {e}")
    
    cursor.close()
    conn.close()
    import mariadb
    
    conn = mariadb.connect("mariadb://user:password@localhost/mydb")
    
    try:
        # Check if connection is alive
        conn.ping()
        print("Connection is alive")
    except mariadb.InterfaceError:
        print("Connection lost")
    finally:
        conn.close()
    import mariadb
    import time
    
    conn = mariadb.connect("mariadb://user:password@localhost/mydb")
    
    try:
        cursor = conn.cursor()
        cursor.execute("SELECT 1")
        cursor.close()
        
        # Simulate connection timeout or network issue
        # In real scenario, connection might be lost
        
        # Reconnect with same credentials
        conn.reconnect()
        print("Reconnected successfully")
        
        cursor = conn.cursor()
        cursor.execute("SELECT 2")
        cursor.close()
        
    except mariadb.Error as e:
        print(f"Error: {e}")
    finally:
        conn.close()
    import mariadb
    
    conn = mariadb.connect("mariadb://user:password@localhost/mydb")
    cursor = conn.cursor()
    
    # Set some session variables
    cursor.execute("SET @my_var = 100")
    cursor.execute("SELECT @my_var")
    print(cursor.fetchone())  # Output: (100,)
    
    # Reset connection - clears session state
    conn.reset()
    
    # Previous cursor is now invalid, create new one
    cursor = conn.cursor()
    cursor.execute("SELECT @my_var")
    print(cursor.fetchone())  # Output: (None,) - variable cleared
    
    cursor.close()
    conn.close()
    import mariadb
    
    conn = mariadb.connect(
        host="localhost",
        user="root",
        password="secret"
    )
    
    print(f"Current database: {conn.database}")  # Output: None
    
    # Select a database
    conn.select_db("mydb")
    print(f"Current database: {conn.database}")  # Output: mydb
    
    cursor = conn.cursor()
    cursor.execute("SELECT DATABASE()")
    print(cursor.fetchone())  # Output: ('mydb',)
    
    cursor.close()
    conn.close()
    import mariadb
    
    conn = mariadb.connect("mariadb://user:password@localhost/mydb")
    cursor = conn.cursor()
    
    # Initially no warnings
    print(conn.show_warnings())  # Output: None
    
    # Generate a warning by inserting value out of range
    cursor.execute("SET session sql_mode=''")
    cursor.execute("CREATE TEMPORARY TABLE test_warn (a tinyint)")
    cursor.execute("INSERT INTO test_warn VALUES (300)")  # Value too large for tinyint
    
    # Get warnings
    warnings = conn.show_warnings()
    if warnings:
        for level, code, message in warnings:
            print(f"{level} ({code}): {message}")
        # Output: Warning (1264): Out of range value for column 'a' at row 1
    
    cursor.close()
    conn.close()
    import mariadb
    
    conn = mariadb.connect("mariadb://user:password@localhost/mydb")
    
    # Create transaction ID
    xid = conn.xid(0, "global_tx_001", "branch_001")
    
    # Begin distributed transaction
    conn.tpc_begin(xid)
    
    cursor = conn.cursor()
    cursor.execute("INSERT INTO orders (product, quantity) VALUES (?, ?)", ("Widget", 10))
    cursor.close()
    
    # Single-phase commit (no prepare)
    conn.tpc_commit(xid)
    
    conn.close()
    import mariadb
    
    conn = mariadb.connect("mariadb://user:password@localhost/mydb")
    
    # Create transaction ID
    xid = conn.xid(0, "global_tx_002", "branch_002")
    
    # Begin distributed transaction
    conn.tpc_begin(xid)
    
    cursor = conn.cursor()
    cursor.execute("UPDATE inventory SET quantity = quantity - 5 WHERE product = ?", ("Widget",))
    cursor.close()
    
    # Prepare transaction (phase 1)
    conn.tpc_prepare()
    
    # Commit transaction (phase 2)
    conn.tpc_commit()
    
    conn.close()
    import mariadb
    
    conn = mariadb.connect("mariadb://user:password@localhost/mydb")
    
    xid = conn.xid(0, "global_tx_003", "branch_003")
    conn.tpc_begin(xid)
    
    cursor = conn.cursor()
    cursor.execute("INSERT INTO transactions (amount) VALUES (?)", (100.00,))
    cursor.close()
    
    # Prepare the transaction (phase 1 of 2PC)
    conn.tpc_prepare()
    
    # At this point, transaction is prepared but not committed
    # Can now commit or rollback
    conn.tpc_commit()
    
    conn.close()
    import mariadb
    
    conn = mariadb.connect("mariadb://user:password@localhost/mydb")
    
    # Get list of pending prepared transactions
    pending_xids = conn.tpc_recover()
    
    if pending_xids:
        print(f"Found {len(pending_xids)} pending transactions")
        for xid_data in pending_xids:
            print(f"Pending XID: {xid_data}")
            # Can commit or rollback these transactions
            # xid = conn.xid(*xid_data)
            # conn.tpc_commit(xid)
    else:
        print("No pending transactions")
    
    conn.close()
    import mariadb
    
    conn = mariadb.connect("mariadb://user:password@localhost/mydb")
    
    xid = conn.xid(0, "global_tx_004", "branch_004")
    conn.tpc_begin(xid)
    
    cursor = conn.cursor()
    try:
        cursor.execute("UPDATE accounts SET balance = balance - 1000 WHERE id = ?", (1,))
        cursor.execute("UPDATE accounts SET balance = balance + 1000 WHERE id = ?", (2,))
        
        # Check for errors
        cursor.execute("SELECT balance FROM accounts WHERE id = 1")
        balance = cursor.fetchone()[0]
        
        if balance < 0:
            # Rollback the distributed transaction
            conn.tpc_rollback()
            print("Transaction rolled back - insufficient funds")
        else:
            conn.tpc_prepare()
            conn.tpc_commit()
            print("Transaction committed")
            
    except mariadb.Error as e:
        conn.tpc_rollback()
        print(f"Error: {e}")
    finally:
        cursor.close()
        conn.close()
    import mariadb
    
    conn = mariadb.connect("mariadb://user:password@localhost/mydb")
    
    if conn.server_mariadb:
        print("Connected to MariaDB server")
        print(f"Version: {conn.server_info}")
        # Use MariaDB-specific features
        cursor = conn.cursor()
        cursor.execute("SELECT JSON_DETAILED('{\"a\": 1}')")
    else:
        print("Connected to MySQL server")
        print(f"Version: {conn.server_info}")
        # Use MySQL-compatible features only
    
    conn.close()

    The cursor class

    MariaDB Connector/Python Cursor Object

    hashtag
    Cursor Parameters

    Cursors are created using the connection.cursor() method and accept the following optional parameters:

    hashtag
    Result Format Parameters

    • buffered (bool) - Buffer all results immediately in memory. When True (default), all rows are fetched and stored in memory. When False, results are streamed from the server, reducing memory usage for large result sets. Default: True

    hashtag
    Protocol Parameters

    • binary (bool) - Use binary protocol (prepared statements) for this cursor. Overrides the connection-level binary setting. When True, uses COM_STMT_PREPARE + COM_STMT_EXECUTE for better performance with repeated queries. Default: Inherits from connection

    hashtag
    Cursor Examples

    Basic cursor:

    Unbuffered cursor for large result sets:

    Dictionary cursor:

    Named tuple cursor:

    Binary protocol cursor:

    Combined parameters:

    hashtag
    Cursor methods

    hashtag
    Cursor.callproc(sp: str, data: Sequence[Any] = ()) -> None

    Executes a stored procedure sp. The data sequence must contain an entry for each parameter the procedure expects.

    Input/Output or Output parameters have to be retrieved by .fetch methods, the .sp_outparams attribute indicates if the result set contains output parameters.

    Arguments: : - sp: Name of stored procedure.

    • data: Optional sequence containing data for placeholder : substitution.

    Example:

    hashtag
    Cursor.execute(sql: str, data: Optional[Union[Sequence[Any], dict]] = None, buffered: Optional[bool] = None) -> None

    Prepare and execute a SQL statement.

    Parameters may be provided as sequence or mapping and will be bound to variables in the operation. Variables are specified as question marks (paramstyle ='qmark'), however for compatibility reasons MariaDB Connector/Python also supports the 'format' and 'pyformat' paramstyles with the restriction, that different paramstyles can't be mixed within a statement.

    A reference to the operation will be retained by the cursor.

    Since version 2.0: If the cursor was created with binary=True, the statement uses the MariaDB binary protocol (prepared statements). With prepared statement caching enabled (default), the first execution prepares the statement and subsequent executions reuse the cached prepared statement for better performance.

    By default execute() method generates a buffered result unless the optional parameter buffered was set to False or the cursor was generated as an unbuffered cursor.

    Protocol Selection (Version 2.0):

    • Text protocol (default): Standard SQL execution, predictable behavior

    • Binary protocol (binary=True): Uses COM_STMT_PREPARE + COM_STMT_EXECUTE

    • Dict parameters: Always use text protocol for named parameter substitution

    hashtag
    Cursor.executemany(sql: str, data: Sequence[Union[Sequence[Any], dict]], buffered: Optional[bool] = None) -> None

    Prepare a database operation (INSERT,UPDATE,REPLACE or DELETE statement) and execute it against all parameter found in sequence.

    Exactly behaves like .execute() but accepts a list of tuples, where each tuple represents data of a row within a table. .executemany() only supports DML (insert, update, delete) statements.

    If the SQL statement contains a RETURNING clause, executemany() returns a result set containing the values for columns listed in the RETURNING clause.

    Example:

    The following example will insert 3 rows:

    To insert special values like NULL or a column default, you need to specify indicators:

    • INDICATOR.NULL is used for NULL values

    • INDICATOR.IGNORE is used to skip update of a column.

    • INDICATOR.DEFAULT is used for a default value (insert/update)

    hashtag
    NOTE

    • All values for a column must have the same data type.

    • Indicators can only be used when connecting to a MariaDB Server 10.2 or newer. MySQL servers don’t support this feature.

    hashtag
    Cursor.fetchall() -> List[Any]

    Fetch all remaining rows of a query result, returning them as a sequence of sequences (e.g. a list of tuples).

    An exception will be raised if the previous call to execute() didn't produce a result set or execute() wasn't called before.

    Example:

    hashtag
    Cursor.fetchmany(size: Optional[int] = None) -> List[Any]

    Fetch the next set of rows of a query result, returning a sequence of sequences (e.g. a list of tuples). An empty sequence is returned when no more rows are available.

    The number of rows to fetch per call is specified by the parameter. If it is not given, the cursor's arraysize determines the number of rows to be fetched. The method should try to fetch as many rows as indicated by the size parameter. If this is not possible due to the specified number of rows not being available, fewer rows may be returned.

    An exception will be raised if the previous call to execute() didn't produce a result set or execute() wasn't called before.

    Example:

    hashtag
    Cursor.fetchone() -> Optional[Any]

    Fetch the next row of a query result set, returning a single sequence, or None if no more data is available.

    An exception will be raised if the previous call to execute() didn't produce a result set or execute() wasn't called before.

    Example:

    hashtag
    Cursor.next() -> Optional[Any]

    Return the next row from the currently executed SQL statement using the same semantics as .fetchone().

    hashtag
    Cursor.nextset() -> Optional[bool]

    Will make the cursor skip to the next available result set, discarding any remaining rows from the current set.

    hashtag
    Cursor.scroll(value: int, mode: str = 'relative') -> None

    Scroll the cursor in the result set to a new position according to mode.

    If mode is “relative” (default), value is taken as offset to the current position in the result set, if set to absolute, value states an absolute target position.

    hashtag
    Cursor.setinputsizes() -> None

    Required by PEP-249. Does nothing in MariaDB Connector/Python

    hashtag
    Cursor.setoutputsize() -> None

    Required by PEP-249. Does nothing in MariaDB Connector/Python

    hashtag
    Cursor attributes

    hashtag
    Cursor.arraysize: int

    (read/write)

    The number of rows to fetch at a time with .fetchmany().

    This read/write attribute defaults to 1 meaning to fetch a single row at a time.

    Example:

    hashtag
    Cursor.buffered: bool

    (read-only)

    Controls whether result sets are buffered in memory or streamed from the server.

    Buffered (True):

    • All result rows are immediately fetched and stored in client memory

    • The entire result set is transferred at once

    • Connection is freed immediately after execute()

    Unbuffered (False, default in 2.0):

    • Results are streamed row-by-row from the server

    • Only the current row is kept in memory

    • Connection remains blocked until all rows are fetched

    Example:

    Best Practices:

    hashtag
    Cursor.close() -> None

    Close the cursor and free resources. After closing, the cursor cannot be used anymore.

    Example:

    hashtag
    Cursor.connection: Connection

    (read-only)

    Returns the reference to the connection object on which the cursor was created.

    Example:

    hashtag
    Cursor.description: Optional[Sequence[Tuple]]

    (read-only)

    This read-only attribute is a sequence of 11-item tuples. Each tuple contains information describing one result column:

    1. name - Column name

    2. type_code - Column type code

    3. display_size - Display size

    This attribute will be None for operations that do not return rows or if the cursor has not had an operation invoked via the .execute*() method yet.

    Example:

    Checking BLOB vs TEXT fields:

    hashtag
    Cursor.lastrowid

    Returns the ID generated by a query on a table with a column having the AUTO_INCREMENT attribute or the value for the last usage of LAST_INSERT_ID().

    If the last query wasn’t an INSERT or UPDATE statement or if the modified table does not have a column with the AUTO_INCREMENT attribute and LAST_INSERT_ID was not used, the returned value will be None

    hashtag
    Cursor.metadata: Optional[Dict[str, List]]

    (read-only)

    Similar to the description property, this property returns a dictionary with complete metadata for all columns in the result set.

    Each dictionary key contains a list of values, one for each column in the result set.

    Dictionary Keys:

    • catalog - Catalog name (always 'def')

    • schema - Current schema/database name

    • field - Column alias name, or original column name if no alias

    Since version 1.1.8

    Example:

    Detecting Extended Types (JSON, UUID, INET, Geometry):

    hashtag
    Cursor.sp_outparams: bool

    (read-only)

    Indicates if the current result set contains OUT or INOUT parameters from a previously executed stored procedure.

    When calling a stored procedure with OUT or INOUT parameters using callproc() or execute(), the output parameters are returned as a separate result set. This attribute is True when the current result set contains these output parameters, and False otherwise.

    Example:

    Example with Multiple Result Sets:

    Using with Binary Protocol:

    hashtag
    Cursor.rowcount: int

    (read-only)

    Returns the number of rows that the last execute*() method produced (for DQL statements like SELECT) or affected (for DML statements like UPDATE, INSERT, DELETE).

    Return Values:

    • Positive number - Number of rows returned (SELECT) or affected (INSERT/UPDATE/DELETE)

    • -1 - No execute*() has been performed, or rowcount cannot be determined

    • 0 - Statement executed but no rows were affected/returned

    Important Notes:

    • For unbuffered cursors (default in 2.0), the exact row count is only available after all rows have been fetched

    • For buffered cursors, the row count is immediately available after execute()

    • For INSERT/UPDATE/DELETE, the row count is always immediately available

    Examples:

    Unbuffered Cursor (Default):

    Buffered Cursor:

    DML Statements (INSERT/UPDATE/DELETE):

    Batch Operations with executemany():

    Practical Use Case - Verify Operation Success:

    hashtag
    Cursor.statement: Optional[str]

    (read-only)

    Returns the last SQL statement that was executed by the cursor.

    Example:

    hashtag
    Cursor.warnings: int

    (read-only)

    Returns the number of warnings from the last executed statement, or zero if there are no warnings.

    Note: Detailed warning messages can be retrieved using the connection.show_warnings() method.

    Example:

    hashtag
    Cursor.rownumber: Optional[int]

    (read-only)

    Returns the current 0-based index of the cursor in the result set, or None if no result set is available.

    This property tracks the position within the current result set as rows are fetched.

    Example:

    hashtag
    Cursor.field_count: int

    (read-only)

    Returns the number of columns in the current result set, or 0 if there is no result set.

    Example:

    hashtag
    Cursor.closed: bool

    (read-only)

    Returns True if the cursor is closed, False otherwise.

    A cursor is considered closed if either the cursor itself was closed or the parent connection was closed.

    Example:

    Connection closure also closes cursors:

    named_tuple
    (
    bool
    ) - Return rows as named tuples instead of regular tuples. Allows accessing columns by name (e.g.,
    row.column_name
    ). Default:
    False
  • dictionary (bool) - Return rows as dictionaries instead of tuples. Allows accessing columns by name (e.g., row['column_name']). Default: False

  • native_object (bool) - Return native Python objects for certain database types. Default: False

  • INDICATOR.ROW is used to skip update/insert of the entire row.
    Multiple cursors can be active on the same connection
  • Higher memory usage for large result sets

  • Better for small to medium result sets

  • Only one unbuffered cursor can be active per connection
  • Lower memory usage - ideal for large result sets

  • Must fetch all rows before executing another query on the same connection

  • internal_size - Internal size
  • precision - Precision

  • scale - Scale

  • null_ok - Whether NULL values are allowed

  • field_flags - Field flags (extension to PEP-249)

  • table_name - Table name (extension to PEP-249)

  • original_column_name - Original column name (extension to PEP-249)

  • original_table_name - Original table name (extension to PEP-249)

  • org_field - Original column name
  • table - Table alias name, or original table name if no alias

  • org_table - Original table name

  • type - Column type (values from mariadb.constants.FIELD_TYPE)

  • charset - Character set (e.g., 'utf8mb4' or 'binary')

  • length - Maximum length of the column

  • max_length - Maximum length of data in the result set

  • decimals - Number of decimals for numeric types

  • flags - Field flags (values from mariadb.constants.FIELD_FLAG)

  • ext_type_or_format - Extended data type (values from mariadb.constants.EXT_FIELD_TYPE)

  • spinner
    import mariadb
    
    conn = mariadb.connect("mariadb://user:password@localhost/mydb")
    cursor = conn.cursor()
    cursor.execute("SELECT id, name FROM users")
    for row in cursor:
        print(f"ID: {row[0]}, Name: {row[1]}")
    cursor.close()
    conn.close()
    # Stream results to reduce memory usage
    cursor = conn.cursor(buffered=False)
    cursor.execute("SELECT * FROM large_table")
    for row in cursor:
        process_row(row)  # Process one row at a time
    cursor.close()
    # Access columns by name
    cursor = conn.cursor(dictionary=True)
    cursor.execute("SELECT id, name, email FROM users WHERE id = ?", (123,))
    user = cursor.fetchone()
    print(f"Name: {user['name']}, Email: {user['email']}")
    cursor.close()
    # Access columns as attributes
    cursor = conn.cursor(named_tuple=True)
    cursor.execute("SELECT id, name, email FROM users WHERE id = ?", (123,))
    user = cursor.fetchone()
    print(f"Name: {user.name}, Email: {user.email}")
    cursor.close()
    # Use prepared statements for this cursor
    cursor = conn.cursor(binary=True)
    # First execution prepares the statement
    cursor.execute("SELECT * FROM users WHERE id = ?", (1,))
    # Subsequent executions reuse the prepared statement
    cursor.execute("SELECT * FROM users WHERE id = ?", (2,))
    cursor.close()
    # Dictionary cursor with streaming results
    cursor = conn.cursor(dictionary=True, buffered=False)
    cursor.execute("SELECT * FROM large_table")
    for row in cursor:
        print(f"Processing: {row['name']}")
    cursor.close()
    >>>cursor.execute("CREATE PROCEDURE p1(IN i1 VAR  CHAR(20), OUT o2 VARCHAR(40))"
                      "BEGIN"
                      "  SELECT 'hello'"
                      "  o2:= 'test'"
                      "END")
    >>>cursor.callproc('p1', ('foo', 0))
    >>> cursor.sp_outparams
    False
    >>> cursor.fetchone()
    ('hello',)
    >>> cursor.nextset()
    True
    >>> cursor.sp_outparams
    True
    >>> cursor.fetchone()
    ('test',)
    data= [
        (1, 'Michael', 'Widenius')
        (2, 'Diego', 'Dupin')
        (3, 'Lawrin', 'Novitsky')
    ]
    cursor.executemany("INSERT INTO colleagues VALUES (?, ?, ?)", data)
    import mariadb
    
    conn = mariadb.connect("mariadb://user:password@localhost/mydb")
    cursor = conn.cursor()
    
    cursor.execute("SELECT id, name, email FROM users")
    
    # Fetch all rows at once
    rows = cursor.fetchall()
    for row in rows:
        print(f"ID: {row[0]}, Name: {row[1]}, Email: {row[2]}")
    
    print(f"Total rows: {len(rows)}")
    
    cursor.close()
    conn.close()
    import mariadb
    
    conn = mariadb.connect("mariadb://user:password@localhost/mydb")
    cursor = conn.cursor()
    
    cursor.execute("SELECT id, name FROM users ORDER BY id")
    
    # Fetch rows in batches of 10
    while True:
        rows = cursor.fetchmany(10)
        if not rows:
            break
        
        print(f"Processing batch of {len(rows)} rows")
        for row in rows:
            print(f"  ID: {row[0]}, Name: {row[1]}")
    
    cursor.close()
    conn.close()
    import mariadb
    
    conn = mariadb.connect("mariadb://user:password@localhost/mydb")
    cursor = conn.cursor()
    
    cursor.execute("SELECT id, name FROM users WHERE id = ?", (1,))
    
    # Fetch single row
    row = cursor.fetchone()
    if row:
        print(f"User found: ID={row[0]}, Name={row[1]}")
    else:
        print("User not found")
    
    cursor.close()
    conn.close()
    import mariadb
    
    conn = mariadb.connect("mariadb://user:password@localhost/mydb")
    cursor = conn.cursor()
    
    # Set arraysize for batch processing
    cursor.arraysize = 100
    
    cursor.execute("SELECT * FROM large_table")
    
    # fetchmany() will now fetch 100 rows at a time by default
    while True:
        rows = cursor.fetchmany()
        if not rows:
            break
        print(f"Processing {len(rows)} rows")
    
    cursor.close()
    conn.close()
    import mariadb
    
    conn = mariadb.connect("mariadb://user:password@localhost/mydb")
    
    # Unbuffered cursor (default) - streams results, low memory usage
    cursor1 = conn.cursor(buffered=False)
    print(f"Buffered: {cursor1.buffered}")  # Output: False
    
    cursor1.execute("SELECT * FROM large_table")  # 1 million rows
    # Rows are streamed one at a time, not all loaded into memory
    for row in cursor1:
        process_row(row)  # Memory efficient
    cursor1.close()
    
    # Buffered cursor - fetches all results immediately into memory
    cursor2 = conn.cursor(buffered=True)
    print(f"Buffered: {cursor2.buffered}")  # Output: True
    
    cursor2.execute("SELECT * FROM small_table")  # 100 rows
    rows = cursor2.fetchall()  # All rows loaded into memory at once
    # Connection is now free for other operations
    cursor2.close()
    
    conn.close()
    import mariadb
    
    conn = mariadb.connect("mariadb://user:password@localhost/mydb")
    
    # Use unbuffered for large result sets to avoid memory issues
    cursor = conn.cursor(buffered=False)
    cursor.execute("SELECT * FROM huge_table")  # Millions of rows
    
    # Process rows one at a time without loading all into memory
    for row in cursor:
        # Each row is fetched on demand
        process_large_row(row)
    
    cursor.close()
    
    # Use buffered for small result sets when you need connection freedom
    cursor = conn.cursor(buffered=True)
    cursor.execute("SELECT * FROM config WHERE active = 1")  # Few rows
    config = cursor.fetchall()  # Safe to load all into memory
    cursor.close()
    
    # Can now use connection for other operations immediately
    cursor2 = conn.cursor()
    cursor2.execute("SELECT COUNT(*) FROM users")
    count = cursor2.fetchone()[0]
    cursor2.close()
    
    conn.close()
    import mariadb
    
    conn = mariadb.connect("mariadb://user:password@localhost/mydb")
    
    # Using context manager (recommended - auto-closes)
    with conn.cursor() as cursor:
        cursor.execute("SELECT COUNT(*) FROM users")
        count = cursor.fetchone()[0]
        print(f"Total users: {count}")
    # Cursor automatically closed here
    
    # Manual close
    cursor = conn.cursor()
    try:
        cursor.execute("SELECT * FROM users LIMIT 5")
        rows = cursor.fetchall()
    finally:
        cursor.close()  # Always close in finally block
    
    conn.close()
    import mariadb
    
    conn = mariadb.connect("mariadb://user:password@localhost/mydb")
    cursor = conn.cursor()
    
    # Access connection from cursor
    print(f"Database: {cursor.connection.database}")
    print(f"User: {cursor.connection.user}")
    print(f"Connection ID: {cursor.connection.connection_id}")
    
    cursor.close()
    conn.close()
    import mariadb
    
    conn = mariadb.connect("mariadb://user:password@localhost/mydb")
    cursor = conn.cursor()
    
    cursor.execute("SELECT id, name, email, created_at FROM users LIMIT 1")
    
    # Get column information
    if cursor.description:
        print("Column Information:")
        for i, col in enumerate(cursor.description):
            print(f"\nColumn {i}:")
            print(f"  Name: {col[0]}")
            print(f"  Type: {col[1]}")
            print(f"  Nullable: {col[6]}")
            print(f"  Table: {col[8]}")
            print(f"  Original Name: {col[9]}")
    
    # Example output:
    # Column 0:
    #   Name: id
    #   Type: 3
    #   Nullable: 0
    #   Table: users
    #   Original Name: id
    
    cursor.close()
    conn.close()
    import mariadb
    from mariadb.constants import FIELD_TYPE, FIELD_FLAG
    
    conn = mariadb.connect("mariadb://user:password@localhost/mydb")
    cursor = conn.cursor()
    
    cursor.execute("SELECT content FROM documents LIMIT 1")
    
    if cursor.description[0][1] == FIELD_TYPE.BLOB:
        if cursor.description[0][7] & FIELD_FLAG.BINARY:
            print("Column is BLOB")
        else:
            print("Column is TEXT")
    
    cursor.close()
    conn.close()
    import mariadb
    from mariadb.constants import FIELD_TYPE, FIELD_FLAG, EXT_FIELD_TYPE
    
    conn = mariadb.connect("mariadb://user:password@localhost/mydb")
    cursor = conn.cursor()
    
    cursor.execute("""
        SELECT 
            id,
            name AS user_name,
            email,
            created_at
        FROM users
        LIMIT 1
    """)
    
    # Get complete metadata
    metadata = cursor.metadata
    
    if metadata:
        print("Complete Column Metadata:")
        print(f"Number of columns: {len(metadata['field'])}\n")
        
        for i in range(len(metadata['field'])):
            print(f"Column {i}:")
            print(f"  Field (alias): {metadata['field'][i]}")
            print(f"  Original field: {metadata['org_field'][i]}")
            print(f"  Table (alias): {metadata['table'][i]}")
            print(f"  Original table: {metadata['org_table'][i]}")
            print(f"  Schema: {metadata['schema'][i]}")
            print(f"  Type: {metadata['type'][i]}")
            print(f"  Charset: {metadata['charset'][i]}")
            print(f"  Length: {metadata['length'][i]}")
            print(f"  Max length: {metadata['max_length'][i]}")
            print(f"  Decimals: {metadata['decimals'][i]}")
            print(f"  Flags: {metadata['flags'][i]}")
            print()
    
    # Example output:
    # Column 0:
    #   Field (alias): id
    #   Original field: id
    #   Table (alias): users
    #   Original table: users
    #   Schema: mydb
    #   Type: 3
    #   Charset: binary
    #   Length: 11
    #   Max length: 1
    #   Decimals: 0
    #   Flags: 16899
    
    cursor.close()
    conn.close()
    import mariadb
    from mariadb.constants import FIELD_TYPE, EXT_FIELD_TYPE
    
    conn = mariadb.connect("mariadb://user:password@localhost/mydb")
    cursor = conn.cursor()
    
    # Create table with extended types
    cursor.execute("""
        CREATE TEMPORARY TABLE test_types (
            data JSON,
            user_id UUID,
            ip_addr INET4,
            location POINT
        )
    """)
    
    cursor.execute("SELECT data, user_id, ip_addr, location FROM test_types")
    metadata = cursor.metadata
    
    # Check extended types
    for i, field_name in enumerate(metadata['field']):
        ext_type = metadata['ext_type_or_format'][i]
        base_type = metadata['type'][i]
        
        print(f"{field_name}:")
        print(f"  Base type: {base_type}")
        
        if ext_type == EXT_FIELD_TYPE.JSON:
            print(f"  Extended type: JSON")
        elif ext_type == EXT_FIELD_TYPE.UUID:
            print(f"  Extended type: UUID")
        elif ext_type == EXT_FIELD_TYPE.INET4:
            print(f"  Extended type: INET4")
        elif ext_type == EXT_FIELD_TYPE.POINT:
            print(f"  Extended type: POINT (Geometry)")
        print()
    
    cursor.close()
    conn.close()
    import mariadb
    
    conn = mariadb.connect("mariadb://user:password@localhost/mydb")
    cursor = conn.cursor()
    
    # Create a stored procedure with OUT parameter
    cursor.execute("DROP PROCEDURE IF EXISTS calculate_total")
    cursor.execute("""
        CREATE PROCEDURE calculate_total(
            IN user_id INT,
            OUT total_amount DECIMAL(10,2)
        )
        BEGIN
            SELECT SUM(amount) INTO total_amount
            FROM orders
            WHERE user_id = user_id;
        END
    """)
    
    # Call the procedure with OUT parameter
    cursor.callproc("calculate_total", (123, 0))
    
    # First check if current result set contains output parameters
    print(f"Has output params: {cursor.sp_outparams}")  # Output: True
    
    # Fetch the output parameter value
    result = cursor.fetchone()
    total = result[0]
    print(f"Total amount: {total}")
    
    cursor.close()
    conn.close()
    import mariadb
    
    conn = mariadb.connect("mariadb://user:password@localhost/mydb")
    cursor = conn.cursor()
    
    # Create procedure that returns data AND has OUT parameter
    cursor.execute("DROP PROCEDURE IF EXISTS get_user_stats")
    cursor.execute("""
        CREATE PROCEDURE get_user_stats(
            IN user_id INT,
            OUT order_count INT
        )
        BEGIN
            -- First result set: user details
            SELECT id, name, email FROM users WHERE id = user_id;
            
            -- Set OUT parameter
            SELECT COUNT(*) INTO order_count
            FROM orders
            WHERE user_id = user_id;
        END
    """)
    
    # Call the procedure
    cursor.callproc("get_user_stats", (123, 0))
    
    # First result set: user details
    print(f"Has output params: {cursor.sp_outparams}")  # Output: False
    user = cursor.fetchone()
    print(f"User: {user}")
    
    # Move to next result set (OUT parameters)
    cursor.nextset()
    print(f"Has output params: {cursor.sp_outparams}")  # Output: True
    out_params = cursor.fetchone()
    order_count = out_params[0]
    print(f"Order count: {order_count}")
    
    cursor.execute("DROP PROCEDURE IF EXISTS get_user_stats")
    cursor.close()
    conn.close()
    import mariadb
    
    conn = mariadb.connect("mariadb://user:password@localhost/mydb")
    cursor = conn.cursor(binary=True)
    
    # Call procedure using CALL statement with binary protocol
    cursor.execute("CALL calculate_total(?, ?)", (123, 0))
    
    # Check if result contains output parameters
    if cursor.sp_outparams:
        result = cursor.fetchone()
        print(f"Total: {result[0]}")
    
    cursor.close()
    conn.close()
    import mariadb
    
    conn = mariadb.connect("mariadb://user:password@localhost/mydb")
    cursor = conn.cursor(buffered=False)  # Default
    
    # Execute SELECT
    cursor.execute("SELECT * FROM users")
    
    # Rowcount is -1 until all rows are fetched
    print(f"Rowcount before fetch: {cursor.rowcount}")  # Output: -1
    
    # Fetch all rows
    rows = cursor.fetchall()
    
    # Now rowcount is available
    print(f"Rowcount after fetch: {cursor.rowcount}")  # Output: 150 (actual count)
    print(f"Rows fetched: {len(rows)}")  # Output: 150
    
    cursor.close()
    conn.close()
    import mariadb
    
    conn = mariadb.connect("mariadb://user:password@localhost/mydb")
    cursor = conn.cursor(buffered=True)
    
    # Execute SELECT
    cursor.execute("SELECT * FROM users WHERE active = 1")
    
    # Rowcount is immediately available for buffered cursors
    print(f"Rowcount: {cursor.rowcount}")  # Output: 42 (immediately)
    
    # Fetch the rows
    rows = cursor.fetchall()
    print(f"Rows fetched: {len(rows)}")  # Output: 42
    
    cursor.close()
    conn.close()
    import mariadb
    
    conn = mariadb.connect("mariadb://user:password@localhost/mydb")
    cursor = conn.cursor()
    
    # INSERT - rowcount shows affected rows
    cursor.execute("INSERT INTO users (name, email) VALUES (?, ?)", 
                   ("John Doe", "john@example.com"))
    print(f"Rows inserted: {cursor.rowcount}")  # Output: 1
    
    # UPDATE - rowcount shows affected rows
    cursor.execute("UPDATE users SET active = 1 WHERE created_at < NOW()")
    print(f"Rows updated: {cursor.rowcount}")  # Output: 25
    
    # DELETE - rowcount shows affected rows
    cursor.execute("DELETE FROM users WHERE active = 0")
    print(f"Rows deleted: {cursor.rowcount}")  # Output: 10
    
    # UPDATE with no matching rows
    cursor.execute("UPDATE users SET active = 1 WHERE id = 99999")
    print(f"Rows updated: {cursor.rowcount}")  # Output: 0 (no rows matched)
    
    conn.commit()
    cursor.close()
    conn.close()
    import mariadb
    
    conn = mariadb.connect("mariadb://user:password@localhost/mydb")
    cursor = conn.cursor()
    
    # Insert multiple rows
    data = [
        ("Alice", "alice@example.com"),
        ("Bob", "bob@example.com"),
        ("Charlie", "charlie@example.com")
    ]
    
    cursor.executemany("INSERT INTO users (name, email) VALUES (?, ?)", data)
    print(f"Total rows inserted: {cursor.rowcount}")  # Output: 3
    
    conn.commit()
    cursor.close()
    conn.close()
    import mariadb
    
    conn = mariadb.connect("mariadb://user:password@localhost/mydb")
    cursor = conn.cursor()
    
    # Update a specific user
    user_id = 123
    cursor.execute("UPDATE users SET last_login = NOW() WHERE id = ?", (user_id,))
    
    if cursor.rowcount == 0:
        print(f"Warning: User {user_id} not found or not updated")
    elif cursor.rowcount == 1:
        print(f"User {user_id} updated successfully")
        conn.commit()
    else:
        print(f"Error: Multiple rows affected ({cursor.rowcount})")
        conn.rollback()
    
    cursor.close()
    conn.close()
    import mariadb
    
    conn = mariadb.connect("mariadb://user:password@localhost/mydb")
    cursor = conn.cursor()
    
    # Execute a query
    cursor.execute("SELECT * FROM users WHERE id = ?", (123,))
    
    # Get the executed statement
    print(f"Last statement: {cursor.statement}")
    # Output: Last statement: SELECT * FROM users WHERE id = ?
    
    # Execute another query
    cursor.execute("UPDATE users SET last_login = NOW() WHERE id = ?", (123,))
    print(f"Last statement: {cursor.statement}")
    # Output: Last statement: UPDATE users SET last_login = NOW() WHERE id = ?
    
    cursor.close()
    conn.close()
    import mariadb
    
    conn = mariadb.connect("mariadb://user:password@localhost/mydb")
    cursor = conn.cursor()
    
    # Execute statement that may generate warnings
    cursor.execute("SET session sql_mode=''")
    cursor.execute("CREATE TEMPORARY TABLE test_warn (a tinyint)")
    cursor.execute("INSERT INTO test_warn VALUES (300)")  # Out of range
    
    # Check warning count from cursor
    if cursor.warnings > 0:
        print(f"Number of warnings: {cursor.warnings}")
        
        # Get detailed warnings from connection
        warnings = conn.show_warnings()
        for level, code, message in warnings:
            print(f"{level} ({code}): {message}")
        # Output: Warning (1264): Out of range value for column 'a' at row 1
    
    cursor.close()
    conn.close()
    import mariadb
    
    conn = mariadb.connect("mariadb://user:password@localhost/mydb")
    cursor = conn.cursor()
    
    cursor.execute("SELECT id, name FROM users ORDER BY id LIMIT 5")
    
    print(f"Initial rownumber: {cursor.rownumber}")  # Output: 0
    
    # Fetch rows one by one
    row1 = cursor.fetchone()
    print(f"After 1st fetch: {cursor.rownumber}")  # Output: 1
    
    row2 = cursor.fetchone()
    print(f"After 2nd fetch: {cursor.rownumber}")  # Output: 2
    
    # Fetch remaining rows
    remaining = cursor.fetchall()
    print(f"After fetchall: {cursor.rownumber}")  # Output: 5
    
    cursor.close()
    conn.close()
    import mariadb
    
    conn = mariadb.connect("mariadb://user:password@localhost/mydb")
    cursor = conn.cursor()
    
    # Before executing any query
    print(f"Field count: {cursor.field_count}")  # Output: 0
    
    # Execute SELECT with 3 columns
    cursor.execute("SELECT id, name, email FROM users LIMIT 1")
    print(f"Field count: {cursor.field_count}")  # Output: 3
    
    # Execute SELECT with all columns
    cursor.execute("SELECT * FROM users LIMIT 1")
    print(f"Field count: {cursor.field_count}")  # Output: (number of columns in users table)
    
    # Execute non-SELECT statement
    cursor.execute("UPDATE users SET active = 1 WHERE id = 1")
    print(f"Field count: {cursor.field_count}")  # Output: 0 (no result set)
    
    cursor.close()
    conn.close()
    import mariadb
    
    conn = mariadb.connect("mariadb://user:password@localhost/mydb")
    cursor = conn.cursor()
    
    print(f"Cursor closed: {cursor.closed}")  # Output: False
    
    # Execute a query
    cursor.execute("SELECT 1")
    print(f"Cursor closed: {cursor.closed}")  # Output: False
    
    # Close the cursor
    cursor.close()
    print(f"Cursor closed: {cursor.closed}")  # Output: True
    
    # Trying to use a closed cursor raises an error
    try:
        cursor.execute("SELECT 2")
    except mariadb.ProgrammingError as e:
        print(f"Error: {e}")  # Output: Error: Cursor is closed
    
    conn.close()
    import mariadb
    
    conn = mariadb.connect("mariadb://user:password@localhost/mydb")
    cursor = conn.cursor()
    
    print(f"Cursor closed: {cursor.closed}")  # Output: False
    
    # Close the connection
    conn.close()
    
    # Cursor is now also considered closed
    print(f"Cursor closed: {cursor.closed}")  # Output: True