mirror of
https://github.com/mariadb-corporation/mariadb-connector-python.git
synced 2025-07-27 13:01:19 +00:00
Merge branch '1.1-binlog' into 1.2
This commit is contained in:
@ -31,6 +31,8 @@
|
||||
#include <docs/common.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include <mariadb_rpl.h>
|
||||
|
||||
#define CHECK_TYPE(obj, type) \
|
||||
(Py_TYPE((obj)) == type || PyType_IsSubtype(Py_TYPE((obj)), type))
|
||||
#define CHECK_TYPE_NO_NONE(obj, type) \
|
||||
@ -126,6 +128,29 @@ enum enum_binary_command {
|
||||
SQL_OTHER=255
|
||||
};
|
||||
|
||||
enum enum_binlog_query_status {
|
||||
QS_FLAGS2= 0x00,
|
||||
QS_SQL_MODE= 0x01,
|
||||
QS_CATALOG= 0x02,
|
||||
QS_AUTO_INCREMENT= 0x03,
|
||||
QS_CHARSET= 0x04,
|
||||
QS_TIMEZONE= 0x05,
|
||||
QS_CATALOG_NZ= 0x06,
|
||||
QS_LC_TIME_NAMES= 0x07,
|
||||
QS_CHARSET_DATABASE= 0x08,
|
||||
QS_TABLE_MAP_FOR_UPDATE= 0x09,
|
||||
QS_MASTER_DATA_WRITTEN= 0x0A,
|
||||
QS_INVOKERS= 0x0B,
|
||||
QS_UPDATED_DB_NAMES= 0x0C,
|
||||
QS_MICROSECONDS= 0x0D,
|
||||
QS_DDL_LOGGED_WITH_XID= 0x10,
|
||||
QS_DEFAULT_COLLATION_FOR_UTF8MB4=0x11,
|
||||
QS_SQL_REQUIRE_PRIMARY_KEY=0x12,
|
||||
QS_DEFAULT_TABLE_ENCRYPTION=0x13,
|
||||
QS_HR_NOW=128,
|
||||
QS_XID=129
|
||||
};
|
||||
|
||||
enum enum_extended_field_type
|
||||
{
|
||||
EXT_TYPE_NONE=0,
|
||||
@ -242,6 +267,17 @@ typedef struct {
|
||||
uint8_t has_indicator;
|
||||
} MrdbParamInfo;
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
PyThreadState *thread_state;
|
||||
MrdbConnection *connection;
|
||||
MARIADB_RPL *rpl;
|
||||
uint8_t closed;
|
||||
uint8_t raw_data;
|
||||
MARIADB_RPL_EVENT *tm_event;
|
||||
PyObject *decryption_key;
|
||||
} MrdbBinlog;
|
||||
|
||||
typedef struct {
|
||||
PyObject *value;
|
||||
char indicator;
|
||||
@ -334,6 +370,7 @@ extern PyTypeObject MrdbPool_Type;
|
||||
extern PyTypeObject Mariadb_Fieldinfo_Type;
|
||||
extern PyTypeObject MrdbConnection_Type;
|
||||
extern PyTypeObject MrdbCursor_Type;
|
||||
extern PyTypeObject MrdbBinlog_Type;
|
||||
|
||||
PyObject *ListOrTuple_GetItem(PyObject *obj, Py_ssize_t index);
|
||||
int Mariadb_traverse(PyObject *self,
|
||||
@ -422,6 +459,7 @@ MrdbParser_end(MrdbParser *p);
|
||||
uint8_t
|
||||
MrdbParser_parse(MrdbParser *p, uint8_t is_batch, char *errmsg, size_t errmsg_len);
|
||||
|
||||
PyObject *Mrdb_GetTimeDelta(MYSQL_TIME *tm);
|
||||
/* Global defines */
|
||||
|
||||
|
||||
@ -530,7 +568,7 @@ MrdbParser_parse(MrdbParser *p, uint8_t is_batch, char *errmsg, size_t errmsg_le
|
||||
(((uint32_t) ((unsigned char) (A)[3])) << 24)) + \
|
||||
(((unsigned long long) ((unsigned char) (A)[4])) << 32) + \
|
||||
(((unsigned long long) ((unsigned char) (A)[5])) << 40))
|
||||
#define uint8_tkorr(A) (*((unsigned long long *) (A)))
|
||||
#define uint8korr(A) (*((unsigned long long *) (A)))
|
||||
#define sint8korr(A) (*((long long *) (A)))
|
||||
#define int2store(T,A) *((uint16_t*) (T))= (uint16_t) (A)
|
||||
#define int3store(T,A) do { *(T)= (unsigned char) ((A));\
|
||||
|
@ -39,6 +39,10 @@ __all__ = ["DataError", "DatabaseError", "Error", "IntegrityError",
|
||||
"__author__", "Cursor", "fieldinfo"]
|
||||
|
||||
|
||||
def binlog(*args, **kwargs):
|
||||
return mariadb._mariadb.BinaryLog(args, kwargs)
|
||||
|
||||
|
||||
def connect(*args, connectionclass=mariadb.connections.Connection, **kwargs):
|
||||
"""
|
||||
Creates a MariaDB Connection object.
|
||||
|
155
mariadb/constants/BINLOG.py
Normal file
155
mariadb/constants/BINLOG.py
Normal file
@ -0,0 +1,155 @@
|
||||
"""
|
||||
Binary log constants
|
||||
"""
|
||||
|
||||
# Options
|
||||
OPT_DUMP_NON_BLOCK = 1
|
||||
OPT_SEND_ANNOTATE_ROWS_EVENT = 2
|
||||
|
||||
# Events
|
||||
UNKNOWN_EVENT = 0
|
||||
START_EVENT_V3 = 1
|
||||
QUERY_EVENT = 2
|
||||
STOP_EVENT = 3
|
||||
ROTATE_EVENT = 4
|
||||
INTVAR_EVENT = 5
|
||||
LOAD_EVENT = 6
|
||||
SLAVE_EVENT = 7
|
||||
CREATE_FILE_EVENT = 8
|
||||
APPEND_BLOCK_EVENT = 9
|
||||
EXEC_LOAD_EVENT = 10
|
||||
DELETE_FILE_EVENT = 11
|
||||
NEW_LOAD_EVENT = 12
|
||||
RAND_EVENT = 13
|
||||
USER_VAR_EVENT = 14
|
||||
FORMAT_DESCRIPTION_EVENT = 15
|
||||
XID_EVENT = 16
|
||||
BEGIN_LOAD_QUERY_EVENT = 17
|
||||
EXECUTE_LOAD_QUERY_EVENT = 18
|
||||
TABLE_MAP_EVENT = 19
|
||||
WRITE_ROWS_EVENT_V1 = 23
|
||||
UPDATE_ROWS_EVENT_V1 = 24
|
||||
DELETE_ROWS_EVENT_V1 = 25
|
||||
INCIDENT_EVENT = 26
|
||||
HEARTBEAT_LOG_EVENT = 27
|
||||
IGNORABLE_LOG_EVENT = 28
|
||||
ROWS_QUERY_LOG_EVENT = 29
|
||||
WRITE_ROWS_EVENT = 30
|
||||
UPDATE_ROWS_EVENT = 31
|
||||
DELETE_ROWS_EVENT = 32
|
||||
GTID_LOG_EVENT = 33
|
||||
ANONYMOUS_GTID_LOG_EVENT = 34
|
||||
PREVIOUS_GTIDS_LOG_EVENT = 35
|
||||
TRANSACTION_CONTEXT_EVENT = 36
|
||||
VIEW_CHANGE_EVENT = 37
|
||||
XA_PREPARE_LOG_EVENT = 38
|
||||
ANNOTATE_ROWS_EVENT = 160
|
||||
BINLOG_CHECKPOINT_EVENT = 161
|
||||
GTID_EVENT = 162
|
||||
GTID_LIST_EVENT = 163
|
||||
START_ENCRYPTION_EVENT = 164
|
||||
QUERY_COMPRESSED_EVENT = 165
|
||||
WRITE_ROWS_COMPRESSED_EVENT_V1 = 166
|
||||
UPDATE_ROWS_COMPRESSED_EVENT_V1 = 167
|
||||
DELETE_ROWS_COMPRESSED_EVENT_V1 = 168
|
||||
WRITE_ROWS_COMPRESSED_EVENT = 169
|
||||
UPDATE_ROWS_COMPRESSED_EVENT = 170
|
||||
DELETE_ROWS_COMPRESSED_EVENT = 171
|
||||
|
||||
# Query status flags
|
||||
QS_FLAGS2 = 0x00
|
||||
QS_SQL_MODE = 0x01
|
||||
QS_CATALOG = 0x02
|
||||
QS_AUTO_INCREMENT = 0x03
|
||||
QS_CHARSET = 0x04
|
||||
QS_TIMEZONE = 0x05
|
||||
QS_CATALOG_NZ = 0x06
|
||||
QS_LC_TIME_NAMES = 0x07
|
||||
QS_CHARSET_DATABASE = 0x08
|
||||
QS_TABLE_MAP_FOR_UPDATE = 0x09
|
||||
QS_MASTER_DATA_WRITTEN = 0x0A
|
||||
QS_INVOKERS = 0x0B
|
||||
QS_UPDATED_DB_NAMES = 0x0C
|
||||
QS_MICROSECONDS = 0x0D
|
||||
# unused
|
||||
QS_COMMIT_TS = 0x0E
|
||||
QS_COMMIT_TS2 = 0x0F
|
||||
# ------
|
||||
QS_EXPLICIT_DEFAULTS_FOR_TIMESTAMP = 0x10
|
||||
QS_DDL_LOGGED_WITH_XID = 0x11
|
||||
QS_DEFAULT_COLLATION_FOR_UTF8 = 0x12
|
||||
QS_SQL_REQUIRE_PRIMARY_KEY = 0x13
|
||||
QS_DEFAULT_TABLE_ENCRYPTION = 0x14
|
||||
QS_HRNOW = 128
|
||||
QS_XID = 129
|
||||
|
||||
# QS2_FLAGS2 bitmask
|
||||
QS_FLAGS2_OPTION_AUTO_IS_NULL = 0x00004000
|
||||
QS_FLAGS2_OPTION_NOT_AUTOCOMMIT = 0x00008000
|
||||
QS_FLAGS2_OPTION_NO_FOREIGN_KEY_CHECKS = 0x40000000
|
||||
QS_FLAGS2_OPTION_RELAXED_UNIQUE_CHECKS = 0x80000000
|
||||
|
||||
# SQL modes
|
||||
SQL_MODE_REAL_AS_FLOAT = 0x00000001
|
||||
SQL_MODE_PIPES_AS_CONCAT = 0x00000002
|
||||
SQL_MODE_ANSI_QUOTES = 0x00000004
|
||||
SQL_MODE_IGNORE_SPACE = 0x00000008
|
||||
SQL_MODE_NOT_USED = 0x00000010
|
||||
SQL_MODE_ONLY_FULL_GROUP_BY = 0x00000020
|
||||
SQL_MODE_NO_UNSIGNED_SUBTRACTION = 0x00000040
|
||||
SQL_MODE_NO_DIR_IN_CREATE = 0x00000080
|
||||
SQL_MODE_POSTGRESQL = 0x00000100
|
||||
SQL_MODE_ORACLE = 0x00000200
|
||||
SQL_MODE_MSSQL = 0x00000400
|
||||
SQL_MODE_DB2 = 0x00000800
|
||||
SQL_MODE_MAXDB = 0x00001000
|
||||
SQL_MODE_NO_KEY_OPTIONS = 0x00002000
|
||||
SQL_MODE_NO_TABLE_OPTIONS = 0x00004000
|
||||
SQL_MODE_NO_FIELD_OPTIONS = 0x00008000
|
||||
SQL_MODE_MYSQL323 = 0x00010000
|
||||
SQL_MODE_MYSQL40 = 0x00020000
|
||||
SQL_MODE_ANSI = 0x00040000
|
||||
SQL_MODE_NO_AUTO_VALUE_ON_ZERO = 0x00080000
|
||||
SQL_MODE_NO_BACKSLASH_ESCAPES = 0x00100000
|
||||
SQL_MODE_STRICT_TRANS_TABLES = 0x00200000
|
||||
SQL_MODE_STRICT_ALL_TABLES = 0x00400000
|
||||
SQL_MODE_NO_ZERO_IN_DATE = 0x00800000
|
||||
SQL_MODE_NO_ZERO_DATE = 0x01000000
|
||||
SQL_MODE_INVALID_DATES = 0x02000000
|
||||
SQL_MODE_ERROR_FOR_DIVISION_BY_ZERO = 0x04000000
|
||||
SQL_MODE_TRADITIONAL = 0x08000000
|
||||
SQL_MODE_NO_AUTO_CREATE_USER = 0x10000000
|
||||
SQL_MODE_HIGH_NOT_PRECEDENCE = 0x20000000
|
||||
SQL_MODE_NO_ENGINE_SUBSTITUTION = 0x40000000
|
||||
SQL_MODE_PAD_CHAR_TO_FULL_LENGTH = 0x80000000
|
||||
|
||||
# GTID_FLAGS
|
||||
GTID_F_STANDALONE = 1
|
||||
GTID_F_GROUP_COMMIT = 2
|
||||
GTID_F_TRANSACTIONAL = 4
|
||||
GTID_F_ALLOW_PARALLEL = 8
|
||||
GTID_F_WAITED = 16
|
||||
GTID_F_DDL = 32
|
||||
|
||||
# HEADER FLAGS
|
||||
LOG_EVENT_BINLOG_IN_USE_F = 0x0001
|
||||
LOG_EVENT_FORCED_ROTATE_F = 0x0002
|
||||
LOG_EVENT_THREAD_SPECIFIC_F = 0x0004
|
||||
LOG_EVENT_SUPPRESS_USE_F = 0x0008
|
||||
LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F = 0x0010
|
||||
LOG_EVENT_ARTIFICIAL_F = 0x0020
|
||||
LOG_EVENT_RELAY_LOG_F = 0x0040
|
||||
LOG_EVENT_IGNORABLE_F = 0x0080
|
||||
LOG_EVENT_NO_FILTER_F = 0x0100
|
||||
LOG_EVENT_MTS_ISOLATE_F = 0x0200
|
||||
LOG_EVENT_SKIP_REPLICATION_F = 0x0400
|
||||
|
||||
# ROWS FLAGS
|
||||
STMT_END_F = 0x0001
|
||||
|
||||
# RESULT TYPES
|
||||
STRING_RESULT = 0
|
||||
REAL_RESULT = 1
|
||||
INT_RESULT = 2
|
||||
ROW_RESULT = 3
|
||||
DECIMAL_RESULT = 4
|
@ -1,2 +1,3 @@
|
||||
__all__ = ["CLIENT", "CURSOR", "FIELD_TYPE", "FIELD_FLAG",
|
||||
"INDICATOR", 'STATUS', 'ERR', 'CAPABILITY']
|
||||
"INDICATOR", 'STATUS', 'ERR', 'CAPABILITY'
|
||||
"BINLOG"]
|
||||
|
@ -119,6 +119,13 @@ PyMODINIT_FUNC PyInit__mariadb(void)
|
||||
goto error;
|
||||
}
|
||||
|
||||
Py_SET_TYPE(&MrdbBinlog_Type, &PyType_Type);
|
||||
if (PyType_Ready(&MrdbBinlog_Type) == -1)
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
PyModule_AddObject(module, "binlog", (PyObject *)&MrdbBinlog_Type);
|
||||
|
||||
/* Import Decimal support (CONPY-49) */
|
||||
if (!(decimal_module= PyImport_ImportModule("decimal")) ||
|
||||
!(decimal_type= PyObject_GetAttr(decimal_module, PyUnicode_FromString("Decimal"))))
|
||||
|
998
mariadb/mariadb_binlog.c
Normal file
998
mariadb/mariadb_binlog.c
Normal file
@ -0,0 +1,998 @@
|
||||
/*****************************************************************************
|
||||
Copyright (C) 2022 Georg Richter and MariaDB Corporation AB
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not see <http://www.gnu.org/licenses>
|
||||
or write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St., Fifth Floor, Boston, MA 02110, USA
|
||||
*****************************************************************************/
|
||||
|
||||
#include "mariadb_python.h"
|
||||
#include "docs/connection.h"
|
||||
#include "docs/exception.h"
|
||||
#include <datetime.h>
|
||||
|
||||
#define binlog__doc__ NULL
|
||||
|
||||
void
|
||||
MrdbBinlog_dealloc(MrdbBinlog *self);
|
||||
|
||||
static PyObject *MrdbBinlog_fetch(MrdbBinlog *self);
|
||||
static PyObject *MrdbBinlog_close(MrdbBinlog *self);
|
||||
static PyObject *MrdbBinlog_filename(MrdbBinlog *self);
|
||||
|
||||
|
||||
#define MA_SET_DICT_ITEM_STRING(dict, key, val)\
|
||||
{\
|
||||
PyObject *x= (val);\
|
||||
if (!PyErr_Occurred()) \
|
||||
{\
|
||||
PyDict_SetItemString(dict, key, x);\
|
||||
Py_DECREF(x);\
|
||||
}\
|
||||
else {\
|
||||
printf("File: %s Line: %d\n", __FILE__, __LINE__);\
|
||||
PyErr_Print();\
|
||||
}\
|
||||
}
|
||||
|
||||
#define STR_AND_LEN(a) (a).str, (a).length
|
||||
|
||||
struct st_event_name {
|
||||
const char *event_name;
|
||||
uint32_t event_type;
|
||||
} event_names[]= {
|
||||
{"UNKNOWN", UNKNOWN_EVENT},
|
||||
{"START_V3", START_EVENT_V3},
|
||||
{"QUERY", QUERY_EVENT},
|
||||
{"STOP", STOP_EVENT},
|
||||
{"ROTATE", ROTATE_EVENT},
|
||||
{"INTVAR", INTVAR_EVENT},
|
||||
{"LOAD", LOAD_EVENT},
|
||||
{"SLAVE", SLAVE_EVENT},
|
||||
{"CREATE_FILE", CREATE_FILE_EVENT},
|
||||
{"APPEND_BLOCK", APPEND_BLOCK_EVENT},
|
||||
{"EXEC_LOAD", EXEC_LOAD_EVENT},
|
||||
{"DELETE_FILE", DELETE_FILE_EVENT},
|
||||
{"NEW_LOAD", NEW_LOAD_EVENT},
|
||||
{"RAND", RAND_EVENT},
|
||||
{"USER_VAR", USER_VAR_EVENT},
|
||||
{"FORMAT_DESCRIPTION", FORMAT_DESCRIPTION_EVENT},
|
||||
{"XID", XID_EVENT},
|
||||
{"BEGIN_LOAD_QUERY", BEGIN_LOAD_QUERY_EVENT},
|
||||
{"EXECUTE_LOAD_QUERY", EXECUTE_LOAD_QUERY_EVENT},
|
||||
{"TABLE_MAP", TABLE_MAP_EVENT},
|
||||
{"WRITE_ROWS_V1", WRITE_ROWS_EVENT_V1},
|
||||
{"UPDATE_ROWS_V1", UPDATE_ROWS_EVENT_V1},
|
||||
{"DELETE_ROWS_V1", DELETE_ROWS_EVENT_V1},
|
||||
{"INCIDENT", INCIDENT_EVENT},
|
||||
{"HEARTBEAT_LOG", HEARTBEAT_LOG_EVENT},
|
||||
{"IGNORABLE", IGNORABLE_LOG_EVENT},
|
||||
{"ROWS_QUERY_LOG", ROWS_QUERY_LOG_EVENT},
|
||||
{"WRITE_ROWS", WRITE_ROWS_EVENT},
|
||||
{"UPDATE_ROWS", UPDATE_ROWS_EVENT},
|
||||
{"DELETE_ROWS", DELETE_ROWS_EVENT},
|
||||
{"GTID_LOG", GTID_LOG_EVENT},
|
||||
{"ANONYMOUS_GTID_LOG", ANONYMOUS_GTID_LOG_EVENT},
|
||||
{"PREVIOUS_GTID_LOG", PREVIOUS_GTIDS_LOG_EVENT},
|
||||
{"TRANSACTION_CONTEXT", TRANSACTION_CONTEXT_EVENT},
|
||||
{"VIEW_CHANGE", VIEW_CHANGE_EVENT},
|
||||
{"XA_PREPARE_LOG", XA_PREPARE_LOG_EVENT},
|
||||
{"PARTIAL_UPDATE_ROWS", PARTIAL_UPDATE_ROWS_EVENT},
|
||||
{"ANNOTATE_ROWS", ANNOTATE_ROWS_EVENT},
|
||||
{"BINLOG_CHECKPOINT", BINLOG_CHECKPOINT_EVENT},
|
||||
{"GTID", GTID_EVENT},
|
||||
{"GTID_LIST", GTID_LIST_EVENT},
|
||||
{"START_ENCRYPTION", START_ENCRYPTION_EVENT},
|
||||
{"QUERY_COMPRESSED", QUERY_COMPRESSED_EVENT},
|
||||
{"WRITE_ROWS_COMPRESSED_V1", WRITE_ROWS_COMPRESSED_EVENT_V1},
|
||||
{"UPDATE_ROWS_COMPRESSED_V1", UPDATE_ROWS_COMPRESSED_EVENT_V1},
|
||||
{"DELETE_ROWS_COMPRESSED_V1", DELETE_ROWS_COMPRESSED_EVENT_V1},
|
||||
{"WRITE_ROWS_COMPRESSED", WRITE_ROWS_COMPRESSED_EVENT},
|
||||
{"UPDATE_ROWS_COMPRESSED", UPDATE_ROWS_COMPRESSED_EVENT},
|
||||
{"DELETE_ROWS_COMPRESSED", DELETE_ROWS_COMPRESSED_EVENT},
|
||||
{NULL, 0}
|
||||
};
|
||||
|
||||
static PyGetSetDef
|
||||
MrdbBinlog_sets[]=
|
||||
{
|
||||
{"filename", (getter)MrdbBinlog_filename, NULL,
|
||||
binlog__doc__, NULL},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
static PyMethodDef
|
||||
MrdbBinlog_Methods[] =
|
||||
{
|
||||
{"fetch", (PyCFunction)MrdbBinlog_fetch,
|
||||
METH_NOARGS,
|
||||
binlog__doc__},
|
||||
{"close", (PyCFunction)MrdbBinlog_close,
|
||||
METH_NOARGS,
|
||||
binlog__doc__},
|
||||
{NULL} /* always last */
|
||||
};
|
||||
|
||||
static struct
|
||||
PyMemberDef MrdbBinlog_Members[] =
|
||||
{
|
||||
{NULL} /* always last */
|
||||
};
|
||||
|
||||
static int
|
||||
MrdbBinlog_Initialize(MrdbBinlog *self,
|
||||
PyObject *args,
|
||||
PyObject *kwargs)
|
||||
{
|
||||
char *key_words[]= {"connection", "filename", "host", "port", "server_id",
|
||||
"start_position", "flags", "raw_data", "verify_checksum", NULL};
|
||||
const char *filename= NULL, *host= NULL;
|
||||
unsigned int server_id= 0, port= 0, flags= 0;
|
||||
unsigned long start_position= 0;
|
||||
uint8_t raw_data= 0;
|
||||
uint8_t verify_checksum= 1;
|
||||
MrdbConnection *connection= NULL;
|
||||
MYSQL *mysql= NULL;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs,
|
||||
"|O!ssiikibb", key_words, &MrdbConnection_Type,
|
||||
&connection, &filename, &host, &port, &server_id,
|
||||
&start_position, &flags, &raw_data, &verify_checksum))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (connection) {
|
||||
if (!connection->mysql)
|
||||
{
|
||||
mariadb_throw_exception(NULL, Mariadb_ProgrammingError, 0,
|
||||
"Connection isn't valid anymore");
|
||||
return -1;
|
||||
}
|
||||
mysql= connection->mysql;
|
||||
}
|
||||
|
||||
if (!(self->rpl= mariadb_rpl_init(mysql)))
|
||||
{
|
||||
mariadb_throw_exception(NULL, Mariadb_ProgrammingError, 0, NULL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
PyDateTime_IMPORT;
|
||||
|
||||
self->connection= connection;
|
||||
|
||||
mariadb_rpl_optionsv(self->rpl, MARIADB_RPL_SERVER_ID, server_id);
|
||||
mariadb_rpl_optionsv(self->rpl, MARIADB_RPL_START, start_position);
|
||||
mariadb_rpl_optionsv(self->rpl, MARIADB_RPL_FILENAME, filename, 0);
|
||||
mariadb_rpl_optionsv(self->rpl, MARIADB_RPL_FLAGS, flags);
|
||||
mariadb_rpl_optionsv(self->rpl, MARIADB_RPL_VERIFY_CHECKSUM, verify_checksum);
|
||||
self->raw_data= raw_data;
|
||||
|
||||
if (host)
|
||||
{
|
||||
if (mysql_optionsv(connection->mysql, MARIADB_OPT_RPL_REGISTER_REPLICA,
|
||||
host, port))
|
||||
{
|
||||
mariadb_throw_exception(self->connection->mysql, Mariadb_ProgrammingError, 0, NULL);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (mariadb_rpl_open(self->rpl))
|
||||
{
|
||||
mariadb_throw_exception(0, Mariadb_ProgrammingError, self->rpl->error_no, self->rpl->error_msg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (PyErr_Occurred())
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mrdb_process_status(PyObject *d_event, char *str_status, size_t status_len)
|
||||
{
|
||||
char *p= str_status, *end= str_status + status_len;
|
||||
PyObject *d_status= PyDict_New();
|
||||
const char *flag_name[]= {"flags2", "sql_mode", "catalog", "auto_increment",
|
||||
"character_set", "time_zone", "catalog_nz", "lc_time_names",
|
||||
"character_set_db", "tablemap_for_update", "master_data_written",
|
||||
"invokers", "updated_db_names", "microseconds"};
|
||||
while (p < end)
|
||||
{
|
||||
u_char status;
|
||||
|
||||
status= *p++;
|
||||
|
||||
switch (status)
|
||||
{
|
||||
case QS_FLAGS2:
|
||||
case QS_MASTER_DATA_WRITTEN:
|
||||
{
|
||||
uint32_t val;
|
||||
val= uint4korr(p);
|
||||
p+= 4;
|
||||
MA_SET_DICT_ITEM_STRING(d_status, flag_name[status], PyLong_FromUnsignedLong((unsigned long)val));
|
||||
}
|
||||
break;
|
||||
case QS_SQL_MODE:
|
||||
case QS_TABLE_MAP_FOR_UPDATE:
|
||||
{
|
||||
uint64_t flags;
|
||||
flags= uint8korr(p);
|
||||
MA_SET_DICT_ITEM_STRING(d_status, flag_name[status], PyLong_FromUnsignedLongLong(flags));
|
||||
p+= 8;
|
||||
}
|
||||
break;
|
||||
case QS_CATALOG:
|
||||
case QS_TIMEZONE:
|
||||
case QS_CATALOG_NZ:
|
||||
{
|
||||
uint8_t len;
|
||||
len= *p++;
|
||||
MA_SET_DICT_ITEM_STRING(d_status, flag_name[status], PyUnicode_FromStringAndSize(p, (Py_ssize_t)len));
|
||||
p+= len;
|
||||
if (status == QS_CATALOG)
|
||||
p++;
|
||||
}
|
||||
break;
|
||||
case QS_UPDATED_DB_NAMES:
|
||||
{
|
||||
uint8_t count, i;
|
||||
PyObject *tuple;
|
||||
count= *p++;
|
||||
if (count) {
|
||||
tuple= PyTuple_New(count);
|
||||
for (i=0; i < count; i++)
|
||||
{
|
||||
PyTuple_SetItem(tuple, i, PyUnicode_FromString(p));
|
||||
p+= (strlen(p) + 1);
|
||||
}
|
||||
MA_SET_DICT_ITEM_STRING(d_status, flag_name[status], tuple);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case QS_LC_TIME_NAMES:
|
||||
{
|
||||
uint16_t val= uint2korr(p);
|
||||
MA_SET_DICT_ITEM_STRING(d_status, flag_name[status], PyLong_FromUnsignedLong((unsigned long)val));
|
||||
p+= 2;
|
||||
break;
|
||||
}
|
||||
case QS_CHARSET_DATABASE:
|
||||
{
|
||||
uint16_t val;
|
||||
MARIADB_CHARSET_INFO *info= NULL;
|
||||
val= uint2korr(p);
|
||||
p+=2;
|
||||
info= mariadb_get_charset_by_nr(val);
|
||||
MA_SET_DICT_ITEM_STRING(d_status, flag_name[status], PyUnicode_FromString(info ? info->csname : "-"));
|
||||
}
|
||||
break;
|
||||
case QS_MICROSECONDS:
|
||||
{
|
||||
uint32_t val;
|
||||
val= uint3korr(p);
|
||||
p+= 3;
|
||||
MA_SET_DICT_ITEM_STRING(d_status, flag_name[status], PyLong_FromUnsignedLong((unsigned long)val));
|
||||
}
|
||||
break;
|
||||
case QS_AUTO_INCREMENT:
|
||||
{
|
||||
PyObject *tuple= PyTuple_New(2);
|
||||
uint16_t val1, val2;
|
||||
val1= uint2korr(p);
|
||||
p+= 2;
|
||||
val2= uint2korr(p);
|
||||
p+=2;
|
||||
PyTuple_SetItem(tuple, 0, PyLong_FromUnsignedLong((unsigned long)val1));
|
||||
PyTuple_SetItem(tuple, 1, PyLong_FromUnsignedLong((unsigned long)val2));
|
||||
MA_SET_DICT_ITEM_STRING(d_status, flag_name[status], tuple);
|
||||
}
|
||||
break;
|
||||
case QS_CHARSET:
|
||||
{
|
||||
PyObject *tuple= PyTuple_New(3);
|
||||
MARIADB_CHARSET_INFO *info= NULL;
|
||||
uint16_t val1, val2, val3;
|
||||
val1= uint2korr(p);
|
||||
p+= 2;
|
||||
val2= uint2korr(p);
|
||||
p+=2;
|
||||
val3= uint2korr(p);
|
||||
p+=2;
|
||||
info= mariadb_get_charset_by_nr(val1);
|
||||
PyTuple_SetItem(tuple, 0, PyUnicode_FromString(info ? info->csname : ""));
|
||||
info= mariadb_get_charset_by_nr(val2);
|
||||
PyTuple_SetItem(tuple, 1, PyUnicode_FromString(info ? info->name : ""));
|
||||
info= mariadb_get_charset_by_nr(val3);
|
||||
PyTuple_SetItem(tuple, 2, PyUnicode_FromString(info ? info->name : ""));
|
||||
MA_SET_DICT_ITEM_STRING(d_status, flag_name[status], tuple);
|
||||
}
|
||||
break;
|
||||
case QS_INVOKERS:
|
||||
{
|
||||
PyObject *dict= PyDict_New();
|
||||
uint8_t len;
|
||||
len= *p++;
|
||||
MA_SET_DICT_ITEM_STRING(dict, "username", PyUnicode_FromStringAndSize(p, (Py_ssize_t)len));
|
||||
p+= len;
|
||||
len= *p++;
|
||||
MA_SET_DICT_ITEM_STRING(dict, "hostname", PyUnicode_FromStringAndSize(p, (Py_ssize_t)len));
|
||||
p+= len;
|
||||
MA_SET_DICT_ITEM_STRING(d_status, flag_name[status], dict);
|
||||
}
|
||||
break;
|
||||
|
||||
case QS_DEFAULT_COLLATION_FOR_UTF8MB4:
|
||||
{
|
||||
p+= 2;
|
||||
break;
|
||||
}
|
||||
|
||||
case QS_DDL_LOGGED_WITH_XID:
|
||||
{
|
||||
p+= 8;
|
||||
break;
|
||||
}
|
||||
|
||||
case QS_DEFAULT_TABLE_ENCRYPTION:
|
||||
{
|
||||
p++;
|
||||
break;
|
||||
}
|
||||
|
||||
case QS_SQL_REQUIRE_PRIMARY_KEY:
|
||||
{
|
||||
p++;
|
||||
break;
|
||||
}
|
||||
|
||||
case QS_XID:
|
||||
{
|
||||
p+= 8;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "status", d_status);
|
||||
}
|
||||
|
||||
static PyObject *MrdbBinlog_fetch(MrdbBinlog *self)
|
||||
{
|
||||
MARIADB_RPL_EVENT *event= NULL;
|
||||
PyObject *ret= NULL;
|
||||
PyObject *d_header;
|
||||
PyObject *d_event;
|
||||
PyObject *raw;
|
||||
uint32_t i= 0;
|
||||
|
||||
if (!(event= mariadb_rpl_fetch(self->rpl, event)))
|
||||
{
|
||||
if (self->rpl->mysql && mysql_errno(self->connection->mysql))
|
||||
{
|
||||
mariadb_throw_exception(self->connection->mysql, Mariadb_ProgrammingError, 0, NULL);
|
||||
return NULL;
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
ret= PyDict_New();
|
||||
if (self->rpl->mysql)
|
||||
raw= PyBytes_FromStringAndSize((char *)event->raw_data + event->raw_data_ofs,
|
||||
event->raw_data_size - event->raw_data_ofs);
|
||||
else
|
||||
raw= PyBytes_FromStringAndSize((char *)event->raw_data, event->raw_data_size);
|
||||
|
||||
if (self->raw_data)
|
||||
{
|
||||
MA_SET_DICT_ITEM_STRING(ret, "raw", raw);
|
||||
}
|
||||
|
||||
d_header= PyDict_New();
|
||||
|
||||
if (self->rpl->encrypted)
|
||||
{
|
||||
MA_SET_DICT_ITEM_STRING(ret, "encrypted", PyLong_FromUnsignedLong((unsigned long)1));
|
||||
MA_SET_DICT_ITEM_STRING(ret, "header", d_header);
|
||||
return ret;
|
||||
} else {
|
||||
MA_SET_DICT_ITEM_STRING(d_header, "event_type",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->event_type));
|
||||
while (event_names[i].event_name)
|
||||
{
|
||||
if (event_names[i].event_type == event->event_type)
|
||||
{
|
||||
MA_SET_DICT_ITEM_STRING(d_header, "event_name", PyUnicode_FromString(event_names[i].event_name));
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
MA_SET_DICT_ITEM_STRING(d_header, "event_length",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->event_length));
|
||||
MA_SET_DICT_ITEM_STRING(d_header, "checksum",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->checksum));
|
||||
MA_SET_DICT_ITEM_STRING(d_header, "timestamp",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->timestamp));
|
||||
MA_SET_DICT_ITEM_STRING(d_header, "server_id",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->server_id));
|
||||
MA_SET_DICT_ITEM_STRING(d_header, "start_position",
|
||||
PyLong_FromUnsignedLong(event->event_type == ROTATE_EVENT ?
|
||||
(unsigned long)event->event.rotate.position :
|
||||
(unsigned long) event->next_event_pos - event->event_length));
|
||||
MA_SET_DICT_ITEM_STRING(d_header, "next_event_position",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->next_event_pos));
|
||||
MA_SET_DICT_ITEM_STRING(d_header, "flags",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->flags));
|
||||
}
|
||||
d_event= PyDict_New();
|
||||
|
||||
switch(event->event_type)
|
||||
{
|
||||
case BEGIN_LOAD_QUERY_EVENT:
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "file_id",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->event.begin_load_query.file_id));
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "data",
|
||||
PyBytes_FromString((char *)event->event.begin_load_query.data));
|
||||
break;
|
||||
case EXECUTE_LOAD_QUERY_EVENT:
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "thread_id",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->event.execute_load_query.thread_id));
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "execution_time",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->event.execute_load_query.execution_time));
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "error_code",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->event.execute_load_query.error_code));
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "file_id",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->event.execute_load_query.file_id));
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "ofs_1",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->event.execute_load_query.ofs1));
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "ofs_2",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->event.execute_load_query.ofs2));
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "duplicate_flag",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->event.execute_load_query.duplicate_flag));
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "status",
|
||||
PyBytes_FromStringAndSize(STR_AND_LEN(event->event.execute_load_query.status_vars)));
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "schema",
|
||||
PyUnicode_FromStringAndSize(STR_AND_LEN(event->event.execute_load_query.schema)));
|
||||
|
||||
break;
|
||||
case STOP_EVENT:
|
||||
break;
|
||||
case USER_VAR_EVENT:
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "variable",
|
||||
PyUnicode_FromStringAndSize(STR_AND_LEN(event->event.uservar.name)));
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "is_null",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->event.uservar.is_null));
|
||||
if (!event->event.uservar.is_null) {
|
||||
MARIADB_CHARSET_INFO *info;
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "type",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->event.uservar.type));
|
||||
info= mariadb_get_charset_by_nr(event->event.uservar.charset_nr);
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "collation",
|
||||
PyUnicode_FromString(info->name));
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "charset",
|
||||
PyUnicode_FromString(info->csname));
|
||||
switch (event->event.uservar.type)
|
||||
{
|
||||
case DECIMAL_RESULT:
|
||||
case REAL_RESULT:
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "value",
|
||||
PyBytes_FromStringAndSize(STR_AND_LEN(event->event.uservar.value)));
|
||||
break;
|
||||
case STRING_RESULT:
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "value",
|
||||
PyBytes_FromStringAndSize(STR_AND_LEN(event->event.uservar.value)));
|
||||
|
||||
break;
|
||||
case INT_RESULT:
|
||||
{
|
||||
uint64_t val= uint8korr(event->event.uservar.value.str);
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "value", (event->event.uservar.flags) ?
|
||||
PyLong_FromUnsignedLongLong(val) :
|
||||
PyLong_FromLongLong((int64_t)val));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
printf("not handled: %d\n", event->event.uservar.type);
|
||||
break;
|
||||
}
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "flags",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->event.uservar.flags));
|
||||
}
|
||||
break;
|
||||
|
||||
case ROTATE_EVENT:
|
||||
{
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "position",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->event.rotate.position));
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "filename",
|
||||
PyUnicode_FromStringAndSize(event->event.rotate.filename.str,
|
||||
event->event.rotate.filename.length));
|
||||
break;
|
||||
}
|
||||
case RAND_EVENT:
|
||||
{
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "rand_seed1",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->event.rand.first_seed));
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "rand_seed2",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->event.rand.second_seed));
|
||||
break;
|
||||
}
|
||||
case FORMAT_DESCRIPTION_EVENT:
|
||||
{
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "format",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->event.format_description.format));
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "server_version",
|
||||
PyUnicode_FromString(event->event.format_description.server_version));
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "timestamp",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->event.format_description.timestamp));
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "header_length",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->event.format_description.header_len));
|
||||
if (event->event.format_description.post_header_lengths.length)
|
||||
{
|
||||
PyObject *list= PyList_New(event->event.format_description.post_header_lengths.length);
|
||||
|
||||
for (uint16_t i= 0; i < event->event.format_description.post_header_lengths.length; i++)
|
||||
{
|
||||
PyList_SetItem(list, i, PyLong_FromUnsignedLong((u_char)event->event.format_description.post_header_lengths.str[i]));
|
||||
}
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "post_header_lengths", list);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GTID_LIST_EVENT:
|
||||
{
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "gtid_count",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->event.gtid_list.gtid_cnt));
|
||||
|
||||
if (event->event.gtid_list.gtid_cnt)
|
||||
{
|
||||
PyObject *tuple= PyTuple_New(event->event.gtid_list.gtid_cnt);
|
||||
uint32_t i;
|
||||
|
||||
for (i=0; i < event->event.gtid_list.gtid_cnt; i++)
|
||||
{
|
||||
PyObject *gtid= PyDict_New();
|
||||
MA_SET_DICT_ITEM_STRING(gtid, "domain_id",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->event.gtid_list.gtid[i].domain_id));
|
||||
MA_SET_DICT_ITEM_STRING(gtid, "server_id",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->event.gtid_list.gtid[i].server_id));
|
||||
MA_SET_DICT_ITEM_STRING(gtid, "sequence_nr",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->event.gtid_list.gtid[i].sequence_nr));
|
||||
PyTuple_SetItem(tuple, i, gtid);
|
||||
}
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "gtid_list", tuple);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case XA_PREPARE_LOG_EVENT:
|
||||
{
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "one_phase",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->event.xa_prepare_log.one_phase));
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "format_id",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->event.xa_prepare_log.format_id));
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "gtrid_len",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->event.xa_prepare_log.gtrid_len));
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "bqual_len",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->event.xa_prepare_log.bqual_len));
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "xid",
|
||||
PyBytes_FromStringAndSize(STR_AND_LEN(event->event.xa_prepare_log.xid)));
|
||||
|
||||
break;
|
||||
}
|
||||
case BINLOG_CHECKPOINT_EVENT:
|
||||
{
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "filename",
|
||||
PyUnicode_FromStringAndSize(STR_AND_LEN(event->event.checkpoint.filename)));
|
||||
break;
|
||||
}
|
||||
case ANONYMOUS_GTID_LOG_EVENT:
|
||||
case PREVIOUS_GTIDS_LOG_EVENT:
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "commit_flag",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->event.gtid_log.commit_flag));
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "source_id",
|
||||
PyBytes_FromStringAndSize(event->event.gtid_log.source_id, 16));
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "sequence_nr",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->event.gtid_log.sequence_nr));
|
||||
break;
|
||||
case GTID_EVENT:
|
||||
{
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "sequence_nr",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->event.gtid.sequence_nr));
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "domain_id",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->event.gtid.domain_id));
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "flags",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->event.gtid.flags));
|
||||
if (event->event.gtid.flags & FL_GROUP_COMMIT_ID)
|
||||
{
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "commit_id",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->event.gtid.commit_id));
|
||||
}
|
||||
#ifdef MARIADB_PACKAGE_VERSION_ID > 30305
|
||||
else if (event->event.gtid.flags & (FL_PREPARED_XA | FL_COMPLETED_XA))
|
||||
{
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "format_id",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->event.gtid.format_id));
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "gtrid_length",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->event.gtid.gtrid_len));
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "bqual_length",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->event.gtid.bqual_len));
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "xid",
|
||||
PyBytes_FromStringAndSize(event->event.gtid.xid.str,
|
||||
event->event.gtid.xid.length));
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case START_ENCRYPTION_EVENT:
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "scheme",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->event.start_encryption.scheme));
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "key_version",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->event.start_encryption.key_version));
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "nonce",
|
||||
PyBytes_FromStringAndSize(event->event.start_encryption.nonce, 12));
|
||||
break;
|
||||
case QUERY_EVENT:
|
||||
case QUERY_COMPRESSED_EVENT:
|
||||
{
|
||||
if (event->event_type == QUERY_COMPRESSED_EVENT)
|
||||
{
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "compressed",
|
||||
PyLong_FromUnsignedLong((unsigned long)1));
|
||||
}
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "status",
|
||||
PyBytes_FromStringAndSize(STR_AND_LEN(event->event.query.status)));
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "thread_id",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->event.query.thread_id));
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "seconds",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->event.query.seconds));
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "schema",
|
||||
PyUnicode_FromStringAndSize(STR_AND_LEN(event->event.query.database)));
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "error_no",
|
||||
PyLong_FromLong((unsigned long)event->event.query.errornr));
|
||||
if (event->event.query.statement.str && event->event.query.statement.length)
|
||||
{
|
||||
PyObject *b= PyBytes_FromStringAndSize(STR_AND_LEN(event->event.query.statement));
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "statement", b);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ANNOTATE_ROWS_EVENT:
|
||||
{
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "statement",
|
||||
PyBytes_FromStringAndSize(STR_AND_LEN(event->event.annotate_rows.statement)));
|
||||
break;
|
||||
}
|
||||
case TABLE_MAP_EVENT:
|
||||
{
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "table_id",
|
||||
PyLong_FromUnsignedLongLong(event->event.table_map.table_id));
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "schema",
|
||||
PyUnicode_FromStringAndSize(STR_AND_LEN(event->event.table_map.database)));
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "table",
|
||||
PyUnicode_FromStringAndSize(STR_AND_LEN(event->event.table_map.table)));
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "column_count",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->event.table_map.column_count));
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "column_types",
|
||||
PyBytes_FromStringAndSize(STR_AND_LEN(event->event.table_map.column_types)));
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "metadata",
|
||||
PyBytes_FromStringAndSize(STR_AND_LEN(event->event.table_map.metadata)));
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "null_indicator",
|
||||
PyBytes_FromStringAndSize((char *)event->event.table_map.null_indicator,
|
||||
(event->event.table_map.column_count + 8) / 7));
|
||||
break;
|
||||
}
|
||||
case WRITE_ROWS_EVENT_V1:
|
||||
case WRITE_ROWS_EVENT:
|
||||
case UPDATE_ROWS_EVENT_V1:
|
||||
case UPDATE_ROWS_EVENT:
|
||||
case DELETE_ROWS_EVENT_V1:
|
||||
case DELETE_ROWS_EVENT:
|
||||
case WRITE_ROWS_COMPRESSED_EVENT_V1:
|
||||
case UPDATE_ROWS_COMPRESSED_EVENT_V1:
|
||||
case DELETE_ROWS_COMPRESSED_EVENT_V1:
|
||||
case WRITE_ROWS_COMPRESSED_EVENT:
|
||||
case UPDATE_ROWS_COMPRESSED_EVENT:
|
||||
case DELETE_ROWS_COMPRESSED_EVENT:
|
||||
{
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "type",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->event.rows.type));
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "table_id",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->event.rows.table_id));
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "flags",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->event.rows.flags));
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "extra_data",
|
||||
PyBytes_FromStringAndSize(event->event.rows.extra_data, event->event.rows.extra_data_size));
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "column_count",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->event.rows.column_count));
|
||||
if (event->event_type == UPDATE_ROWS_EVENT ||
|
||||
event->event_type == UPDATE_ROWS_EVENT_V1)
|
||||
{
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "update_bitmap",
|
||||
PyBytes_FromStringAndSize((void *)event->event.rows.column_update_bitmap, (event->event.rows.column_count + 7) / 8));
|
||||
}
|
||||
if (event->event.rows.row_data_size)
|
||||
{
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "row_data",
|
||||
PyBytes_FromStringAndSize(event->event.rows.row_data, event->event.rows.row_data_size));
|
||||
}
|
||||
if (self->tm_event)
|
||||
{
|
||||
MARIADB_RPL_ROW *row, *tmp;
|
||||
uint64_t row_count= 0;
|
||||
PyObject *list= PyList_New(0);
|
||||
|
||||
tmp= row= mariadb_rpl_extract_rows(self->rpl, self->tm_event, event);
|
||||
while (tmp)
|
||||
{
|
||||
PyObject *tpl= PyTuple_New(tmp->column_count);
|
||||
for (i=0; i < row->column_count; i++)
|
||||
{
|
||||
PyObject *col= Py_None;
|
||||
MARIADB_RPL_VALUE column= tmp->columns[i];
|
||||
|
||||
if (column.is_null)
|
||||
{
|
||||
PyTuple_SetItem(tpl, i, Py_None);
|
||||
continue;
|
||||
}
|
||||
switch(column.field_type) {
|
||||
case MYSQL_TYPE_TINY:
|
||||
case MYSQL_TYPE_YEAR:
|
||||
case MYSQL_TYPE_SHORT:
|
||||
case MYSQL_TYPE_INT24:
|
||||
case MYSQL_TYPE_LONG:
|
||||
case MYSQL_TYPE_LONGLONG:
|
||||
col= PyLong_FromUnsignedLongLong(column.val.ull);
|
||||
break;
|
||||
case MYSQL_TYPE_DOUBLE:
|
||||
col= PyFloat_FromDouble(column.val.d);
|
||||
break;
|
||||
case MYSQL_TYPE_FLOAT:
|
||||
col= PyFloat_FromDouble((double)column.val.f);
|
||||
break;
|
||||
case MYSQL_TYPE_TINY_BLOB:
|
||||
case MYSQL_TYPE_MEDIUM_BLOB:
|
||||
case MYSQL_TYPE_BLOB:
|
||||
case MYSQL_TYPE_LONG_BLOB:
|
||||
case MYSQL_TYPE_GEOMETRY:
|
||||
case MYSQL_TYPE_BIT:
|
||||
col= PyBytes_FromStringAndSize(column.val.str.str, column.val.str.length);
|
||||
break;
|
||||
case MYSQL_TYPE_STRING:
|
||||
case MYSQL_TYPE_VARCHAR:
|
||||
case MYSQL_TYPE_VAR_STRING:
|
||||
case MYSQL_TYPE_NEWDECIMAL:
|
||||
col= PyBytes_FromStringAndSize(column.val.str.str, column.val.str.length);
|
||||
break;
|
||||
case MYSQL_TYPE_DATE:
|
||||
{
|
||||
#define MAX_DATE_LEN 10
|
||||
MYSQL_TIME *tm= &column.val.tm;
|
||||
char str_date[MAX_DATE_LEN + 1];
|
||||
|
||||
snprintf(str_date, MAX_DATE_LEN + 1, "%04d-%02d-%02d",
|
||||
tm->year, tm->month, tm->day);
|
||||
col= PyUnicode_FromStringAndSize(str_date, MAX_DATE_LEN);
|
||||
break;
|
||||
}
|
||||
case MYSQL_TYPE_TIME:
|
||||
col= Mrdb_GetTimeDelta(&column.val.tm);
|
||||
break;
|
||||
case MYSQL_TYPE_DATETIME:
|
||||
{
|
||||
#define MAX_DATETIME_LEN 26
|
||||
MYSQL_TIME *tm= &column.val.tm;
|
||||
char str_dt[MAX_DATETIME_LEN + 1];
|
||||
|
||||
if (tm->second_part)
|
||||
snprintf(str_dt, MAX_DATETIME_LEN, "%04d-%02d-%02d %02d:%02d:%02d.%ld",
|
||||
tm->year, tm->month, tm->day, tm->hour, tm->minute, tm->second, tm->second_part);
|
||||
else
|
||||
snprintf(str_dt, MAX_DATETIME_LEN, "%04d-%02d-%02d %02d:%02d:%02d",
|
||||
tm->year, tm->month, tm->day, tm->hour, tm->minute, tm->second);
|
||||
col= PyUnicode_FromString(str_dt);
|
||||
break;
|
||||
}
|
||||
case MYSQL_TYPE_TIMESTAMP2:
|
||||
{
|
||||
col= PyUnicode_FromStringAndSize(column.val.str.str, column.val.str.length);
|
||||
break;
|
||||
}
|
||||
case MYSQL_TYPE_ENUM:
|
||||
case MYSQL_TYPE_SET:
|
||||
{
|
||||
col= PyUnicode_FromStringAndSize(column.val.str.str, column.val.str.length);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printf("unhandled type: %d!\n", column.field_type);
|
||||
exit(0);
|
||||
break;
|
||||
}
|
||||
PyTuple_SetItem(tpl, i, col);
|
||||
}
|
||||
PyList_Append(list,tpl);
|
||||
row_count++;
|
||||
tmp= tmp->next;
|
||||
}
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "data", list);
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "row_count",
|
||||
PyLong_FromUnsignedLongLong(row_count));
|
||||
|
||||
/* If STMT_END flag is set, we can free and unset table_map event */
|
||||
if (event->event.rows.flags & STMT_END_F)
|
||||
{
|
||||
mariadb_free_rpl_event(self->tm_event);
|
||||
self->tm_event= NULL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case XID_EVENT:
|
||||
{
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "transaction_nr",
|
||||
PyLong_FromUnsignedLongLong((unsigned long long)event->event.xid.transaction_nr));
|
||||
break;
|
||||
}
|
||||
case INTVAR_EVENT:
|
||||
{
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "int_type",
|
||||
PyLong_FromUnsignedLong((unsigned long)event->event.intvar.type));
|
||||
MA_SET_DICT_ITEM_STRING(d_event, "int_value",
|
||||
PyLong_FromUnsignedLongLong(event->event.intvar.value));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
if (!self->raw_data)
|
||||
MA_SET_DICT_ITEM_STRING(ret, "raw", raw);
|
||||
break;
|
||||
}
|
||||
|
||||
MA_SET_DICT_ITEM_STRING(ret, "header", d_header);
|
||||
MA_SET_DICT_ITEM_STRING(ret, "event", d_event);
|
||||
|
||||
if (event->event_type == TABLE_MAP_EVENT)
|
||||
{
|
||||
self->tm_event= event;
|
||||
}
|
||||
else {
|
||||
mariadb_free_rpl_event(event);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int MrdbBinlog_traverse(
|
||||
MrdbBinlog *self,
|
||||
visitproc visit,
|
||||
void *arg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyObject *MrdbBinlog_repr(MrdbBinlog *self)
|
||||
{
|
||||
char cobj_repr[384];
|
||||
|
||||
if (!self->closed)
|
||||
snprintf(cobj_repr, 384, "<mariadb.binlog connected to '%s' at %p>",
|
||||
self->connection->host, self);
|
||||
else
|
||||
snprintf(cobj_repr, 384, "<mariadb.binlog (closed) at %p>",
|
||||
self);
|
||||
return PyUnicode_FromString(cobj_repr);
|
||||
}
|
||||
|
||||
PyTypeObject MrdbBinlog_Type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
"mariadb.binlog",
|
||||
sizeof(MrdbBinlog),
|
||||
0,
|
||||
(destructor)MrdbBinlog_dealloc, /* tp_dealloc */
|
||||
0, /*tp_print*/
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* PyAsyncMethods* */
|
||||
(reprfunc)MrdbBinlog_repr, /* tp_repr */
|
||||
|
||||
/* Method suites for standard classes */
|
||||
|
||||
0, /* (PyNumberMethods *) tp_as_number */
|
||||
0, /* (PySequenceMethods *) tp_as_sequence */
|
||||
0, /* (PyMappingMethods *) tp_as_mapping */
|
||||
|
||||
/* More standard operations (here for binary compatibility) */
|
||||
|
||||
0, /* (hashfunc) tp_hash */
|
||||
0, /* (ternaryfunc) tp_call */
|
||||
0, /* (reprfunc) tp_str */
|
||||
0, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
|
||||
/* Functions to access object as input/output buffer */
|
||||
0, /* (PyBufferProcs *) tp_as_buffer */
|
||||
|
||||
/* (tp_flags) Flags to define presence of optional/expanded features */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE,
|
||||
binlog__doc__, /* tp_doc Documentation string */
|
||||
|
||||
/* call function for all accessible objects */
|
||||
(traverseproc)MrdbBinlog_traverse, /* tp_traverse */
|
||||
|
||||
/* delete references to contained objects */
|
||||
0, /* tp_clear */
|
||||
|
||||
/* rich comparisons */
|
||||
0, /* (richcmpfunc) tp_richcompare */
|
||||
|
||||
/* weak reference enabler */
|
||||
0, /* (long) tp_weaklistoffset */
|
||||
|
||||
/* Iterators */
|
||||
0, /* (getiterfunc) tp_iter */
|
||||
0, /* (iternextfunc) tp_iternext */
|
||||
|
||||
/* Attribute descriptor and subclassing stuff */
|
||||
(struct PyMethodDef *)MrdbBinlog_Methods, /* tp_methods */
|
||||
(struct PyMemberDef *)MrdbBinlog_Members, /* tp_members */
|
||||
MrdbBinlog_sets, /* (struct getsetlist *) tp_getset; */
|
||||
0, /* (struct _typeobject *) tp_base; */
|
||||
0, /* (PyObject *) tp_dict */
|
||||
0, /* (descrgetfunc) tp_descr_get */
|
||||
0, /* (descrsetfunc) tp_descr_set */
|
||||
0, /* (long) tp_dictoffset */
|
||||
(initproc)MrdbBinlog_Initialize, /* tp_init */
|
||||
PyType_GenericAlloc, //NULL, /* tp_alloc */
|
||||
PyType_GenericNew, //NULL, /* tp_new */
|
||||
NULL, /* tp_free Low-level free-memory routine */
|
||||
0, /* (PyObject *) tp_bases */
|
||||
0, /* (PyObject *) tp_mro method resolution order */
|
||||
0, /* (PyObject *) tp_defined */
|
||||
};
|
||||
|
||||
/* destructor of MariaDB Connection object */
|
||||
void MrdbBinlog_dealloc(MrdbBinlog *self)
|
||||
{
|
||||
if (self)
|
||||
{
|
||||
Py_TYPE(self)->tp_free((PyObject*)self);
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject *MrdbBinlog_close(MrdbBinlog *self)
|
||||
{
|
||||
if (self->rpl)
|
||||
mariadb_rpl_close(self->rpl);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *MrdbBinlog_filename(MrdbBinlog *self)
|
||||
{
|
||||
char *filename= NULL;
|
||||
size_t len= 0;
|
||||
|
||||
if (mariadb_rpl_get_optionsv(self->rpl, MARIADB_RPL_FILENAME, &filename, &len) ||
|
||||
!filename || !len)
|
||||
{
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
return PyUnicode_FromStringAndSize(filename, (Py_ssize_t)len);
|
||||
}
|
@ -416,7 +416,7 @@ error:
|
||||
return 1;
|
||||
}
|
||||
|
||||
static PyObject *Mrdb_GetTimeDelta(MYSQL_TIME *tm)
|
||||
PyObject *Mrdb_GetTimeDelta(MYSQL_TIME *tm)
|
||||
{
|
||||
int days, hour, minute, second, second_part;
|
||||
|
||||
|
3
setup.py
3
setup.py
@ -119,6 +119,7 @@ setup(name='mariadb',
|
||||
install_requires=['packaging'],
|
||||
ext_modules=[Extension('mariadb._mariadb',
|
||||
['mariadb/mariadb.c',
|
||||
'mariadb/mariadb_binlog.c',
|
||||
'mariadb/mariadb_codecs.c',
|
||||
'mariadb/mariadb_connection.c',
|
||||
'mariadb/mariadb_cursor.c',
|
||||
@ -133,8 +134,10 @@ setup(name='mariadb',
|
||||
extra_objects=cfg.extra_objects
|
||||
)],
|
||||
py_modules=['mariadb.__init__',
|
||||
'mariadb.binary_log',
|
||||
'mariadb.connectionpool',
|
||||
'mariadb.connections',
|
||||
'mariadb.constants.BINLOG',
|
||||
'mariadb.constants.CAPABILITY',
|
||||
'mariadb.constants.CLIENT',
|
||||
'mariadb.constants.CURSOR',
|
||||
|
Reference in New Issue
Block a user