You've already forked mariadb-connector-c
mirror of
https://github.com/mariadb-corporation/mariadb-connector-c.git
synced 2025-08-07 02:42:49 +03:00
Added support for all (?) events
- All (MariaDB and MySQL) events are now supported - Added new api functions: - mariadb_rpl_error: returns error message - mariadb_rpl_errno: returns error number - mariadb_rpl_extract_rows: extract values of ROW_EVENTS - Added decryption support - Added uncompression -
This commit is contained in:
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "external/crypto_wrapper"]
|
||||||
|
path = external/crypto_wrapper
|
||||||
|
url = https://github.com/9EOR9/crypto_wrapper
|
@@ -50,6 +50,8 @@ MACRO(ADD_OPTION _name _text _default)
|
|||||||
ENDIF()
|
ENDIF()
|
||||||
ENDMACRO()
|
ENDMACRO()
|
||||||
|
|
||||||
|
ADD_OPTION(WITH_CRYPTO "build with cryptograpy support" OFF)
|
||||||
|
|
||||||
### Options ###
|
### Options ###
|
||||||
IF(NOT WIN32)
|
IF(NOT WIN32)
|
||||||
ADD_OPTION(WITH_MYSQLCOMPAT "creates libmysql* symbolic links" OFF)
|
ADD_OPTION(WITH_MYSQLCOMPAT "creates libmysql* symbolic links" OFF)
|
||||||
@@ -314,6 +316,9 @@ IF(NOT WITH_SSL STREQUAL "OFF")
|
|||||||
IF(WIN32)
|
IF(WIN32)
|
||||||
CHECK_INCLUDE_FILES (${OPENSSL_INCLUDE_DIR}/openssl/applink.c HAVE_OPENSSL_APPLINK_C)
|
CHECK_INCLUDE_FILES (${OPENSSL_INCLUDE_DIR}/openssl/applink.c HAVE_OPENSSL_APPLINK_C)
|
||||||
ENDIF()
|
ENDIF()
|
||||||
|
IF(WITH_CRYPTO)
|
||||||
|
SET(WITH_CRYPTO=openssl)
|
||||||
|
ENDIF()
|
||||||
INCLUDE_DIRECTORIES(BEFORE ${OPENSSL_INCLUDE_DIR})
|
INCLUDE_DIRECTORIES(BEFORE ${OPENSSL_INCLUDE_DIR})
|
||||||
|
|
||||||
|
|
||||||
@@ -340,6 +345,9 @@ IF(NOT WITH_SSL STREQUAL "OFF")
|
|||||||
SET(SSL_LIBRARIES ${GNUTLS_LIBRARY})
|
SET(SSL_LIBRARIES ${GNUTLS_LIBRARY})
|
||||||
SET(TLS_LIBRARY_VERSION "GnuTLS ${GNUTLS_VERSION_STRING}")
|
SET(TLS_LIBRARY_VERSION "GnuTLS ${GNUTLS_VERSION_STRING}")
|
||||||
INCLUDE_DIRECTORIES(${GNUTLS_INCLUDE_DIR})
|
INCLUDE_DIRECTORIES(${GNUTLS_INCLUDE_DIR})
|
||||||
|
IF(WITH_CRYPTO)
|
||||||
|
SET(WITH_CRYPTO=nettle)
|
||||||
|
ENDIF()
|
||||||
ELSE()
|
ELSE()
|
||||||
MESSAGE(FATAL_ERROR "GnuTLS not found")
|
MESSAGE(FATAL_ERROR "GnuTLS not found")
|
||||||
ENDIF()
|
ENDIF()
|
||||||
@@ -353,6 +361,9 @@ IF(NOT WITH_SSL STREQUAL "OFF")
|
|||||||
INCLUDE_DIRECTORIES("${CC_SOURCE_DIR}/plugins/pvio/")
|
INCLUDE_DIRECTORIES("${CC_SOURCE_DIR}/plugins/pvio/")
|
||||||
SET(SSL_LIBRARIES secur32)
|
SET(SSL_LIBRARIES secur32)
|
||||||
SET(TLS_LIBRARY_VERSION "Schannel ${CMAKE_SYSTEM_VERSION}")
|
SET(TLS_LIBRARY_VERSION "Schannel ${CMAKE_SYSTEM_VERSION}")
|
||||||
|
IF(WITH_CRYPTO)
|
||||||
|
SET(WITH_CRYPTO=schannel)
|
||||||
|
ENDIF()
|
||||||
ENDIF()
|
ENDIF()
|
||||||
ENDIF()
|
ENDIF()
|
||||||
MESSAGE1(TLS_LIBRARY_VERSION "TLS library/version: ${TLS_LIBRARY_VERSION}")
|
MESSAGE1(TLS_LIBRARY_VERSION "TLS library/version: ${TLS_LIBRARY_VERSION}")
|
||||||
@@ -360,6 +371,12 @@ IF(NOT WITH_SSL STREQUAL "OFF")
|
|||||||
MARK_AS_ADVANCED(SSL_SOURCES)
|
MARK_AS_ADVANCED(SSL_SOURCES)
|
||||||
ENDIF()
|
ENDIF()
|
||||||
|
|
||||||
|
IF(WITH_CRYPTO)
|
||||||
|
ADD_DEFINITIONS(-DHAVE_CRYPTO=1)
|
||||||
|
ADD_SUBDIRECTORY(${CC_SOURCE_DIR}/external/crypto_wrapper)
|
||||||
|
INCLUDE_DIRECTORIES(${CC_SOURCE_DIR}/external/crypto_wrapper/include)
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
SET(ENABLED_LOCAL_INFILE "AUTO" CACHE STRING "If we should should enable LOAD DATA LOCAL by default (OFF/ON/AUTO)")
|
SET(ENABLED_LOCAL_INFILE "AUTO" CACHE STRING "If we should should enable LOAD DATA LOCAL by default (OFF/ON/AUTO)")
|
||||||
MARK_AS_ADVANCED(ENABLED_LOCAL_INFILE)
|
MARK_AS_ADVANCED(ENABLED_LOCAL_INFILE)
|
||||||
IF (ENABLED_LOCAL_INFILE MATCHES "^(0|FALSE)$")
|
IF (ENABLED_LOCAL_INFILE MATCHES "^(0|FALSE)$")
|
||||||
|
1
external/crypto_wrapper
vendored
Submodule
1
external/crypto_wrapper
vendored
Submodule
Submodule external/crypto_wrapper added at 006ee66ca7
64
include/ma_decimal.h
Normal file
64
include/ma_decimal.h
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
/* Copyright (C) 2000 Sergei Golubchik
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _decimal_h
|
||||||
|
#define _decimal_h
|
||||||
|
|
||||||
|
typedef enum {TRUNCATE=0, HALF_EVEN, HALF_UP, CEILING, FLOOR} decimal_round_mode;
|
||||||
|
typedef int32 decimal_digit;
|
||||||
|
|
||||||
|
typedef struct st_decimal {
|
||||||
|
int intg, frac, len;
|
||||||
|
my_bool sign;
|
||||||
|
decimal_digit *buf;
|
||||||
|
} decimal;
|
||||||
|
|
||||||
|
int decimal2string(decimal *from, char *to, int *to_len);
|
||||||
|
int bin2decimal(const char *from, decimal *to, int precision, int scale);
|
||||||
|
|
||||||
|
int decimal_size(int precision, int scale);
|
||||||
|
int decimal_bin_size(int precision, int scale);
|
||||||
|
int decimal_result_size(decimal *from1, decimal *from2, char op, int param);
|
||||||
|
|
||||||
|
|
||||||
|
/* set a decimal to zero */
|
||||||
|
|
||||||
|
#define decimal_make_zero(dec) do { \
|
||||||
|
(dec)->buf[0]=0; \
|
||||||
|
(dec)->intg=1; \
|
||||||
|
(dec)->frac=0; \
|
||||||
|
(dec)->sign=0; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
returns the length of the buffer to hold string representation
|
||||||
|
of the decimal (including decimal dot, possible sign and \0)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define decimal_string_size(dec) ((dec)->intg + (dec)->frac + ((dec)->frac > 0) + 2)
|
||||||
|
|
||||||
|
/* negate a decimal */
|
||||||
|
#define decimal_neg(dec) do { (dec)->sign^=1; } while(0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
conventions:
|
||||||
|
|
||||||
|
decimal_smth() == 0 -- everything's ok
|
||||||
|
decimal_smth() <= 1 -- result is usable, but precision loss is possible
|
||||||
|
decimal_smth() <= 2 -- result can be unusable, most significant digits
|
||||||
|
could've been lost
|
||||||
|
decimal_smth() > 2 -- no result was generated
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define E_DEC_OK 0
|
||||||
|
#define E_DEC_TRUNCATED 1
|
||||||
|
#define E_DEC_OVERFLOW 2
|
||||||
|
#define E_DEC_DIV_ZERO 4
|
||||||
|
#define E_DEC_BAD_NUM 8
|
||||||
|
#define E_DEC_OOM 16
|
||||||
|
|
||||||
|
#define E_DEC_ERROR 31
|
||||||
|
#define E_DEC_FATAL_ERROR 30
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@@ -749,6 +749,7 @@ typedef char bool; /* Ordinary boolean values 0 1 */
|
|||||||
/* Optimized store functions for Intel x86 */
|
/* Optimized store functions for Intel x86 */
|
||||||
#define int1store(T,A) *((int8*) (T)) = (A)
|
#define int1store(T,A) *((int8*) (T)) = (A)
|
||||||
#define uint1korr(A) (*(((uint8*)(A))))
|
#define uint1korr(A) (*(((uint8*)(A))))
|
||||||
|
#define sint1korr(A) (*(((int8*)(A))))
|
||||||
#if defined(__i386__) || defined(_WIN32)
|
#if defined(__i386__) || defined(_WIN32)
|
||||||
#define sint2korr(A) (*((int16 *) (A)))
|
#define sint2korr(A) (*((int16 *) (A)))
|
||||||
#define sint3korr(A) ((int32) ((((uchar) (A)[2]) & 128) ? \
|
#define sint3korr(A) ((int32) ((((uchar) (A)[2]) & 128) ? \
|
||||||
|
@@ -81,7 +81,12 @@ enum mariadb_rpl_option {
|
|||||||
MARIADB_RPL_GTID_CALLBACK, /* GTID callback function */
|
MARIADB_RPL_GTID_CALLBACK, /* GTID callback function */
|
||||||
MARIADB_RPL_GTID_DATA, /* GTID data */
|
MARIADB_RPL_GTID_DATA, /* GTID data */
|
||||||
MARIADB_RPL_BUFFER,
|
MARIADB_RPL_BUFFER,
|
||||||
MARIADB_RPL_VERIFY_CHECKSUM
|
MARIADB_RPL_VERIFY_CHECKSUM,
|
||||||
|
MARIADB_RPL_UNCOMPRESS,
|
||||||
|
MARIADB_RPL_HOST,
|
||||||
|
MARIADB_RPL_PORT,
|
||||||
|
MARIADB_RPL_EXTRACT_VALUES,
|
||||||
|
MARIADB_RPL_DECRYPTION_KEY
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Event types: From MariaDB Server sql/log_event.h */
|
/* Event types: From MariaDB Server sql/log_event.h */
|
||||||
@@ -164,6 +169,7 @@ enum mariadb_rpl_event {
|
|||||||
#define COMPLETE_ROWS_F 0x08
|
#define COMPLETE_ROWS_F 0x08
|
||||||
#define NO_CHECK_CONSTRAINT_CHECKS_F 0x80
|
#define NO_CHECK_CONSTRAINT_CHECKS_F 0x80
|
||||||
|
|
||||||
|
|
||||||
enum mariadb_rpl_status_code {
|
enum mariadb_rpl_status_code {
|
||||||
Q_FLAGS2_CODE= 0x00,
|
Q_FLAGS2_CODE= 0x00,
|
||||||
Q_SQL_MODE_CODE= 0x01,
|
Q_SQL_MODE_CODE= 0x01,
|
||||||
@@ -190,6 +196,21 @@ enum mariadb_rpl_status_code {
|
|||||||
Q_XID= 129 /* xid: 8 bytes */
|
Q_XID= 129 /* xid: 8 bytes */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum opt_metadata_field_type
|
||||||
|
{
|
||||||
|
SIGNEDNESS = 1,
|
||||||
|
DEFAULT_CHARSET,
|
||||||
|
COLUMN_CHARSET,
|
||||||
|
COLUMN_NAME,
|
||||||
|
SET_STR_VALUE,
|
||||||
|
ENUM_STR_VALUE,
|
||||||
|
GEOMETRY_TYPE,
|
||||||
|
SIMPLE_PRIMARY_KEY,
|
||||||
|
PRIMARY_KEY_WITH_PREFIX,
|
||||||
|
ENUM_AND_SET_DEFAULT_CHARSET,
|
||||||
|
ENUM_AND_SET_COLUMN_CHARSET
|
||||||
|
};
|
||||||
|
|
||||||
/* Log Event flags */
|
/* Log Event flags */
|
||||||
|
|
||||||
/* used in FOMRAT_DESCRIPTION_EVENT. Indicates if it
|
/* used in FOMRAT_DESCRIPTION_EVENT. Indicates if it
|
||||||
@@ -251,14 +272,13 @@ typedef struct st_mariadb_gtid {
|
|||||||
unsigned long long sequence_nr;
|
unsigned long long sequence_nr;
|
||||||
} MARIADB_GTID;
|
} MARIADB_GTID;
|
||||||
|
|
||||||
|
|
||||||
/* Generic replication handle */
|
/* Generic replication handle */
|
||||||
typedef struct st_mariadb_rpl {
|
typedef struct st_mariadb_rpl {
|
||||||
unsigned int version;
|
unsigned int version;
|
||||||
MYSQL *mysql;
|
MYSQL *mysql;
|
||||||
char *filename;
|
char *filename;
|
||||||
uint32_t filename_length;
|
uint32_t filename_length;
|
||||||
unsigned char *buffer;
|
|
||||||
unsigned long buffer_size;
|
|
||||||
uint32_t server_id;
|
uint32_t server_id;
|
||||||
unsigned long start_position;
|
unsigned long start_position;
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
@@ -270,8 +290,35 @@ typedef struct st_mariadb_rpl {
|
|||||||
FILE *fp;
|
FILE *fp;
|
||||||
uint32_t error_no;
|
uint32_t error_no;
|
||||||
char error_msg[MYSQL_ERRMSG_SIZE];
|
char error_msg[MYSQL_ERRMSG_SIZE];
|
||||||
|
uint8_t uncompress;
|
||||||
|
char *host;
|
||||||
|
uint32_t port;
|
||||||
|
uint8_t extract_values;
|
||||||
|
char nonce[12];
|
||||||
|
uint8_t encrypted;
|
||||||
|
char *decryption_key;
|
||||||
} MARIADB_RPL;
|
} MARIADB_RPL;
|
||||||
|
|
||||||
|
typedef struct st_mariadb_rpl_value {
|
||||||
|
enum enum_field_types field_type;
|
||||||
|
uint8_t is_null;
|
||||||
|
uint8_t is_signed;
|
||||||
|
union {
|
||||||
|
int64_t ll;
|
||||||
|
uint64_t ull;
|
||||||
|
float f;
|
||||||
|
double d;
|
||||||
|
MYSQL_TIME tm;
|
||||||
|
MARIADB_STRING str;
|
||||||
|
} val;
|
||||||
|
} MARIADB_RPL_VALUE;
|
||||||
|
|
||||||
|
typedef struct st_rpl_mariadb_row {
|
||||||
|
uint32_t column_count;
|
||||||
|
MARIADB_RPL_VALUE *columns;
|
||||||
|
struct st_rpl_mariadb_row *next;
|
||||||
|
} MARIADB_RPL_ROW;
|
||||||
|
|
||||||
/* Event header */
|
/* Event header */
|
||||||
struct st_mariadb_rpl_rotate_event {
|
struct st_mariadb_rpl_rotate_event {
|
||||||
unsigned long long position;
|
unsigned long long position;
|
||||||
@@ -324,10 +371,21 @@ struct st_mariadb_rpl_table_map_event {
|
|||||||
unsigned long long table_id;
|
unsigned long long table_id;
|
||||||
MARIADB_STRING database;
|
MARIADB_STRING database;
|
||||||
MARIADB_STRING table;
|
MARIADB_STRING table;
|
||||||
unsigned int column_count;
|
uint32_t column_count;
|
||||||
MARIADB_STRING column_types;
|
MARIADB_STRING column_types;
|
||||||
MARIADB_STRING metadata;
|
MARIADB_STRING metadata;
|
||||||
unsigned char *null_indicator;
|
unsigned char *null_indicator;
|
||||||
|
unsigned char *signed_indicator;
|
||||||
|
MARIADB_CONST_DATA column_names;
|
||||||
|
MARIADB_CONST_DATA geometry_types;
|
||||||
|
uint32_t default_charset;
|
||||||
|
MARIADB_CONST_DATA column_charsets;
|
||||||
|
MARIADB_CONST_DATA simple_primary_keys;
|
||||||
|
MARIADB_CONST_DATA prefixed_primary_keys;
|
||||||
|
MARIADB_CONST_DATA set_values;
|
||||||
|
MARIADB_CONST_DATA enum_values;
|
||||||
|
uint8_t enum_set_default_charset;
|
||||||
|
MARIADB_CONST_DATA enum_set_column_charsets;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct st_mariadb_rpl_rand_event {
|
struct st_mariadb_rpl_rand_event {
|
||||||
@@ -386,6 +444,7 @@ struct st_mariadb_rpl_rows_event {
|
|||||||
size_t extra_data_size;
|
size_t extra_data_size;
|
||||||
void *extra_data;
|
void *extra_data;
|
||||||
uint8_t compressed;
|
uint8_t compressed;
|
||||||
|
uint32_t row_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct st_mariadb_rpl_heartbeat_event {
|
struct st_mariadb_rpl_heartbeat_event {
|
||||||
@@ -415,6 +474,7 @@ typedef struct st_mariadb_rpl_event
|
|||||||
MA_MEM_ROOT memroot;
|
MA_MEM_ROOT memroot;
|
||||||
unsigned char *raw_data;
|
unsigned char *raw_data;
|
||||||
size_t raw_data_size;
|
size_t raw_data_size;
|
||||||
|
size_t raw_data_ofs;
|
||||||
unsigned int checksum;
|
unsigned int checksum;
|
||||||
char ok;
|
char ok;
|
||||||
enum mariadb_rpl_event event_type;
|
enum mariadb_rpl_event event_type;
|
||||||
@@ -423,7 +483,6 @@ typedef struct st_mariadb_rpl_event
|
|||||||
unsigned int event_length;
|
unsigned int event_length;
|
||||||
unsigned int next_event_pos;
|
unsigned int next_event_pos;
|
||||||
unsigned short flags;
|
unsigned short flags;
|
||||||
void *raw_data;
|
|
||||||
/****************/
|
/****************/
|
||||||
union {
|
union {
|
||||||
struct st_mariadb_rpl_rotate_event rotate;
|
struct st_mariadb_rpl_rotate_event rotate;
|
||||||
@@ -449,21 +508,41 @@ typedef struct st_mariadb_rpl_event
|
|||||||
/* Added in C/C 3.3.0 */
|
/* Added in C/C 3.3.0 */
|
||||||
uint8_t is_semi_sync;
|
uint8_t is_semi_sync;
|
||||||
uint8_t semi_sync_flags;
|
uint8_t semi_sync_flags;
|
||||||
|
/* Added in C/C 3.3.5 */
|
||||||
|
MARIADB_RPL *rpl;
|
||||||
} MARIADB_RPL_EVENT;
|
} MARIADB_RPL_EVENT;
|
||||||
|
|
||||||
/* compression uses myisampack format */
|
/* compression uses myisampack format */
|
||||||
#define myisam_uint1korr(B) ((uint8_t)(*B))
|
#define myisam_uint1korr(B) ((uint8_t)(*B))
|
||||||
|
#define myisam_sint1korr(B) ((int8_t)(*B))
|
||||||
#define myisam_uint2korr(B)\
|
#define myisam_uint2korr(B)\
|
||||||
((uint16_t)(((uint16_t)(((const uchar*)(B))[1])) | ((uint16_t) (((const uchar*) (B))[0]) << 8)))
|
((uint16_t)(((uint16_t)(((const uchar*)(B))[1])) | ((uint16_t) (((const uchar*) (B))[0]) << 8)))
|
||||||
|
#define myisam_sint2korr(B)\
|
||||||
|
((int16_t)(((int16_t)(((const uchar*)(B))[1])) | ((int16_t) (((const uchar*) (B))[0]) << 8)))
|
||||||
#define myisam_uint3korr(B)\
|
#define myisam_uint3korr(B)\
|
||||||
((uint32_t)(((uint32_t)(((const uchar*)(B))[2])) |\
|
((uint32_t)(((uint32_t)(((const uchar*)(B))[2])) |\
|
||||||
(((uint32_t)(((const uchar*)(B))[1])) << 8) |\
|
(((uint32_t)(((const uchar*)(B))[1])) << 8) |\
|
||||||
(((uint32_t)(((const uchar*)(B))[0])) << 16)))
|
(((uint32_t)(((const uchar*)(B))[0])) << 16)))
|
||||||
|
#define myisam_sint3korr(B)\
|
||||||
|
((int32_t)(((int32_t)(((const uchar*)(B))[2])) |\
|
||||||
|
(((int32_t)(((const uchar*)(B))[1])) << 8) |\
|
||||||
|
(((int32_t)(((const uchar*)(B))[0])) << 16)))
|
||||||
#define myisam_uint4korr(B)\
|
#define myisam_uint4korr(B)\
|
||||||
((uint32_t)(((uint32_t)(((const uchar*)(B))[3])) |\
|
((uint32_t)(((uint32_t)(((const uchar*)(B))[3])) |\
|
||||||
(((uint32_t)(((const uchar*)(B))[2])) << 8) |\
|
(((uint32_t)(((const uchar*)(B))[2])) << 8) |\
|
||||||
(((uint32_t)(((const uchar*) (B))[1])) << 16) |\
|
(((uint32_t)(((const uchar*) (B))[1])) << 16) |\
|
||||||
(((uint32_t)(((const uchar*) (B))[0])) << 24)))
|
(((uint32_t)(((const uchar*) (B))[0])) << 24)))
|
||||||
|
#define myisam_sint4korr(B)\
|
||||||
|
((int32_t)(((int32_t)(((const uchar*)(B))[3])) |\
|
||||||
|
(((int32_t)(((const uchar*)(B))[2])) << 8) |\
|
||||||
|
(((int32_t)(((const uchar*) (B))[1])) << 16) |\
|
||||||
|
(((int32_t)(((const uchar*) (B))[0])) << 24)))
|
||||||
|
#define mi_uint5korr(B)\
|
||||||
|
((uint64_t)(((uint32_t) (((const uchar*) (B))[4])) |\
|
||||||
|
(((uint32_t) (((const uchar*) (B))[3])) << 8) |\
|
||||||
|
(((uint32_t) (((const uchar*) (B))[2])) << 16) |\
|
||||||
|
(((uint32_t) (((const uchar*) (B))[1])) << 24)) |\
|
||||||
|
(((uint64_t) (((const uchar*) (B))[0])) << 32))
|
||||||
|
|
||||||
#define RPL_SAFEGUARD(rpl, event, condition) \
|
#define RPL_SAFEGUARD(rpl, event, condition) \
|
||||||
if (!(condition))\
|
if (!(condition))\
|
||||||
@@ -485,8 +564,40 @@ if (!(condition))\
|
|||||||
(a) == DELETE_ROWS_EVENT || (a) == WRITE_ROWS_COMPRESSED_EVENT ||\
|
(a) == DELETE_ROWS_EVENT || (a) == WRITE_ROWS_COMPRESSED_EVENT ||\
|
||||||
(a) == UPDATE_ROWS_COMPRESSED_EVENT || (a) == DELETE_ROWS_COMPRESSED_EVENT)
|
(a) == UPDATE_ROWS_COMPRESSED_EVENT || (a) == DELETE_ROWS_COMPRESSED_EVENT)
|
||||||
|
|
||||||
|
#define IS_ROW_EVENT(a)\
|
||||||
|
((a)->event_type == WRITE_ROWS_COMPRESSED_EVENT_V1 ||\
|
||||||
|
(a)->event_type == UPDATE_ROWS_COMPRESSED_EVENT_V1 ||\
|
||||||
|
(a)->event_type == DELETE_ROWS_COMPRESSED_EVENT_V1 ||\
|
||||||
|
(a)->event_type == WRITE_ROWS_EVENT_V1 ||\
|
||||||
|
(a)->event_type == UPDATE_ROWS_EVENT_V1 ||\
|
||||||
|
(a)->event_type == DELETE_ROWS_EVENT_V1 ||\
|
||||||
|
(a)->event_type == WRITE_ROWS_EVENT ||\
|
||||||
|
(a)->event_type == UPDATE_ROWS_EVENT ||\
|
||||||
|
(a)->event_type == DELETE_ROWS_EVENT)
|
||||||
|
|
||||||
|
static inline uint64_t uintNkorr(uint8_t len, u_char *p)
|
||||||
|
{
|
||||||
|
switch (len) {
|
||||||
|
case 1:
|
||||||
|
return *p;
|
||||||
|
case 2:
|
||||||
|
return uint2korr(p);
|
||||||
|
case 3:
|
||||||
|
return uint3korr(p);
|
||||||
|
case 4:
|
||||||
|
return uint4korr(p);
|
||||||
|
case 8:
|
||||||
|
return uint8korr(p);
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Function prototypes */
|
/* Function prototypes */
|
||||||
MARIADB_RPL * STDCALL mariadb_rpl_init_ex(MYSQL *mysql, unsigned int version);
|
MARIADB_RPL * STDCALL mariadb_rpl_init_ex(MYSQL *mysql, unsigned int version);
|
||||||
|
const char * STDCALL mariadb_rpl_error(MARIADB_RPL *rpl);
|
||||||
|
uint32_t STDCALL mariadb_rpl_errno(MARIADB_RPL *rpl);
|
||||||
|
|
||||||
int mariadb_rpl_optionsv(MARIADB_RPL *rpl, enum mariadb_rpl_option, ...);
|
int mariadb_rpl_optionsv(MARIADB_RPL *rpl, enum mariadb_rpl_option, ...);
|
||||||
int mariadb_rpl_get_optionsv(MARIADB_RPL *rpl, enum mariadb_rpl_option, ...);
|
int mariadb_rpl_get_optionsv(MARIADB_RPL *rpl, enum mariadb_rpl_option, ...);
|
||||||
@@ -496,6 +607,111 @@ void STDCALL mariadb_rpl_close(MARIADB_RPL *rpl);
|
|||||||
MARIADB_RPL_EVENT * STDCALL mariadb_rpl_fetch(MARIADB_RPL *rpl, MARIADB_RPL_EVENT *event);
|
MARIADB_RPL_EVENT * STDCALL mariadb_rpl_fetch(MARIADB_RPL *rpl, MARIADB_RPL_EVENT *event);
|
||||||
void STDCALL mariadb_free_rpl_event(MARIADB_RPL_EVENT *event);
|
void STDCALL mariadb_free_rpl_event(MARIADB_RPL_EVENT *event);
|
||||||
|
|
||||||
|
MARIADB_RPL_ROW * STDCALL
|
||||||
|
mariadb_rpl_extract_rows(MARIADB_RPL *rpl,
|
||||||
|
MARIADB_RPL_EVENT *tm_event,
|
||||||
|
MARIADB_RPL_EVENT *row_event);
|
||||||
|
|
||||||
|
/* Returned from get_latest_key_version() */
|
||||||
|
#define ENCRYPTION_KEY_VERSION_INVALID (~(unsigned int)0)
|
||||||
|
#define ENCRYPTION_KEY_NOT_ENCRYPTED (0)
|
||||||
|
|
||||||
|
#define ENCRYPTION_KEY_SYSTEM_DATA 1
|
||||||
|
#define ENCRYPTION_KEY_TEMPORARY_DATA 2
|
||||||
|
|
||||||
|
/* Returned from get_key() */
|
||||||
|
#define ENCRYPTION_KEY_BUFFER_TOO_SMALL (100)
|
||||||
|
|
||||||
|
#define ENCRYPTION_FLAG_DECRYPT 0
|
||||||
|
#define ENCRYPTION_FLAG_ENCRYPT 1
|
||||||
|
#define ENCRYPTION_FLAG_NOPAD 2
|
||||||
|
|
||||||
|
struct st_mariadb_encryption {
|
||||||
|
int interface_version; /**< version plugin uses */
|
||||||
|
|
||||||
|
/********************* KEY MANAGEMENT ***********************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
Function returning latest key version for a given key id.
|
||||||
|
|
||||||
|
@return A version or ENCRYPTION_KEY_VERSION_INVALID to indicate an error.
|
||||||
|
*/
|
||||||
|
unsigned int (*get_latest_key_version)(unsigned int key_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Function returning a key for a key version
|
||||||
|
|
||||||
|
@param key_id The requested key id
|
||||||
|
@param version The requested key version
|
||||||
|
@param key The key will be stored there. Can be NULL -
|
||||||
|
in which case no key will be returned
|
||||||
|
@param key_length in: key buffer size
|
||||||
|
out: the actual length of the key
|
||||||
|
|
||||||
|
This method can be used to query the key length - the required
|
||||||
|
buffer size - by passing key==NULL.
|
||||||
|
|
||||||
|
If the buffer size is less than the key length the content of the
|
||||||
|
key buffer is undefined (the plugin is free to partially fill it with
|
||||||
|
the key data or leave it untouched).
|
||||||
|
|
||||||
|
@return 0 on success, or
|
||||||
|
ENCRYPTION_KEY_VERSION_INVALID, ENCRYPTION_KEY_BUFFER_TOO_SMALL
|
||||||
|
or any other non-zero number for errors
|
||||||
|
*/
|
||||||
|
unsigned int (*get_key)(unsigned int key_id, unsigned int version,
|
||||||
|
unsigned char *key, unsigned int *key_length);
|
||||||
|
|
||||||
|
/********************* ENCRYPTION **************************************/
|
||||||
|
/*
|
||||||
|
The caller uses encryption as follows:
|
||||||
|
1. Create the encryption context object of the crypt_ctx_size() bytes.
|
||||||
|
2. Initialize it with crypt_ctx_init().
|
||||||
|
3. Repeat crypt_ctx_update() until there are no more data to encrypt.
|
||||||
|
4. Write the remaining output bytes and destroy the context object
|
||||||
|
with crypt_ctx_finish().
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns the size of the encryption context object in bytes
|
||||||
|
*/
|
||||||
|
unsigned int (*crypt_ctx_size)(unsigned int key_id, unsigned int key_version);
|
||||||
|
/**
|
||||||
|
Initializes the encryption context object.
|
||||||
|
*/
|
||||||
|
int (*crypt_ctx_init)(void *ctx, const unsigned char *key, unsigned int klen,
|
||||||
|
const unsigned char *iv, unsigned int ivlen, int flags,
|
||||||
|
unsigned int key_id, unsigned int key_version);
|
||||||
|
/**
|
||||||
|
Processes (encrypts or decrypts) a chunk of data
|
||||||
|
|
||||||
|
Writes the output to th dst buffer. note that it might write
|
||||||
|
more bytes that were in the input. or less. or none at all.
|
||||||
|
*/
|
||||||
|
int (*crypt_ctx_update)(void *ctx, const unsigned char *src,
|
||||||
|
unsigned int slen, unsigned char *dst,
|
||||||
|
unsigned int *dlen);
|
||||||
|
/**
|
||||||
|
Writes the remaining output bytes and destroys the encryption context
|
||||||
|
|
||||||
|
crypt_ctx_update might've cached part of the output in the context,
|
||||||
|
this method will flush these data out.
|
||||||
|
*/
|
||||||
|
int (*crypt_ctx_finish)(void *ctx, unsigned char *dst, unsigned int *dlen);
|
||||||
|
/**
|
||||||
|
Returns the length of the encrypted data
|
||||||
|
|
||||||
|
It returns the exact length, given only the source length.
|
||||||
|
Which means, this API only supports encryption algorithms where
|
||||||
|
the length of the encrypted data only depends on the length of the
|
||||||
|
input (a.k.a. compression is not supported).
|
||||||
|
*/
|
||||||
|
unsigned int (*encrypted_length)(unsigned int slen, unsigned int key_id,
|
||||||
|
unsigned int key_version);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@@ -68,6 +68,12 @@ typedef struct st_ma_const_string
|
|||||||
size_t length;
|
size_t length;
|
||||||
} MARIADB_CONST_STRING;
|
} MARIADB_CONST_STRING;
|
||||||
|
|
||||||
|
typedef struct st_ma_const_data
|
||||||
|
{
|
||||||
|
const unsigned char *data;
|
||||||
|
size_t length;
|
||||||
|
} MARIADB_CONST_DATA;
|
||||||
|
|
||||||
|
|
||||||
#ifndef ST_MA_USED_MEM_DEFINED
|
#ifndef ST_MA_USED_MEM_DEFINED
|
||||||
#define ST_MA_USED_MEM_DEFINED
|
#define ST_MA_USED_MEM_DEFINED
|
||||||
|
@@ -33,6 +33,7 @@ SET(MARIADB_LIB_SYMBOLS
|
|||||||
mariadb_rpl_fetch
|
mariadb_rpl_fetch
|
||||||
mariadb_rpl_optionsv
|
mariadb_rpl_optionsv
|
||||||
mariadb_rpl_get_optionsv
|
mariadb_rpl_get_optionsv
|
||||||
|
mariadb_rpl_extract_rows
|
||||||
mariadb_rpl_init_ex
|
mariadb_rpl_init_ex
|
||||||
mariadb_free_rpl_event
|
mariadb_free_rpl_event
|
||||||
mariadb_field_attr
|
mariadb_field_attr
|
||||||
@@ -303,6 +304,7 @@ SET(LIBMARIADB_SOURCES ${LIBMARIADB_SOURCES}
|
|||||||
${CC_SOURCE_DIR}/plugins/auth/my_auth.c
|
${CC_SOURCE_DIR}/plugins/auth/my_auth.c
|
||||||
ma_array.c
|
ma_array.c
|
||||||
ma_charset.c
|
ma_charset.c
|
||||||
|
ma_decimal.c
|
||||||
ma_hashtbl.c
|
ma_hashtbl.c
|
||||||
ma_net.c
|
ma_net.c
|
||||||
mariadb_charset.c
|
mariadb_charset.c
|
||||||
@@ -433,9 +435,12 @@ IF(WIN32)
|
|||||||
"FILE_DESCRIPTION:Dynamic lib for client/server communication")
|
"FILE_DESCRIPTION:Dynamic lib for client/server communication")
|
||||||
ENDIF()
|
ENDIF()
|
||||||
|
|
||||||
|
IF(WITH_CRYPTO)
|
||||||
|
SET(CRYPTO_LIBS cw_crypt)
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
ADD_LIBRARY(mariadbclient STATIC ${MARIADB_OBJECTS} ${EMPTY_FILE})
|
ADD_LIBRARY(mariadbclient STATIC ${MARIADB_OBJECTS} ${EMPTY_FILE})
|
||||||
TARGET_LINK_LIBRARIES(mariadbclient ${SYSTEM_LIBS})
|
TARGET_LINK_LIBRARIES(mariadbclient ${SYSTEM_LIBS} ${CRYPTO_LIBS})
|
||||||
|
|
||||||
IF(UNIX)
|
IF(UNIX)
|
||||||
ADD_LIBRARY(libmariadb SHARED ${libmariadb_RC} ${MARIADB_OBJECTS} ${EMPTY_FILE})
|
ADD_LIBRARY(libmariadb SHARED ${libmariadb_RC} ${MARIADB_OBJECTS} ${EMPTY_FILE})
|
||||||
@@ -445,7 +450,7 @@ ELSE()
|
|||||||
SET_TARGET_PROPERTIES(libmariadb PROPERTIES LINKER_LANGUAGE C)
|
SET_TARGET_PROPERTIES(libmariadb PROPERTIES LINKER_LANGUAGE C)
|
||||||
ENDIF()
|
ENDIF()
|
||||||
|
|
||||||
TARGET_LINK_LIBRARIES(libmariadb LINK_PRIVATE ${SYSTEM_LIBS})
|
TARGET_LINK_LIBRARIES(libmariadb LINK_PRIVATE ${SYSTEM_LIBS} ${CRYPTO_LIBS})
|
||||||
|
|
||||||
SIGN_TARGET(libmariadb)
|
SIGN_TARGET(libmariadb)
|
||||||
|
|
||||||
|
479
libmariadb/ma_decimal.c
Normal file
479
libmariadb/ma_decimal.c
Normal file
@@ -0,0 +1,479 @@
|
|||||||
|
/* Copyright (C) 2004 Sergei Golubchik
|
||||||
|
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
=======================================================================
|
||||||
|
NOTE: this library implements SQL standard "exact numeric" type
|
||||||
|
and is not at all generic, but rather intentinally crippled to
|
||||||
|
follow the standard :)
|
||||||
|
=======================================================================
|
||||||
|
Quoting the standard
|
||||||
|
(SQL:2003, Part 2 Foundations, aka ISO/IEC 9075-2:2003)
|
||||||
|
|
||||||
|
4.4.2 Characteristics of numbers, page 27:
|
||||||
|
|
||||||
|
An exact numeric type has a precision P and a scale S. P is a positive
|
||||||
|
integer that determines the number of significant digits in a
|
||||||
|
particular radix R, where R is either 2 or 10. S is a non-negative
|
||||||
|
integer. Every value of an exact numeric type of scale S is of the
|
||||||
|
form n*10^{-S}, where n is an integer such that ?-R^P <= n <= R^P.
|
||||||
|
|
||||||
|
[...]
|
||||||
|
|
||||||
|
If an assignment of some number would result in a loss of its most
|
||||||
|
significant digit, an exception condition is raised. If least
|
||||||
|
significant digits are lost, implementation-defined rounding or
|
||||||
|
truncating occurs, with no exception condition being raised.
|
||||||
|
|
||||||
|
[...]
|
||||||
|
|
||||||
|
Whenever an exact or approximate numeric value is assigned to an exact
|
||||||
|
numeric value site, an approximation of its value that preserves
|
||||||
|
leading significant digits after rounding or truncating is represented
|
||||||
|
in the declared type of the target. The value is converted to have the
|
||||||
|
precision and scale of the target. The choice of whether to truncate
|
||||||
|
or round is implementation-defined.
|
||||||
|
|
||||||
|
[...]
|
||||||
|
|
||||||
|
All numeric values between the smallest and the largest value,
|
||||||
|
inclusive, in a given exact numeric type have an approximation
|
||||||
|
obtained by rounding or truncation for that type; it is
|
||||||
|
implementation-defined which other numeric values have such
|
||||||
|
approximations.
|
||||||
|
|
||||||
|
5.3 <literal>, page 143
|
||||||
|
|
||||||
|
<exact numeric literal> ::=
|
||||||
|
<unsigned integer> [ <period> [ <unsigned integer> ] ]
|
||||||
|
| <period> <unsigned integer>
|
||||||
|
|
||||||
|
6.1 <data type>, page 165:
|
||||||
|
|
||||||
|
19) The <scale> of an <exact numeric type> shall not be greater than
|
||||||
|
the <precision> of the <exact numeric type>.
|
||||||
|
|
||||||
|
20) For the <exact numeric type>s DECIMAL and NUMERIC:
|
||||||
|
|
||||||
|
a) The maximum value of <precision> is implementation-defined.
|
||||||
|
<precision> shall not be greater than this value.
|
||||||
|
b) The maximum value of <scale> is implementation-defined. <scale>
|
||||||
|
shall not be greater than this maximum value.
|
||||||
|
|
||||||
|
21) NUMERIC specifies the data type exact numeric, with the decimal
|
||||||
|
precision and scale specified by the <precision> and <scale>.
|
||||||
|
|
||||||
|
22) DECIMAL specifies the data type exact numeric, with the decimal
|
||||||
|
scale specified by the <scale> and the implementation-defined
|
||||||
|
decimal precision equal to or greater than the value of the
|
||||||
|
specified <precision>.
|
||||||
|
|
||||||
|
6.26 <numeric value expression>, page 241:
|
||||||
|
|
||||||
|
1) If the declared type of both operands of a dyadic arithmetic
|
||||||
|
operator is exact numeric, then the declared type of the result is
|
||||||
|
an implementation-defined exact numeric type, with precision and
|
||||||
|
scale determined as follows:
|
||||||
|
|
||||||
|
a) Let S1 and S2 be the scale of the first and second operands
|
||||||
|
respectively.
|
||||||
|
b) The precision of the result of addition and subtraction is
|
||||||
|
implementation-defined, and the scale is the maximum of S1 and S2.
|
||||||
|
c) The precision of the result of multiplication is
|
||||||
|
implementation-defined, and the scale is S1 + S2.
|
||||||
|
d) The precision and scale of the result of division are
|
||||||
|
implementation-defined.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ma_global.h>
|
||||||
|
#include <ma_sys.h> /* for my_alloca */
|
||||||
|
#include <ma_decimal.h>
|
||||||
|
#include <mysql.h>
|
||||||
|
#include <mariadb_rpl.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#define alloca _malloca
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef decimal_digit dec1;
|
||||||
|
typedef longlong dec2;
|
||||||
|
|
||||||
|
#define unlikely(A) (A)
|
||||||
|
#define DIG_PER_DEC1 9
|
||||||
|
#define DIG_MASK 100000000
|
||||||
|
#define DIG_BASE 1000000000
|
||||||
|
#define DIG_BASE2 LL(1000000000000000000)
|
||||||
|
#define ROUND_UP(X) (((X)+DIG_PER_DEC1-1)/DIG_PER_DEC1)
|
||||||
|
static const dec1 powers10[DIG_PER_DEC1+1]={
|
||||||
|
1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000};
|
||||||
|
static const int dig2bytes[DIG_PER_DEC1+1]={0, 1, 1, 2, 2, 3, 3, 4, 4, 4};
|
||||||
|
|
||||||
|
#define sanity(d) DBUG_ASSERT((d)->len >0 && ((d)->buf[0] | \
|
||||||
|
(d)->buf[(d)->len-1] | 1))
|
||||||
|
|
||||||
|
#define FIX_INTG_FRAC_ERROR(len, intg1, frac1, error) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
if (unlikely(intg1+frac1 > (len))) \
|
||||||
|
{ \
|
||||||
|
if (unlikely(intg1 > (len))) \
|
||||||
|
{ \
|
||||||
|
intg1=(len); \
|
||||||
|
frac1=0; \
|
||||||
|
error=E_DEC_OVERFLOW; \
|
||||||
|
} \
|
||||||
|
else \
|
||||||
|
{ \
|
||||||
|
frac1=(len)-intg1; \
|
||||||
|
error=E_DEC_TRUNCATED; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
else \
|
||||||
|
error=E_DEC_OK; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define ADD(to, from1, from2, carry) /* assume carry <= 1 */ \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
dec1 a=(from1)+(from2)+(carry); \
|
||||||
|
if (((carry)= a >= DIG_BASE)) /* no division here! */ \
|
||||||
|
a-=DIG_BASE; \
|
||||||
|
(to)=a; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define ADD2(to, from1, from2, carry) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
dec1 a=(from1)+(from2)+(carry); \
|
||||||
|
if (((carry)= a >= DIG_BASE)) \
|
||||||
|
a-=DIG_BASE; \
|
||||||
|
if (unlikely(a >= DIG_BASE)) \
|
||||||
|
{ \
|
||||||
|
a-=DIG_BASE; \
|
||||||
|
carry++; \
|
||||||
|
} \
|
||||||
|
(to)=a; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define SUB(to, from1, from2, carry) /* to=from1-from2 */ \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
dec1 a=(from1)-(from2)-(carry); \
|
||||||
|
if (((carry)= a < 0)) \
|
||||||
|
a+=DIG_BASE; \
|
||||||
|
(to)=a; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define SUB2(to, from1, from2, carry) /* to=from1-from2 */ \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
dec1 a=(from1)-(from2)-(carry); \
|
||||||
|
if (((carry)= a < 0)) \
|
||||||
|
a+=DIG_BASE; \
|
||||||
|
if (unlikely(a < 0)) \
|
||||||
|
{ \
|
||||||
|
a+=DIG_BASE; \
|
||||||
|
carry++; \
|
||||||
|
} \
|
||||||
|
(to)=a; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
Convert decimal to its printable string representation
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
decimal2string()
|
||||||
|
from - value to convert
|
||||||
|
to - points to buffer where string representation should be stored
|
||||||
|
*to_len - in: size of to buffer
|
||||||
|
out: length of the actually written string
|
||||||
|
|
||||||
|
RETURN VALUE
|
||||||
|
E_DEC_OK/E_DEC_TRUNCATED/E_DEC_OVERFLOW
|
||||||
|
*/
|
||||||
|
|
||||||
|
int decimal2string(decimal *from, char *to, int *to_len)
|
||||||
|
{
|
||||||
|
int len, intg=from->intg, frac=from->frac, i;
|
||||||
|
int error=E_DEC_OK;
|
||||||
|
char *s=to;
|
||||||
|
dec1 *buf, *buf0=from->buf, tmp;
|
||||||
|
|
||||||
|
DBUG_ASSERT(*to_len >= 2+from->sign);
|
||||||
|
|
||||||
|
/* removing leading zeroes */
|
||||||
|
i=((intg-1) % DIG_PER_DEC1)+1;
|
||||||
|
while (intg > 0 && *buf0 == 0)
|
||||||
|
{
|
||||||
|
intg-=i;
|
||||||
|
i=DIG_PER_DEC1;
|
||||||
|
buf0++;
|
||||||
|
}
|
||||||
|
if (intg > 0)
|
||||||
|
{
|
||||||
|
for (i=(intg-1) % DIG_PER_DEC1; *buf0 < powers10[i--]; intg--) ;
|
||||||
|
DBUG_ASSERT(intg > 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
intg=0;
|
||||||
|
if (unlikely(intg+frac==0))
|
||||||
|
{
|
||||||
|
intg=1;
|
||||||
|
tmp=0;
|
||||||
|
buf0=&tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
len= from->sign + intg + test(frac) + frac;
|
||||||
|
if (unlikely(len > --*to_len)) /* reserve one byte for \0 */
|
||||||
|
{
|
||||||
|
int i=len-*to_len;
|
||||||
|
error= (frac && i <= frac + 1) ? E_DEC_TRUNCATED : E_DEC_OVERFLOW;
|
||||||
|
if (frac && i >= frac + 1) i--;
|
||||||
|
if (i > frac)
|
||||||
|
{
|
||||||
|
intg-= i-frac;
|
||||||
|
frac= 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
frac-=i;
|
||||||
|
len= from->sign + intg + test(frac) + frac;
|
||||||
|
}
|
||||||
|
*to_len=len;
|
||||||
|
s[len]=0;
|
||||||
|
|
||||||
|
if (from->sign)
|
||||||
|
*s++='-';
|
||||||
|
|
||||||
|
if (frac)
|
||||||
|
{
|
||||||
|
char *s1=s+intg;
|
||||||
|
buf=buf0+ROUND_UP(intg);
|
||||||
|
*s1++='.';
|
||||||
|
for (; frac>0; frac-=DIG_PER_DEC1)
|
||||||
|
{
|
||||||
|
dec1 x=*buf++;
|
||||||
|
for (i=min(frac, DIG_PER_DEC1); i; i--)
|
||||||
|
{
|
||||||
|
dec1 y=x/DIG_MASK;
|
||||||
|
*s1++='0'+(uchar)y;
|
||||||
|
x-=y*DIG_MASK;
|
||||||
|
x*=10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s+=intg;
|
||||||
|
for (buf=buf0+ROUND_UP(intg); intg>0; intg-=DIG_PER_DEC1)
|
||||||
|
{
|
||||||
|
dec1 x=*--buf;
|
||||||
|
for (i=min(intg, DIG_PER_DEC1); i; i--)
|
||||||
|
{
|
||||||
|
dec1 y=x/10;
|
||||||
|
*--s='0'+(uchar)(x-y*10);
|
||||||
|
x=y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Convert string to decimal
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
str2decl()
|
||||||
|
from - value to convert
|
||||||
|
to - decimal where where the result will be stored
|
||||||
|
to->buf and to->len must be set.
|
||||||
|
end - if not NULL, *end will be set to the char where
|
||||||
|
conversion ended
|
||||||
|
fixed - use to->intg, to->frac as limits for input number
|
||||||
|
|
||||||
|
NOTE
|
||||||
|
to->intg and to->frac can be modified even when fixed=1
|
||||||
|
(but only decreased, in this case)
|
||||||
|
|
||||||
|
RETURN VALUE
|
||||||
|
E_DEC_OK/E_DEC_TRUNCATED/E_DEC_OVERFLOW/E_DEC_BAD_NUM/E_DEC_OOM
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Convert decimal to its binary fixed-length representation
|
||||||
|
two representations of the same length can be compared with memcmp
|
||||||
|
with the correct -1/0/+1 result
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
decimal2bin()
|
||||||
|
from - value to convert
|
||||||
|
to - points to buffer where string representation should be stored
|
||||||
|
precision/scale - see decimal_bin_size() below
|
||||||
|
|
||||||
|
NOTE
|
||||||
|
the buffer is assumed to be of the size decimal_bin_size(precision, scale)
|
||||||
|
|
||||||
|
RETURN VALUE
|
||||||
|
E_DEC_OK/E_DEC_TRUNCATED/E_DEC_OVERFLOW
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Restores decimal from its binary fixed-length representation
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
bin2decimal()
|
||||||
|
from - value to convert
|
||||||
|
to - result
|
||||||
|
precision/scale - see decimal_bin_size() below
|
||||||
|
|
||||||
|
NOTE
|
||||||
|
see decimal2bin()
|
||||||
|
the buffer is assumed to be of the size decimal_bin_size(precision, scale)
|
||||||
|
|
||||||
|
RETURN VALUE
|
||||||
|
E_DEC_OK/E_DEC_TRUNCATED/E_DEC_OVERFLOW
|
||||||
|
*/
|
||||||
|
|
||||||
|
int bin2decimal(const char *from, decimal *to, int precision, int scale)
|
||||||
|
{
|
||||||
|
int error=E_DEC_OK,
|
||||||
|
intg= precision - scale,
|
||||||
|
intg0= intg / DIG_PER_DEC1,
|
||||||
|
frac0= scale / DIG_PER_DEC1,
|
||||||
|
intg0x= intg - intg0 * DIG_PER_DEC1,
|
||||||
|
frac0x= scale - frac0*DIG_PER_DEC1,
|
||||||
|
intg1= intg0 + (intg0x > 0),
|
||||||
|
frac1= frac0 + (frac0x > 0),
|
||||||
|
tmp_size= decimal_bin_size(precision, scale);
|
||||||
|
char *tmp;
|
||||||
|
dec1 *buf= to->buf,
|
||||||
|
mask=(*from & 0x80) ? 0 : -1;
|
||||||
|
char *stop;
|
||||||
|
|
||||||
|
/* Initial implementation from Sergei modified "from" buffer, (which errored
|
||||||
|
in binlog api when verifying checksum), so we declare from as read only and use
|
||||||
|
a stack buffer instead */
|
||||||
|
tmp= (char *)alloca(tmp_size);
|
||||||
|
memcpy(tmp, from, tmp_size);
|
||||||
|
*tmp^= 0x80; /* remove sign bit */
|
||||||
|
from= tmp;
|
||||||
|
|
||||||
|
sanity(to);
|
||||||
|
|
||||||
|
FIX_INTG_FRAC_ERROR(to->len, intg1, frac1, error);
|
||||||
|
if (unlikely(error))
|
||||||
|
{
|
||||||
|
if (intg1 < intg0+(intg0x>0))
|
||||||
|
{
|
||||||
|
from+= dig2bytes[intg0x] + sizeof(dec1)*(intg0 - intg1);
|
||||||
|
frac0= frac0x= intg0x= 0;
|
||||||
|
intg0= intg1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
frac0x= 0;
|
||||||
|
frac0= frac1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
to->sign= (mask != 0);
|
||||||
|
to->intg= intg0 * DIG_PER_DEC1 + intg0x;
|
||||||
|
to->frac= frac0 * DIG_PER_DEC1 + frac0x;
|
||||||
|
|
||||||
|
if (intg0x)
|
||||||
|
{
|
||||||
|
int i= dig2bytes[intg0x];
|
||||||
|
dec1 x;
|
||||||
|
switch (i)
|
||||||
|
{
|
||||||
|
case 1: x=myisam_sint1korr(from); break;
|
||||||
|
case 2: x=myisam_sint2korr(from); break;
|
||||||
|
case 3: x=myisam_sint3korr(from); break;
|
||||||
|
case 4: x=myisam_sint4korr(from); break;
|
||||||
|
default: DBUG_ASSERT(0);
|
||||||
|
}
|
||||||
|
from+=i;
|
||||||
|
*buf=x ^ mask;
|
||||||
|
if (buf > to->buf || *buf != 0)
|
||||||
|
buf++;
|
||||||
|
else
|
||||||
|
to->intg-=intg0x;
|
||||||
|
}
|
||||||
|
for (stop=(char *)from+intg0*sizeof(dec1); from < stop; from+=sizeof(dec1))
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(sizeof(dec1) == 4);
|
||||||
|
*buf=myisam_sint4korr(from) ^ mask;
|
||||||
|
if (buf > to->buf || *buf != 0)
|
||||||
|
buf++;
|
||||||
|
else
|
||||||
|
to->intg-=DIG_PER_DEC1;
|
||||||
|
}
|
||||||
|
DBUG_ASSERT(to->intg >=0);
|
||||||
|
for (stop=(char *)from+frac0*sizeof(dec1); from < stop; from+=sizeof(dec1))
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(sizeof(dec1) == 4);
|
||||||
|
*buf=myisam_sint4korr(from) ^ mask;
|
||||||
|
buf++;
|
||||||
|
}
|
||||||
|
if (frac0x)
|
||||||
|
{
|
||||||
|
int i=dig2bytes[frac0x];
|
||||||
|
dec1 x;
|
||||||
|
switch (i)
|
||||||
|
{
|
||||||
|
case 1: x=myisam_sint1korr(from); break;
|
||||||
|
case 2: x=myisam_sint2korr(from); break;
|
||||||
|
case 3: x=myisam_sint3korr(from); break;
|
||||||
|
case 4: x=myisam_sint4korr(from); break;
|
||||||
|
default: DBUG_ASSERT(0);
|
||||||
|
}
|
||||||
|
*buf=(x ^ mask) * powers10[DIG_PER_DEC1 - frac0x];
|
||||||
|
buf++;
|
||||||
|
}
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Returns the size of array to hold a decimal with given precision and scale
|
||||||
|
|
||||||
|
RETURN VALUE
|
||||||
|
size in dec1
|
||||||
|
(multiply by sizeof(dec1) to get the size if bytes)
|
||||||
|
*/
|
||||||
|
|
||||||
|
int decimal_size(int precision, int scale)
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(scale >= 0 && precision > 0 && scale <= precision);
|
||||||
|
return ROUND_UP(precision-scale)+ROUND_UP(scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Returns the size of array to hold a binary representation of a decimal
|
||||||
|
|
||||||
|
RETURN VALUE
|
||||||
|
size in bytes
|
||||||
|
*/
|
||||||
|
|
||||||
|
int decimal_bin_size(int precision, int scale)
|
||||||
|
{
|
||||||
|
int intg=precision-scale,
|
||||||
|
intg0=intg/DIG_PER_DEC1, frac0=scale/DIG_PER_DEC1,
|
||||||
|
intg0x=intg-intg0*DIG_PER_DEC1, frac0x=scale-frac0*DIG_PER_DEC1;
|
||||||
|
|
||||||
|
DBUG_ASSERT(scale >= 0 && precision > 0 && scale <= precision);
|
||||||
|
return intg0*sizeof(dec1)+dig2bytes[intg0x]+
|
||||||
|
frac0*sizeof(dec1)+dig2bytes[frac0x];
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user