mirror of
https://github.com/mariadb-corporation/mariadb-connector-python.git
synced 2025-08-02 13:56:54 +00:00
CONPY-3:
New connection methods: - autocommit - ping - kill - reconnect - escape_string - reset - change_user New attributes: - user (read only) - database (read/write) - connection_id (read only) - warnings (read only) - auto_reconnect (read/write) New Cursor attribute: - warnings (read only)
This commit is contained in:
@ -80,10 +80,7 @@ typedef struct {
|
|||||||
PyObject *tls_cipher;
|
PyObject *tls_cipher;
|
||||||
PyObject *tls_version;
|
PyObject *tls_version;
|
||||||
PyObject *host;
|
PyObject *host;
|
||||||
PyObject *user;
|
|
||||||
PyObject *schema;
|
|
||||||
PyObject *unix_socket;
|
PyObject *unix_socket;
|
||||||
unsigned long thread_id;
|
|
||||||
int port;
|
int port;
|
||||||
PyObject *charset;
|
PyObject *charset;
|
||||||
PyObject *collation;
|
PyObject *collation;
|
||||||
@ -205,8 +202,14 @@ PyObject *MrdbIndicator_Object(uint32_t type);
|
|||||||
long MrdbIndicator_AsLong(PyObject *v);
|
long MrdbIndicator_AsLong(PyObject *v);
|
||||||
PyObject *Mariadb_DBAPIType_Object(uint32_t type);
|
PyObject *Mariadb_DBAPIType_Object(uint32_t type);
|
||||||
PyObject *MrdbConnection_affected_rows(MrdbConnection *self);
|
PyObject *MrdbConnection_affected_rows(MrdbConnection *self);
|
||||||
|
PyObject *MrdbConnection_ping(MrdbConnection *self);
|
||||||
|
PyObject *MrdbConnection_kill(MrdbConnection *self, PyObject *args);
|
||||||
|
PyObject *MrdbConnection_reconnect(MrdbConnection *self);
|
||||||
|
PyObject *MrdbConnection_reset(MrdbConnection *self);
|
||||||
PyObject *MrdbConnection_autocommit(MrdbConnection *self,
|
PyObject *MrdbConnection_autocommit(MrdbConnection *self,
|
||||||
PyObject *toggle);
|
PyObject *args);
|
||||||
|
PyObject *MrdbConnection_change_user(MrdbConnection *self,
|
||||||
|
PyObject *args);
|
||||||
PyObject *MrdbConnection_rollback(MrdbConnection *self);
|
PyObject *MrdbConnection_rollback(MrdbConnection *self);
|
||||||
PyObject *MrdbConnection_commit(MrdbConnection *self);
|
PyObject *MrdbConnection_commit(MrdbConnection *self);
|
||||||
PyObject *MrdbConnection_close(MrdbConnection *self);
|
PyObject *MrdbConnection_close(MrdbConnection *self);
|
||||||
@ -243,14 +246,12 @@ uint8_t mariadb_param_update(void *data, MYSQL_BIND *bind, uint32_t row_nr);
|
|||||||
#define MARIADB_FEATURE_SUPPORTED(mysql,version)\
|
#define MARIADB_FEATURE_SUPPORTED(mysql,version)\
|
||||||
(mysql_get_server_version((mysql)) >= (version))
|
(mysql_get_server_version((mysql)) >= (version))
|
||||||
|
|
||||||
#define MARIADB_CHECK_CONNECTION(connection)\
|
#define MARIADB_CHECK_CONNECTION(connection, ret)\
|
||||||
if (!connection || !connection->mysql) {\
|
if (!connection || !connection->mysql) {\
|
||||||
mariadb_throw_exception(connection->mysql, Mariadb_Error, 0,\
|
mariadb_throw_exception(connection->mysql, Mariadb_Error, 0,\
|
||||||
"Invalid connection or not connected");\
|
"Invalid connection or not connected");\
|
||||||
return NULL;\
|
return (ret);\
|
||||||
}\
|
}
|
||||||
if ((connection)->thread_id != mysql_thread_id((connection)->mysql))\
|
|
||||||
MrdbConnection_SetAttributes((connection));
|
|
||||||
|
|
||||||
#define MARIADB_CHECK_TPC(connection)\
|
#define MARIADB_CHECK_TPC(connection)\
|
||||||
if (connection->tpc_state == TPC_STATE_NONE) {\
|
if (connection->tpc_state == TPC_STATE_NONE) {\
|
||||||
|
2
setup.py
2
setup.py
@ -44,7 +44,7 @@ if sys.platform != "win32":
|
|||||||
libs = mariadb_config("libs_sys")
|
libs = mariadb_config("libs_sys")
|
||||||
mariadb_version= mariadb_config("cc_version")
|
mariadb_version= mariadb_config("cc_version")
|
||||||
if mariadb_version[0] < "3.0.6":
|
if mariadb_version[0] < "3.0.6":
|
||||||
print("Connector MariaDB/Pythin requires MariaDB Connector/C 3.0.6 or newer")
|
print("Connector MariaDB/Python requires MariaDB Connector/C 3.0.6 or newer")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
mariadb_libraries= [dequote(c[2:])
|
mariadb_libraries= [dequote(c[2:])
|
||||||
for c in libs
|
for c in libs
|
||||||
|
@ -28,13 +28,31 @@ static PyObject *MrdbConnection_cursor(MrdbConnection *self,
|
|||||||
static char mariadb_connection_documentation[] =
|
static char mariadb_connection_documentation[] =
|
||||||
"Returns a MariaDB connection object";
|
"Returns a MariaDB connection object";
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *MrdbConnection_exception(PyObject *self, void *closure);
|
||||||
MrdbConnection_exception(PyObject *self, void *closure);
|
|
||||||
#define GETTER_EXCEPTION(name, exception)\
|
#define GETTER_EXCEPTION(name, exception)\
|
||||||
{ name,MrdbConnection_exception, NULL, "doc", &exception }
|
{ name,MrdbConnection_exception, NULL, "doc", &exception }
|
||||||
|
static PyObject *MrdbConnection_getid(MrdbConnection *self, void *closure);
|
||||||
|
static PyObject *MrdbConnection_getuser(MrdbConnection *self, void *closure);
|
||||||
|
static PyObject *MrdbConnection_getreconnect(MrdbConnection *self,
|
||||||
|
void *closure);
|
||||||
|
static int MrdbConnection_setreconnect(MrdbConnection *self,
|
||||||
|
PyObject *args,
|
||||||
|
void *closure);
|
||||||
|
static PyObject *MrdbConnection_getdb(MrdbConnection *self, void *closure);
|
||||||
|
static int MrdbConnection_setdb(MrdbConnection *self, PyObject *arg, void *closure);
|
||||||
|
static PyObject *MrdbConnection_escape_string(MrdbConnection *self,
|
||||||
|
PyObject *args);
|
||||||
|
|
||||||
|
static PyObject *MrdbConnection_warnings(MrdbConnection *self);
|
||||||
static PyGetSetDef MrdbConnection_sets[]=
|
static PyGetSetDef MrdbConnection_sets[]=
|
||||||
{
|
{
|
||||||
|
{"connection_id", (getter)MrdbConnection_getid, NULL, "connection id", NULL},
|
||||||
|
{"database", (getter)MrdbConnection_getdb, (setter)MrdbConnection_setdb, "database in use", NULL},
|
||||||
|
{"auto_reconnect", (getter)MrdbConnection_getreconnect,
|
||||||
|
(setter)MrdbConnection_setreconnect,
|
||||||
|
"reconnect automatically if connection dropped", NULL},
|
||||||
|
{"user", (getter)MrdbConnection_getuser, NULL, "user nane", NULL},
|
||||||
|
{"warnings", (getter)MrdbConnection_warnings, NULL, "number of warnings which were produced from last running connection command", NULL},
|
||||||
GETTER_EXCEPTION("Error", Mariadb_Error),
|
GETTER_EXCEPTION("Error", Mariadb_Error),
|
||||||
GETTER_EXCEPTION("Warning", Mariadb_Warning),
|
GETTER_EXCEPTION("Warning", Mariadb_Warning),
|
||||||
GETTER_EXCEPTION("InterfaceError", Mariadb_InterfaceError),
|
GETTER_EXCEPTION("InterfaceError", Mariadb_InterfaceError),
|
||||||
@ -72,9 +90,15 @@ static PyMethodDef MrdbConnection_Methods[] =
|
|||||||
{"tpc_commit",
|
{"tpc_commit",
|
||||||
(PyCFunction)MrdbConnection_tpc_commit,
|
(PyCFunction)MrdbConnection_tpc_commit,
|
||||||
METH_VARARGS,
|
METH_VARARGS,
|
||||||
"When called with no arguments, .tpc_commit() commits a TPC transaction previously prepared with .tpc_prepare()."
|
"When called with no arguments, .tpc_commit() commits a TPC transaction "
|
||||||
"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."
|
"previously prepared with .tpc_prepare()."
|
||||||
"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 .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."},
|
||||||
{"tpc_prepare",
|
{"tpc_prepare",
|
||||||
(PyCFunction)MrdbConnection_tpc_prepare,
|
(PyCFunction)MrdbConnection_tpc_prepare,
|
||||||
METH_NOARGS,
|
METH_NOARGS,
|
||||||
@ -86,12 +110,15 @@ static PyMethodDef MrdbConnection_Methods[] =
|
|||||||
{"tpc_rollback",
|
{"tpc_rollback",
|
||||||
(PyCFunction)MrdbConnection_tpc_rollback,
|
(PyCFunction)MrdbConnection_tpc_rollback,
|
||||||
METH_VARARGS,
|
METH_VARARGS,
|
||||||
"When called with no arguments, .tpc_rollback() rolls back a TPC transaction. It may be called before or after .tpc_prepare()."
|
"When called with no arguments, .tpc_rollback() rolls back a TPC "
|
||||||
"When called with a transaction ID xid, it rolls back the given transaction."},
|
"transaction. It may be called before or after .tpc_prepare()."
|
||||||
|
"When called with a transaction ID xid, it rolls back the given "
|
||||||
|
"transaction."},
|
||||||
{"xid",
|
{"xid",
|
||||||
(PyCFunction)MrdbConnection_xid,
|
(PyCFunction)MrdbConnection_xid,
|
||||||
METH_VARARGS,
|
METH_VARARGS,
|
||||||
"Returns a transaction ID object suitable for passing to the .tpc_*() methods of this connection"},
|
"Returns a transaction ID object suitable for passing to the .tpc_*() "
|
||||||
|
"methods of this connection" },
|
||||||
/* additional methods */
|
/* additional methods */
|
||||||
{
|
{
|
||||||
"auto_commit",
|
"auto_commit",
|
||||||
@ -99,16 +126,53 @@ static PyMethodDef MrdbConnection_Methods[] =
|
|||||||
METH_VARARGS,
|
METH_VARARGS,
|
||||||
"Toggles autocommit mode on or off"
|
"Toggles autocommit mode on or off"
|
||||||
},
|
},
|
||||||
|
{ "ping",
|
||||||
|
(PyCFunction)MrdbConnection_ping,
|
||||||
|
METH_NOARGS,
|
||||||
|
"Checks whether the connection to the database server is working. "
|
||||||
|
"If it has gone down, and the reconnect option was set, an automatic "
|
||||||
|
"reconnect is attempted."
|
||||||
|
},
|
||||||
|
{ "change_user",
|
||||||
|
(PyCFunction)MrdbConnection_change_user,
|
||||||
|
METH_VARARGS,
|
||||||
|
"Changes the user and default database of the current connection. "
|
||||||
|
"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, the current user authentication will remain."
|
||||||
|
},
|
||||||
|
{ "kill",
|
||||||
|
(PyCFunction)MrdbConnection_kill,
|
||||||
|
METH_VARARGS,
|
||||||
|
"This function is used to ask the server to kill a MariaDB thread "
|
||||||
|
"specified by the processid parameter. This value must be retrieved "
|
||||||
|
"by SHOW PROCESSLIST."
|
||||||
|
},
|
||||||
|
{ "reconnect",
|
||||||
|
(PyCFunction)MrdbConnection_reconnect,
|
||||||
|
METH_NOARGS,
|
||||||
|
"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."
|
||||||
|
},
|
||||||
|
{ "reset",
|
||||||
|
(PyCFunction)MrdbConnection_reset,
|
||||||
|
METH_NOARGS,
|
||||||
|
"Resets the current connection and clears session state and pending "
|
||||||
|
"results. Open cursors will become invalid and cannot be used anymore."
|
||||||
|
},
|
||||||
|
{ "escape_string",
|
||||||
|
(PyCFunction)MrdbConnection_escape_string,
|
||||||
|
METH_VARARGS,
|
||||||
|
"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."
|
||||||
|
},
|
||||||
{NULL} /* alwa+ys last */
|
{NULL} /* alwa+ys last */
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct PyMemberDef MrdbConnection_Members[] =
|
static struct PyMemberDef MrdbConnection_Members[] =
|
||||||
{
|
{
|
||||||
{"connection_id",
|
|
||||||
T_LONG,
|
|
||||||
offsetof(MrdbConnection, thread_id),
|
|
||||||
READONLY,
|
|
||||||
"Internal id of the connection."},
|
|
||||||
{"character_set",
|
{"character_set",
|
||||||
T_OBJECT,
|
T_OBJECT,
|
||||||
offsetof(MrdbConnection, charset),
|
offsetof(MrdbConnection, charset),
|
||||||
@ -119,11 +183,6 @@ static struct PyMemberDef MrdbConnection_Members[] =
|
|||||||
offsetof(MrdbConnection, collation),
|
offsetof(MrdbConnection, collation),
|
||||||
READONLY,
|
READONLY,
|
||||||
"Client character set collation"},
|
"Client character set collation"},
|
||||||
{"database",
|
|
||||||
T_OBJECT,
|
|
||||||
offsetof(MrdbConnection, schema),
|
|
||||||
READONLY,
|
|
||||||
"Default schema (database)"},
|
|
||||||
{"dsn",
|
{"dsn",
|
||||||
T_OBJECT,
|
T_OBJECT,
|
||||||
offsetof(MrdbConnection, dsn),
|
offsetof(MrdbConnection, dsn),
|
||||||
@ -144,11 +203,6 @@ static struct PyMemberDef MrdbConnection_Members[] =
|
|||||||
offsetof(MrdbConnection, host),
|
offsetof(MrdbConnection, host),
|
||||||
READONLY,
|
READONLY,
|
||||||
"Name or address of database server"},
|
"Name or address of database server"},
|
||||||
{"user",
|
|
||||||
T_OBJECT,
|
|
||||||
offsetof(MrdbConnection, user),
|
|
||||||
READONLY,
|
|
||||||
"user name"},
|
|
||||||
{"tls_cipher",
|
{"tls_cipher",
|
||||||
T_OBJECT,
|
T_OBJECT,
|
||||||
offsetof(MrdbConnection, tls_cipher),
|
offsetof(MrdbConnection, tls_cipher),
|
||||||
@ -176,13 +230,10 @@ void MrdbConnection_SetAttributes(MrdbConnection *self)
|
|||||||
MY_CHARSET_INFO cinfo;
|
MY_CHARSET_INFO cinfo;
|
||||||
|
|
||||||
Mrdb_ConnAttrStr(self->mysql, &self->host, MARIADB_CONNECTION_HOST);
|
Mrdb_ConnAttrStr(self->mysql, &self->host, MARIADB_CONNECTION_HOST);
|
||||||
Mrdb_ConnAttrStr(self->mysql, &self->user, MARIADB_CONNECTION_USER);
|
|
||||||
Mrdb_ConnAttrStr(self->mysql, &self->schema, MARIADB_CONNECTION_SCHEMA);
|
|
||||||
Mrdb_ConnAttrStr(self->mysql, &self->tls_cipher, MARIADB_CONNECTION_SSL_CIPHER);
|
Mrdb_ConnAttrStr(self->mysql, &self->tls_cipher, MARIADB_CONNECTION_SSL_CIPHER);
|
||||||
Mrdb_ConnAttrStr(self->mysql, &self->tls_version, MARIADB_CONNECTION_TLS_VERSION);
|
Mrdb_ConnAttrStr(self->mysql, &self->tls_version, MARIADB_CONNECTION_TLS_VERSION);
|
||||||
Mrdb_ConnAttrStr(self->mysql, &self->unix_socket, MARIADB_CONNECTION_UNIX_SOCKET);
|
Mrdb_ConnAttrStr(self->mysql, &self->unix_socket, MARIADB_CONNECTION_UNIX_SOCKET);
|
||||||
mariadb_get_infov(self->mysql, MARIADB_CONNECTION_PORT, &self->port);
|
mariadb_get_infov(self->mysql, MARIADB_CONNECTION_PORT, &self->port);
|
||||||
self->thread_id= mysql_thread_id(self->mysql);
|
|
||||||
mariadb_get_infov(self->mysql, MARIADB_CONNECTION_MARIADB_CHARSET_INFO, &cinfo);
|
mariadb_get_infov(self->mysql, MARIADB_CONNECTION_MARIADB_CHARSET_INFO, &cinfo);
|
||||||
self->charset= PyUnicode_FromString(cinfo.csname);
|
self->charset= PyUnicode_FromString(cinfo.csname);
|
||||||
self->collation= PyUnicode_FromString(cinfo.name);
|
self->collation= PyUnicode_FromString(cinfo.name);
|
||||||
@ -193,6 +244,7 @@ MrdbConnection_Initialize(MrdbConnection *self,
|
|||||||
PyObject *args,
|
PyObject *args,
|
||||||
PyObject *dsnargs)
|
PyObject *dsnargs)
|
||||||
{
|
{
|
||||||
|
int rc;
|
||||||
/* Todo: we need to support all dsn parameters, the current
|
/* Todo: we need to support all dsn parameters, the current
|
||||||
implementation is just a small subset.
|
implementation is just a small subset.
|
||||||
*/
|
*/
|
||||||
@ -271,22 +323,25 @@ MrdbConnection_Initialize(MrdbConnection *self,
|
|||||||
if (ssl_verify_cert)
|
if (ssl_verify_cert)
|
||||||
mysql_optionsv(self->mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, (unsigned char *) &ssl_verify_cert);
|
mysql_optionsv(self->mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, (unsigned char *) &ssl_verify_cert);
|
||||||
Py_BEGIN_ALLOW_THREADS;
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
if (!mysql_real_connect(self->mysql, host, user, password, schema, port,
|
mysql_real_connect(self->mysql, host, user, password, schema, port,
|
||||||
socket, client_flags))
|
socket, client_flags);
|
||||||
|
Py_END_ALLOW_THREADS;
|
||||||
|
if (mysql_errno(self->mysql))
|
||||||
{
|
{
|
||||||
mariadb_throw_exception(self->mysql, Mariadb_InterfaceError, 0, NULL);
|
mariadb_throw_exception(self->mysql, Mariadb_InterfaceError, 0, NULL);
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* make sure that we use a utf8 connection */
|
/* make sure that we use a utf8 connection */
|
||||||
if (mysql_set_character_set(self->mysql, "utf8"))
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
|
rc= mysql_set_character_set(self->mysql, "utf8");
|
||||||
|
Py_END_ALLOW_THREADS;
|
||||||
|
if (rc)
|
||||||
{
|
{
|
||||||
mariadb_throw_exception(self->mysql, Mariadb_InterfaceError, 0, NULL);
|
mariadb_throw_exception(self->mysql, Mariadb_InterfaceError, 0, NULL);
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
end:
|
||||||
end:
|
|
||||||
Py_END_ALLOW_THREADS;
|
|
||||||
if (PyErr_Occurred())
|
if (PyErr_Occurred())
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@ -408,7 +463,7 @@ MrdbConnection_dealloc(MrdbConnection *self)
|
|||||||
|
|
||||||
PyObject *MrdbConnection_close(MrdbConnection *self)
|
PyObject *MrdbConnection_close(MrdbConnection *self)
|
||||||
{
|
{
|
||||||
MARIADB_CHECK_CONNECTION(self);
|
MARIADB_CHECK_CONNECTION(self, NULL);
|
||||||
/* Todo: check if all the cursor stuff is deleted (when using prepared
|
/* Todo: check if all the cursor stuff is deleted (when using prepared
|
||||||
statemnts this should be handled in mysql_close) */
|
statemnts this should be handled in mysql_close) */
|
||||||
Py_BEGIN_ALLOW_THREADS
|
Py_BEGIN_ALLOW_THREADS
|
||||||
@ -443,7 +498,7 @@ MrdbConnection_exception(PyObject *self, void *closure)
|
|||||||
/* {{{ MrdbConnection_commit */
|
/* {{{ MrdbConnection_commit */
|
||||||
PyObject *MrdbConnection_commit(MrdbConnection *self)
|
PyObject *MrdbConnection_commit(MrdbConnection *self)
|
||||||
{
|
{
|
||||||
MARIADB_CHECK_CONNECTION(self);
|
MARIADB_CHECK_CONNECTION(self, NULL);
|
||||||
|
|
||||||
if (self->tpc_state != TPC_STATE_NONE)
|
if (self->tpc_state != TPC_STATE_NONE)
|
||||||
{
|
{
|
||||||
@ -467,7 +522,7 @@ end:
|
|||||||
/* {{{ MrdbConnection_rollback */
|
/* {{{ MrdbConnection_rollback */
|
||||||
PyObject *MrdbConnection_rollback(MrdbConnection *self)
|
PyObject *MrdbConnection_rollback(MrdbConnection *self)
|
||||||
{
|
{
|
||||||
MARIADB_CHECK_CONNECTION(self);
|
MARIADB_CHECK_CONNECTION(self, NULL);
|
||||||
|
|
||||||
if (self->tpc_state != TPC_STATE_NONE)
|
if (self->tpc_state != TPC_STATE_NONE)
|
||||||
{
|
{
|
||||||
@ -495,7 +550,7 @@ PyObject *MrdbConnection_autocommit(MrdbConnection *self,
|
|||||||
PyObject *args)
|
PyObject *args)
|
||||||
{
|
{
|
||||||
int autocommit;
|
int autocommit;
|
||||||
MARIADB_CHECK_CONNECTION(self);
|
MARIADB_CHECK_CONNECTION(self, NULL);
|
||||||
|
|
||||||
if (PyArg_ParseTuple(args, "p", &autocommit))
|
if (PyArg_ParseTuple(args, "p", &autocommit))
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -585,7 +640,7 @@ PyObject *MrdbConnection_tpc_commit(MrdbConnection *self, PyObject *args)
|
|||||||
long branch_qualifier= 0;
|
long branch_qualifier= 0;
|
||||||
char stmt[128];
|
char stmt[128];
|
||||||
|
|
||||||
MARIADB_CHECK_CONNECTION(self);
|
MARIADB_CHECK_CONNECTION(self, NULL);
|
||||||
MARIADB_CHECK_TPC(self);
|
MARIADB_CHECK_TPC(self);
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "|(ssi)", &format_id,
|
if (!PyArg_ParseTuple(args, "|(ssi)", &format_id,
|
||||||
@ -639,7 +694,7 @@ PyObject *MrdbConnection_tpc_rollback(MrdbConnection *self, PyObject *args)
|
|||||||
long branch_qualifier= 0;
|
long branch_qualifier= 0;
|
||||||
char stmt[128];
|
char stmt[128];
|
||||||
|
|
||||||
MARIADB_CHECK_CONNECTION(self);
|
MARIADB_CHECK_CONNECTION(self, NULL);
|
||||||
MARIADB_CHECK_TPC(self);
|
MARIADB_CHECK_TPC(self);
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "|(ssi)", &format_id,
|
if (!PyArg_ParseTuple(args, "|(ssi)", &format_id,
|
||||||
@ -688,7 +743,7 @@ PyObject *MrdbConnection_tpc_prepare(MrdbConnection *self)
|
|||||||
{
|
{
|
||||||
char stmt[128];
|
char stmt[128];
|
||||||
|
|
||||||
MARIADB_CHECK_CONNECTION(self);
|
MARIADB_CHECK_CONNECTION(self, NULL);
|
||||||
MARIADB_CHECK_TPC(self);
|
MARIADB_CHECK_TPC(self);
|
||||||
|
|
||||||
if (self->tpc_state == TPC_STATE_PREPARE)
|
if (self->tpc_state == TPC_STATE_PREPARE)
|
||||||
@ -728,7 +783,7 @@ PyObject *MrdbConnection_tpc_recover(MrdbConnection *self)
|
|||||||
MYSQL_RES *result;
|
MYSQL_RES *result;
|
||||||
MYSQL_ROW row;
|
MYSQL_ROW row;
|
||||||
|
|
||||||
MARIADB_CHECK_CONNECTION(self);
|
MARIADB_CHECK_CONNECTION(self, NULL);
|
||||||
MARIADB_CHECK_TPC(self);
|
MARIADB_CHECK_TPC(self);
|
||||||
|
|
||||||
Py_BEGIN_ALLOW_THREADS;
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
@ -769,3 +824,245 @@ end:
|
|||||||
return List;
|
return List;
|
||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ MrdbConnection_ping */
|
||||||
|
PyObject *MrdbConnection_ping(MrdbConnection *self)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
|
rc= mysql_ping(self->mysql);
|
||||||
|
Py_END_ALLOW_THREADS;
|
||||||
|
|
||||||
|
if (rc)
|
||||||
|
{
|
||||||
|
mariadb_throw_exception(self->mysql, Mariadb_DatabaseError, 0, NULL);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ MrdbConnection_change_user */
|
||||||
|
PyObject *MrdbConnection_change_user(MrdbConnection *self,
|
||||||
|
PyObject *args)
|
||||||
|
{
|
||||||
|
const char *user= NULL,
|
||||||
|
*password= NULL,
|
||||||
|
*database= NULL;
|
||||||
|
int rc= 0;
|
||||||
|
MARIADB_CHECK_CONNECTION(self, NULL);
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "sss", &user, &password, &database))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
|
rc= mysql_change_user(self->mysql, user, password, database);
|
||||||
|
Py_END_ALLOW_THREADS;
|
||||||
|
|
||||||
|
if (rc)
|
||||||
|
{
|
||||||
|
mariadb_throw_exception(self->mysql, Mariadb_DatabaseError, 0, NULL);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ MrdbConnection_kill */
|
||||||
|
PyObject *MrdbConnection_kill(MrdbConnection *self, PyObject *args)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
unsigned long thread_id= 0;
|
||||||
|
|
||||||
|
MARIADB_CHECK_CONNECTION(self, NULL);
|
||||||
|
if (!PyArg_ParseTuple(args, "l", &thread_id))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
|
rc= mysql_kill(self->mysql, thread_id);
|
||||||
|
Py_END_ALLOW_THREADS;
|
||||||
|
|
||||||
|
if (rc)
|
||||||
|
{
|
||||||
|
mariadb_throw_exception(self->mysql, Mariadb_DatabaseError, 0, NULL);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* {{{ MrdbConnection_getid */
|
||||||
|
static PyObject *MrdbConnection_getid(MrdbConnection *self, void *closure)
|
||||||
|
{
|
||||||
|
PyObject *p;
|
||||||
|
|
||||||
|
MARIADB_CHECK_CONNECTION(self, NULL);
|
||||||
|
p= PyLong_FromUnsignedLong(mysql_thread_id(self->mysql));
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ MrdbConnection_getreconnect */
|
||||||
|
static PyObject *MrdbConnection_getreconnect(MrdbConnection *self,
|
||||||
|
void *closure)
|
||||||
|
{
|
||||||
|
uint8_t reconnect= 0;
|
||||||
|
|
||||||
|
if (self->mysql)
|
||||||
|
mysql_get_option(self->mysql, MYSQL_OPT_RECONNECT, &reconnect);
|
||||||
|
|
||||||
|
if (reconnect)
|
||||||
|
Py_RETURN_TRUE;
|
||||||
|
|
||||||
|
Py_RETURN_FALSE;
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
static int MrdbConnection_setreconnect(MrdbConnection *self,
|
||||||
|
PyObject *args,
|
||||||
|
void *closure)
|
||||||
|
{
|
||||||
|
uint8_t reconnect;
|
||||||
|
|
||||||
|
if (!self->mysql)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!args || Py_TYPE(args) != &PyBool_Type)
|
||||||
|
{
|
||||||
|
PyErr_SetString(PyExc_TypeError, "Argument must be boolean");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
reconnect= PyObject_IsTrue(args);
|
||||||
|
mysql_optionsv(self->mysql, MYSQL_OPT_RECONNECT, &reconnect);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *MrdbConnection_getuser(MrdbConnection *self, void *closure)
|
||||||
|
{
|
||||||
|
PyObject *p;
|
||||||
|
char *user= NULL;
|
||||||
|
|
||||||
|
MARIADB_CHECK_CONNECTION(self, NULL);
|
||||||
|
|
||||||
|
mariadb_get_infov(self->mysql, MARIADB_CONNECTION_USER, &user);
|
||||||
|
p= PyUnicode_FromString(user);
|
||||||
|
return p;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static int MrdbConnection_setdb(MrdbConnection *self, PyObject *db,
|
||||||
|
void *closure)
|
||||||
|
{
|
||||||
|
int rc= 0;
|
||||||
|
char *schema;
|
||||||
|
|
||||||
|
MARIADB_CHECK_CONNECTION(self, -1);
|
||||||
|
|
||||||
|
if (!db || Py_TYPE(db) != &PyUnicode_Type)
|
||||||
|
{
|
||||||
|
PyErr_SetString(PyExc_TypeError, "Argument must be string");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
schema= PyUnicode_AsUTF8(db);
|
||||||
|
|
||||||
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
|
rc= mysql_select_db(self->mysql, schema);
|
||||||
|
Py_END_ALLOW_THREADS;
|
||||||
|
|
||||||
|
if (rc)
|
||||||
|
{
|
||||||
|
mariadb_throw_exception(self->mysql, Mariadb_DatabaseError, 0, NULL);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *MrdbConnection_getdb(MrdbConnection *self, void *closure)
|
||||||
|
{
|
||||||
|
PyObject *p;
|
||||||
|
char *db= NULL;
|
||||||
|
|
||||||
|
MARIADB_CHECK_CONNECTION(self, NULL);
|
||||||
|
|
||||||
|
mariadb_get_infov(self->mysql, MARIADB_CONNECTION_SCHEMA, &db);
|
||||||
|
p= PyUnicode_FromString(db);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject *MrdbConnection_reconnect(MrdbConnection *self)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
uint8_t reconnect= 1;
|
||||||
|
uint8_t save_reconnect;
|
||||||
|
|
||||||
|
MARIADB_CHECK_CONNECTION(self, NULL);
|
||||||
|
|
||||||
|
mysql_get_option(self->mysql, MYSQL_OPT_RECONNECT, &save_reconnect);
|
||||||
|
if (!save_reconnect)
|
||||||
|
mysql_optionsv(self->mysql, MYSQL_OPT_RECONNECT, &reconnect);
|
||||||
|
|
||||||
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
|
rc= mariadb_reconnect(self->mysql);
|
||||||
|
Py_END_ALLOW_THREADS;
|
||||||
|
|
||||||
|
if (!save_reconnect)
|
||||||
|
mysql_optionsv(self->mysql, MYSQL_OPT_RECONNECT, &save_reconnect);
|
||||||
|
|
||||||
|
if (rc)
|
||||||
|
{
|
||||||
|
mariadb_throw_exception(self->mysql, Mariadb_DatabaseError, 0, NULL);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject *MrdbConnection_reset(MrdbConnection *self)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
MARIADB_CHECK_CONNECTION(self, NULL);
|
||||||
|
|
||||||
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
|
rc= mysql_reset_connection(self->mysql);
|
||||||
|
Py_END_ALLOW_THREADS;
|
||||||
|
|
||||||
|
if (rc)
|
||||||
|
{
|
||||||
|
mariadb_throw_exception(self->mysql, Mariadb_DatabaseError, 0, NULL);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *MrdbConnection_warnings(MrdbConnection *self)
|
||||||
|
{
|
||||||
|
MARIADB_CHECK_CONNECTION(self, NULL);
|
||||||
|
|
||||||
|
return PyLong_FromLong((long)mysql_warning_count(self->mysql));
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *MrdbConnection_escape_string(MrdbConnection *self,
|
||||||
|
PyObject *args)
|
||||||
|
{
|
||||||
|
PyObject *string= NULL,
|
||||||
|
*new_string= NULL;
|
||||||
|
size_t from_length, to_length;
|
||||||
|
char *from, *to;
|
||||||
|
|
||||||
|
/* escaping depends on the server status, so we need a valid
|
||||||
|
connection */
|
||||||
|
MARIADB_CHECK_CONNECTION(self, NULL);
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "O!", &PyUnicode_Type, &string))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
from= PyUnicode_AsUTF8AndSize(string, (Py_ssize_t *)&from_length);
|
||||||
|
to= (char *)alloca(from_length * 2 + 1);
|
||||||
|
to_length= mysql_real_escape_string(self->mysql, to, from, from_length);
|
||||||
|
new_string= PyUnicode_FromStringAndSize(to, to_length);
|
||||||
|
return new_string;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -55,10 +55,13 @@ static char *mariadb_named_tuple_desc= "Named tupled row";
|
|||||||
static PyObject *Mariadb_no_operation(MrdbCursor *,
|
static PyObject *Mariadb_no_operation(MrdbCursor *,
|
||||||
PyObject *);
|
PyObject *);
|
||||||
static PyObject *Mariadb_row_count(MrdbCursor *self);
|
static PyObject *Mariadb_row_count(MrdbCursor *self);
|
||||||
|
static PyObject *MrdbCursor_warnings(MrdbCursor *self);
|
||||||
|
|
||||||
static PyGetSetDef MrdbCursor_sets[]=
|
static PyGetSetDef MrdbCursor_sets[]=
|
||||||
{
|
{
|
||||||
{"rowcount", (getter)Mariadb_row_count, NULL, "doc", NULL},
|
{"rowcount", (getter)Mariadb_row_count, NULL, "doc", NULL},
|
||||||
|
{"warnings", (getter)MrdbCursor_warnings, NULL,
|
||||||
|
"Number of warnings which were produced from last execute() call", NULL},
|
||||||
{NULL}
|
{NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -449,7 +452,7 @@ PyObject *MrdbCursor_execute(MrdbCursor *self,
|
|||||||
|
|
||||||
if (rc)
|
if (rc)
|
||||||
{
|
{
|
||||||
mariadb_throw_exception(self->stmt->mysql, Mariadb_InterfaceError, 0, NULL);
|
mariadb_throw_exception(self->stmt->mysql, Mariadb_DatabaseError, 0, NULL);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
/* if we have a result set, we can't process it - so we will return
|
/* if we have a result set, we can't process it - so we will return
|
||||||
@ -470,7 +473,7 @@ PyObject *MrdbCursor_execute(MrdbCursor *self,
|
|||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
/* throw exception from statement handle */
|
/* throw exception from statement handle */
|
||||||
mariadb_throw_exception(self->stmt, Mariadb_InterfaceError, 1, NULL);
|
mariadb_throw_exception(self->stmt, Mariadb_DatabaseError, 1, NULL);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -480,7 +483,7 @@ PyObject *MrdbCursor_execute(MrdbCursor *self,
|
|||||||
Py_END_ALLOW_THREADS;
|
Py_END_ALLOW_THREADS;
|
||||||
if (rc)
|
if (rc)
|
||||||
{
|
{
|
||||||
mariadb_throw_exception(self->stmt, Mariadb_InterfaceError, 1, NULL);
|
mariadb_throw_exception(self->stmt, Mariadb_DatabaseError, 1, NULL);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -994,3 +997,10 @@ static PyObject *Mariadb_row_count(MrdbCursor *self)
|
|||||||
return PyLong_FromLongLong(row_count);
|
return PyLong_FromLongLong(row_count);
|
||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
|
static PyObject *MrdbCursor_warnings(MrdbCursor *self)
|
||||||
|
{
|
||||||
|
MARIADB_CHECK_STMT(self);
|
||||||
|
|
||||||
|
return PyLong_FromLong((long)mysql_stmt_warning_count(self->stmt));
|
||||||
|
}
|
||||||
|
@ -29,4 +29,3 @@ class CursorTest(unittest.TestCase):
|
|||||||
print("rows fetched", len(list_out))
|
print("rows fetched", len(list_out))
|
||||||
self.assertEqual(list_in,list_out)
|
self.assertEqual(list_in,list_out)
|
||||||
cursor.close()
|
cursor.close()
|
||||||
|
|
||||||
|
108
test/nondbapi.py
Normal file
108
test/nondbapi.py
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
#!/usr/bin/env python -O
|
||||||
|
|
||||||
|
import mariadb
|
||||||
|
import datetime
|
||||||
|
import unittest
|
||||||
|
import collections
|
||||||
|
import time
|
||||||
|
|
||||||
|
class CursorTest(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.connection= mariadb.connection(default_file='default.cnf')
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
del self.connection
|
||||||
|
|
||||||
|
def test_ping(self):
|
||||||
|
new_conn= mariadb.connection(default_file='default.cnf')
|
||||||
|
id= new_conn.connection_id;
|
||||||
|
self.connection.kill(id)
|
||||||
|
try:
|
||||||
|
new_conn.ping()
|
||||||
|
except mariadb.DatabaseError:
|
||||||
|
pass
|
||||||
|
del new_conn
|
||||||
|
new_conn= mariadb.connection(default_file='default.cnf')
|
||||||
|
new_conn.auto_reconnect= True
|
||||||
|
id= new_conn.connection_id;
|
||||||
|
self.connection.kill(id)
|
||||||
|
new_conn.ping()
|
||||||
|
new_id= new_conn.connection_id
|
||||||
|
self.assertTrue(id != new_id)
|
||||||
|
del new_conn
|
||||||
|
|
||||||
|
def test_change_user(self):
|
||||||
|
cursor= self.connection.cursor()
|
||||||
|
cursor.execute("create or replace user foo@localhost")
|
||||||
|
cursor.execute("GRANT ALL on test.* TO 'foo'@'localhost'")
|
||||||
|
new_conn= mariadb.connection(default_file='default.cnf')
|
||||||
|
new_conn.change_user("foo", "", "test")
|
||||||
|
self.assertEqual("foo", new_conn.user)
|
||||||
|
del new_conn
|
||||||
|
cursor.execute("drop user foo@localhost")
|
||||||
|
del cursor
|
||||||
|
|
||||||
|
def test_db(self):
|
||||||
|
cursor= self.connection.cursor()
|
||||||
|
cursor.execute("CREATE OR REPLACE schema test1")
|
||||||
|
self.assertEqual(self.connection.database, "test")
|
||||||
|
self.connection.database= "test1"
|
||||||
|
self.assertEqual(self.connection.database, "test1")
|
||||||
|
self.connection.database= "test"
|
||||||
|
self.assertEqual(self.connection.database, "test")
|
||||||
|
cursor.execute("USE test1")
|
||||||
|
self.assertEqual(self.connection.database, "test1")
|
||||||
|
cursor.execute("USE test")
|
||||||
|
cursor.execute("DROP SCHEMA test1")
|
||||||
|
del cursor
|
||||||
|
|
||||||
|
def test_reconnect(self):
|
||||||
|
new_conn= mariadb.connection(default_file='default.cnf')
|
||||||
|
conn1_id= new_conn.connection_id
|
||||||
|
self.connection.kill(conn1_id)
|
||||||
|
new_conn.reconnect()
|
||||||
|
conn2_id= new_conn.connection_id
|
||||||
|
self.assertFalse(conn1_id == conn2_id)
|
||||||
|
del new_conn
|
||||||
|
|
||||||
|
def test_reset(self):
|
||||||
|
cursor= self.connection.cursor()
|
||||||
|
cursor.execute("SELECT 1 UNION SELECT 2")
|
||||||
|
try:
|
||||||
|
self.connection.ping()
|
||||||
|
except mariadb.DatabaseError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
self.connection.reset()
|
||||||
|
self.connection.ping()
|
||||||
|
del cursor
|
||||||
|
|
||||||
|
def test_warnings(self):
|
||||||
|
conn= self.connection
|
||||||
|
cursor= conn.cursor()
|
||||||
|
|
||||||
|
cursor.execute("SET session sql_mode=''")
|
||||||
|
cursor.execute("CREATE OR REPLACE TABLE t1 (a tinyint)")
|
||||||
|
cursor.execute("INSERT INTO t1 VALUES (300)")
|
||||||
|
|
||||||
|
self.assertEqual(conn.warnings,1)
|
||||||
|
self.assertEqual(conn.warnings, cursor.warnings)
|
||||||
|
del cursor
|
||||||
|
|
||||||
|
def test_escape(self):
|
||||||
|
cursor= self.connection.cursor()
|
||||||
|
cursor.execute("CREATE OR REPLACE TABLE t1 (a varchar(100))")
|
||||||
|
str= 'This is a \ and a "'
|
||||||
|
cmd= "INSERT INTO t1 VALUES('%s')" % str
|
||||||
|
|
||||||
|
try:
|
||||||
|
cursor.execute(cmd)
|
||||||
|
except mariadb.DatabaseError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
str= self.connection.escape_string(str)
|
||||||
|
cmd= "INSERT INTO t1 VALUES('%s')" % str
|
||||||
|
cursor.execute(cmd)
|
||||||
|
del cursor
|
||||||
|
|
Reference in New Issue
Block a user