mirror of
https://github.com/mariadb-corporation/mariadb-connector-python.git
synced 2025-08-07 11:39:43 +00:00
cursor:
added keyword quote_sequences (default=true) connection: moved tpc functions to native python moved autocommit to native python
This commit is contained in:
Binary file not shown.
@ -22,9 +22,11 @@ import socket
|
|||||||
import time
|
import time
|
||||||
|
|
||||||
from mariadb.constants import STATUS
|
from mariadb.constants import STATUS
|
||||||
|
from mariadb.constants import TPC_STATE
|
||||||
|
|
||||||
_DEFAULT_CHARSET = "utf8mb4"
|
_DEFAULT_CHARSET = "utf8mb4"
|
||||||
_DEFAULT_COLLATION = "utf8mb4_general_ci"
|
_DEFAULT_COLLATION = "utf8mb4_general_ci"
|
||||||
|
_MAX_TPC_XID_SIZE=64
|
||||||
|
|
||||||
class Connection(mariadb._mariadb.connection):
|
class Connection(mariadb._mariadb.connection):
|
||||||
"""MariaDB connection class"""
|
"""MariaDB connection class"""
|
||||||
@ -34,11 +36,14 @@ class Connection(mariadb._mariadb.connection):
|
|||||||
self.__in_use= 0
|
self.__in_use= 0
|
||||||
self.__pool = None
|
self.__pool = None
|
||||||
self.__last_used = 0
|
self.__last_used = 0
|
||||||
|
self.tpc_state= TPC_STATE.NONE
|
||||||
|
self._xid= None
|
||||||
|
|
||||||
# self._autocommit= kwargs.pop("autocommit", True)
|
autocommit= kwargs.pop("autocommit", False)
|
||||||
self._converter= kwargs.pop("converter", None)
|
self._converter= kwargs.pop("converter", None)
|
||||||
|
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
self.autocommit= autocommit
|
||||||
|
|
||||||
def cursor(self, **kwargs):
|
def cursor(self, **kwargs):
|
||||||
cursor= mariadb.Cursor(self, **kwargs)
|
cursor= mariadb.Cursor(self, **kwargs)
|
||||||
@ -58,9 +63,197 @@ class Connection(mariadb._mariadb.connection):
|
|||||||
"Closes connection."
|
"Closes connection."
|
||||||
self.close()
|
self.close()
|
||||||
|
|
||||||
|
def commit(self):
|
||||||
|
if self.tpc_state > TPC_STATE.NONE:
|
||||||
|
raise mariadb.ProgrammingError("commit() is not allowed if a TPC transaction is active")
|
||||||
|
self._execute_command("COMMIT")
|
||||||
|
self._read_response()
|
||||||
|
|
||||||
|
def rollback(self):
|
||||||
|
if self.tpc_state > TPC_STATE.NONE:
|
||||||
|
raise mariadb.ProgrammingError("rollback() is not allowed if a TPC transaction is active")
|
||||||
|
self._execute_command("ROLLBACK")
|
||||||
|
self._read_response()
|
||||||
|
|
||||||
def get_server_version(self):
|
def get_server_version(self):
|
||||||
return self.server_version_info
|
return self.server_version_info
|
||||||
|
|
||||||
|
class xid(tuple):
|
||||||
|
"""
|
||||||
|
A transaction ID object suitable for passing to the .tpc_*()
|
||||||
|
methods of this connection.
|
||||||
|
"""
|
||||||
|
def __new__(self, format_id, transaction_id, branch_qualifier):
|
||||||
|
if not isinstance(format_id, int):
|
||||||
|
raise TypeError("argument 1 must be int, not %s", type(format_id).__name__)
|
||||||
|
if not isinstance(transaction_id, str):
|
||||||
|
raise TypeError("argument 2 must be str, not %s", type(transaction_id).__mane__)
|
||||||
|
if not isinstance(branch_qualifier, str):
|
||||||
|
raise TypeError("argument 3 must be str, not %s", type(transaction_id).__name__)
|
||||||
|
if len(transaction_id) > _MAX_TPC_XID_SIZE:
|
||||||
|
raise mariadb.ProgrammingError("Maximum length of transaction_id exceeded.")
|
||||||
|
if len(branch_qualifier) > _MAX_TPC_XID_SIZE:
|
||||||
|
raise mariadb.ProgrammingError("Maximum length of branch_qualifier exceeded.")
|
||||||
|
if format_id == 0:
|
||||||
|
format_id= 1
|
||||||
|
return super().__new__(self, (format_id, transaction_id, branch_qualifier))
|
||||||
|
|
||||||
|
def tpc_begin(self, xid):
|
||||||
|
"""
|
||||||
|
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 of a transaction
|
||||||
|
(i.e. nothing may have 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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if type(xid).__name__ != "xid":
|
||||||
|
raise TypeError("argument 1 must be xid not %s", type(xid).__name__)
|
||||||
|
stmt= "XA BEGIN '%s','%s',%s" % (xid[1], xid[2], xid[0])
|
||||||
|
try:
|
||||||
|
self._execute_command(stmt)
|
||||||
|
self._read_response()
|
||||||
|
except:
|
||||||
|
raise
|
||||||
|
self.tpc_state= TPC_STATE.XID
|
||||||
|
self._xid= xid
|
||||||
|
|
||||||
|
def tpc_commit(self, xid=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 of a transaction, and
|
||||||
|
is intended for use in recovery."
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not xid:
|
||||||
|
xid= self._xid
|
||||||
|
|
||||||
|
if self.tpc_state == TPC_STATE.NONE:
|
||||||
|
raise mariadb.ProgrammingError("Transaction not started.")
|
||||||
|
if xid is None and self.tpc_state != TPC_STATE.PREPARE:
|
||||||
|
raise mariadb.ProgrammingError("Transaction is not prepared.")
|
||||||
|
if xid and type(xid).__name__ != "xid":
|
||||||
|
raise TypeError("argument 1 must be xid not %s" % type(xid).__name__)
|
||||||
|
|
||||||
|
if self.tpc_state < TPC_STATE.PREPARE:
|
||||||
|
stmt= "XA END '%s','%s',%s" % (xid[1], xid[2], xid[0])
|
||||||
|
self._execute_command(stmt)
|
||||||
|
try:
|
||||||
|
self._read_response()
|
||||||
|
except:
|
||||||
|
self._xid= None
|
||||||
|
self.tpc_state= TPC_STATE.NONE
|
||||||
|
raise
|
||||||
|
|
||||||
|
stmt= "XA COMMIT '%s','%s',%s" % (xid[1], xid[2], xid[0])
|
||||||
|
if self.tpc_state < TPC_STATE.PREPARE:
|
||||||
|
stmt= stmt + " ONE PHASE"
|
||||||
|
try:
|
||||||
|
self._execute_command(stmt)
|
||||||
|
self._read_response()
|
||||||
|
except:
|
||||||
|
self._xid= None
|
||||||
|
self.tpc_state= TPC_STATE.NONE
|
||||||
|
raise
|
||||||
|
|
||||||
|
#cleanup
|
||||||
|
self._xid= None
|
||||||
|
self.tpc_state= TPC_STATE.NONE
|
||||||
|
|
||||||
|
def tpc_prepare(self):
|
||||||
|
"""
|
||||||
|
Performs the first phase of a transaction started with .tpc_begin().
|
||||||
|
A ProgrammingError will be raised if this method outside of a TPC
|
||||||
|
transaction.
|
||||||
|
|
||||||
|
After calling .tpc_prepare(), no statements can be executed until
|
||||||
|
.tpc_commit() or .tpc_rollback() have been called.
|
||||||
|
"""
|
||||||
|
if self.tpc_state == TPC_STATE.NONE:
|
||||||
|
raise mariadb.ProgrammingError("Transaction not started.")
|
||||||
|
if self.tpc_state == TPC_STATE.PREPARE:
|
||||||
|
raise mariadb.ProgrammingError("Transaction is already in prepared state.")
|
||||||
|
|
||||||
|
xid= self._xid
|
||||||
|
stmt= "XA END '%s','%s',%s" % (xid[1], xid[2], xid[0])
|
||||||
|
try:
|
||||||
|
self._execute_command(stmt)
|
||||||
|
self._read_response()
|
||||||
|
except:
|
||||||
|
self._xid= None
|
||||||
|
self.tpc_state= TPC_STATE.NONE
|
||||||
|
raise
|
||||||
|
|
||||||
|
stmt= "XA PREPARE '%s','%s',%s" % (xid[1], xid[2], xid[0])
|
||||||
|
try:
|
||||||
|
self._execute_command(stmt)
|
||||||
|
self._read_response()
|
||||||
|
except:
|
||||||
|
self._xid= None
|
||||||
|
self.tpc_state= TPC_STATE.NONE
|
||||||
|
raise
|
||||||
|
|
||||||
|
self.tpc_state= TPC_STATE.PREPARE
|
||||||
|
|
||||||
|
def tpc_rollback(self, xid=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 of a TPC
|
||||||
|
transaction.
|
||||||
|
|
||||||
|
After calling .tpc_prepare(), no statements can be executed until
|
||||||
|
.tpc_commit() or .tpc_rollback() have been called.
|
||||||
|
"""
|
||||||
|
if self.tpc_state == TPC_STATE.NONE:
|
||||||
|
raise mariadb.ProgrammingError("Transaction not started.")
|
||||||
|
if xid and type(xid).__name__ != "xid":
|
||||||
|
raise TypeError("argument 1 must be xid not %s" % type(xid).__name__)
|
||||||
|
|
||||||
|
if not xid:
|
||||||
|
xid= self._xid
|
||||||
|
|
||||||
|
if self.tpc_state < TPC_STATE.PREPARE:
|
||||||
|
stmt= "XA END '%s','%s',%s" % (xid[1], xid[2], xid[0])
|
||||||
|
self._execute_command(stmt)
|
||||||
|
try:
|
||||||
|
self._read_response()
|
||||||
|
except:
|
||||||
|
self._xid= None
|
||||||
|
self.tpc_state= TPC_STATE.NONE
|
||||||
|
raise
|
||||||
|
|
||||||
|
stmt= "XA ROLLBACK '%s','%s',%s" % (xid[1], xid[2], xid[0])
|
||||||
|
try:
|
||||||
|
self._execute_command(stmt)
|
||||||
|
self._read_response()
|
||||||
|
except:
|
||||||
|
self._xid= None
|
||||||
|
self.tpc_state= TPC_STATE.NONE
|
||||||
|
raise
|
||||||
|
|
||||||
|
self.tpc_state= TPC_STATE.PREPARE
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def character_set(self):
|
def character_set(self):
|
||||||
"""Client character set."""
|
"""Client character set."""
|
||||||
@ -81,6 +274,20 @@ class Connection(mariadb._mariadb.connection):
|
|||||||
version= self.server_version
|
version= self.server_version
|
||||||
return (int(version / 10000), int((version % 10000) / 100), version % 100)
|
return (int(version / 10000), int((version % 10000) / 100), version % 100)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def get_autocommit(self):
|
||||||
|
return bool(self.server_status & STATUS.AUTOCOMMIT)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def set_autocommit(self, mode):
|
||||||
|
if bool(mode) == self.autocommit:
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
self._execute_command("SET AUTOCOMMIT=%s" % int(mode))
|
||||||
|
self._read_response()
|
||||||
|
except:
|
||||||
|
raise
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def socket(self):
|
def socket(self):
|
||||||
"""Returns the socket used for database connection"""
|
"""Returns the socket used for database connection"""
|
||||||
|
3
mariadb/constants/TPC_STATE.py
Normal file
3
mariadb/constants/TPC_STATE.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
NONE=0
|
||||||
|
XID=1
|
||||||
|
PREPARE=2
|
@ -59,6 +59,7 @@ class Cursor(mariadb._mariadb.cursor):
|
|||||||
|
|
||||||
self._parseinfo= None
|
self._parseinfo= None
|
||||||
self._data= None
|
self._data= None
|
||||||
|
self._quote_sequence= True
|
||||||
|
|
||||||
if not connection:
|
if not connection:
|
||||||
raise mariadb.ProgrammingError("Invalid or no connection provided")
|
raise mariadb.ProgrammingError("Invalid or no connection provided")
|
||||||
@ -76,6 +77,7 @@ class Cursor(mariadb._mariadb.cursor):
|
|||||||
self._prepared= kwargs.pop("prepared", False)
|
self._prepared= kwargs.pop("prepared", False)
|
||||||
self._force_binary= kwargs.pop("binary", False)
|
self._force_binary= kwargs.pop("binary", False)
|
||||||
self._cursor_type= kwargs.pop("cursor_type", 0)
|
self._cursor_type= kwargs.pop("cursor_type", 0)
|
||||||
|
self._quote_sequence= kwargs.pop("quote_sequence", True)
|
||||||
|
|
||||||
super().__init__(connection, **kwargs)
|
super().__init__(connection, **kwargs)
|
||||||
|
|
||||||
@ -101,12 +103,13 @@ class Cursor(mariadb._mariadb.cursor):
|
|||||||
else:
|
else:
|
||||||
if isinstance(val, (bytes, bytearray)):
|
if isinstance(val, (bytes, bytearray)):
|
||||||
replace= "\"%s\"" % self.connection.escape_string(val.decode(encoding='latin1'))
|
replace= "\"%s\"" % self.connection.escape_string(val.decode(encoding='latin1'))
|
||||||
|
if isinstance(val, (list,tuple)) and self._quote_sequence == False:
|
||||||
|
replace= tuple(val)
|
||||||
else:
|
else:
|
||||||
replace= "\"%s\"" % self.connection.escape_string(val.__str__())
|
replace= "\"%s\"" % self.connection.escape_string(val.__str__())
|
||||||
start= self._paramlist[i] + replace_diff
|
ofs= self._paramlist[i] + replace_diff
|
||||||
end= self._paramlist[i] + replace_diff + 1
|
|
||||||
|
|
||||||
new_stmt= new_stmt[:start] + replace.__str__() + new_stmt[end:]
|
new_stmt= new_stmt[:ofs] + replace.__str__() + new_stmt[ofs+1:]
|
||||||
replace_diff+= len(replace) - 1
|
replace_diff+= len(replace) - 1
|
||||||
return new_stmt
|
return new_stmt
|
||||||
|
|
||||||
|
@ -883,6 +883,7 @@ mariadb_get_column_info(PyObject *obj, MrdbParamInfo *paraminfo)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
/* If Object has string representation, we will use string representation */
|
||||||
/* no corresponding object, return error */
|
/* no corresponding object, return error */
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ char *dsn_keys[]= {
|
|||||||
"client_flag", "pool_name", "pool_size",
|
"client_flag", "pool_name", "pool_size",
|
||||||
"pool_reset_connection", "plugin_dir",
|
"pool_reset_connection", "plugin_dir",
|
||||||
"username", "db", "passwd",
|
"username", "db", "passwd",
|
||||||
"autocommit", "converter", "asynchronous",
|
"converter", "asynchronous",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -84,26 +84,19 @@ MrdbConnection_escape_string(MrdbConnection *self, PyObject *args);
|
|||||||
static PyObject *
|
static PyObject *
|
||||||
MrdbConnection_warnings(MrdbConnection *self);
|
MrdbConnection_warnings(MrdbConnection *self);
|
||||||
|
|
||||||
static PyObject *
|
|
||||||
MrdbConnection_getautocommit(MrdbConnection *self);
|
|
||||||
|
|
||||||
static int
|
|
||||||
MrdbConnection_setautocommit(MrdbConnection *self, PyObject *arg,
|
|
||||||
void *closure);
|
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
MrdbConnection_get_server_status(MrdbConnection *self);
|
MrdbConnection_get_server_status(MrdbConnection *self);
|
||||||
|
|
||||||
PyObject *
|
static PyObject *
|
||||||
MrdbConnection_executecommand(MrdbConnection *self,
|
MrdbConnection_executecommand(MrdbConnection *self,
|
||||||
PyObject *args);
|
PyObject *args);
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
MrdbConnection_readresponse(MrdbConnection *self);
|
||||||
|
|
||||||
static PyGetSetDef
|
static PyGetSetDef
|
||||||
MrdbConnection_sets[]=
|
MrdbConnection_sets[]=
|
||||||
{
|
{
|
||||||
{"autocommit", (getter)MrdbConnection_getautocommit,
|
|
||||||
(setter)MrdbConnection_setautocommit,
|
|
||||||
connection_autocommit__doc__, NULL},
|
|
||||||
{"connection_id", (getter)MrdbConnection_getid, NULL,
|
{"connection_id", (getter)MrdbConnection_getid, NULL,
|
||||||
connection_connection_id__doc__, NULL},
|
connection_connection_id__doc__, NULL},
|
||||||
{"database", (getter)MrdbConnection_getdb, (setter)MrdbConnection_setdb,
|
{"database", (getter)MrdbConnection_getdb, (setter)MrdbConnection_setdb,
|
||||||
@ -142,41 +135,14 @@ MrdbConnection_Methods[] =
|
|||||||
{"connect", (PyCFunction)MrdbConnection_connect,
|
{"connect", (PyCFunction)MrdbConnection_connect,
|
||||||
METH_VARARGS | METH_KEYWORDS,
|
METH_VARARGS | METH_KEYWORDS,
|
||||||
connection_connect__doc__},
|
connection_connect__doc__},
|
||||||
{"commit", (PyCFunction)MrdbConnection_commit,
|
|
||||||
METH_NOARGS,
|
|
||||||
connection_commit__doc__},
|
|
||||||
{"rollback", (PyCFunction)MrdbConnection_rollback,
|
|
||||||
METH_NOARGS,
|
|
||||||
connection_rollback__doc__},
|
|
||||||
{"cursor", (PyCFunction)MrdbConnection_cursor,
|
{"cursor", (PyCFunction)MrdbConnection_cursor,
|
||||||
METH_VARARGS | METH_KEYWORDS,
|
METH_VARARGS | METH_KEYWORDS,
|
||||||
connection_cursor__doc__},
|
connection_cursor__doc__},
|
||||||
/*TPC methods */
|
/*TPC methods */
|
||||||
{"tpc_begin",
|
|
||||||
(PyCFunction)MrdbConnection_tpc_begin,
|
|
||||||
METH_VARARGS,
|
|
||||||
connection_tpc_begin__doc__},
|
|
||||||
{"tpc_commit",
|
|
||||||
(PyCFunction)MrdbConnection_tpc_commit,
|
|
||||||
METH_VARARGS,
|
|
||||||
connection_tpc_commit__doc__,
|
|
||||||
},
|
|
||||||
{"tpc_prepare",
|
|
||||||
(PyCFunction)MrdbConnection_tpc_prepare,
|
|
||||||
METH_NOARGS,
|
|
||||||
connection_tpc_prepare__doc__,},
|
|
||||||
{"tpc_recover",
|
{"tpc_recover",
|
||||||
(PyCFunction)MrdbConnection_tpc_recover,
|
(PyCFunction)MrdbConnection_tpc_recover,
|
||||||
METH_NOARGS,
|
METH_NOARGS,
|
||||||
connection_tpc_recover__doc__},
|
connection_tpc_recover__doc__},
|
||||||
{"tpc_rollback",
|
|
||||||
(PyCFunction)MrdbConnection_tpc_rollback,
|
|
||||||
METH_VARARGS,
|
|
||||||
connection_tpc_rollback__doc__},
|
|
||||||
{"xid",
|
|
||||||
(PyCFunction)MrdbConnection_xid,
|
|
||||||
METH_VARARGS,
|
|
||||||
connection_xid__doc__},
|
|
||||||
/* additional methods */
|
/* additional methods */
|
||||||
{ "ping",
|
{ "ping",
|
||||||
(PyCFunction)MrdbConnection_ping,
|
(PyCFunction)MrdbConnection_ping,
|
||||||
@ -211,8 +177,12 @@ MrdbConnection_Methods[] =
|
|||||||
/* Internal methods */
|
/* Internal methods */
|
||||||
{ "_execute_command",
|
{ "_execute_command",
|
||||||
(PyCFunction)MrdbConnection_executecommand,
|
(PyCFunction)MrdbConnection_executecommand,
|
||||||
METH_VARARGS, NULL
|
METH_VARARGS,
|
||||||
|
NULL
|
||||||
},
|
},
|
||||||
|
{"_read_response", (PyCFunction)MrdbConnection_readresponse,
|
||||||
|
METH_NOARGS,
|
||||||
|
NULL},
|
||||||
{NULL} /* always last */
|
{NULL} /* always last */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -327,7 +297,6 @@ MrdbConnection_Initialize(MrdbConnection *self,
|
|||||||
unsigned int local_infile= 0xFF;
|
unsigned int local_infile= 0xFF;
|
||||||
unsigned int connect_timeout=0, read_timeout=0, write_timeout=0,
|
unsigned int connect_timeout=0, read_timeout=0, write_timeout=0,
|
||||||
compress= 0, ssl_verify_cert= 0;
|
compress= 0, ssl_verify_cert= 0;
|
||||||
PyObject *autocommit_obj= NULL;
|
|
||||||
PyObject *converter= NULL;
|
PyObject *converter= NULL;
|
||||||
PyObject *asynchronous= NULL;
|
PyObject *asynchronous= NULL;
|
||||||
|
|
||||||
@ -344,7 +313,7 @@ MrdbConnection_Initialize(MrdbConnection *self,
|
|||||||
&client_flags, &pool_name, &pool_size,
|
&client_flags, &pool_name, &pool_size,
|
||||||
&reset_session, &plugin_dir,
|
&reset_session, &plugin_dir,
|
||||||
&user, &schema, &password,
|
&user, &schema, &password,
|
||||||
&PyBool_Type, &autocommit_obj,
|
&PyBool_Type,
|
||||||
&converter,
|
&converter,
|
||||||
&PyBool_Type, &asynchronous))
|
&PyBool_Type, &asynchronous))
|
||||||
{
|
{
|
||||||
@ -456,26 +425,6 @@ MrdbConnection_Initialize(MrdbConnection *self,
|
|||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!autocommit_obj ||
|
|
||||||
(autocommit_obj && CHECK_TYPE(autocommit_obj, &PyBool_Type)))
|
|
||||||
{
|
|
||||||
uint8_t autocommit= (autocommit_obj) ?
|
|
||||||
(uint8_t) PyLong_AsUnsignedLong(autocommit_obj) : 0;
|
|
||||||
uint8_t server_autocommit;
|
|
||||||
uint32_t server_status;
|
|
||||||
|
|
||||||
mariadb_get_infov(self->mysql, MARIADB_CONNECTION_SERVER_STATUS, &server_status);
|
|
||||||
server_autocommit= server_status & SERVER_STATUS_AUTOCOMMIT;
|
|
||||||
|
|
||||||
if (server_autocommit != autocommit)
|
|
||||||
{
|
|
||||||
if (mysql_autocommit(self->mysql, autocommit))
|
|
||||||
{
|
|
||||||
mariadb_throw_exception(self->mysql, NULL, 0, NULL);
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* CONPY-129: server_version_info */
|
/* CONPY-129: server_version_info */
|
||||||
self->server_version= mysql_get_server_version(self->mysql);
|
self->server_version= mysql_get_server_version(self->mysql);
|
||||||
self->server_info= mysql_get_server_info(self->mysql);
|
self->server_info= mysql_get_server_info(self->mysql);
|
||||||
@ -610,7 +559,7 @@ void MrdbConnection_dealloc(MrdbConnection *self)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *
|
static PyObject *
|
||||||
MrdbConnection_executecommand(MrdbConnection *self,
|
MrdbConnection_executecommand(MrdbConnection *self,
|
||||||
PyObject *args)
|
PyObject *args)
|
||||||
{
|
{
|
||||||
@ -680,7 +629,7 @@ MrdbConnection_commit(MrdbConnection *self)
|
|||||||
if (self->tpc_state != TPC_STATE_NONE)
|
if (self->tpc_state != TPC_STATE_NONE)
|
||||||
{
|
{
|
||||||
mariadb_throw_exception(self->mysql, Mariadb_ProgrammingError,
|
mariadb_throw_exception(self->mysql, Mariadb_ProgrammingError,
|
||||||
0, "rollback() is not allowed if a TPC transaction is active");
|
0, "commit() is not allowed if a TPC transaction is active");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
Py_BEGIN_ALLOW_THREADS;
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
@ -719,270 +668,6 @@ MrdbConnection_rollback(MrdbConnection *self)
|
|||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
PyObject *
|
|
||||||
Mariadb_DBAPIType_Object(uint32_t type)
|
|
||||||
{
|
|
||||||
PyObject *types= Py_BuildValue("(I)", (uint32_t)type);
|
|
||||||
PyObject *number= PyObject_CallObject((PyObject *)&Mariadb_DBAPIType_Type,
|
|
||||||
types);
|
|
||||||
Py_DECREF(types);
|
|
||||||
return number;
|
|
||||||
} */
|
|
||||||
|
|
||||||
PyObject *
|
|
||||||
MrdbConnection_xid(MrdbConnection *self, PyObject *args)
|
|
||||||
{
|
|
||||||
PyObject *xid= NULL;
|
|
||||||
int format_id= 1;
|
|
||||||
char *branch_qualifier= NULL,
|
|
||||||
*transaction_id= NULL;
|
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "iss", &format_id,
|
|
||||||
&transaction_id,
|
|
||||||
&branch_qualifier))
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strlen(transaction_id) > MAX_TPC_XID_SIZE ||
|
|
||||||
strlen(branch_qualifier) > MAX_TPC_XID_SIZE)
|
|
||||||
{
|
|
||||||
mariadb_throw_exception(NULL, Mariadb_ProgrammingError, 0,
|
|
||||||
"Maximum length of transaction_id or branch_qualifier exceeded.");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!format_id)
|
|
||||||
format_id= 1;
|
|
||||||
|
|
||||||
if (!(xid= Py_BuildValue("(iss)", format_id,
|
|
||||||
transaction_id,
|
|
||||||
branch_qualifier)))
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return xid;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject *
|
|
||||||
MrdbConnection_tpc_begin(MrdbConnection *self, PyObject *args)
|
|
||||||
{
|
|
||||||
char *transaction_id= 0;
|
|
||||||
char *branch_qualifier= 0;
|
|
||||||
int format_id= 1;
|
|
||||||
char stmt[192];
|
|
||||||
int rc= 0;
|
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "(iss)", &format_id,
|
|
||||||
&transaction_id,
|
|
||||||
&branch_qualifier))
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
snprintf(stmt, 191, "XA BEGIN '%s', '%s', %d", transaction_id, branch_qualifier, format_id);
|
|
||||||
Py_BEGIN_ALLOW_THREADS;
|
|
||||||
rc= mysql_query(self->mysql, stmt);
|
|
||||||
Py_END_ALLOW_THREADS;
|
|
||||||
|
|
||||||
if (rc)
|
|
||||||
{
|
|
||||||
mariadb_throw_exception(self->mysql, NULL, 0, NULL);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
self->tpc_state= TPC_STATE_XID;
|
|
||||||
snprintf(self->xid, 149, "'%s', '%s', %d", transaction_id, branch_qualifier, format_id);
|
|
||||||
|
|
||||||
Py_RETURN_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject *
|
|
||||||
MrdbConnection_tpc_commit(MrdbConnection *self, PyObject *args)
|
|
||||||
{
|
|
||||||
char *transaction_id= 0;
|
|
||||||
int format_id=1;
|
|
||||||
char *branch_qualifier= 0;
|
|
||||||
char stmt[192];
|
|
||||||
|
|
||||||
MARIADB_CHECK_CONNECTION(self, NULL);
|
|
||||||
MARIADB_CHECK_TPC(self);
|
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "|(iss)", &format_id,
|
|
||||||
&transaction_id,
|
|
||||||
&branch_qualifier))
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!args && self->tpc_state != TPC_STATE_PREPARE)
|
|
||||||
{
|
|
||||||
mariadb_throw_exception(NULL, Mariadb_ProgrammingError, 0,
|
|
||||||
"transaction is not in prepared state");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
Py_BEGIN_ALLOW_THREADS;
|
|
||||||
if (self->tpc_state < TPC_STATE_PREPARE)
|
|
||||||
{
|
|
||||||
if (transaction_id) {
|
|
||||||
snprintf(stmt, 191, "XA END '%s', '%s', %d",
|
|
||||||
transaction_id, branch_qualifier, format_id);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
snprintf(stmt, 191, "XA END %s", self->xid);
|
|
||||||
}
|
|
||||||
if (mysql_query(self->mysql, stmt))
|
|
||||||
{
|
|
||||||
mariadb_throw_exception(self->mysql, NULL, 0, NULL);
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (transaction_id)
|
|
||||||
{
|
|
||||||
snprintf(stmt, 191, "XA COMMIT '%s', '%s', %d %s",
|
|
||||||
transaction_id, branch_qualifier, format_id,
|
|
||||||
self->tpc_state < TPC_STATE_PREPARE ? "ONE PHASE" : "");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
snprintf(stmt, 191, "XA COMMIT %s %s",
|
|
||||||
self->xid,
|
|
||||||
self->tpc_state < TPC_STATE_PREPARE ? "ONE PHASE" : "");
|
|
||||||
}
|
|
||||||
if (mysql_query(self->mysql, stmt))
|
|
||||||
{
|
|
||||||
mariadb_throw_exception(self->mysql, NULL, 0, NULL);
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
end:
|
|
||||||
Py_END_ALLOW_THREADS;
|
|
||||||
|
|
||||||
if (PyErr_Occurred())
|
|
||||||
return NULL;
|
|
||||||
self->xid[0]= 0;
|
|
||||||
self->tpc_state= TPC_STATE_NONE;
|
|
||||||
|
|
||||||
Py_RETURN_NONE;
|
|
||||||
}
|
|
||||||
/* }}} */
|
|
||||||
|
|
||||||
/* {{{ MrdbConnection_tpc_rollback */
|
|
||||||
PyObject *MrdbConnection_tpc_rollback(MrdbConnection *self, PyObject *args)
|
|
||||||
{
|
|
||||||
char *transaction_id= 0;
|
|
||||||
int format_id=1;
|
|
||||||
char *branch_qualifier= 0;
|
|
||||||
char stmt[192];
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
MARIADB_CHECK_CONNECTION(self, NULL);
|
|
||||||
MARIADB_CHECK_TPC(self);
|
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "|(iss)", &format_id,
|
|
||||||
&transaction_id,
|
|
||||||
&branch_qualifier))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (!args && self->tpc_state != TPC_STATE_PREPARE)
|
|
||||||
{
|
|
||||||
mariadb_throw_exception(NULL, Mariadb_ProgrammingError, 0,
|
|
||||||
"transaction is not in prepared state");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (self->tpc_state < TPC_STATE_PREPARE)
|
|
||||||
{
|
|
||||||
if (transaction_id)
|
|
||||||
{
|
|
||||||
snprintf(stmt, 191, "XA END '%s', '%s', %d",
|
|
||||||
transaction_id, branch_qualifier, format_id);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
snprintf(stmt, 191, "XA END %s", self->xid);
|
|
||||||
}
|
|
||||||
Py_BEGIN_ALLOW_THREADS;
|
|
||||||
rc= mysql_query(self->mysql, stmt);
|
|
||||||
Py_END_ALLOW_THREADS;
|
|
||||||
if (rc)
|
|
||||||
{
|
|
||||||
mariadb_throw_exception(self->mysql, NULL, 0, NULL);
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (transaction_id)
|
|
||||||
{
|
|
||||||
snprintf(stmt, 191, "XA ROLLBACK '%s', '%s', %d",
|
|
||||||
transaction_id, branch_qualifier, format_id);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
snprintf(stmt, 191, "XA ROLLBACK %s", self->xid);
|
|
||||||
}
|
|
||||||
|
|
||||||
Py_BEGIN_ALLOW_THREADS;
|
|
||||||
rc= mysql_query(self->mysql, stmt);
|
|
||||||
Py_END_ALLOW_THREADS;
|
|
||||||
|
|
||||||
if (rc)
|
|
||||||
{
|
|
||||||
mariadb_throw_exception(self->mysql, NULL, 0, NULL);
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
end:
|
|
||||||
|
|
||||||
if (PyErr_Occurred())
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
self->xid[0]= 0;
|
|
||||||
self->tpc_state= TPC_STATE_NONE;
|
|
||||||
Py_RETURN_NONE;
|
|
||||||
}
|
|
||||||
/* }}} */
|
|
||||||
|
|
||||||
/* {{{ MrdbConnection_tpc_prepare */
|
|
||||||
PyObject *MrdbConnection_tpc_prepare(MrdbConnection *self)
|
|
||||||
{
|
|
||||||
char stmt[192];
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
MARIADB_CHECK_CONNECTION(self, NULL);
|
|
||||||
MARIADB_CHECK_TPC(self);
|
|
||||||
|
|
||||||
if (self->tpc_state == TPC_STATE_PREPARE)
|
|
||||||
{
|
|
||||||
mariadb_throw_exception(NULL, Mariadb_ProgrammingError, 0,
|
|
||||||
"transaction is already in prepared state");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
snprintf(stmt, 191, "XA END %s", self->xid);
|
|
||||||
Py_BEGIN_ALLOW_THREADS;
|
|
||||||
rc= mysql_query(self->mysql, stmt);
|
|
||||||
Py_END_ALLOW_THREADS;
|
|
||||||
|
|
||||||
if (rc)
|
|
||||||
{
|
|
||||||
mariadb_throw_exception(self->mysql, NULL, 0, NULL);
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
snprintf(stmt, 191, "XA PREPARE %s", self->xid);
|
|
||||||
Py_BEGIN_ALLOW_THREADS;
|
|
||||||
rc= mysql_query(self->mysql, stmt);
|
|
||||||
Py_END_ALLOW_THREADS;
|
|
||||||
|
|
||||||
if (rc)
|
|
||||||
{
|
|
||||||
mariadb_throw_exception(self->mysql, NULL, 0, NULL);
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
end:
|
|
||||||
if (PyErr_Occurred())
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
self->tpc_state= TPC_STATE_PREPARE;
|
|
||||||
Py_RETURN_NONE;
|
|
||||||
}
|
|
||||||
/* }}} */
|
|
||||||
|
|
||||||
/* {{{ MrdbConnection_tpc_recover */
|
/* {{{ MrdbConnection_tpc_recover */
|
||||||
PyObject *MrdbConnection_tpc_recover(MrdbConnection *self)
|
PyObject *MrdbConnection_tpc_recover(MrdbConnection *self)
|
||||||
{
|
{
|
||||||
@ -1304,46 +989,6 @@ static PyObject *MrdbConnection_escape_string(MrdbConnection *self,
|
|||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
/* {{{ MrdbConnection_setautocommit */
|
|
||||||
static int MrdbConnection_setautocommit(MrdbConnection *self, PyObject *arg,
|
|
||||||
void *closure)
|
|
||||||
{
|
|
||||||
int rc= 0;
|
|
||||||
|
|
||||||
MARIADB_CHECK_CONNECTION(self, -1);
|
|
||||||
|
|
||||||
if (!arg || !CHECK_TYPE(arg, &PyBool_Type))
|
|
||||||
{
|
|
||||||
PyErr_SetString(PyExc_TypeError, "Argument must be boolean");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
Py_BEGIN_ALLOW_THREADS;
|
|
||||||
rc= mysql_autocommit(self->mysql, PyObject_IsTrue(arg));
|
|
||||||
Py_END_ALLOW_THREADS;
|
|
||||||
|
|
||||||
if (rc)
|
|
||||||
{
|
|
||||||
mariadb_throw_exception(self->mysql, NULL, 0, NULL);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/* }}} */
|
|
||||||
|
|
||||||
/* {{{ MrdbConnection_getautocommit */
|
|
||||||
static PyObject *MrdbConnection_getautocommit(MrdbConnection *self)
|
|
||||||
{
|
|
||||||
uint32_t server_status;
|
|
||||||
|
|
||||||
MARIADB_CHECK_CONNECTION(self, NULL);
|
|
||||||
|
|
||||||
mariadb_get_infov(self->mysql, MARIADB_CONNECTION_SERVER_STATUS, &server_status);
|
|
||||||
if (server_status & SERVER_STATUS_AUTOCOMMIT)
|
|
||||||
Py_RETURN_TRUE;
|
|
||||||
Py_RETURN_FALSE;
|
|
||||||
}
|
|
||||||
/* }}} */
|
|
||||||
|
|
||||||
static PyObject *MrdbConnection_get_server_status(MrdbConnection *self)
|
static PyObject *MrdbConnection_get_server_status(MrdbConnection *self)
|
||||||
{
|
{
|
||||||
uint32_t server_status;
|
uint32_t server_status;
|
||||||
@ -1375,6 +1020,22 @@ static PyObject *MrdbConnection_query(MrdbConnection *self, PyObject *args)
|
|||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PyObject *MrdbConnection_readresponse(MrdbConnection *self)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
|
rc= self->mysql->methods->db_read_query_result(self->mysql);
|
||||||
|
Py_END_ALLOW_THREADS;
|
||||||
|
|
||||||
|
if (rc)
|
||||||
|
{
|
||||||
|
mariadb_throw_exception(self->mysql, NULL, 0, NULL);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
/* vim: set tabstop=4 */
|
/* vim: set tabstop=4 */
|
||||||
/* vim: set shiftwidth=4 */
|
/* vim: set shiftwidth=4 */
|
||||||
/* vim: set expandtab */
|
/* vim: set expandtab */
|
||||||
|
2
setup.py
2
setup.py
@ -96,7 +96,7 @@ setup(name='mariadb',
|
|||||||
extra_objects= cfg.extra_objects
|
extra_objects= cfg.extra_objects
|
||||||
)],
|
)],
|
||||||
py_modules=['mariadb.__init__', 'mariadb.constants.CLIENT', 'mariadb.constants.CURSOR',
|
py_modules=['mariadb.__init__', 'mariadb.constants.CLIENT', 'mariadb.constants.CURSOR',
|
||||||
'mariadb.constants.STATUS',
|
'mariadb.constants.STATUS', 'mariadb.constants.TPC_STATE',
|
||||||
'mariadb.field', 'mariadb.dbapi20', 'mariadb.connections', 'mariadb.connectionpool',
|
'mariadb.field', 'mariadb.dbapi20', 'mariadb.connections', 'mariadb.connectionpool',
|
||||||
'mariadb.cursor', 'mariadb.release_info', 'mariadb.async_connections', 'mariadb.codecs',
|
'mariadb.cursor', 'mariadb.release_info', 'mariadb.async_connections', 'mariadb.codecs',
|
||||||
'mariadb.constants.FIELD_TYPE', 'mariadb.constants.FIELD_FLAG', 'mariadb.constants.INDICATOR'],
|
'mariadb.constants.FIELD_TYPE', 'mariadb.constants.FIELD_FLAG', 'mariadb.constants.INDICATOR'],
|
||||||
|
Reference in New Issue
Block a user