diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index e6e34bb..9186e88 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -22,6 +22,7 @@ SET(MARIADB_CLIENT_INCLUDES ${CC_SOURCE_DIR}/include/mariadb_com.h ${CC_SOURCE_DIR}/include/ob_protocol20.h ${CC_SOURCE_DIR}/include/ob_object.h ${CC_SOURCE_DIR}/include/ob_full_link_trace.h + ${CC_SOURCE_DIR}/include/ob_load_balance.h ${CC_SOURCE_DIR}/include/mariadb_rpl.h ) IF(NOT IS_SUBPROJECT) diff --git a/include/errmsg.h b/include/errmsg.h index 5c4f5fd..81f968b 100644 --- a/include/errmsg.h +++ b/include/errmsg.h @@ -27,6 +27,7 @@ extern "C" { void init_client_errs(void); extern const char *client_errors[]; /* Error messages */ extern const char *mariadb_client_errors[]; /* Error messages */ +extern const char *ob_client_errors[]; #ifdef __cplusplus } #endif @@ -35,11 +36,14 @@ extern const char *mariadb_client_errors[]; /* Error messages */ #define CR_MIN_ERROR 2000 /* For easier client code */ #define CR_MAX_ERROR 2999 -#define CER_MIN_ERROR 5000 -#define CER_MAX_ERROR 5999 +#define CER_MIN_ERROR 5000 +#define CER_MAX_ERROR 5999 +#define OB_MIN_ERROR 8000 +#define OB_MAX_ERROR 8999 #define CER(X) mariadb_client_errors[(X)-CER_MIN_ERROR] #define ER(X) client_errors[(X)-CR_MIN_ERROR] -#define CLIENT_ERRMAP 2 /* Errormap used by ma_error() */ +#define OBER(X) ob_client_errors[(X)-OB_MIN_ERROR] +#define CLIENT_ERRMAP 3 /* Errormap used by ma_error() */ #define CR_UNKNOWN_ERROR 2000 #define CR_SOCKET_CREATE_ERROR 2001 @@ -105,4 +109,24 @@ extern const char *mariadb_client_errors[]; /* Error messages */ /* Always last, if you add new error codes please update the value for CR_MARIADB_LAST_ERROR */ #define CR_MARIADB_LAST_ERROR CR_VERSION_MISMATCH + +/* +oceanbase erros: +*/ +#define CR_STATUS_ERROR_NOT_READY 8000 +#define CR_STATUS_ERROR_NOT_GET_RESULT 8001 +#define CR_STATES_ERROR_NEXT_RESULT 8002 +#define CR_STATUS_ERROR_CURSOR_FETCH 8003 +#define CR_STATUS_ERROR_FETCH_ORACLE_IMPLICIT_CURSOR 8004 +#define CR_STATUS_ERROR_FETCH_ORACLE_BUFFERED_RESULT 8005 +#define CR_STATUS_ERROR_STMT_USE_RESULT 8006 +#define CR_STATUS_ERROR_STMT_FETCH 8007 +#define CR_FETCH_FIELD_COUNT_IS_ZERO 8008 +#define CR_STATUS_ERROR_STORE_RESULT 8009 +#define CR_STATUS_ERROR_NOT_STMT_RESULT 8010 +#define CR_STATES_ERROR_NOT_PREPARED 8011 +#define CR_STATUS_ERROR_STMT_NEXT_RESULT 8012 +#define CR_STATES_ERROR_NOT_PREPARED_EXECUTE_V2 8013 +#define CR_OB_LAST_ERROR CR_STATES_ERROR_NOT_PREPARED_EXECUTE_V2 + #endif diff --git a/include/ma_global.h b/include/ma_global.h index 7d556a5..92e66b5 100644 --- a/include/ma_global.h +++ b/include/ma_global.h @@ -1115,8 +1115,16 @@ typedef unsigned long long intptr; #define OB_ERROR -4000 #define UNUSED(x) (void)x -#define OB_LIKELY(x) __builtin_expect(!!(x),1) -#define OB_UNLIKELY(x) __builtin_expect(!!(x),0) +#ifdef _WIN32 + #define OB_LIKELY(x) (x) + #define OB_UNLIKELY(x) (x) + #define __UINT64_C(c) c ## ULL + #define __INT64_C(c) c ## LL +#else + #define OB_LIKELY(x) __builtin_expect(!!(x),1) + #define OB_UNLIKELY(x) __builtin_expect(!!(x),0) +#endif + #define OB_ISNULL(statement) (OB_UNLIKELY(NULL == (statement))) #define OB_NOT_NULL(statement) (OB_LIKELY(NULL != (statement))) diff --git a/include/ma_pvio.h b/include/ma_pvio.h index 05a0748..fd632a8 100644 --- a/include/ma_pvio.h +++ b/include/ma_pvio.h @@ -114,6 +114,7 @@ struct st_ma_pvio_methods my_bool (*is_alive)(MARIADB_PVIO *pvio); my_bool (*has_data)(MARIADB_PVIO *pvio, ssize_t *data_len); int(*shutdown)(MARIADB_PVIO *pvio); + int(*socket5_auth)(MARIADB_PVIO *pvio, char *user, char *pwd, char *host, unsigned short port); }; /* Function prototypes */ @@ -135,5 +136,6 @@ my_bool ma_pvio_connect(MARIADB_PVIO *pvio, MA_PVIO_CINFO *cinfo); my_bool ma_pvio_is_alive(MARIADB_PVIO *pvio); my_bool ma_pvio_get_handle(MARIADB_PVIO *pvio, void *handle); my_bool ma_pvio_has_data(MARIADB_PVIO *pvio, ssize_t *length); +int ma_pvio_socket5_auth(MARIADB_PVIO *pvio, char *user, char *pwd, char *host, unsigned short port); #endif /* _ma_pvio_h_ */ diff --git a/include/ma_sys.h b/include/ma_sys.h index cadffe8..a8f97b6 100644 --- a/include/ma_sys.h +++ b/include/ma_sys.h @@ -51,7 +51,7 @@ do {\ ma_init();\ } while(0) -#define MAXMAPS (4) /* Number of error message maps */ +#define MAXMAPS (5) /* Number of error message maps */ #define ERRMOD (1000) /* Max number of errors in a map */ #define ERRMSGSIZE (SC_MAXWIDTH) /* Max length of a error message */ #define NRERRBUFFS (2) /* Buffers for parameters */ diff --git a/include/mariadb_com.h b/include/mariadb_com.h index 3f2a721..bcae248 100644 --- a/include/mariadb_com.h +++ b/include/mariadb_com.h @@ -381,7 +381,9 @@ enum ObCapabilityFlagShift OBCLIENT_CAP_PROXY_NEW_EXTRA_INFO_SHIFT, OBCLIENT_CAP_PROXY_SESSION_VAR_SYNC_SHIFT, OBCLIENT_CAP_PROXY_WEAK_STALE_FEEDBACK_SHIFT, - OBCLIENT_CAP_PROXY_FULL_LINK_TRACE_SHOW_TRACE_SHIFT + OBCLIENT_CAP_PROXY_FULL_LINK_TRACE_SHOW_TRACE_SHIFT, + OBCLIENT_CAP_SERVER_DUP_SESS_INFO_SYNC_SHIFT, + OBCLIENT_CAP_PROXY_LOCAL_INFILES_SHIFT }; #define OBCLIENT_TEST_CAPABILITY(cap, tg_cap) (((cap) & (tg_cap)) == (tg_cap)) @@ -403,6 +405,7 @@ enum ObCapabilityFlagShift #define OBCLIENT_CAP_PROXY_SESSION_VAR_SYNC OBCLIENT_CAP_GET_TYPE(OBCLIENT_CAP_PROXY_SESSION_VAR_SYNC_SHIFT) #define OBCLIENT_CAP_PROXY_WEAK_STALE_FEEDBACK OBCLIENT_CAP_GET_TYPE(OBCLIENT_CAP_PROXY_WEAK_STALE_FEEDBACK_SHIFT) #define OBCLIENT_CAP_PROXY_FULL_LINK_TRACE_SHOW_TRACE OBCLIENT_CAP_GET_TYPE(OBCLIENT_CAP_PROXY_FULL_LINK_TRACE_SHOW_TRACE_SHIFT) +#define OBCLIENT_CAP_PROXY_LOCAL_INFILES OBCLIENT_CAP_GET_TYPE(OBCLIENT_CAP_PROXY_LOCAL_INFILES_SHIFT) static const unsigned long OBPROXY_DEFAULT_CAPABILITY_FLAG = (OBCLIENT_CAP_OB_PROTOCOL_V2 @@ -419,6 +422,9 @@ static const char *const OB_MYSQL_CAPABILITY_FLAG = "__proxy_capability_flag"; static const char *const OB_MYSQL_CLIENT_MODE = "__mysql_client_type"; static const char *const OB_MYSQL_CLIENT_OBPROXY_MODE = "__ob_proxy"; static const char *const OB_MYSQL_CONNECTION_ID = "__connection_id"; +static const char *const OB_MYSQL_CLIENT_NAME_KEY = "__ob_client_name"; +static const char *const OB_MYSQL_CLIENT_NAME_VALUE = "OceanBase Connector/C"; +static const char *const OB_MYSQL_CLIENT_VERSION_KEY = "__ob_client_version"; static const char *const OB_MYSQL_PROXY_CONNECTION_ID = "__proxy_connection_id"; static const char *const OB_MYSQL_GLOBAL_VARS_VERSION = "__global_vars_version"; @@ -437,6 +443,7 @@ enum ObCapabilityFlagLob static const unsigned long OBCLIENT_CAP_OB_LOB_LOCATOR_V2_FLAG = OBCLIENT_CAP_OB_LOB_LOCATOR_V2; static const char *const OB_MYSQL_LOB_LOCATOR_V2 = "__ob_client_attribute_capability_flag"; +static const char *const OB_MYSQL_PROXY_USER_NAME = "__ob_client_proxy_user_name"; typedef enum enum_field_types { MYSQL_TYPE_DECIMAL, MYSQL_TYPE_TINY, MYSQL_TYPE_SHORT, MYSQL_TYPE_LONG, diff --git a/include/mariadb_stmt.h b/include/mariadb_stmt.h index 5f1d03c..b7c55e8 100644 --- a/include/mariadb_stmt.h +++ b/include/mariadb_stmt.h @@ -49,6 +49,15 @@ do { \ (a)->last_error[MYSQL_ERRMSG_SIZE - 1]= 0;\ } while (0) +#define SET_OB_CLIENT_STMT_ERROR(a, b, c, d) \ +do { \ + (a)->last_errno= (b);\ + strncpy((a)->sqlstate, (c), SQLSTATE_LENGTH);\ + (a)->sqlstate[SQLSTATE_LENGTH]= 0;\ + strncpy((a)->last_error, (d) ? (d) : OBER((b)), MYSQL_ERRMSG_SIZE);\ + (a)->last_error[MYSQL_ERRMSG_SIZE - 1]= 0;\ +} while (0) + #define CLEAR_CLIENT_STMT_ERROR(a) \ do { \ (a)->last_errno= 0;\ @@ -471,8 +480,18 @@ enum enum_ob_client_lob_locatorv2 }; my_bool determine_ob_client_lob_locatorv2(MYSQL *mysql); my_bool get_use_ob_client_lob_locatorv2(MYSQL *mysql); +/*end for support lobv2*/ -my_bool set_nls_format(MYSQL *mysql); +enum enum_load_infiles +{ + LOAD_INFILES_FORCE_CLOSE = 0, + LOAD_INFILES_AUTO_OPEN, + LOAD_INFILES_FORCE_OPEN, + LOAD_INFILES_FLAY_MAX +}; +my_bool determine_load_infiles(MYSQL *mysql); +my_bool get_use_load_infiles(MYSQL *mysql); +/*end for load infiles*/ /* add for support bindbyname for plarray */ struct prepare_extend_args_t diff --git a/include/mysql.h b/include/mysql.h index f335705..fb626ad 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -171,6 +171,15 @@ enum ObClientRoutineParamInOut (a)->net.last_error[MYSQL_ERRMSG_SIZE - 1]= 0;\ } while(0) +#define SET_OB_CLIENT_ERROR(a, b, c, d) \ + do { \ + (a)->net.last_errno= (b);\ + strncpy((a)->net.sqlstate, (c), SQLSTATE_LENGTH);\ + (a)->net.sqlstate[SQLSTATE_LENGTH]= 0;\ + strncpy((a)->net.last_error, (d) ? (d) : OBER((b)), MYSQL_ERRMSG_SIZE - 1);\ + (a)->net.last_error[MYSQL_ERRMSG_SIZE - 1]= 0;\ + } while(0) + /* For mysql_async.c */ #define set_mariadb_error(A,B,C) SET_CLIENT_ERROR((A),(B),(C),0) extern const char *SQLSTATE_UNKNOWN; @@ -279,7 +288,8 @@ extern const char *SQLSTATE_UNKNOWN; MARIADB_OPT_MULTI_STATEMENTS, MARIADB_OPT_INTERACTIVE, MARIADB_OPT_PROXY_HEADER, - MARIADB_OPT_IO_WAIT + MARIADB_OPT_IO_WAIT, + OB_OPT_PROXY_USER = 8000 /*ob option start 8000*/ }; enum mariadb_value { @@ -340,7 +350,7 @@ struct st_mysql_options { unsigned int connect_timeout, read_timeout, write_timeout; unsigned int port, protocol; unsigned long client_flag; - char *host,*user,*password,*unix_socket,*db; + char *host,*user,*password,*unix_socket,*db,*proxy_user; struct st_dynamic_array *init_command; char *my_cnf_file,*my_cnf_group, *charset_dir, *charset_name; char *ssl_key; /* PEM key file */ @@ -369,7 +379,7 @@ struct st_mysql_options { typedef struct st_mysql { NET net; /* Communication parameters */ void *unused_0; - char *host,*user,*passwd,*unix_socket,*server_version,*host_info; + char *host,*user,*passwd,*unix_socket,*server_version,*host_info,*proxy_user; char *info,*db; const struct ma_charset_info_st *charset; /* character set */ MYSQL_FIELD *fields; @@ -410,9 +420,14 @@ struct st_mysql_options { my_bool can_use_full_link_trace; my_bool can_use_ob_client_lob_locatorv2; my_bool can_use_flt_show_trace; + my_bool can_use_load_infiles; unsigned long ob_server_version; unsigned long ob_proxy_version; unsigned long capability; // system varaiable + my_bool is_socket5; //1 open socket5 + char socket5_authtype; + char *socket5_host, *socket5_user, *socket5_pwd; + int socket5_port; } MYSQL; /** @@ -425,9 +440,9 @@ struct st_mysql_options { * This structure is used as mysql->extension.res_extension field */ typedef struct st_ob_result_extension { - ulong pkt_len; + unsigned long pkt_len; char *pkt_buffer; - MYSQL_FIELD *mysql_fields; // fieldϢ + MYSQL_FIELD *mysql_fields; // 保存field信息 } OB_RES_EXT; struct st_mysql_trace_info; @@ -1017,6 +1032,8 @@ struct st_mariadb_methods { #define mysql_library_end mysql_server_end /* new api functions */ +void ob_get_libobclient_version(int *major, int *minor, int *patch, char* version, int len); +void ob_set_socket5_proxy(MYSQL *mysql, char socket5_authtype, char *socket5_host, int socket5_port, char *socket5_user, char *socket5_pwd); #define HAVE_MYSQL_REAL_CONNECT diff --git a/include/ob_full_link_trace.h b/include/ob_full_link_trace.h index 6a2c11e..10537c1 100644 --- a/include/ob_full_link_trace.h +++ b/include/ob_full_link_trace.h @@ -305,7 +305,7 @@ typedef struct st_fltfunc flt_get_serialize_size_func get_serialize_size_func; } FLTFunc; -typedef struct st_uuid +typedef struct st_obclient_uuid { union { struct { @@ -321,8 +321,8 @@ typedef struct st_uuid uint8_t node[6]; }; }; -} UUID; -DEFINE_TO_STRING_FUNC_FOR(UUID); +} OBCLIENT_UUID; +DEFINE_TO_STRING_FUNC_FOR(OBCLIENT_UUID); enum enum_flt_tagtype{ FLT_TAG_COMMAND_NAME = 0, @@ -342,7 +342,7 @@ DEFINE_TO_STRING_FUNC_FOR(ObTagCtx); typedef struct st_obspanctx { uint16_t span_type_; - UUID span_id_; + OBCLIENT_UUID span_id_; struct st_obspanctx *source_span_; my_bool is_follow_; int64_t start_ts_; @@ -363,8 +363,8 @@ struct st_obtrace my_bool slow_query_print_; FLTInfo *flt; // point to flt struct uint64_t uuid_random_seed[2]; - UUID trace_id_; - UUID root_span_id_; + OBCLIENT_UUID trace_id_; + OBCLIENT_UUID root_span_id_; LIST *current_span_list_; LIST *free_span_list_; ObSpanCtx *last_active_span_; @@ -407,11 +407,11 @@ DEFINE_FLT_SERIALIZE_FUNC(nosupport); // FLT_EXTRA_INFO_TYPE_END my_bool flt_is_vaild(FLTInfo *flt); -int serialize_UUID(char *buf, const int64_t buf_len, int64_t* pos, UUID *uuid); -int deserialize_UUID(const char *buf, const int64_t buf_len, int64_t *pos, UUID *uuid); +int serialize_UUID(char *buf, const int64_t buf_len, int64_t* pos, OBCLIENT_UUID *uuid); +int deserialize_UUID(const char *buf, const int64_t buf_len, int64_t *pos, OBCLIENT_UUID *uuid); int uuid4_init(uint64_t *seed, size_t seed_size); -UUID uuid4_generate(uint64_t *seed); +OBCLIENT_UUID uuid4_generate(uint64_t *seed); int flt_init(FLTInfo *flt); void flt_end(FLTInfo *flt); diff --git a/include/ob_load_balance.h b/include/ob_load_balance.h new file mode 100644 index 0000000..d27a728 --- /dev/null +++ b/include/ob_load_balance.h @@ -0,0 +1,66 @@ +#ifndef _OB_LOAD_BALANCE_H_ +#define _OB_LOAD_BALANCE_H_ +#include "mysql.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _st_obclient_lb_Address { + char host[128]; + unsigned int port; +}ObClientLbAddress; + +typedef struct _st_obclient_lb_AddressList { + ObClientLbAddress *address_list; + unsigned int address_list_count; +}ObClientLbAddressList; + +typedef struct _st_obclient_lb_config{ + int retry_all_downs; //总的次数 + int black_remove_strategy; //2001 + int black_remove_timeout; //移出黑名单时间 + int black_append_strategy; //3002 NORMAL, 3001 RETRYDURATION + int black_append_retrytimes; //单个address次数 + int black_append_duration; //时间duration内,执行>= retrytimes次加黑 + + unsigned int mysql_connect_timeout; + unsigned int mysql_read_timeout; + unsigned int mysql_write_timeout; + my_bool mysql_is_local_infile; + unsigned int mysql_local_infile; + unsigned int mysql_opt_protocol; + my_bool mysql_is_proxy_mode; + my_bool mysql_is_compress; + my_bool mysql_opt_secure_auth; + char* mysql_init_command; + char* mysql_charset_name; + char* mysql_opt_plugin_dir; + char* mysql_opt_default_auth; + char* mysql_program_name; + char* mysql_ob_proxy_user; + my_bool mysql_opt_interactive; + my_bool mysql_report_data_truncation; + my_bool mysql_opt_reconnect; + + my_bool mysql_opt_use_ssl; + my_bool mysql_opt_ssl_verify_server_cert; + char *mysql_opt_ssl_key; + char *mysql_opt_ssl_cert; + char *mysql_opt_ssl_ca; + char *mysql_opt_ssl_capath; + char *mysql_opt_ssl_cipher; + char *mysql_opt_ssl_crl; + char *mysql_opt_ssl_crlpath; + char *mysql_opt_tls_version; +}ObClientLbConfig; + + +MYSQL* ob_mysql_real_connect(MYSQL* mysql, const char* tns_name, ObClientLbAddressList *addr_list, ObClientLbConfig *config, + const char *user, const char *passwd, const char *db, const char *unix_socket, unsigned long client_flag, ObClientLbAddress* success); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/ob_object.h b/include/ob_object.h index fd0b8d0..20df81b 100644 --- a/include/ob_object.h +++ b/include/ob_object.h @@ -87,7 +87,7 @@ typedef enum enum_obobjtype ObMaxType // invalid type, or count of obj type } ObObjType; -enum enum_obcollationtype +typedef enum enum_obcollationtype { CS_TYPE_INVALID = 0, CS_TYPE_GBK_CHINESE_CI = 28, @@ -104,7 +104,7 @@ enum enum_obcollationtype CS_TYPE_MAX, } ObCollationType; -enum enum_obcollationlevel +typedef enum enum_obcollationlevel { CS_LEVEL_EXPLICIT = 0, CS_LEVEL_NONE = 1, diff --git a/include/ob_protocol20.h b/include/ob_protocol20.h index d2d9efd..9c7f2e1 100644 --- a/include/ob_protocol20.h +++ b/include/ob_protocol20.h @@ -103,6 +103,7 @@ typedef struct st_ob20protocol // extra info FLTInfo *flt; // full link trace + my_bool update_request_id; } Ob20Protocol; typedef int (*extrainfo_serialize_func)(char *buf, const int64_t len, int64_t *pos, void *data); diff --git a/include/ob_utils.h b/include/ob_utils.h new file mode 100644 index 0000000..c761224 --- /dev/null +++ b/include/ob_utils.h @@ -0,0 +1,13 @@ +#ifndef _OB_UTILS_H_ +#define _OB_UTILS_H_ +#include "mysql.h" +#include "ma_global.h" + +#ifdef _WIN32 +int gettimeofday(struct timeval *tp, void *tzp); +#endif + +int ob_gettimeofday(struct timeval *tp, void *tzp); +int64_t get_current_time_us(); + +#endif diff --git a/libmariadb/CMakeLists.txt b/libmariadb/CMakeLists.txt index 5205678..3bb1b2d 100644 --- a/libmariadb/CMakeLists.txt +++ b/libmariadb/CMakeLists.txt @@ -341,6 +341,9 @@ SET(MARIADB_NONBLOCK_SYMBOLS get_ob_lob_locator_version get_ob_lob_payload_data_len stmt_get_data_from_lobv2 + ob_mysql_real_connect + ob_get_libobclient_version + ob_set_socket5_proxy ) # handle static plugins @@ -392,6 +395,9 @@ ob_full_link_trace.c ob_rwlock.c ob_cond.c ob_thread_key.c +ob_load_balance.c +ob_utils.c +ob_tnsname.c ${CC_BINARY_DIR}/libmariadb/ma_client_plugin.c ma_io.c ${SSL_SOURCES} diff --git a/libmariadb/ma_errmsg.c b/libmariadb/ma_errmsg.c index fee192f..8889c25 100644 --- a/libmariadb/ma_errmsg.c +++ b/libmariadb/ma_errmsg.c @@ -162,6 +162,25 @@ const char *mariadb_client_errors[] = "" }; +const char *ob_client_errors[] = +{ + /*8000*/ "The previous packet of data is still unprocessed before new command", + /*8001*/ "Status is not MYSQL_STATUS_GET_RESULT in mysql_store_result/mysql_use_result", + /*8002*/ "Status is not MYSQL_STATUS_READY in mysql_next_result", + /*8003*/ "State less than MYSQL_STMT_USE_OR_STORE_CALLED in stmt_cursor_fetch", + /*8004*/ "State less than or equal to MYSQL_STMT_EXECUTED in mysql_stmt_fetch_oracle_implicit_cursor", + /*8005*/ "State less than or equal to MYSQL_STMT_EXECUTED in mysql_stmt_fetch_oracle_buffered_result", + /*8006*/ "State is error in _mysql_stmt_use_result", + /*8007*/ "State less than or equal to MYSQL_STMT_EXECUTED in mysql_stmt_fetch", + /*8008*/ "fetch field count is zero", + /*8009*/ "State less than MYSQL_STMT_EXECUTED in mysql_stmt_store_result", + /*8010*/ "States is not MYSQL_STATUS_STMT_RESULT in mysql_stmt_store_result", + /*8011*/ "stmt is not prepared before mysql_stmt_execute", + /*8012*/ "state less than MYSQL_STMT_EXECUTED in mysql_stmt_next_result", + /*8013*/ "stmt is not prepared before mysql_stmt_execute_v2", + "" +}; + const char ** NEAR my_errmsg[MAXMAPS]={0,0,0,0}; char NEAR errbuff[NRERRBUFFS][ERRMSGSIZE]; diff --git a/libmariadb/ma_loaddata.c b/libmariadb/ma_loaddata.c index c59285e..4dbdcd2 100644 --- a/libmariadb/ma_loaddata.c +++ b/libmariadb/ma_loaddata.c @@ -51,6 +51,7 @@ #include #endif #include +#include typedef struct st_mysql_infile_info { @@ -200,6 +201,11 @@ my_bool mysql_handle_local_infile(MYSQL *conn, const char *filename, my_bool can mysql_set_local_infile_default(conn); } + //ob20 don't update requestid + if (conn->net.use_ob20protocol && OB_NOT_NULL(conn->net.ob20protocol)) { + conn->net.ob20protocol->update_request_id = 0; + } + if (!(conn->options.client_flag & CLIENT_LOCAL_FILES) || !can_local_infile) { @@ -230,7 +236,7 @@ my_bool mysql_handle_local_infile(MYSQL *conn, const char *filename, my_bool can /* read data */ while ((bufread= conn->options.local_infile_read(info, (char *)buf, buflen)) > 0) { - if (ma_net_write(&conn->net, (unsigned char *)buf, bufread)) + if (ma_net_write(&conn->net, (unsigned char *)buf, bufread) || ma_net_flush(&conn->net)) { my_set_error(conn, CR_SERVER_LOST, SQLSTATE_UNKNOWN, NULL); goto infile_error; @@ -238,7 +244,7 @@ my_bool mysql_handle_local_infile(MYSQL *conn, const char *filename, my_bool can } /* send empty packet for eof */ - if (ma_net_write(&conn->net, (unsigned char *)"", 0) || + if (ma_net_write(&conn->net, (unsigned char *)"", 0) || ma_net_flush(&conn->net)) { my_set_error(conn, CR_SERVER_LOST, SQLSTATE_UNKNOWN, NULL); @@ -257,6 +263,9 @@ my_bool mysql_handle_local_infile(MYSQL *conn, const char *filename, my_bool can result = 0; infile_error: + if (conn->net.use_ob20protocol && OB_NOT_NULL(conn->net.ob20protocol)) { + conn->net.ob20protocol->update_request_id = 1; + } conn->options.local_infile_end(info); free(buf); return(result); diff --git a/libmariadb/ma_net.c b/libmariadb/ma_net.c index 4d8bb4a..fe62aeb 100644 --- a/libmariadb/ma_net.c +++ b/libmariadb/ma_net.c @@ -203,7 +203,7 @@ int ma_net_write(NET *net, const uchar *packet, size_t len) uchar buff[NET_HEADER_SIZE]; unsigned long max_packet_length = MAX_PACKET_LENGTH; // update ob20 request id - if (net->use_ob20protocol && OB_NOT_NULL(net->ob20protocol)) { + if (net->use_ob20protocol && OB_NOT_NULL(net->ob20protocol) && net->ob20protocol->update_request_id) { update_request_id(&net->ob20protocol->header.request_id); } while (len >= max_packet_length) diff --git a/libmariadb/ma_pvio.c b/libmariadb/ma_pvio.c index 12569b0..a303a7e 100644 --- a/libmariadb/ma_pvio.c +++ b/libmariadb/ma_pvio.c @@ -516,6 +516,13 @@ my_bool ma_pvio_has_data(MARIADB_PVIO *pvio, ssize_t *data_len) return 1; } /* }}} */ +int ma_pvio_socket5_auth(MARIADB_PVIO *pvio, char *user, char *pwd, char *host, unsigned short port) +{ + if (pvio && pvio->methods->socket5_auth) + return pvio->methods->socket5_auth(pvio, user, pwd, host, port); + return -1; +} + #ifdef HAVE_TLS /* {{{ my_bool ma_pvio_start_ssl */ diff --git a/libmariadb/ma_stmt_codec.c b/libmariadb/ma_stmt_codec.c index b2bac13..b3da063 100644 --- a/libmariadb/ma_stmt_codec.c +++ b/libmariadb/ma_stmt_codec.c @@ -1251,7 +1251,7 @@ void ps_fetch_oracle_interval(MYSQL_BIND *param, const MYSQL_FIELD *field, uchar { case MYSQL_TYPE_OB_INTERVAL_DS: { *param->length = sizeof(ORACLE_INTERVAL); - if (length != 14) { + if (param->buffer_length < sizeof(ORACLE_INTERVAL) || length != 14) { *param->error = 1; } else { ORACLE_INTERVAL * interval = (ORACLE_INTERVAL*)param->buffer; @@ -1269,7 +1269,7 @@ void ps_fetch_oracle_interval(MYSQL_BIND *param, const MYSQL_FIELD *field, uchar } case MYSQL_TYPE_OB_INTERVAL_YM: { *param->length = sizeof(ORACLE_INTERVAL); - if (length != 7) { + if (param->buffer_length < sizeof(ORACLE_INTERVAL) || length != 7) { *param->error = 1; } else { ORACLE_INTERVAL * interval = (ORACLE_INTERVAL*)param->buffer; diff --git a/libmariadb/mariadb_lib.c b/libmariadb/mariadb_lib.c index 1260e7b..a26b6b9 100644 --- a/libmariadb/mariadb_lib.c +++ b/libmariadb/mariadb_lib.c @@ -469,7 +469,8 @@ mthd_my_send_cmd(MYSQL *mysql,enum enum_server_command command, const char *arg, if (mysql->status != MYSQL_STATUS_READY || mysql->server_status & SERVER_MORE_RESULTS_EXIST) { - SET_CLIENT_ERROR(mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); + //SET_CLIENT_ERROR(mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); + SET_OB_CLIENT_ERROR(mysql, CR_STATUS_ERROR_NOT_READY, SQLSTATE_UNKNOWN, 0); goto end; } @@ -753,6 +754,7 @@ struct st_default_options mariadb_defaults[] = {MYSQL_SERVER_PUBLIC_KEY, MARIADB_OPTION_STR, "server-public-key"}, {MYSQL_OPT_BIND, MARIADB_OPTION_STR, "bind-address"}, {MYSQL_OPT_SSL_ENFORCE, MARIADB_OPTION_BOOL, "ssl-enforce"}, + {OB_OPT_PROXY_USER, MARIADB_OPTION_STR, "proxy-user"}, {0, 0, NULL} }; @@ -2019,6 +2021,7 @@ mysql_init(MYSQL *mysql) !(mysql->extension= (struct st_mariadb_extension *) calloc(1, sizeof(struct st_mariadb_extension)))) goto error; + mysql->options.report_data_truncation= 1; mysql->options.connect_timeout=CONNECT_TIMEOUT; mysql->charset= mysql_find_charset_name(MARIADB_DEFAULT_CHARSET); @@ -2142,17 +2145,25 @@ ma_set_ob_connect_attrs(MYSQL *mysql) cap &= ~OBCLIENT_CAP_PROXY_NEW_EXTRA_INFO; cap &= ~OBCLIENT_CAP_PROXY_FULL_LINK_TRACE_SHOW_TRACE; } + if (mysql->can_use_load_infiles) { + cap |= OBCLIENT_CAP_PROXY_LOCAL_INFILES; + } snprintf(cap_buf, OB_MAX_UINT64_BUF_LEN, "%lu", cap); rc += mysql_optionsv(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, OB_MYSQL_CAPABILITY_FLAG, cap_buf); rc += mysql_optionsv(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, OB_MYSQL_CLIENT_MODE, "__ob_libobclient"); + rc += mysql_optionsv(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, OB_MYSQL_CLIENT_NAME_KEY, OB_MYSQL_CLIENT_NAME_VALUE); + rc += mysql_optionsv(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, OB_MYSQL_CLIENT_VERSION_KEY, LIBOBCLIENT_VERSION); if (mysql->can_use_ob_client_lob_locatorv2) { caplob |= OBCLIENT_CAP_OB_LOB_LOCATOR_V2; snprintf(caplob_buf, OB_MAX_UINT64_BUF_LEN, "%lu", caplob); rc += mysql_optionsv(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, OB_MYSQL_LOB_LOCATOR_V2, caplob_buf); } + if (mysql->proxy_user && mysql->proxy_user[0]) { + rc += mysql_optionsv(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, OB_MYSQL_PROXY_USER_NAME, mysql->proxy_user); + } return rc; } @@ -2365,6 +2376,38 @@ static int get_ob_server_version(MYSQL *con) } return 0; } +static my_bool set_nls_format(MYSQL *mysql) +{ + my_bool bret = TRUE; + if (mysql->oracle_mode) { + char *nls_date_format = getenv("NLS_DATE_FORMAT"); + char *nls_timestamp_format = getenv("NLS_TIMESTAMP_FORMAT"); + char *nls_timestamp_tz_format = getenv("NLS_TIMESTAMP_TZ_FORMAT"); + + if (NULL != nls_date_format) { + char change_date_format_sql[100]; + snprintf(change_date_format_sql, 100, "ALTER SESSION SET NLS_DATE_FORMAT='%s';", nls_date_format); + if (mysql_query(mysql, change_date_format_sql)) { + bret = FALSE; + } + } + if (bret && NULL != nls_timestamp_format) { + char change_timestamp_format_sql[100]; + snprintf(change_timestamp_format_sql, 100, "ALTER SESSION SET NLS_TIMESTAMP_FORMAT='%s';", nls_timestamp_format); + if (mysql_query(mysql, change_timestamp_format_sql)) { + bret = FALSE; + } + } + if (bret && NULL != nls_timestamp_tz_format) { + char change_timestamp_tz_format_sql[100]; + snprintf(change_timestamp_tz_format_sql, 100, "ALTER SESSION SET NLS_TIMESTAMP_TZ_FORMAT='%s';", nls_timestamp_tz_format); + if (mysql_query(mysql, change_timestamp_tz_format_sql)) { + bret = FALSE; + } + } + } + return bret; +} MYSQL *mthd_my_real_connect(MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, @@ -2483,6 +2526,10 @@ MYSQL *mthd_my_real_connect(MYSQL *mysql, const char *host, const char *user, cinfo.host= host; cinfo.port= port; cinfo.type= PVIO_TYPE_SOCKET; + if (mysql->is_socket5) { + cinfo.host = mysql->socket5_host; + cinfo.port = mysql->socket5_port; + } sprintf(host_info=buff,ER(CR_TCP_CONNECTION), cinfo.host); } /* Initialize and load pvio plugin */ @@ -2496,6 +2543,16 @@ MYSQL *mthd_my_real_connect(MYSQL *mysql, const char *host, const char *user, goto error; } + //socket5 + if (mysql->is_socket5) + { + int ret = 0; + if (0 != (ret = ma_pvio_socket5_auth(pvio, mysql->socket5_user, mysql->socket5_pwd, (char*)host, port))) { + my_set_error(mysql, CR_SOCKET_CREATE_ERROR, SQLSTATE_UNKNOWN, "socket5 proxy communication fail(%d).", ret); + goto error; + } + } + if (mysql->options.extension && mysql->options.extension->proxy_header) { char *hdr = mysql->options.extension->proxy_header; @@ -2567,9 +2624,13 @@ MYSQL *mthd_my_real_connect(MYSQL *mysql, const char *host, const char *user, /* Save connection information */ if (!user) user=""; + if (mysql->options.proxy_user && mysql->options.proxy_user[0]) { + mysql->proxy_user = strdup(mysql->options.proxy_user); + } + if (!(mysql->host_info= strdup(host_info)) || !(mysql->host= strdup(cinfo.host ? cinfo.host : "")) || - !(mysql->user=strdup(user)) || + !(mysql->user=strdup(user ? user:"")) || !(mysql->passwd=strdup(passwd))) { SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0); @@ -2688,6 +2749,7 @@ MYSQL *mthd_my_real_connect(MYSQL *mysql, const char *host, const char *user, determine_full_link_trace(mysql); determine_ob_client_lob_locatorv2(mysql); determine_flt_show_trace(mysql); + determine_load_infiles(mysql); if (run_plugin_auth(mysql, scramble_data, scramble_len, scramble_plugin, db)) @@ -3040,6 +3102,9 @@ static void mysql_close_options(MYSQL *mysql) free(mysql->options.ssl_capath); free(mysql->options.ssl_cipher); + if (mysql->options.proxy_user) { + free(mysql->options.proxy_user); + } if (mysql->options.extension) { struct mysql_async_context *ctxt; @@ -3081,13 +3146,9 @@ static void mysql_close_memory(MYSQL *mysql) free(mysql->db); free(mysql->unix_socket); free(mysql->server_version); - if (mysql->extension) { - free(mysql->extension); - mysql->extension = NULL; - } - if (mysql->ob_extension) { - mysql_extension_free((struct st_mysql_extension *)mysql->ob_extension); - mysql->ob_extension = NULL; + if (mysql->proxy_user) { + free(mysql->proxy_user); + mysql->proxy_user = 0; } mysql->host_info= mysql->host= mysql->unix_socket= mysql->server_version=mysql->user=mysql->passwd=mysql->db=0; @@ -3106,9 +3167,11 @@ void my_set_error(MYSQL *mysql, if (!format) { if (error_nr >= CR_MIN_ERROR && error_nr <= CR_MYSQL_LAST_ERROR) - errmsg= ER(error_nr); + errmsg = ER(error_nr); else if (error_nr >= CER_MIN_ERROR && error_nr <= CR_MARIADB_LAST_ERROR) - errmsg= CER(error_nr); + errmsg = CER(error_nr); + else if (error_nr >= OB_MIN_ERROR && error_nr <= CR_OB_LAST_ERROR) + errmsg = OBER(error_nr); else errmsg= ER(CR_UNKNOWN_ERROR); } @@ -3176,20 +3239,45 @@ mysql_close(MYSQL *mysql) mysql_close_options(mysql); ma_clear_session_state(mysql); - if (mysql->net.extension) + if (mysql->net.extension) { free(mysql->net.extension); + mysql->net.extension = NULL; + } mysql->host_info=mysql->user=mysql->passwd=mysql->db=0; + mysql->proxy_user = 0; /* Clear pointers for better safety */ memset((char*) &mysql->options, 0, sizeof(mysql->options)); - if (mysql->extension) + if (mysql->extension) { free(mysql->extension); + mysql->extension = NULL; + } + + if (mysql->ob_extension) { + mysql_extension_free((struct st_mysql_extension *)mysql->ob_extension); + mysql->ob_extension = NULL; + } + + mysql->is_socket5 = 0; + if (mysql->socket5_host) { + free(mysql->socket5_host); + mysql->socket5_host = NULL; + } + if (mysql->socket5_user) { + free(mysql->socket5_user); + mysql->socket5_user = NULL; + } + if (mysql->socket5_pwd) { + free(mysql->socket5_pwd); + mysql->socket5_pwd = NULL; + } /* Clear pointers for better safety */ mysql->net.extension = NULL; mysql->extension = NULL; + mysql->ob_extension = NULL; mysql->net.pvio= 0; if (mysql->free_me) @@ -3542,7 +3630,8 @@ mysql_store_result(MYSQL *mysql) return(0); if (mysql->status != MYSQL_STATUS_GET_RESULT) { - SET_CLIENT_ERROR(mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); + //SET_CLIENT_ERROR(mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); + SET_CLIENT_ERROR(mysql, CR_STATUS_ERROR_NOT_GET_RESULT, SQLSTATE_UNKNOWN, 0); return(0); } mysql->status=MYSQL_STATUS_READY; /* server is ready */ @@ -3591,7 +3680,8 @@ mysql_use_result(MYSQL *mysql) return(0); if (mysql->status != MYSQL_STATUS_GET_RESULT) { - SET_CLIENT_ERROR(mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); + //SET_CLIENT_ERROR(mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); + SET_CLIENT_ERROR(mysql, CR_STATUS_ERROR_NOT_GET_RESULT, SQLSTATE_UNKNOWN, 0); return(0); } if (!(result=(MYSQL_RES*) calloc(1, sizeof(*result)+ @@ -4227,6 +4317,8 @@ mysql_optionsv(MYSQL *mysql,enum mysql_option option, ...) case MARIADB_OPT_USER: OPT_SET_VALUE_STR(&mysql->options, user, arg1); break; + case OB_OPT_PROXY_USER: + OPT_SET_VALUE_STR(&mysql->options, proxy_user, arg1); case MARIADB_OPT_HOST: OPT_SET_VALUE_STR(&mysql->options, host, arg1); break; @@ -4753,7 +4845,8 @@ int STDCALL mysql_next_result(MYSQL *mysql) /* make sure communication is not blocking */ if (mysql->status != MYSQL_STATUS_READY) { - SET_CLIENT_ERROR(mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); + //SET_CLIENT_ERROR(mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); + SET_CLIENT_ERROR(mysql, CR_STATES_ERROR_NEXT_RESULT, SQLSTATE_UNKNOWN, 0); return(1); } @@ -5558,3 +5651,40 @@ struct st_mariadb_methods MARIADB_DEFAULT_METHODS = { /* API functions */ &MARIADB_API }; + +void ob_get_libobclient_version(int *major, int *minor, int *patch, char* version, int len) +{ + if (major) + *major = LIBOBCLIENT_VERSION_MAJOR; + if (minor) + *minor = LIBOBCLIENT_VERSION_MINOR; + if (patch) + *patch = LIBOBCLIENT_VERSION_PATCH; + if (version) + memcpy(version, LIBOBCLIENT_VERSION, min(len, strlen(LIBOBCLIENT_VERSION))); +} + +void ob_set_socket5_proxy(MYSQL *mysql, char socket5_authtype, char *socket5_host, int socket5_port, char *socket5_user, char *socket5_pwd) +{ + mysql->is_socket5 = 1; + mysql->socket5_authtype = socket5_authtype; + mysql->socket5_port = socket5_port; + if (mysql->socket5_host) { + free(mysql->socket5_host); + mysql->socket5_host = NULL; + } + if (mysql->socket5_user) { + free(mysql->socket5_user); + mysql->socket5_user = NULL; + } + if (mysql->socket5_pwd) { + free(mysql->socket5_pwd); + mysql->socket5_pwd = NULL; + } + if (socket5_host) + mysql->socket5_host = strdup(socket5_host); + if (socket5_user) + mysql->socket5_user = strdup(socket5_user); + if (socket5_pwd) + mysql->socket5_pwd = strdup(socket5_pwd); +} \ No newline at end of file diff --git a/libmariadb/mariadb_stmt.c b/libmariadb/mariadb_stmt.c index f3f57b3..81fc724 100644 --- a/libmariadb/mariadb_stmt.c +++ b/libmariadb/mariadb_stmt.c @@ -116,6 +116,8 @@ void stmt_set_error(MYSQL_STMT *stmt, error= ER(error_nr); else if (error_nr >= CER_MIN_ERROR && error_nr <= CR_MARIADB_LAST_ERROR) error= CER(error_nr); + else if (error_nr >=OB_MIN_ERROR && error_nr <=CR_OB_LAST_ERROR) + error = OBER(error_nr); stmt->last_errno= error_nr; ma_strmake(stmt->sqlstate, sqlstate, SQLSTATE_LENGTH); @@ -211,7 +213,13 @@ static int stmt_unbuffered_fetch(MYSQL_STMT *stmt, uchar **row) if (stmt->mysql->net.read_pos[0] == 254) { + //EOF, update server_status + char *p = stmt->mysql->net.read_pos; *row = NULL; + p++; + stmt->upsert_status.warning_count = stmt->mysql->warning_count = uint2korr(p); + p += 2; + stmt->upsert_status.server_status = stmt->mysql->server_status = uint2korr(p); stmt->fetch_row_func= stmt_unbuffered_eof; return(MYSQL_NO_DATA); } @@ -347,7 +355,8 @@ static int stmt_cursor_fetch(MYSQL_STMT *stmt, uchar **row) int back_status = 0; if (stmt->state < MYSQL_STMT_USE_OR_STORE_CALLED) { - SET_CLIENT_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); + //SET_CLIENT_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); + SET_OB_CLIENT_STMT_ERROR(stmt, CR_STATUS_ERROR_CURSOR_FETCH, SQLSTATE_UNKNOWN, 0); return(1); } if (stmt->mysql == NULL) @@ -744,7 +753,8 @@ int STDCALL mysql_stmt_fetch_oracle_implicit_cursor(MYSQL_STMT *stmt, my_bool is int rc = 0; if (stmt->state <= MYSQL_STMT_EXECUTED) { - SET_CLIENT_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); + //SET_CLIENT_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); + SET_OB_CLIENT_STMT_ERROR(stmt, CR_STATUS_ERROR_FETCH_ORACLE_IMPLICIT_CURSOR, SQLSTATE_UNKNOWN, 0); return(1); } if ((rc = do_stmt_read_row_from_oracle_implicit_cursor(stmt, &row, is_need_fetch_from_server))) @@ -767,7 +777,8 @@ int STDCALL mysql_stmt_fetch_oracle_buffered_result(MYSQL_STMT *stmt) int rc = 0; if (stmt->state <= MYSQL_STMT_EXECUTED) { - SET_CLIENT_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); + //SET_CLIENT_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); + SET_OB_CLIENT_STMT_ERROR(stmt, CR_STATUS_ERROR_FETCH_ORACLE_BUFFERED_RESULT, SQLSTATE_UNKNOWN, 0); return(1); } /* just read the buffered result for some situation, not to fetch the result from ObServer any more */ @@ -804,9 +815,9 @@ void mthd_stmt_flush_unbuffered(MYSQL_STMT *stmt) } if (packet_len < 8 && *pos == 254) /* EOF */ { + stmt->mysql->server_status = uint2korr(pos + 3); if (mariadb_connection(stmt->mysql)) { - stmt->mysql->server_status= uint2korr(pos + 3); if (in_resultset) goto end; in_resultset= 1; @@ -899,7 +910,8 @@ MYSQL_RES *_mysql_stmt_use_result(MYSQL_STMT *stmt) (stmt->cursor_exists && mysql->status != MYSQL_STATUS_READY) || (stmt->state != MYSQL_STMT_WAITING_USE_OR_STORE)) { - SET_CLIENT_ERROR(mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); + //SET_CLIENT_ERROR(mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); + SET_OB_CLIENT_ERROR(mysql, CR_STATUS_ERROR_STMT_USE_RESULT, SQLSTATE_UNKNOWN, 0); return(NULL); } @@ -2935,13 +2947,15 @@ int STDCALL mysql_stmt_fetch(MYSQL_STMT *stmt) if (stmt->state <= MYSQL_STMT_EXECUTED) { - SET_CLIENT_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); + //SET_CLIENT_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); + SET_OB_CLIENT_STMT_ERROR(stmt, CR_STATUS_ERROR_STMT_FETCH, SQLSTATE_UNKNOWN, 0); return(1); } if (stmt->state < MYSQL_STMT_WAITING_USE_OR_STORE || !stmt->field_count) { - SET_CLIENT_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); + //SET_CLIENT_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); + SET_OB_CLIENT_STMT_ERROR(stmt, CR_FETCH_FIELD_COUNT_IS_ZERO, SQLSTATE_UNKNOWN, 0); return(1); } else if (stmt->state== MYSQL_STMT_WAITING_USE_OR_STORE) { @@ -3276,8 +3290,10 @@ int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt) if (stmt->state < MYSQL_STMT_EXECUTED) { - SET_CLIENT_ERROR(stmt->mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); - SET_CLIENT_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); + //SET_CLIENT_ERROR(stmt->mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); + //SET_CLIENT_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); + SET_OB_CLIENT_ERROR(stmt->mysql, CR_STATUS_ERROR_STORE_RESULT, SQLSTATE_UNKNOWN, 0); + SET_OB_CLIENT_STMT_ERROR(stmt, CR_STATUS_ERROR_STORE_RESULT, SQLSTATE_UNKNOWN, 0); return(1); } @@ -3299,8 +3315,10 @@ int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt) } else if (stmt->mysql->status != MYSQL_STATUS_STMT_RESULT) { - SET_CLIENT_ERROR(stmt->mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); - SET_CLIENT_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); + //SET_CLIENT_ERROR(stmt->mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); + //SET_CLIENT_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); + SET_OB_CLIENT_ERROR(stmt->mysql, CR_STATUS_ERROR_NOT_STMT_RESULT, SQLSTATE_UNKNOWN, 0); + SET_OB_CLIENT_STMT_ERROR(stmt, CR_STATUS_ERROR_NOT_STMT_RESULT, SQLSTATE_UNKNOWN, 0); return(1); } @@ -3632,8 +3650,8 @@ my_bool cli_read_piece_result(MYSQL_STMT *stmt) int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt) { MYSQL *mysql= stmt->mysql; - char *request; - int ret; + char *request = NULL; + int ret = 0; size_t request_len= 0; FLT_DECLARE; @@ -3645,8 +3663,10 @@ int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt) if (stmt->state < MYSQL_STMT_PREPARED) { - SET_CLIENT_ERROR(mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); - SET_CLIENT_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); + //SET_CLIENT_ERROR(mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); + //SET_CLIENT_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); + SET_OB_CLIENT_ERROR(mysql, CR_STATES_ERROR_NOT_PREPARED, SQLSTATE_UNKNOWN, 0); + SET_OB_CLIENT_STMT_ERROR(stmt, CR_STATES_ERROR_NOT_PREPARED, SQLSTATE_UNKNOWN, 0); return(1); } @@ -4064,6 +4084,7 @@ static ulong calculate_param_object_type_len(MYSQL *mysql, MYSQL_COMPLEX_BIND_OB static ulong calculate_param_array_type_len(MYSQL *mysql, MYSQL_COMPLEX_BIND_ARRAY *param) { ulong len; + MYSQL_COMPLEX_BIND_OBJECT *param_tmp = (MYSQL_COMPLEX_BIND_OBJECT *)param; MYSQL_COMPLEX_BIND_HEADER *header = (MYSQL_COMPLEX_BIND_HEADER *)param->buffer; //shcema_name @@ -4073,15 +4094,19 @@ static ulong calculate_param_array_type_len(MYSQL *mysql, MYSQL_COMPLEX_BIND_ARR //elem_type len += 1; - if (MYSQL_TYPE_OBJECT == header->buffer_type) { - MYSQL_COMPLEX_BIND_OBJECT sub_header; - sub_header.owner_name = ((MYSQL_COMPLEX_BIND_OBJECT*)header)->owner_name; - sub_header.type_name = ((MYSQL_COMPLEX_BIND_OBJECT*)header)->type_name; - len += calculate_param_object_type_len(mysql, &sub_header); - } else if (MYSQL_TYPE_ARRAY == header->buffer_type) { - MYSQL_COMPLEX_BIND_ARRAY sub_header; - sub_header.buffer = header->buffer; - len += calculate_param_array_type_len(mysql, &sub_header); + + //elem length may be zero + if (param_tmp->length > 0) { + if (MYSQL_TYPE_OBJECT == header->buffer_type) { + MYSQL_COMPLEX_BIND_OBJECT sub_header; + sub_header.owner_name = ((MYSQL_COMPLEX_BIND_OBJECT*)header)->owner_name; + sub_header.type_name = ((MYSQL_COMPLEX_BIND_OBJECT*)header)->type_name; + len += calculate_param_object_type_len(mysql, &sub_header); + } else if (MYSQL_TYPE_ARRAY == header->buffer_type) { + MYSQL_COMPLEX_BIND_ARRAY sub_header; + sub_header.buffer = header->buffer; + len += calculate_param_array_type_len(mysql, &sub_header); + } } return len; @@ -4125,8 +4150,10 @@ int STDCALL mysql_stmt_next_result(MYSQL_STMT *stmt) if (stmt->state < MYSQL_STMT_EXECUTED) { - SET_CLIENT_ERROR(stmt->mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); - SET_CLIENT_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); + //SET_CLIENT_ERROR(stmt->mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); + //SET_CLIENT_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); + SET_OB_CLIENT_ERROR(stmt->mysql, CR_STATUS_ERROR_STMT_NEXT_RESULT, SQLSTATE_UNKNOWN, 0); + SET_OB_CLIENT_STMT_ERROR(stmt, CR_STATUS_ERROR_STMT_NEXT_RESULT, SQLSTATE_UNKNOWN, 0); return(1); } @@ -4841,6 +4868,37 @@ my_bool get_use_ob_client_lob_locatorv2(MYSQL *mysql) return FALSE; } + +my_bool determine_load_infiles(MYSQL *mysql) +{ + my_bool bret = TRUE; + int ival = LOAD_INFILES_AUTO_OPEN; //default is AUTO + int tmp_val = 0; + char* env = getenv("ENABLE_LOAD_INFILES"); + if (env) { + tmp_val = atoi(env); + if (tmp_val >= 0 && tmp_val < LOAD_INFILES_FLAY_MAX) { + ival = tmp_val; + } + } + if (ival == LOAD_INFILES_FORCE_OPEN) { + bret = TRUE; + } else if (ival == LOAD_INFILES_FORCE_CLOSE) { + bret = FALSE; + } + if (mysql) { + mysql->can_use_load_infiles = bret; + } + DBUG_RETURN(bret); +} +my_bool get_use_load_infiles(MYSQL *mysql) +{ + if (mysql) { + return mysql->can_use_load_infiles; + } + return FALSE; +} + uint8_t get_ob_lob_locator_version(void *lob) { uint8_t ver = 0; @@ -4875,7 +4933,7 @@ int64_t get_ob_lob_payload_data_len(void *lob) int tmp_len = tmp->extern_header.payload_offset_+ tmp->extern_header.payload_size_; char *tmp_buf = tmp->data_; uint16_t ex_size = uint2korr(tmp_buf); - int offset = MAX_OB_LOB_LOCATOR_HEADER_LENGTH + sizeof(uint16) + ex_size + tmp->extern_header.rowkey_size_ + sizeof(ObClientLobCommon) + sizeof(ObClientLobData); + int offset = sizeof(uint16) + ex_size + tmp->extern_header.rowkey_size_ + sizeof(ObClientLobCommon) + sizeof(ObClientLobData); if (tmp_len > offset) { len = uint8korr(tmp_buf + offset - 8); } @@ -4908,10 +4966,10 @@ int prepare_execute_v2(MYSQL *mysql, MYSQL_STMT* stmt, const char* query, MYSQL_ } return ret; } -int stmt_get_data_from_lobv2( MYSQL *mysql, void * lob, enum_field_types type, - int64_t char_offset, int64_t byte_offset, int64_t char_len, int64_t byte_len, char *buf, const int64_t buf_len, int64_t *data_len, int64_t *act_len) +int get_lob_data(MYSQL *mysql, void* lob, enum_field_types type, + int64_t offset, int64_t* char_len, int64_t* byte_len, char *buf, const int64_t buf_len) { - int ret = -1; + int ret = 0; const char *read_sql = "call DBMS_LOB.read(?, ?, ?, ?)"; MYSQL_BIND param_bind[4]; MYSQL_BIND param_res[2]; @@ -4919,30 +4977,98 @@ int stmt_get_data_from_lobv2( MYSQL *mysql, void * lob, enum_field_types type, int64_t length = 0; OB_LOB_LOCATOR_V2 *loblocator = (OB_LOB_LOCATOR_V2*)lob; + memset(param_bind, 0, sizeof(param_bind)); + param_bind[0].buffer = lob; + param_bind[0].buffer_length = loblocator->extern_header.payload_size_ + loblocator->extern_header.payload_offset_ + MAX_OB_LOB_LOCATOR_HEADER_LENGTH; + param_bind[0].buffer_type = type; + param_bind[1].buffer = (char *)byte_len; + param_bind[1].buffer_type = MYSQL_TYPE_LONGLONG; + param_bind[2].buffer = (char *)&offset; + param_bind[2].buffer_type = MYSQL_TYPE_LONGLONG; + param_bind[3].is_null = ¶m_bind[3].is_null_value; + *param_bind[3].is_null = 1; + if (MYSQL_TYPE_ORA_CLOB == type) { + param_bind[3].buffer_type = MYSQL_TYPE_VAR_STRING; + } else { + param_bind[3].buffer_type = MYSQL_TYPE_OB_RAW; + } + + //result + memset(param_res, 0, sizeof(param_res)); + param_res[0].error = ¶m_res[0].error_value; + param_res[0].is_null = ¶m_res[0].is_null_value; + param_res[0].buffer = &length; + param_res[0].buffer_type = MYSQL_TYPE_LONGLONG; + param_res[1].error = ¶m_res[1].error_value; + param_res[1].is_null = ¶m_res[1].is_null_value; + param_res[1].length = ¶m_res[1].length_value; + param_res[1].buffer = buf; + param_res[1].buffer_length = buf_len; + if (MYSQL_TYPE_ORA_CLOB == type) { + param_res[1].buffer_type = MYSQL_TYPE_VAR_STRING; + } else { + param_res[1].buffer_type = MYSQL_TYPE_OB_RAW; + } + + if (NULL == (stmt = mysql_stmt_init(mysql))) { + ret = -1; + } else if (prepare_execute_v2(mysql, stmt, read_sql, param_bind)) { + ret = -1; + } else if (mysql_stmt_bind_result(stmt, param_res)) { + ret = -1; + } else { + int64_t data_len = 0; + ret = mysql_stmt_fetch(stmt); + if (0 == ret) { + *byte_len = param_res[1].length_value; + *char_len = length; + } else if (MYSQL_DATA_TRUNCATED == ret) { + *byte_len = param_res[1].length_value; + *char_len = length; + ret = 0; + } else { + ret = -1; + } + if (NULL != stmt) { + mysql_stmt_close(stmt); + } + } + return ret; +} +int stmt_get_data_from_lobv2( MYSQL *mysql, void * lob, enum_field_types type, + int64_t char_offset, int64_t byte_offset, int64_t char_len, int64_t byte_len, char *buf, const int64_t buf_len, int64_t *data_len, int64_t *act_len) +{ +#define DBMS_LOB_MAX_LENGTH 32766 + int ret = -1; + int64_t length = 0; + OB_LOB_LOCATOR_V2 *loblocator = (OB_LOB_LOCATOR_V2*)lob; + char_offset = char_offset; char_len = char_len; if (!mysql) { - SET_CLIENT_STMT_ERROR(stmt, CR_SERVER_LOST, unknown_sqlstate, NULL); + SET_CLIENT_ERROR(mysql, CR_SERVER_LOST, unknown_sqlstate, NULL); DBUG_RETURN(1); } if (NULL == lob) { - SET_CLIENT_STMT_ERROR(stmt, CR_UNKNOWN_ERROR, unknown_sqlstate, NULL); + SET_CLIENT_ERROR(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate, NULL); DBUG_RETURN(1); } if (OBCLIENT_LOB_LOCATORV2 != get_ob_lob_locator_version(lob)) { - SET_CLIENT_STMT_ERROR(stmt, CR_UNKNOWN_ERROR, unknown_sqlstate, NULL); + SET_CLIENT_ERROR(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate, NULL); DBUG_RETURN(1); } if (type != MYSQL_TYPE_ORA_CLOB && type != MYSQL_TYPE_ORA_BLOB) { - SET_CLIENT_STMT_ERROR(stmt, CR_UNKNOWN_ERROR, unknown_sqlstate, NULL); + SET_CLIENT_ERROR(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate, NULL); DBUG_RETURN(1); } if (1 != loblocator->common.has_extern) { - SET_CLIENT_STMT_ERROR(stmt, CR_UNKNOWN_ERROR, unknown_sqlstate, NULL); + SET_CLIENT_ERROR(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate, NULL); DBUG_RETURN(1); } + *act_len = get_ob_lob_payload_data_len(loblocator); + if (1 == loblocator->common.is_inrow_) { length = byte_len > buf_len ? buf_len : byte_len; length = length > loblocator->extern_header.payload_size_ ? loblocator->extern_header.payload_size_ : length; @@ -4953,106 +5079,46 @@ int stmt_get_data_from_lobv2( MYSQL *mysql, void * lob, enum_field_types type, *act_len = loblocator->extern_header.payload_size_; ret = 0; } else { - int64_t tmp_len = byte_len + 1; - char *tmp_buf = calloc(1, byte_len); - if (NULL != tmp_buf) { - //params - memset(param_bind, 0, sizeof(param_bind)); - param_bind[0].buffer = lob; - param_bind[0].buffer_length = loblocator->extern_header.payload_size_ + loblocator->extern_header.payload_offset_ + MAX_OB_LOB_LOCATOR_HEADER_LENGTH; - param_bind[0].buffer_type = type; - param_bind[1].buffer = (char *)&tmp_len; - param_bind[1].buffer_type = MYSQL_TYPE_LONGLONG; - param_bind[2].buffer = (char *)&byte_offset; - param_bind[2].buffer_type = MYSQL_TYPE_LONGLONG; - param_bind[3].is_null = ¶m_bind[3].is_null_value; - *param_bind[3].is_null = 1; - if (MYSQL_TYPE_ORA_CLOB == type) { - param_bind[3].buffer_type = MYSQL_TYPE_VAR_STRING; + char *pdata = buf; + int64_t amtp = 0; + int64_t read_len = 0; + int64_t char_len; + int64_t buf_use = 0; + + do { + if (byte_len - amtp > DBMS_LOB_MAX_LENGTH) { + read_len = DBMS_LOB_MAX_LENGTH; + } else if (byte_len - amtp > 0) { + read_len = (byte_len - amtp); } else { - param_bind[3].buffer_type = MYSQL_TYPE_OB_RAW; + ret = 0; + break; } - //result - memset(param_res, 0, sizeof(param_res)); - param_res[0].error = ¶m_res[0].error_value; - param_res[0].is_null = ¶m_res[0].is_null_value; - param_res[0].buffer = &length; - param_res[0].buffer_type = MYSQL_TYPE_LONGLONG; - param_res[1].error = ¶m_res[1].error_value; - param_res[1].is_null = ¶m_res[1].is_null_value; - param_res[1].length = ¶m_res[1].length_value; - param_res[1].buffer = tmp_buf; - param_res[1].buffer_length = tmp_len; - if (MYSQL_TYPE_ORA_CLOB == type) { - param_res[1].buffer_type = MYSQL_TYPE_VAR_STRING; + if (0 != get_lob_data(mysql, lob, type, byte_offset, &char_len, &read_len, pdata, buf_len - buf_use)) { + ret = -1; + break; + } + if (type == MYSQL_TYPE_ORA_CLOB) { + byte_offset += char_len; } else { - param_res[1].buffer_type = MYSQL_TYPE_OB_RAW; + byte_offset += read_len; } - if (NULL == (stmt = mysql_stmt_init(mysql))) { - ret = -1; - } else if (prepare_execute_v2(mysql, stmt, read_sql, param_bind)) { - ret = -1; - } else if (mysql_stmt_bind_result(stmt, param_res)) { - ret = -1; - } else { - ret = mysql_stmt_fetch(stmt); - if (0 == ret) { - *data_len = param_res[1].length_value; - *act_len = *data_len; - if (*data_len > byte_len) { - *data_len = byte_len > buf_len ? buf_len : byte_len; - } else { - *data_len = *data_len > buf_len ? buf_len : *data_len; - } - memcpy(buf, tmp_buf, *data_len); - } - } + amtp += char_len; + pdata += read_len; + buf_use += read_len; + *data_len += read_len; - if (NULL != stmt) { - mysql_stmt_close(stmt); + if (buf_len - buf_use <= 0 || buf_use >= *act_len) { + ret = 0; + break; } - - free(tmp_buf); - tmp_buf = NULL; - } + } while (read_len >= DBMS_LOB_MAX_LENGTH); } return ret; } -my_bool set_nls_format(MYSQL *mysql) -{ - my_bool bret = TRUE; - if (mysql->oracle_mode) { - char *nls_date_format = getenv("NLS_DATE_FORMAT"); - char *nls_timestamp_format = getenv("NLS_TIMESTAMP_FORMAT"); - char *nls_timestamp_tz_format = getenv("NLS_TIMESTAMP_TZ_FORMAT"); - - if (NULL != nls_date_format) { - char change_date_format_sql[100]; - snprintf(change_date_format_sql, 100, "ALTER SESSION SET NLS_DATE_FORMAT='%s';", nls_date_format); - if (mysql_query(mysql, change_date_format_sql)) { - bret = FALSE; - } - } - if (bret && NULL != nls_timestamp_format) { - char change_timestamp_format_sql[100]; - snprintf(change_timestamp_format_sql, 100, "ALTER SESSION SET NLS_TIMESTAMP_FORMAT='%s';", nls_timestamp_format); - if (mysql_query(mysql, change_timestamp_format_sql)) { - bret = FALSE; - } - } - if (bret && NULL != nls_timestamp_tz_format) { - char change_timestamp_tz_format_sql[100]; - snprintf(change_timestamp_tz_format_sql, 100, "ALTER SESSION SET NLS_TIMESTAMP_TZ_FORMAT='%s';", nls_timestamp_tz_format); - if (mysql_query(mysql, change_timestamp_tz_format_sql)) { - bret = FALSE; - } - } - } - return bret; -} /* * judge where can use prepare_execute protocol * use version to judge @@ -5775,7 +5841,7 @@ static int stmt_read_prepare_execute_response(MYSQL_STMT* stmt) } if (param_count != 0) { - if (stmt->is_handle_returning_into && stmt->field_count + stmt->param_count == param_count) + if (stmt->is_handle_returning_into /*&& stmt->field_count + stmt->param_count == param_count*/) { /* It needs to exec prepare operation for the sql with piece data send and returning ... into, Like: * UPDATE TABLE ta SET c1 = :v1, c2 =:v2, c3 = :v3 RETURNING c0 INTO :c0 @@ -5875,8 +5941,10 @@ int STDCALL mysql_stmt_execute_v2(MYSQL_STMT *stmt, if (stmt->state < MYSQL_STMT_PREPARED) { - SET_CLIENT_ERROR(mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); - SET_CLIENT_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); + //SET_CLIENT_ERROR(mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); + //SET_CLIENT_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); + SET_OB_CLIENT_ERROR(mysql, CR_STATES_ERROR_NOT_PREPARED_EXECUTE_V2, SQLSTATE_UNKNOWN, 0); + SET_OB_CLIENT_STMT_ERROR(stmt, CR_STATES_ERROR_NOT_PREPARED_EXECUTE_V2, SQLSTATE_UNKNOWN, 0); return(1); } diff --git a/libmariadb/ob_cond.c b/libmariadb/ob_cond.c index 6956a7f..b412c75 100644 --- a/libmariadb/ob_cond.c +++ b/libmariadb/ob_cond.c @@ -25,7 +25,7 @@ #ifdef _WIN32 #include - +#include union ft64 { FILETIME ft; __int64 i64; diff --git a/libmariadb/ob_full_link_trace.c b/libmariadb/ob_full_link_trace.c index 5cbb16a..47a3d78 100644 --- a/libmariadb/ob_full_link_trace.c +++ b/libmariadb/ob_full_link_trace.c @@ -15,6 +15,7 @@ #include "mariadb_com.h" #include "ob_protocol20.h" #include "ob_serialize.h" +#include "ob_utils.h" #define TYPE_LENGTH 2 #define LEN_LENGTH 4 @@ -103,14 +104,6 @@ inline void flt_set_send_trans_flag(FLTInfo *flt, my_bool flag) } } -static inline int64_t get_current_time_us() -{ - struct timeval tv; - // todo: Here to be compatible with windows - gettimeofday(&tv, NULL); - return tv.tv_sec * 1000000 + tv.tv_usec; -} - static inline double flt_get_pct(uint64_t *seed) { uint64_t rand64; @@ -1359,9 +1352,9 @@ int uuid4_init(uint64_t *seed, size_t seed_size) { } -UUID uuid4_generate(uint64_t *seed) { +OBCLIENT_UUID uuid4_generate(uint64_t *seed) { uint64_t word; - UUID ret; + OBCLIENT_UUID ret; /* get random */ word = xorshift128plus(seed); // word[1] = xorshift128plus(seed); @@ -1826,7 +1819,7 @@ void reset_tag(ObTrace *trace, ObSpanCtx *span, ObTagCtx *tag) } } -int serialize_UUID(char *buf, const int64_t buf_len, int64_t *pos, UUID *uuid) +int serialize_UUID(char *buf, const int64_t buf_len, int64_t *pos, OBCLIENT_UUID *uuid) { int ret = OB_SUCCESS; if (OB_FAIL(encode_i64(buf, buf_len, pos, uuid->high_))) { @@ -1837,7 +1830,7 @@ int serialize_UUID(char *buf, const int64_t buf_len, int64_t *pos, UUID *uuid) return ret; } -int deserialize_UUID(const char *buf, const int64_t buf_len, int64_t *pos, UUID *uuid) +int deserialize_UUID(const char *buf, const int64_t buf_len, int64_t *pos, OBCLIENT_UUID *uuid) { int ret = OB_SUCCESS; if (OB_FAIL(decode_i64(buf, buf_len, pos, (int64_t *)(&uuid->high_)))) { @@ -1848,7 +1841,7 @@ int deserialize_UUID(const char *buf, const int64_t buf_len, int64_t *pos, UUID return ret; } -DEFINE_TO_STRING_FUNC_FOR(UUID) +DEFINE_TO_STRING_FUNC_FOR(OBCLIENT_UUID) { int ret = OB_SUCCESS; int64_t tmp_pos = *pos; diff --git a/libmariadb/ob_load_balance.c b/libmariadb/ob_load_balance.c new file mode 100644 index 0000000..9f820f6 --- /dev/null +++ b/libmariadb/ob_load_balance.c @@ -0,0 +1,562 @@ +#include +#include +#if defined(_WIN32) +#include +#include +#else +#include +#endif + +#include "mysql.h" +#include "ob_rwlock.h" +#include "ma_global.h" +#include "errmsg.h" +#include "ob_utils.h" +#include "ob_tnsname.h" +#include "ob_load_balance.h" + +//#define DEBUG_LOAD_BALANCE 1 +#define CONNECT_CNT_INIT 32 + +typedef enum _enum_ob_lb_address_state +{ + OBCLIENT_LB_BLACK, // black + OBCLIENT_LB_WHITE, // white + OBCLIENT_LB_GRAY, // gray + OBCLIENT_LB_MAX_STATE +}ObLbAddressState; + +typedef struct _st_ob_lb_address { + char host[128]; + int port; + int weight; + int state; + int64_t black_time; + int64_t last_time; + void *connect_info; +}ObLbAddress; + +typedef struct _st_ob_lb_address_list { + ObClientLBOption option; //ROTATION,SERVERAFFINITY,RANDOM + unsigned int count; //count + unsigned int rotation_flag; + ObLbAddress *add_arr; +}ObLbAddressList; + +typedef struct _st_connect_info { + int connect_cnt; + int connect_max; + int64_t *connect_list; +}ConnectInfo; + +static void init_connect_info(ObLbAddress *address) { + if (NULL == address->connect_info) { + ConnectInfo *p = malloc(sizeof(ConnectInfo)); + if (NULL != p) { + p->connect_cnt = 0; + p->connect_max = CONNECT_CNT_INIT; + p->connect_list = malloc(sizeof(int64_t) * p->connect_max); + } + address->connect_info = p; + } else { + ConnectInfo *p = (ConnectInfo*)(address->connect_info); + if (p->connect_cnt >= p->connect_max - 1) { + p->connect_max *= 2; + p->connect_list = realloc(p->connect_list, sizeof(int64_t) * p->connect_max); + } + } +} +static void release_connect_info(ObLbAddress *address) { + if (NULL != address->connect_info) { + ConnectInfo *p = (ConnectInfo *)(address->connect_info); + if (NULL != p->connect_list) { + free(p->connect_list); + p->connect_list = NULL; + } + free(address->connect_info); + address->connect_info = NULL; + } +} +static my_bool check_connect_info(ObLbAddress* address) { + my_bool rst = 1; + if (NULL != address->connect_info) { + ConnectInfo *p = (ConnectInfo *)(address->connect_info); + rst = NULL != p->connect_list ? 1 : 0; + } else { + rst = 0; + } + return rst; +} + +static void append_ob_address_connect_info(ObLbAddress * address) { + init_connect_info(address); + if (check_connect_info(address)) { + ConnectInfo *p = (ConnectInfo*)(address->connect_info); + int64_t *tmp = (int64_t*)p->connect_list; + tmp[p->connect_cnt] = get_current_time_us(); + p->connect_cnt++; + address->last_time = get_current_time_us(); + } else { + address->state = OBCLIENT_LB_BLACK; + address->black_time = get_current_time_us(); + } +} + +static ObLbAddress* get_ob_address_by_address_list(ObLbAddressList *addr_list) +{ + ObLbAddress* rst = NULL; + unsigned int cnt = addr_list->count; + unsigned int i = 0, j = 0; + unsigned int weight = 0; + + if (cnt > 0) { + int *idxarr = calloc(1, sizeof(int) * cnt); + if (idxarr != NULL) { + int valid_cnt = 0; + memset(idxarr, 0, sizeof(int) * cnt); + for (i = 0; i < cnt; i++) { + if (addr_list->add_arr[i].weight <= 0) { + addr_list->add_arr[i].weight = 1; + } + if (OBCLIENT_LB_WHITE == addr_list->add_arr[i].state) { + idxarr[valid_cnt] = i; + weight += addr_list->add_arr[i].weight; + valid_cnt++; + } + } + + if (valid_cnt == 0) { + rst = NULL; + } else if (valid_cnt == 1) { + rst = &(addr_list->add_arr[idxarr[0]]); + } else { + switch (addr_list->option) { + case OBCLIENT_LB_OPTION_RANDOM: { + unsigned int random_index = (unsigned int)rand() % valid_cnt; + rst = &(addr_list->add_arr[idxarr[random_index]]); + break; + } + case OBCLIENT_LB_OPTION_SERVERAFFINITY: { + int rand_number = (int)rand() % weight + 1; + int index = 0; + for (index = 0; index < valid_cnt; ++index) { + rand_number -= addr_list->add_arr[idxarr[index]].weight; + if (index == valid_cnt - 1 || rand_number <= 0) { + rst = &(addr_list->add_arr[idxarr[index]]); + break; + } + } + break; + } + case OBCLIENT_LB_OPTION_ROTATION: { + for (i = addr_list->rotation_flag%cnt; i < cnt; i++) { + addr_list->rotation_flag++; + if (OBCLIENT_LB_WHITE == addr_list->add_arr[i].state) { + rst = &(addr_list->add_arr[i]); + addr_list->add_arr[i].last_time = get_current_time_us(); + break; + } + } + break; + } + } + } + free(idxarr); + + if (NULL != rst) { + append_ob_address_connect_info(rst); + } + } + } + return rst; +} + +static void check_ob_address_black(ObLbAddress * address, ObClientLbConfig *config) { + if (!check_connect_info(address)) + address->state = OBCLIENT_LB_BLACK; + + if (OBCLIENT_LB_WHITE == address->state) { + ConnectInfo *info = (ConnectInfo *)address->connect_info; + switch (config->black_append_strategy) { + case OBCLIENT_LB_OPTION_NORMAL: { + address->state = OBCLIENT_LB_BLACK; + address->black_time = get_current_time_us(); +#ifdef DEBUG_LOAD_BALANCE + printf("white 2 black: %s, %d\n", address->host, address->port); +#endif + } + break; + case OBCLIENT_LB_OPTION_RETRY_DERUATION: { + int idx = 0; + int newsize = 0; + int len = info->connect_cnt; + int64_t *list = info->connect_list; + int64_t curtime = get_current_time_us(); + int64_t duration = config->black_append_duration * 1000;// ��λmsתΪus + for (idx = 0; idx < len; idx++) { + if (curtime - list[idx] <= duration) { + break; + } + } + newsize = len - idx; + if (0 != idx) { + int64_t* offset = info->connect_list + idx; + memmove(info->connect_list, offset, newsize); + } + info->connect_cnt = newsize; + if (info->connect_cnt >= config->black_append_retrytimes) { + address->state = OBCLIENT_LB_BLACK; + address->black_time = get_current_time_us(); +#ifdef DEBUG_LOAD_BALANCE + printf("white 2 black: %s, %d\n", address->host, address->port); +#endif + } + } + break; + } + } +} + +static void check_ob_address_white(ObLbAddressList * addr_list, ObClientLbConfig *config) { + unsigned int i = 0; + int64_t curtime = get_current_time_us(); + int64_t timeout = config->black_remove_timeout * 1000; + ObLbAddress* address = addr_list->add_arr; + if (timeout > 0) { + for (i = 0; i < addr_list->count; i++) { + if (OBCLIENT_LB_BLACK == address[i].state) { + if (curtime - address[i].black_time >= timeout) { + address[i].state = OBCLIENT_LB_WHITE; +#ifdef DEBUG_LOAD_BALANCE + printf("black 2 white: %s, %d\n", address->host, address->port); +#endif + } + } + } + } +} + +static int init_oblb_addresslist(ObLbAddressList* list, ObClientLbAddressList* addrlist) { + int ret = 0; + + if (!list || !addrlist || !addrlist->address_list || addrlist->address_list_count <= 0) { + ret = -1; + } else if (OB_ISNULL(list->add_arr = (ObLbAddress*)malloc(addrlist->address_list_count * sizeof(ObLbAddress)))) { + ret = -1; + } else { + unsigned int i = 0; + memset(list->add_arr, 0, addrlist->address_list_count * sizeof(ObLbAddress)); + for (i = 0; i < addrlist->address_list_count; i++) { + memcpy(list->add_arr[i].host, addrlist->address_list[i].host, strlen(addrlist->address_list[i].host)); + list->add_arr[i].port = addrlist->address_list[i].port; + list->add_arr[i].weight = 1; + list->add_arr[i].state = OBCLIENT_LB_WHITE; + } + list->count = addrlist->address_list_count; + list->rotation_flag = 0; + list->option = OBCLIENT_LB_OPTION_ROTATION; + } + return ret; +} +static int init_oblb_addresslist_tns(ObLbAddressList* list, ObClientAddressList* addrlist) { + int ret = 0; + if (!list || !addrlist || !addrlist->address || addrlist->address_count <= 0) { + ret = -1; + } else if (OB_ISNULL(list->add_arr = (ObLbAddress*)malloc(addrlist->address_count * sizeof(ObLbAddress)))){ + ret = -1; + } else { + unsigned int i = 0; + memset(list->add_arr, 0, addrlist->address_count * sizeof(ObLbAddress)); + for (i = 0; i < addrlist->address_count; i++) { + memcpy(list->add_arr[i].host, addrlist->address[i].host, addrlist->address[i].host_len); + list->add_arr[i].port = addrlist->address[i].port; + list->add_arr[i].weight = addrlist->address[i].weight; + list->add_arr[i].state = OBCLIENT_LB_WHITE; + } + list->count = addrlist->address_count; + list->rotation_flag = 0; + list->option = addrlist->oblb_strategy; + } + return ret; +} + +static MYSQL* connect_by_addresslist(MYSQL* mysql, ObLbAddressList *addr_list, ObClientLbConfig *config, + const char *user, const char *passwd, const char *db, const char *unix_socket, unsigned long client_flag, ObClientLbAddress* success) +{ + ObLbAddress *address = NULL; + MYSQL* tmp = NULL; + unsigned int i = 0; + int err = 0; + + unsigned int mysql_connect_timeout = 0; + unsigned int mysql_read_timeout = 0; + unsigned int mysql_write_timeout = 0; + my_bool mysql_is_local_infile = 0; + unsigned int mysql_local_infile = 0; + unsigned int mysql_opt_protocol = 0; + my_bool mysql_is_proxy_mode = 0; + my_bool mysql_is_compress = 0; + my_bool mysql_opt_secure_auth = 0; + + char *mysql_init_command = NULL; + char *mysql_charset_name = NULL; + char* mysql_opt_plugin_dir = NULL; + char* mysql_opt_default_auth = NULL; + char* mysql_program_name = NULL; + char* mysql_ob_proxy_user = NULL; + my_bool mysql_opt_interactive = 0; + my_bool mysql_report_data_truncation = 0; + my_bool mysql_opt_reconnect = 0; + + my_bool mysql_opt_use_ssl = 0; + my_bool mysql_opt_ssl_verify_server_cert = 0; + char *mysql_opt_ssl_key = NULL; + char *mysql_opt_ssl_cert = NULL; + char *mysql_opt_ssl_ca = NULL; + char *mysql_opt_ssl_capath = NULL; + char *mysql_opt_ssl_cipher = NULL; + char *mysql_opt_ssl_crl = NULL; + char *mysql_opt_ssl_crlpath = NULL; + char *mysql_opt_tls_version = NULL; + + if (mysql == NULL || addr_list == NULL || config == NULL || addr_list->add_arr == NULL || addr_list->count <= 0) { + return NULL; + } + + if (addr_list->option != OBCLIENT_LB_OPTION_RANDOM && + addr_list->option != OBCLIENT_LB_OPTION_ROTATION && + addr_list->option != OBCLIENT_LB_OPTION_SERVERAFFINITY) { + addr_list->option = OBCLIENT_LB_OPTION_ROTATION; + } + if (config->black_append_strategy != OBCLIENT_LB_OPTION_NORMAL && + config->black_append_strategy != OBCLIENT_LB_OPTION_RETRY_DERUATION) { + config->black_append_strategy = OBCLIENT_LB_OPTION_NORMAL; + } + if (config->retry_all_downs <= 0) config->retry_all_downs = addr_list->count; + if (config->black_append_duration <= 0) config->black_append_duration = 60 * 1000; + if (config->black_append_retrytimes <= 0) config->black_append_retrytimes = 1; + + for (i = 0; i < addr_list->count; i++) { + addr_list->add_arr[i].state = OBCLIENT_LB_WHITE; + addr_list->add_arr[i].connect_info = NULL; + if (addr_list->add_arr[i].weight <= 0) { + addr_list->add_arr[i].weight = 1; + } + init_connect_info(&(addr_list->add_arr[i])); + } + + //init mysql options + mysql_connect_timeout = config->mysql_connect_timeout; + mysql_read_timeout = config->mysql_read_timeout; + mysql_write_timeout = config->mysql_write_timeout; + mysql_is_proxy_mode = config->mysql_is_proxy_mode; + mysql_init_command = config->mysql_init_command; + mysql_charset_name = config->mysql_charset_name; + mysql_is_compress = config->mysql_is_compress; + mysql_is_local_infile = config->mysql_is_local_infile; + mysql_local_infile = config->mysql_local_infile; + mysql_opt_protocol = config->mysql_opt_protocol; + mysql_opt_plugin_dir = config->mysql_opt_plugin_dir; + mysql_ob_proxy_user = config->mysql_ob_proxy_user; + mysql_opt_default_auth = config->mysql_opt_default_auth; + mysql_program_name = config->mysql_program_name; + mysql_opt_secure_auth = config->mysql_opt_secure_auth; + mysql_opt_interactive = config->mysql_opt_interactive; + mysql_report_data_truncation = config->mysql_report_data_truncation; + mysql_opt_reconnect = config->mysql_opt_reconnect; + + mysql_opt_use_ssl = config->mysql_opt_use_ssl; + mysql_opt_ssl_verify_server_cert = config->mysql_opt_ssl_verify_server_cert; + mysql_opt_ssl_key = config->mysql_opt_ssl_key; + mysql_opt_ssl_cert = config->mysql_opt_ssl_cert; + mysql_opt_ssl_ca = config->mysql_opt_ssl_ca; + mysql_opt_ssl_capath = config->mysql_opt_ssl_capath; + mysql_opt_ssl_cipher = config->mysql_opt_ssl_cipher; + mysql_opt_ssl_crl = config->mysql_opt_ssl_crl; + mysql_opt_ssl_crlpath = config->mysql_opt_ssl_crlpath; + mysql_opt_tls_version = config->mysql_opt_tls_version; + + do { + //check address white + check_ob_address_white(addr_list, config); + + //get address + if (NULL == (address = get_ob_address_by_address_list(addr_list))) { + break; + } + + if (OBCLIENT_LB_WHITE != address->state) { + continue; + } + +#ifdef DEBUG_LOAD_BALANCE + printf("host:%s,port:%d,state:%d\n", address->host, address->port, address->state); +#endif + + //mysql options + if (mysql_connect_timeout > 0) + mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, &mysql_connect_timeout); + if (mysql_read_timeout > 0) + mysql_options(mysql, MYSQL_OPT_READ_TIMEOUT, &mysql_read_timeout); + if (mysql_write_timeout > 0) + mysql_options(mysql, MYSQL_OPT_WRITE_TIMEOUT, &mysql_write_timeout); + if (mysql_is_proxy_mode) + mysql->ob_server_version = 0xfe; + if (mysql_init_command && *mysql_init_command) + mysql_options(mysql, MYSQL_INIT_COMMAND, mysql_init_command); + if (mysql_charset_name && *mysql_charset_name) + mysql_options(mysql, MYSQL_SET_CHARSET_NAME, mysql_charset_name); + if (mysql_is_compress) + mysql_options(mysql, MYSQL_OPT_COMPRESS, NullS); + if (mysql_is_local_infile) + mysql_options(mysql, MYSQL_OPT_LOCAL_INFILE, (char*)&mysql_local_infile); + if (mysql_opt_protocol) + mysql_options(mysql, MYSQL_OPT_PROTOCOL, (char*)&mysql_opt_protocol); + if (mysql_opt_plugin_dir && *mysql_opt_plugin_dir) + mysql_options(mysql, MYSQL_PLUGIN_DIR, mysql_opt_plugin_dir); + if (mysql_opt_default_auth && *mysql_opt_default_auth) + mysql_options(mysql, MYSQL_DEFAULT_AUTH, mysql_opt_default_auth); + if (mysql_program_name && *mysql_program_name) { + mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_RESET, 0); + mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "program_name", mysql_program_name); + } + if (mysql_ob_proxy_user && *mysql_ob_proxy_user) + mysql_options(mysql, OB_OPT_PROXY_USER, mysql_ob_proxy_user); + if (mysql_opt_secure_auth) + mysql_options(mysql, MYSQL_SECURE_AUTH, (char *)&mysql_opt_secure_auth); + if (mysql_opt_interactive) + mysql_options(mysql, MARIADB_OPT_INTERACTIVE, (char *)&mysql_opt_interactive); + if (mysql_report_data_truncation) + mysql_options(mysql, MYSQL_REPORT_DATA_TRUNCATION, (char *)&mysql_report_data_truncation); + if (mysql_opt_reconnect) + mysql_options(mysql, MYSQL_OPT_RECONNECT, (char *)&mysql_opt_reconnect); + + if (mysql_opt_use_ssl) { + mysql_ssl_set(mysql, mysql_opt_ssl_key, mysql_opt_ssl_cert, mysql_opt_ssl_ca, mysql_opt_ssl_capath, mysql_opt_ssl_cipher); + mysql_options(mysql, MYSQL_OPT_SSL_CRL, mysql_opt_ssl_crl); + mysql_options(mysql, MYSQL_OPT_SSL_CRLPATH, mysql_opt_ssl_crlpath); + mysql_options(mysql, MARIADB_OPT_TLS_VERSION, mysql_opt_tls_version); + } + if (mysql_opt_ssl_verify_server_cert) + mysql_options(mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, (char*)&mysql_opt_ssl_verify_server_cert); + + //connect to server + if (NULL != (tmp = mysql_real_connect(mysql, address->host, user, passwd, db, address->port, unix_socket, client_flag))) { + //connect success + if (success) { + memcpy(success->host, address->host, strlen(address->host)); + success->port = address->port; + } + break; + } else { + //connect fail, user/passwd is error break; + err = mysql_errno(mysql); + if (1045 == err) { + break; + } + } + + //check black + check_ob_address_black(address, config); + + config->retry_all_downs--; + } while (address && config->retry_all_downs > 0); + + //release connect + for (i = 0; i < addr_list->count; i++) { + release_connect_info(&(addr_list->add_arr[i])); + } + + return tmp; +} + +static MYSQL* connect_by_tnsname(MYSQL* mysql, const char* tns_name, ObClientLbConfig * config, + const char *user, const char* passwd, const char *db, const char* unix_socket, unsigned long client_flag, ObClientLbAddress *success) +{ + int ret = 0; + MYSQL *tmp = NULL; + my_bool find = 0; + ObClientTns tns; + const char *sid = db; + char new_user_name[256] = { 0 }; + int user_len = strlen((const char *)user ? user : ""); + + if (OB_FAIL(ObClientTnsInit(&tns))) { + tmp = NULL; + } else if (OB_FAIL(ObClientTnsBuild(&tns, tns_name, strlen(tns_name), &find))) { + tmp = NULL; + } else if (1 != find || !tns.tns_service || !tns.tns_service->description || tns.tns_service->description_count == 0) { + tmp = NULL; + } else { + unsigned int i = 0; + ObClientDescription *des = tns.tns_service->description; +#ifdef DEBUG_LOAD_BALANCE + ObClientTnsDisplay(&tns); +#endif + + strncpy(new_user_name, (const char *)user ? user : "", user_len); + + if (des && des->connect_data) { + if (!des->connect_data->use_default_sid) { + sid = des->connect_data->service_name; + } + if (des->connect_data->user_extra_info_len > 0) { + strncpy(new_user_name + user_len, (const char *)des->connect_data->user_extra_info, des->connect_data->user_extra_info_len); + } + } + + //tns config + config->retry_all_downs = des->retry_all_downs; + config->black_remove_strategy = des->black_list_conf.remove_strategy; + config->black_remove_timeout = des->black_list_conf.remove_timeout; + config->black_append_strategy = des->black_list_conf.append_strategy; + config->black_append_duration = des->black_list_conf.duration; + config->black_append_retrytimes = des->black_list_conf.retry_times; + + for (i = 0; i < des->address_list_count; i++) { + ObLbAddressList list; + memset(&list, 0, sizeof(list)); +#ifdef DEBUG_LOAD_BALANCE + printf("------------------------------------------\n"); +#endif + + if (OB_SUCC(init_oblb_addresslist_tns(&list, &(des->address_list[i])))) { + tmp = connect_by_addresslist(mysql, &list, config, new_user_name, passwd, sid, unix_socket, client_flag, success); + } + if (list.add_arr) { + free(list.add_arr); + list.add_arr = NULL; + list.count = 0; + } + if (tmp) { + break; + } + } + } + ObClientTnsClear(&tns); + return tmp; +} + +MYSQL* ob_mysql_real_connect(MYSQL* mysql, const char* tns_name, ObClientLbAddressList *addr_list, ObClientLbConfig *config, + const char *user, const char *passwd, const char *db, const char *unix_socket, unsigned long client_flag, ObClientLbAddress* success) +{ + int ret = 0; + MYSQL *tmp = NULL; + + if (tns_name && *tns_name) { + tmp = connect_by_tnsname(mysql, tns_name, config, user, passwd, db, unix_socket, client_flag, success); + } else { + ObLbAddressList list; + memset(&list, 0, sizeof(list)); + if (OB_SUCC(init_oblb_addresslist(&list, addr_list))) { + tmp = connect_by_addresslist(mysql, &list, config, user, passwd, db, unix_socket, client_flag, success); + } + if (list.add_arr) { + free(list.add_arr); + list.add_arr = NULL; + list.count = 0; + } + } + + return tmp; +} diff --git a/libmariadb/ob_protocol20.c b/libmariadb/ob_protocol20.c index e61d65c..4ac7f82 100644 --- a/libmariadb/ob_protocol20.c +++ b/libmariadb/ob_protocol20.c @@ -331,6 +331,7 @@ int ob20_init(Ob20Protocol *ob20protocol, unsigned long conid, my_bool use_flt) ob20protocol->extra_info_list.current = NULL; ob20protocol->header.connection_id = conid; ob20protocol->flt = NULL; + ob20protocol->update_request_id = 1; if (use_flt) { ob20protocol->flt = malloc(sizeof(FLTInfo)); if (OB_ISNULL(ob20protocol->flt)) { @@ -715,4 +716,4 @@ int ob20_set_extra_info(MYSQL *mysql, ExtraInfoKeyType key, void *value) ob20protocol->extra_info_list.list = list_add(ob20protocol->extra_info_list.list, extra_info_list_item); } return ret; -} \ No newline at end of file +} diff --git a/libmariadb/ob_tnsname.c b/libmariadb/ob_tnsname.c new file mode 100644 index 0000000..13eacd9 --- /dev/null +++ b/libmariadb/ob_tnsname.c @@ -0,0 +1,1592 @@ +#include "ob_tnsname.h" + +#include +#include +#include +#include + +#define TNS_NO_DATA 100 +#define TNS_PARSE_FAIL_BREAK() {if(OB_FAIL(ret)) break;} + +#define TNS_PARSE(parse_params, token_type) \ + do \ + { \ + if (OB_SUCC(ret)) { \ + if (OB_FAIL(ObClientTnsParse(parse_params, token_type))) {; \ + } else { \ + /* do nothing */ \ + } \ + } \ + } while (0) + +#define TNS_GET_KEY_TYPE(parse_params) \ + do \ + { \ + if (OB_SUCC(ret)) { \ + if (OB_FAIL(ObClientTnsGetKeyType(parse_params))) {; \ + } else if (OBCLIENT_LB_ERROR_KEY == parse_params->key_type) { \ + ret = -1; \ + } \ + } \ + } while (0) + +#define TNS_PARSE_STRING_VALUE(parse_params, dest_str, dest_len, dest_limit) \ + do \ + { \ + TNS_PARSE(parse_params, TNS_KEY); \ + if (OB_SUCC(ret) && parse_params->tns_key_len <= dest_limit) { \ + dest_len = parse_params->tns_key_len; \ + strncpy(dest_str, parse_params->tns_key, parse_params->tns_key_len); \ + } else { ; \ + } \ + } while (0) + +#define TNS_PARSE_INTRGER_VALUE(parse_params, des_value) \ + do \ + { \ + int err; \ + char *endptr; \ + TNS_PARSE(parse_params, TNS_KEY); \ + endptr = parse_params->tns_key + parse_params->tns_key_len; \ + des_value = strtoll10(parse_params->tns_key, &endptr, &err); \ + if ((parse_params->tns_key_len != endptr - parse_params->tns_key)) { \ + ret = -1; \ + } \ + } while (0) + +#define TNS_KEY_ARRAY_SIZE(array) (sizeof(array) / sizeof(const char *)) + +/** + * 如果需要加入新的key type,需要确定好字符串长度,加入到相应长度的tns_key_x数组中 + * 并且在tns_keytype_x中设置好type即可 + */ +static const char *tns_key_0[] = {0}; +static const char *tns_key_1[] = {0}; +static const char *tns_key_2[] = {0}; +static const char *tns_key_3[] = {"SID"}; +static const char *tns_key_4[] = {"OBLB", "HOST", "PORT", "NAME"}; +static const char *tns_key_5[] = {0}; +static const char *tns_key_6[] = {"WEIGHT"}; +static const char *tns_key_7[] = {"ADDRESS", "TIMEOUT", "OB_MODE"}; +static const char *tns_key_8[] = {"PROTOCOL", "DURATION" }; +static const char *tns_key_9[] = {0}; +static const char *tns_key_10[] = {"RETRYTIMES"}; +static const char *tns_key_11[] = {"DESCRIPTION", "RETRY_TIMES"}; +static const char *tns_key_12[] = {"ADDRESS_LIST", "CONNECT_DATA", "SERVICE_NAME"}; +static const char *tns_key_13[] = {"OBLB_STRATEGY"}; +static const char *tns_key_14[] = {"OBLB_BLACKLIST"}; +static const char *tns_key_15[] = {"REMOVE_STRATEGY", "APPEND_STRATEGY", "USE_DEFAULT_SID"}; +static const char *tns_key_16[] = {"SESSION_VARIABLE"}; +static const char *tns_key_17[] = {"OBLB_READ_TIMEOUT"}; +static const char *tns_key_18[] = {"OB_USER_EXTRA_INFO", "OBLB_RETRY_TIMEOUT", "OBLB_WRITE_TIMEOUT"}; +static const char *tns_key_19[] = {"OBLB_GROUP_STRATEGY"}; +static const char *tns_key_20[] = {"OBLB_RETRY_ALL_DOWNS", "OBLB_CONNECT_TIMEOUT"}; + +static ObClientLBKeyType tns_keytype_0[] = { OBCLIENT_LB_ERROR_KEY }; +static ObClientLBKeyType tns_keytype_1[] = { OBCLIENT_LB_ERROR_KEY }; +static ObClientLBKeyType tns_keytype_2[] = { OBCLIENT_LB_ERROR_KEY }; +static ObClientLBKeyType tns_keytype_3[] = { OBCLIENT_LB_SID}; +static ObClientLBKeyType tns_keytype_4[] = { OBCLIENT_LB_OBLB, OBCLIENT_LB_HOST, OBCLIENT_LB_PORT, OBCLIENT_LB_NAME}; +static ObClientLBKeyType tns_keytype_5[] = { OBCLIENT_LB_ERROR_KEY }; +static ObClientLBKeyType tns_keytype_6[] = { OBCLIENT_LB_WEIGHT}; +static ObClientLBKeyType tns_keytype_7[] = { OBCLIENT_LB_ADDRESS, OBCLIENT_LB_TIMEOUT, OBCLIENT_LB_OB_MODE}; +static ObClientLBKeyType tns_keytype_8[] = { OBCLIENT_LB_PROTOCOL, OBCLIENT_LB_DRUATION}; +static ObClientLBKeyType tns_keytype_9[] = { OBCLIENT_LB_ERROR_KEY }; +static ObClientLBKeyType tns_keytype_10[] = { OBCLIENT_LB_RETRY_TIMES }; +static ObClientLBKeyType tns_keytype_11[] = { OBCLIENT_LB_DESCRIPTION, OBCLIENT_LB_RETRY_TIMES }; +static ObClientLBKeyType tns_keytype_12[] = { OBCLIENT_LB_ADDRESS_LIST, OBCLIENT_LB_CONNECT_DATA, OBCLIENT_LB_SERVICE_NAME}; +static ObClientLBKeyType tns_keytype_13[] = { OBCLIENT_LB_OBLB_STRATEGY}; +static ObClientLBKeyType tns_keytype_14[] = { OBCLIENT_LB_OBLB_BLACKLIST}; +static ObClientLBKeyType tns_keytype_15[] = { OBCLIENT_LB_REMOVE_STRATEGY, OBCLIENT_LB_APPEND_STRATEGY, OBCLIENT_LB_USE_DEFAULT_SID}; +static ObClientLBKeyType tns_keytype_16[] = { OBCLIENT_LB_SESSION_VARIABLE}; +static ObClientLBKeyType tns_keytype_17[] = { OBCLIENT_LB_READ_TIMEOUT}; +static ObClientLBKeyType tns_keytype_18[] = { OBCLIENT_LB_EXTRA_INFO, OBCLIENT_LB_OBLB_RETRY_TIMEOUT, OBCLIENT_LB_WRITE_TIMEOUT}; +static ObClientLBKeyType tns_keytype_19[] = { OBCLIENT_LB_OBLB_GROUP_STRATEGY }; +static ObClientLBKeyType tns_keytype_20[] = { OBCLIENT_LB_OBLB_RETRY_ALL_DOWNS, OBCLIENT_LB_CONNECT_TIMEOUT}; + +static const void *tns_key_array[] = { + tns_key_0, tns_key_1, tns_key_2, tns_key_3, tns_key_4, tns_key_5, tns_key_6, tns_key_7, tns_key_8, + tns_key_9, tns_key_10, tns_key_11, tns_key_12, tns_key_13, tns_key_14, tns_key_15, tns_key_16, tns_key_17, + tns_key_18, tns_key_19, tns_key_20 +}; + +static const void *tns_keytype_array[] = { + tns_keytype_0, tns_keytype_1, tns_keytype_2, tns_keytype_3, tns_keytype_4, tns_keytype_5, tns_keytype_6, tns_keytype_7, tns_keytype_8, + tns_keytype_9, tns_keytype_10, tns_keytype_11, tns_keytype_12, tns_keytype_13, tns_keytype_14, tns_keytype_15, tns_keytype_16, tns_keytype_17, + tns_keytype_18, tns_keytype_19, tns_keytype_20 +}; + +static const unsigned int tns_key_array_size[] = { + TNS_KEY_ARRAY_SIZE(tns_key_0), TNS_KEY_ARRAY_SIZE(tns_key_1), TNS_KEY_ARRAY_SIZE(tns_key_2), + TNS_KEY_ARRAY_SIZE(tns_key_3), TNS_KEY_ARRAY_SIZE(tns_key_4), TNS_KEY_ARRAY_SIZE(tns_key_5), + TNS_KEY_ARRAY_SIZE(tns_key_6), TNS_KEY_ARRAY_SIZE(tns_key_7), TNS_KEY_ARRAY_SIZE(tns_key_8), + TNS_KEY_ARRAY_SIZE(tns_key_9), TNS_KEY_ARRAY_SIZE(tns_key_10), TNS_KEY_ARRAY_SIZE(tns_key_11), + TNS_KEY_ARRAY_SIZE(tns_key_12), TNS_KEY_ARRAY_SIZE(tns_key_13), TNS_KEY_ARRAY_SIZE(tns_key_14), + TNS_KEY_ARRAY_SIZE(tns_key_15), TNS_KEY_ARRAY_SIZE(tns_key_16), TNS_KEY_ARRAY_SIZE(tns_key_17), + TNS_KEY_ARRAY_SIZE(tns_key_18), TNS_KEY_ARRAY_SIZE(tns_key_19), TNS_KEY_ARRAY_SIZE(tns_key_20) +}; + +int ObClientTnsInit(ObClientTns *tns) +{ + int ret = 0; + + if (OB_ISNULL(tns)) { + ret = -1; + } else { + memset(tns, 0, sizeof(*tns)); + tns->tns_service = NULL; + tns->tns_service_count = 0; + } + + return ret; +} + +int ObClientTnsClear(ObClientTns *tns) +{ + int ret = 0; + + if (OB_ISNULL(tns)) { + ret = 0; + } else if (OB_ISNULL(tns->tns_service) || 0 == tns->tns_service_count) { + ret = 0; + } else { + ObClientTnsServiceClear(tns->tns_service); + } + + return ret; +} + +int ObClientTnsDisplay(ObClientTns *tns) +{ + int ret = 0; + FILE *display_file = stdout; + const char *display_file_name = NULL; + + if (OB_ISNULL(tns)) { + ret = -1; + } else if (0 == tns->tns_service_count || OB_ISNULL(tns->tns_service)) { + ret = -1; + } else { + my_bool need_close = 0; + if (OB_NOT_NULL(display_file_name = getenv("OBCI_TNS_DISPLAY"))) { + if (OB_ISNULL(display_file = fopen(display_file_name, "r"))) { + ret = -1; + } + need_close = 1; + } + + if (OB_SUCC(ret)) { + unsigned int i; + ObClientTnsService *tns_service = tns->tns_service; + + fprintf(display_file, "Tns:\n"); + fprintf(display_file, "--tns_serivce_count:%u\n", tns->tns_service_count); + + for (i = 0; i < tns->tns_service_count && OB_SUCC(ret); ++i) { + if (OB_FAIL(ObClientTnsServiceDisplay(tns_service, display_file))) { + ; + } + } + } + if (need_close && display_file) { + fclose(display_file); + } + } + + return ret; +} + +static int ObClientTnsBuildGetFile(ObClientTnsParseParams *parse_params) +{ + int ret = 0; + int prefix_len; + char file_name[OBCLIENT_TNS_KEY_SIZE + 1] = {0}; + + if (OB_ISNULL(parse_params)) { + ret = -1; + } else { + if (OB_NOT_NULL(parse_params->tns_name = getenv("OBCI_TNS_FILE"))) { + strncpy(file_name, parse_params->tns_name, OBCLIENT_TNS_KEY_SIZE); + } else if (OB_NOT_NULL(parse_params->tns_name = getenv("TNS_ADMIN"))) { + prefix_len = strlen(parse_params->tns_name); + strncpy(file_name, parse_params->tns_name, OBCLIENT_TNS_KEY_SIZE); + strncpy(file_name + prefix_len, "/tnsnames.ora", OBCLIENT_TNS_KEY_SIZE - prefix_len); + } else if (OB_NOT_NULL(parse_params->tns_name = getenv("ORACLE_HOME"))) { + prefix_len = strlen(parse_params->tns_name); + strncpy(file_name, parse_params->tns_name, OBCLIENT_TNS_KEY_SIZE); + strncpy(file_name + prefix_len, "/network/admin/tnsnames.ora", OBCLIENT_TNS_KEY_SIZE - prefix_len); + } else { + ret = TNS_NO_DATA; + } + if (OB_SUCC(ret)) { + if (OB_ISNULL(parse_params->tns_file = fopen(file_name, "r"))) { + ret = -1; + } + } + } + + return ret; +} + +my_bool IsDescriptionTns(char* description, unsigned int description_len) { + my_bool ret = 0; + int i = 0, j = 0; + char str[20] = { 0 }; //(DESCRIPTION= + for (i = 0; i < (int)description_len && j <13; i++) { + if (description[i] == ' ' || description[i] == '\t' || + description[i] == '\r' || description[i] == '\n') { + continue; + } + str[j++] = description[i]; + } + if (0 == strncasecmp(str, "(DESCRIPTION=", 13)) { + ret = 1; + } + return ret; +} + +int ObClientTnsBuild(ObClientTns *tns, const char *dbname, unsigned int dbname_len, my_bool *find) +{ + int ret = 0; + ObClientTnsParseParams parse_params; + + memset(&parse_params, 0, sizeof(parse_params)); + parse_params.tns_file = NULL; + parse_params.mode = TNS_MODE_FILE; + + if (OB_ISNULL(tns) || OB_ISNULL(dbname) || OB_ISNULL(find)) { + ret = -1; + } else if (IsDescriptionTns((char*)dbname, dbname_len)) { + ret = ObClientTnsBuildDes(tns, dbname, dbname_len, find); + } else if (OB_FAIL(ObClientTnsBuildGetFile(&parse_params))) { + ret = 0; + *find = FALSE; + } else { + *find = FALSE; + while (OB_SUCC(ret) && 0 == parse_params.is_eof && FALSE == *find) { + // 解析tns_service name + TNS_PARSE(&parse_params, TNS_KEY); + // 解析等于号 + TNS_PARSE(&parse_params, TNS_EQUAL_SIGN); + // 比较key是否和dbname一样,不同则跳过整个kv对,一样则进入解析流程, 这里大小写敏感 + if (OB_SUCC(ret)) { + if (dbname_len != parse_params.tns_key_len || 0 != strncmp((const char *)dbname, parse_params.tns_key, dbname_len)) { + // 这里跳过这个tns service下所有pair + ret = ObClientTnsServiceSkip(&parse_params); + } else { + // 这里进入解析 + if (OB_FAIL(ObClientTnsServiceBuild(tns, &parse_params))) { + ret = -1; + } else { + *find = TRUE; + } + } + } + } + if (OB_FAIL(ret)) { + *find = FALSE; + if (TNS_NO_DATA == ret) { + ret = 0; + } + } + } + + if (OB_NOT_NULL(parse_params.tns_file)) { + fclose(parse_params.tns_file); + } + + return ret; +} + +int ObClientTnsBuildDes(ObClientTns *tns, const char *dbname, unsigned int dbname_len, my_bool *find) +{ + int ret = 0; + ObClientTnsParseParams parse_params; + ObClientTnsService *tns_service = NULL; + + memset(&parse_params, 0, sizeof(parse_params)); + parse_params.tns_file = NULL; + parse_params.mode = TNS_MODE_DESCRIPTION; + parse_params.description = (char*)dbname; + parse_params.description_len = dbname_len; + parse_params.description_offset = 0; + + if (OB_ISNULL(tns) || OB_ISNULL(dbname) || OB_ISNULL(find)) { + ret = -1; + *find = FALSE; + } else { + *find = FALSE; + + // 解析左侧括号 + TNS_PARSE(&parse_params, TNS_LEFT_PARENTHESES); + // DESCRIPTION + TNS_PARSE(&parse_params, TNS_KEY); + TNS_GET_KEY_TYPE((&parse_params)); + // 解析等于号 + TNS_PARSE(&parse_params, TNS_EQUAL_SIGN); + if (OB_SUCC(ret)) { + if (OBCLIENT_LB_DESCRIPTION != parse_params.key_type) { + ret = -1; + } else { + if (OB_ISNULL(tns_service = malloc(sizeof(*tns_service) + parse_params.tns_key_len))) { + ret = -1; + } else if (OB_FAIL(ObClientTnsServiceInit(tns_service, parse_params.tns_key_len, parse_params.tns_key))) { + ret = -1; + } else if (OB_FAIL(ObClientDescriptionBuild(tns_service, &parse_params))) { + ret = -1; + } + TNS_PARSE(&parse_params, TNS_RIGHT_PARENTHESES); + + //test end + if (OB_SUCC(ret)) { + int st = ObClientTnsParseBlank(&parse_params); + if (st != TNS_NO_DATA) + ret = -1; + } + if (OB_SUCC(ret) && TNS_RIGHT_PARENTHESES == parse_params.tns_token_type) { + tns->tns_service_count++; + if (OB_ISNULL(tns->tns_service)) { + tns->tns_service = tns_service; + } + // 最后将ret改为success,由调用函数继续解析 + ret = 0; + } else { + ObClientTnsServiceClear(tns_service); + free(tns_service); + ret = -1; + } + if (OB_SUCC(ret)) { + *find = TRUE; + } + } + } + + if (OB_FAIL(ret)) { + *find = FALSE; + if (TNS_NO_DATA == ret) { + ret = 0; + } + } + } + return ret; +} + +int ObClientTnsServiceCheck(ObClientTnsService *tns_service) +{ + int ret = 0; + if (OB_ISNULL(tns_service)) { + ret = -1; + } else { + if (tns_service->description_count == tns_service->description_memory) { + int new_memory = tns_service->description_memory + OBCLIENT_TNS_MEMORY_COUNT; + char * tmp = realloc(tns_service->description, new_memory * sizeof(ObClientDescription)); + if (tmp) { + tns_service->description = (ObClientDescription*)tmp; + tns_service->description_memory = new_memory; + } else { + ret = -1; + } + } + } + return ret; +} +int ObClientTnsServiceInit(ObClientTnsService *tns_service, unsigned int name_size, const char *name) +{ + int ret = 0; + + if (OB_ISNULL(tns_service)) { + ret = -1; + } else { + memset(tns_service, 0, sizeof(*tns_service)); + tns_service->description_count = 0; + tns_service->description_memory = 0; + tns_service->net_service_name_len = name_size; + strncpy(tns_service->net_service_name, name, min(name_size, OBCLIENT_TNS_BUFFER_SIZE)); + ret = ObClientSystemVariablesInit(&tns_service->sys_vars); + } + + return ret; +} + +int ObClientTnsServiceClear(ObClientTnsService *tns_service) +{ + int ret = 0; + + if (OB_ISNULL(tns_service) || OB_ISNULL(tns_service->description) || 0 == tns_service->description_count) { + ret = -1; + } else if (OB_FAIL(ObClientSystemVariablesClear(&tns_service->sys_vars))) { + ; + } else { + unsigned int i; + for (i = 0; i < tns_service->description_count && OB_SUCC(ret); ++i) { + ObClientDescription *description = &(tns_service->description[i]); + ObClientDescriptionClear(description); + } + free(tns_service->description); + tns_service->description = NULL; + tns_service->description_count = 0; + tns_service->description_memory = 0; + } + + return ret; +} + +int ObClientTnsServiceDisplay(ObClientTnsService *tns_service, FILE *display_file) +{ + int ret = 0; + + if (OB_ISNULL(tns_service) || OB_ISNULL(display_file)) { + ret = -1; + } else if (0 == strncasecmp("OBCISYSTEMVARIABLES", tns_service->net_service_name, tns_service->net_service_name_len)) { + ret = ObClientSystemVariablesDisplay(&tns_service->sys_vars, display_file); + } else if (0 == tns_service->description_count || OB_ISNULL(tns_service->description)) { + ret = -1; + } else { + unsigned int i; + + fprintf(display_file, "--TnsService:%.*s\n", tns_service->net_service_name_len, tns_service->net_service_name); + fprintf(display_file, "----description_count:%u\n", tns_service->description_count); + + for (i = 0; i < tns_service->description_count && OB_SUCC(ret); ++i) { + ObClientDescription *description = &(tns_service->description[i]); + ObClientDescriptionDisplay(description, display_file); + } + + ObClientSystemVariablesDisplay(&tns_service->sys_vars, display_file); + } + + return ret; +} + +int ObClientTnsServiceBuild(ObClientTns *tns, ObClientTnsParseParams *parse_params) +{ + int ret = 0; + ObClientTnsService *tns_service = NULL; + + if (OB_ISNULL(tns) || OB_ISNULL(parse_params)) { + ret = -1; + } else { + int is_sys_vars = FALSE; + + // 上个函数解析的name + if (OB_SUCC(ret)) { + if (OB_ISNULL(tns_service = malloc(sizeof(*tns_service) + parse_params->tns_key_len))) { + ret = -1; + } else if (OB_FAIL(ObClientTnsServiceInit(tns_service, parse_params->tns_key_len, parse_params->tns_key))) { + ret = -1; + } else if (0 == strncasecmp("OBCISYSTEMVARIABLES", parse_params->tns_key, parse_params->tns_key_len)) { + is_sys_vars = TRUE; + } + } + + if (OB_SUCC(ret)) { + int parse_ok = 0; + // 循环处理pair + while (OB_SUCC(ret)) { + // 解析左括号 + TNS_PARSE(parse_params, TNS_LEFT_PARENTHESES); + TNS_PARSE_FAIL_BREAK(); + // 解析key + TNS_PARSE(parse_params, TNS_KEY); + // 得到key type + TNS_GET_KEY_TYPE(parse_params); + if (is_sys_vars) { //sys_vars中错误的key不影响其他项 + ret = 0; + } + // 解析等于号, 上面得到的key不会被覆盖 + TNS_PARSE(parse_params, TNS_EQUAL_SIGN); + // 这里的key必须得到description,否则报错 + if (OB_SUCC(ret)) { + if (is_sys_vars) { + ret = ObClientSystemVariablesBuild(&tns_service->sys_vars, parse_params); + } else { + if (OBCLIENT_LB_DESCRIPTION != parse_params->key_type) { + ret = -1; + } else { + ret = ObClientDescriptionBuild(tns_service, parse_params); + } + } + } + TNS_PARSE(parse_params, TNS_RIGHT_PARENTHESES); + if (OB_SUCC(ret)) { + parse_ok = 1; + } + } + if (parse_ok && TNS_RIGHT_PARENTHESES == parse_params->tns_token_type) { + tns->tns_service_count++; + if (OB_ISNULL(tns->tns_service)) { + tns->tns_service = tns_service; + } + ret = 0; + } else { + ObClientTnsServiceClear(tns_service); + free(tns_service); + ret = -1; + } + } + } + + return ret; +} + +int ObClientTnsServiceSkip(ObClientTnsParseParams *parse_params) +{ + int ret = 0; + + if (OB_ISNULL(parse_params)) { + ret = -1; + } else { + int left_parentheses = 1; + char ch; + + if (0 == strncmp("OBCISYSTEMVARIABLES", parse_params->tns_key, parse_params->tns_key_len)) { + parse_params->is_eof = 1; + } else { + // 首先定位到第一个左括号 + TNS_PARSE(parse_params, TNS_LEFT_PARENTHESES); + + while (OB_SUCC(ret) && left_parentheses != 0) { + if (OB_FAIL(ObClientTnsCheckBuffer(parse_params))) { + if (TRUE == parse_params->is_eof) { + ret = TNS_NO_DATA; + } + } else { + while (parse_params->buffer_pos < parse_params->buffer_len + && left_parentheses != 0) { + ch = parse_params->tns_buffer[parse_params->buffer_pos++]; + if ('(' == ch) { + left_parentheses++; + } else if (')' == ch) { + left_parentheses--; + } + } + } + } + } + } + + return ret; +} + +int ObClientTnsServiceExtraInfoGet(ObClientTnsService *tns_service, char *extra_info, int *extra_info_len, int *ob_mode) +{ + int ret = 0; + ObClientDescription *des; + ObClientConnectData *con_data; + + if (OB_ISNULL(tns_service) || OB_ISNULL(extra_info) || OB_ISNULL(extra_info) || OB_ISNULL(ob_mode)) { + ret = -1; + } else if (0 == tns_service->description_count || OB_ISNULL(des = tns_service->description)) { + ret = -1; + } else if (OB_ISNULL(con_data = des->connect_data)) { + ret = -1; + } else if (0 != con_data->user_extra_info_len) { + *extra_info_len = con_data->user_extra_info_len; + strncpy(extra_info, con_data->user_extra_info, *extra_info_len); + *ob_mode = con_data->ob_mode; + } + + return ret; +} + +int ObClientTnsServiceDblinkGet(ObClientTnsService *tns_service, char *dblink, int *dblink_len) +{ + int ret = 0; + ObClientAddress *address; + ObClientDescription *des; + ObClientAddressList *address_list; + ObClientConnectData *con_data; + + if (OB_ISNULL(tns_service) || OB_ISNULL(dblink) || OB_ISNULL(dblink_len)) { + ret = -1; + } else if (0 == tns_service->description_count || OB_ISNULL(des = tns_service->description)) { + ret = -1; + } else if (0 == des->address_list_count || OB_ISNULL(address_list = des->address_list)) { + ret = -1; + } else if (0 == address_list->address_count || OB_ISNULL(address = address_list->address)){ + ret = -1; + } else if (OB_ISNULL(con_data = des->connect_data)) { + ret = -1; + } else { + int tmp_dblink_len = 0; + if (con_data->use_default_sid) { + // get dblink from address, host:port, use default schema + tmp_dblink_len = snprintf(dblink, OBCLIENT_TNS_KEY_SIZE, "%.*s:%d", address->host_len, address->host, address->port); + } else { + // get dblink from address, host:port/service_name + tmp_dblink_len = snprintf(dblink, OBCLIENT_TNS_KEY_SIZE, "%.*s:%d/%.*s", + address->host_len, address->host, address->port, con_data->service_name_len, con_data->service_name); + } + if (tmp_dblink_len <= 0) { + ret = -1; + } else { + *dblink_len = tmp_dblink_len; + } + } + + return ret; +} + +int ObClientDescriptionCheck(ObClientDescription *des) +{ + int ret = 0; + if (OB_ISNULL(des)) { + ret = -1; + } else { + if (des->address_list_count == des->address_list_memory) { + int new_memory = des->address_list_memory + OBCLIENT_TNS_MEMORY_COUNT; + char * tmp = realloc(des->address_list, new_memory * sizeof(ObClientAddressList)); + if (tmp) { + des->address_list = (ObClientAddressList*)tmp; + des->address_list_memory = new_memory; + } else { + ret = -1; + } + } + } + return ret; +} + +int ObClientDescriptionInit(ObClientDescription *des) +{ + int ret = 0; + + if (OB_ISNULL(des)) { + ret = -1; + } else { + memset(des, 0, sizeof(*des)); + if (OB_FAIL(ObClientBlacklistConfInit(&des->black_list_conf))) { + ret = -1; + } else if (OB_FAIL(ObClientDescriptionCheck(des))) { + ret = -1; + } else { + ObClientAddressList *address_list = &(des->address_list[0]); + ObClientAddressListInit(address_list); + des->address_list_count = 1; //默认的0给非address list 使用 + + des->connect_data = NULL; + des->retry_all_downs = 120; // 默认执行120次 + des->retry_timeout = 10000; // 超时时间,默认10s + des->connect_timout = 0; // 超时时间,默认0s, 也就是一直等待 + des->read_timout = 0; // 读取时间,默认0s, 也就是一直等待 + des->write_timout = 0; // 发送时间,默认0s, 也就是一直等待 + des->oblb = FALSE; + des->oblb_group_strategy = OBCLIENT_LB_OPTION_GROUP_ROTATION; + } + } + + return ret; +} + +int ObClientDescriptionClear(ObClientDescription *des) +{ + int ret = 0; + + if (OB_ISNULL(des)) { + ret = 0; + } else { + if (OB_ISNULL(des->address_list) || 0 == des->address_list_memory) { + ret = 0; + } else { + unsigned int i; + for (i = 0; i < des->address_list_count && OB_SUCC(ret); ++i) { + ObClientAddressList *address_list = &(des->address_list[i]); + ObClientAddressListClear(address_list); + } + free(des->address_list); + des->address_list = NULL; + des->address_list_count = 0; + des->address_list_memory = 0; + } + + if (OB_NOT_NULL(des->connect_data)) { + ObClientConnectDataClear(des->connect_data); + free(des->connect_data); + des->connect_data = NULL; + } + } + + return ret; +} + +int ObClientDescriptionDisplay(ObClientDescription *des, FILE *display_file) +{ + int ret = 0; + + if (OB_ISNULL(des) || OB_ISNULL(display_file) || 0 == des->address_list_count || OB_ISNULL(des->address_list)) { + ret = -1; + } else { + unsigned int i; + + fprintf(display_file, "----Discription:\n"); + fprintf(display_file, "------oblb:%d\n", des->oblb); + fprintf(display_file, "------oblb_group_strategy:%d\n", des->oblb_group_strategy); + fprintf(display_file, "------retry_all_downs:%ld\n", des->retry_all_downs); + fprintf(display_file, "------retry_timeout:%ld\n", des->retry_timeout); + fprintf(display_file, "------connect_timeout:%ld\n", des->connect_timout); + fprintf(display_file, "------read_timeout:%ld\n", des->read_timout); + fprintf(display_file, "------write_timeout:%ld\n", des->write_timout); + fprintf(display_file, "------append_strategy:%d\n", des->black_list_conf.append_strategy); + fprintf(display_file, "------remove_strategy:%d\n", des->black_list_conf.remove_strategy); + fprintf(display_file, "------remove_timeout:%ld\n", des->black_list_conf.remove_timeout); + fprintf(display_file, "------duration:%ld\n", des->black_list_conf.duration); + fprintf(display_file, "------retry_times:%ld\n", des->black_list_conf.retry_times); + fprintf(display_file, "------address_list_count:%u\n", des->address_list_count); + + for (i = 0; i < des->address_list_count && OB_SUCC(ret); ++i) { + ObClientAddressListDisplay(&(des->address_list[i]), display_file); + } + + if (OB_NOT_NULL(des->connect_data)) { + ObClientConnectDataDisplay(des->connect_data, display_file); + } + } + + return ret; +} + +int ObClientDescriptionBuild(ObClientTnsService *tns_service, ObClientTnsParseParams *parse_params) +{ + int ret = 0; + ObClientDescription *des = NULL; + + if (OB_ISNULL(tns_service) || OB_ISNULL(parse_params)) { + ret = -1; + } else if (OB_FAIL(ObClientTnsServiceCheck(tns_service))) { + ret = -1; + } else if (OB_ISNULL(des = &(tns_service->description[tns_service->description_count]))) { + ret = -1; + } else if (OB_FAIL(ObClientDescriptionInit(des))) { + ret = -1; + } else { + // 进入解析description流程 + // 循环处理pair + while (OB_SUCC(ret)) { + // 解析左括号 + TNS_PARSE(parse_params, TNS_LEFT_PARENTHESES); + // 解析key + TNS_PARSE(parse_params, TNS_KEY); + // 得到key type + TNS_GET_KEY_TYPE(parse_params); + // 解析等于号, 上面得到的key不会被覆盖 + TNS_PARSE(parse_params, TNS_EQUAL_SIGN); + // 这里处理所有description下面的选项 + if (OB_SUCC(ret)) { + if (OBCLIENT_LB_OBLB == parse_params->key_type) { + TNS_PARSE(parse_params, TNS_KEY); + if (0 == strncasecmp(parse_params->tns_key, "ON", parse_params->tns_key_len)) { + des->oblb = TRUE; + } else if (0 == strncasecmp(parse_params->tns_key, "OFF", parse_params->tns_key_len)) { + des->oblb = FALSE; + } else { + ret = -1; + } + } else if (OBCLIENT_LB_OBLB_RETRY_ALL_DOWNS == parse_params->key_type) { + TNS_PARSE_INTRGER_VALUE(parse_params, des->retry_all_downs); + } else if (OBCLIENT_LB_OBLB_RETRY_TIMEOUT == parse_params->key_type) { + TNS_PARSE_INTRGER_VALUE(parse_params, des->retry_timeout); + } else if (OBCLIENT_LB_CONNECT_TIMEOUT == parse_params->key_type) { + TNS_PARSE_INTRGER_VALUE(parse_params, des->connect_timout); + } else if (OBCLIENT_LB_READ_TIMEOUT == parse_params->key_type) { + TNS_PARSE_INTRGER_VALUE(parse_params, des->read_timout); + } else if (OBCLIENT_LB_WRITE_TIMEOUT == parse_params->key_type) { + TNS_PARSE_INTRGER_VALUE(parse_params, des->write_timout); + } else if (OBCLIENT_LB_OBLB_GROUP_STRATEGY == parse_params->key_type) { + TNS_PARSE(parse_params, TNS_KEY); + if (0 == strncasecmp(parse_params->tns_key, "ROTATION", parse_params->tns_key_len)) { + des->oblb_group_strategy = OBCLIENT_LB_OPTION_GROUP_ROTATION; + } else { + ret = -1; + } + } else if (OBCLIENT_LB_OBLB_BLACKLIST == parse_params->key_type) { + ret = ObClientBlacklistConfBuild(&des->black_list_conf, parse_params); + } else if (OBCLIENT_LB_ADDRESS_LIST == parse_params->key_type) { + ret = ObClientAddressListBuild(des, parse_params); + } else if (OBCLIENT_LB_CONNECT_DATA == parse_params->key_type) { + ret = ObClientConnectDataBuild(des, parse_params); + } else if (OBCLIENT_LB_ADDRESS == parse_params->key_type) { + // 没有ADDRESSLIST的情况, 兼容之前结构 + ObClientAddressList* address_list = NULL; + if (OB_FAIL(ObClientDescriptionCheck(des))) { + ret = -1; + } else if (OB_ISNULL(address_list = &(des->address_list[0]))) { + ret = -1; + } else if (OB_FAIL(ObClientAddressBuild(address_list, parse_params))) { + ret = -1; + } + } else { + ret = -1; + } + } + TNS_PARSE(parse_params, TNS_RIGHT_PARENTHESES); + } + if (TNS_RIGHT_PARENTHESES == parse_params->tns_token_type) { + tns_service->description_count++; + ret = 0; + } else { + ret = -1; + } + } + + return ret; +} + +int ObClientRemoveStrategyBuild(ObClientBlacklistConf *black, ObClientTnsParseParams *parse_params) +{ + int ret = 0; + + if (OB_ISNULL(black) || OB_ISNULL(parse_params)) { + ret = -1; + } else { + // 进入解析流程 + // 循环处理pair + while (OB_SUCC(ret)) { + // 解析左括号 + TNS_PARSE(parse_params, TNS_LEFT_PARENTHESES); + // 解析key + TNS_PARSE(parse_params, TNS_KEY); + // 得到key type + TNS_GET_KEY_TYPE(parse_params); + // 解析等于号, 上面得到的key不会被覆盖 + TNS_PARSE(parse_params, TNS_EQUAL_SIGN); + // 这里处理所有下面的选项 + if (OB_SUCC(ret)) { + if (OBCLIENT_LB_NAME == parse_params->key_type) { + TNS_PARSE(parse_params, TNS_KEY); + if (0 == strncasecmp(parse_params->tns_key, "TIMEOUT", parse_params->tns_key_len)) { + black->remove_strategy = OBCLIENT_LB_OPTION_TIMEOUT; + } else { + ret = -1; + } + } else if (OBCLIENT_LB_TIMEOUT == parse_params->key_type) { + TNS_PARSE_INTRGER_VALUE(parse_params, black->remove_timeout); + } else { + ret = -1; + } + } + TNS_PARSE(parse_params, TNS_RIGHT_PARENTHESES); + } + if (TNS_RIGHT_PARENTHESES == parse_params->tns_token_type) { + ret = 0; + } else { + ret = -1; + } + } + + return ret; +} + +int ObClientAppendStrategyBuild(ObClientBlacklistConf *black, ObClientTnsParseParams *parse_params) +{ + int ret = 0; + + if (OB_ISNULL(black) || OB_ISNULL(parse_params)) { + ret = -1; + } else { + // 进入解析流程 + // 循环处理pair + while (OB_SUCC(ret)) { + // 解析左括号 + TNS_PARSE(parse_params, TNS_LEFT_PARENTHESES); + // 解析key + TNS_PARSE(parse_params, TNS_KEY); + // 得到key type + TNS_GET_KEY_TYPE(parse_params); + // 解析等于号, 上面得到的key不会被覆盖 + TNS_PARSE(parse_params, TNS_EQUAL_SIGN); + // 这里处理所有下面的选项 + if (OB_SUCC(ret)) { + if (OBCLIENT_LB_NAME == parse_params->key_type) { + TNS_PARSE(parse_params, TNS_KEY); + if (0 == strncasecmp(parse_params->tns_key, "RETRYDURATION", parse_params->tns_key_len)) { + black->append_strategy = OBCLIENT_LB_OPTION_RETRY_DERUATION; + } else { + ret = -1; + } + } else if (OBCLIENT_LB_RETRY_TIMES == parse_params->key_type) { + TNS_PARSE_INTRGER_VALUE(parse_params, black->retry_times); + } else if (OBCLIENT_LB_DRUATION == parse_params->key_type) { + TNS_PARSE_INTRGER_VALUE(parse_params, black->duration); + } else { + ret = -1; + } + } + TNS_PARSE(parse_params, TNS_RIGHT_PARENTHESES); + } + if (TNS_RIGHT_PARENTHESES == parse_params->tns_token_type) { + ret = 0; + } else { + ret = -1; + } + } + + return ret; +} + +// 默认黑名单策略:todo 和 jdbc对齐 +int ObClientBlacklistConfInit(ObClientBlacklistConf *black_list_conf) +{ + int ret = 0; + + if (OB_ISNULL(black_list_conf)) { + ret = -1; + } else { + memset(black_list_conf, 0, sizeof(*black_list_conf)); + black_list_conf->append_strategy = OBCLIENT_LB_OPTION_NORMAL; + black_list_conf->remove_strategy = OBCLIENT_LB_OPTION_TIMEOUT; + black_list_conf->retry_times = 1; // 默认1次 + black_list_conf->duration = 10; // 默认10ms + black_list_conf->remove_timeout = 50; // 默认50ms + } + + return ret; +} + +int ObClientBlacklistConfBuild(ObClientBlacklistConf *black_list_conf, ObClientTnsParseParams *parse_params) +{ + int ret = 0; + + if (OB_ISNULL(black_list_conf) || OB_ISNULL(parse_params)) { + ret = -1; + } else { + // 进入解析black_list_conf流程 + // 循环处理pair + while (OB_SUCC(ret)) { + // 解析左括号 + TNS_PARSE(parse_params, TNS_LEFT_PARENTHESES); + // 解析key + TNS_PARSE(parse_params, TNS_KEY); + // 得到key type + TNS_GET_KEY_TYPE(parse_params); + // 解析等于号, 上面得到的key不会被覆盖 + TNS_PARSE(parse_params, TNS_EQUAL_SIGN); + // 这里处理所有address_list下面的选项 + if (OB_SUCC(ret)) { + if (OBCLIENT_LB_REMOVE_STRATEGY == parse_params->key_type) { + ret = ObClientRemoveStrategyBuild(black_list_conf, parse_params); + } else if (OBCLIENT_LB_APPEND_STRATEGY == parse_params->key_type) { + ret = ObClientAppendStrategyBuild(black_list_conf, parse_params); + } else { + ret = -1; + } + } + TNS_PARSE(parse_params, TNS_RIGHT_PARENTHESES); + } + if (TNS_RIGHT_PARENTHESES == parse_params->tns_token_type) { + ret = 0; + } else { + ret = -1; + } + } + + return ret; +} + +int ObClientAddressListCheck(ObClientAddressList *address_list) +{ + int ret = 0; + if (OB_ISNULL(address_list)) { + ret = -1; + } else { + if (address_list->address_count == address_list->address_memory) { + int new_memory = address_list->address_memory + OBCLIENT_TNS_MEMORY_COUNT; + char *tmp = realloc(address_list->address, new_memory * sizeof(ObClientAddress)); + if (tmp) { + address_list->address = (ObClientAddress*)tmp; + address_list->address_memory = new_memory; + } else { + ret = -1; + } + } + } + return ret; +} +int ObClientAddressListInit(ObClientAddressList *address_list) +{ + int ret = 0; + + if (OB_ISNULL(address_list)) { + ret = -1; + } else { + memset(address_list, 0, sizeof(ObClientAddressList)); + ret = ObClientAddressListCheck(address_list); + } + + return ret; +} + +int ObClientAddressListClear(ObClientAddressList *address_list) +{ + int ret = 0; + if (OB_ISNULL(address_list)) { + ret = 0; + } else { + if (OB_ISNULL(address_list->address) || 0 == address_list->address_memory) { + ret = 0; + } else { + free(address_list->address); + address_list->address = NULL; + address_list->address_count = 0; + address_list->address_memory = 0; + } + } + return ret; +} + +int ObClientAddressListDisplay(ObClientAddressList *address_list, FILE *display_file) +{ + int ret = 0; + + if (OB_ISNULL(address_list) || OB_ISNULL(display_file) || OB_ISNULL(address_list->address) || 0 == address_list->address_count) { + ret = -1; + } else { + unsigned int i; + fprintf(display_file, "------AddressList:\n"); + fprintf(display_file, "--------address_count:%u\n", address_list->address_count); + fprintf(display_file, "--------oblb_strategy:%d\n", address_list->oblb_strategy); + for (i = 0; i < address_list->address_count && OB_SUCC(ret); ++i) { + ObClientAddressDisplay(&(address_list->address[i]), display_file); + } + } + + return ret; +} + +int ObClientAddressListBuild(ObClientDescription *des, ObClientTnsParseParams *parse_params) +{ + int ret = 0; + ObClientAddressList *address_list = NULL; + + if (OB_ISNULL(des) || OB_ISNULL(parse_params)) { + ret = -1; + } else if (OB_FAIL(ObClientDescriptionCheck(des))) { + ret = -1; + } else if (OB_ISNULL(address_list = &(des->address_list[des->address_list_count]))) { + ret = -1; + } else if (OB_FAIL(ObClientAddressListInit(address_list))) { + } else { + // 进入解析address_list流程 + // 循环处理pair + while (OB_SUCC(ret)) { + // 解析左括号 + TNS_PARSE(parse_params, TNS_LEFT_PARENTHESES); + // 解析key + TNS_PARSE(parse_params, TNS_KEY); + // 得到key type + TNS_GET_KEY_TYPE(parse_params); + // 解析等于号, 上面得到的key不会被覆盖 + TNS_PARSE(parse_params, TNS_EQUAL_SIGN); + // 这里处理所有address_list下面的选项 + if (OB_SUCC(ret)) { + if (OBCLIENT_LB_ADDRESS == parse_params->key_type) { + ret = ObClientAddressBuild(address_list, parse_params); + } else if (OBCLIENT_LB_OBLB_STRATEGY == parse_params->key_type) { + TNS_PARSE(parse_params, TNS_KEY); + if (0 == strncasecmp(parse_params->tns_key, "RANDOM", parse_params->tns_key_len)) { + address_list->oblb_strategy = OBCLIENT_LB_OPTION_RANDOM; + } else if (0 == strncasecmp(parse_params->tns_key, "SERVERAFFINITY", parse_params->tns_key_len)) { + address_list->oblb_strategy = OBCLIENT_LB_OPTION_SERVERAFFINITY; + } else if (0 == strncasecmp(parse_params->tns_key, "ROTATION", parse_params->tns_key_len)) { + address_list->oblb_strategy = OBCLIENT_LB_OPTION_ROTATION; + } else { + ret = -1; + } + } else if (OBCLIENT_LB_OBLB == parse_params->key_type) { + TNS_PARSE(parse_params, TNS_KEY); + if (0 == strncasecmp(parse_params->tns_key, "ON", parse_params->tns_key_len)) { + address_list->oblb = TRUE; + } else if (0 == strncasecmp(parse_params->tns_key, "OFF", parse_params->tns_key_len)) { + address_list->oblb = FALSE; + } else { + ret = -1; + } + } else { + ret = -1; + } + } + TNS_PARSE(parse_params, TNS_RIGHT_PARENTHESES); + } + if (TNS_RIGHT_PARENTHESES == parse_params->tns_token_type) { + des->address_list_count++; + ret = 0; + } else { + ret = -1; + } + } + + return ret; +} + +int ObClientAddressInit(ObClientAddress *address) +{ + int ret = 0; + + if (OB_ISNULL(address)) { + ret = -1; + } else { + memset(address, 0, sizeof(*address)); + address->weight = 1; + } + + return ret; +} + +int ObClientAddressClear(ObClientAddress *address) +{ + // now, do nothing + UNUSED(address); + return 0; +} + +int ObClientAddressDisplay(ObClientAddress *address, FILE *display_file) +{ + int ret = 0; + + if (OB_ISNULL(address) || OB_ISNULL(display_file)) { + ret = -1; + } else { + fprintf(display_file, "--------Address:\n"); + fprintf(display_file, "----------host:%.*s\n", address->host_len, address->host); + fprintf(display_file, "----------port:%d\n", address->port); + fprintf(display_file, "----------weight:%ld\n", address->weight); + } + + return ret; +} + +int ObClientAddressBuild(ObClientAddressList *address_list, ObClientTnsParseParams *parse_params) +{ + int ret = 0; + ObClientAddress *address = NULL; + + if (OB_ISNULL(address_list) || OB_ISNULL(parse_params)) { + ret = -1; + } else if (OB_FAIL(ObClientAddressListCheck(address_list))) { + ret = -1; + } else if (OB_ISNULL(address = &(address_list->address[address_list->address_count]))) { + ret = -1; + } else if (OB_FAIL(ObClientAddressInit(address))) { + ret = -1; + } else { + // 进入解析address流程 + // 循环处理pair + while (OB_SUCC(ret)) { + // 解析左括号 + TNS_PARSE(parse_params, TNS_LEFT_PARENTHESES); + // 解析key + TNS_PARSE(parse_params, TNS_KEY); + // 得到key type + TNS_GET_KEY_TYPE(parse_params); + // 解析等于号, 上面得到的key不会被覆盖 + TNS_PARSE(parse_params, TNS_EQUAL_SIGN); + // 这里处理所有address下面的选项 + if (OB_SUCC(ret)) { + if (OBCLIENT_LB_PROTOCOL == parse_params->key_type) { + TNS_PARSE_STRING_VALUE(parse_params, address->protocol, address->protocol_len, OBCLIENT_TNS_PORT_BUFFER_SIZE); + if (address->protocol_len != 3 || 0 != strncasecmp(address->protocol, "TCP", address->protocol_len)) { + ret = -1; + } + } else if (OBCLIENT_LB_HOST == parse_params->key_type) { + TNS_PARSE_STRING_VALUE(parse_params, address->host, address->host_len, OBCLIENT_TNS_HOST_BUFFER_SIZE); + } else if (OBCLIENT_LB_PORT == parse_params->key_type) { + TNS_PARSE_INTRGER_VALUE(parse_params, address->port); + } else if (OBCLIENT_LB_WEIGHT == parse_params->key_type) { + TNS_PARSE_INTRGER_VALUE(parse_params, address->weight); + } else { + ret = -1; + } + } + TNS_PARSE(parse_params, TNS_RIGHT_PARENTHESES); + } + if (TNS_RIGHT_PARENTHESES == parse_params->tns_token_type) { + // 正常结束, 没有data,并且是右括号结束 + address_list->address_count++; + ret = 0; + } else { + ret = -1; + } + } + + return ret; +} + +int ObClientConnectDataInit(ObClientConnectData *con_data) +{ + int ret = 0; + + if (OB_ISNULL(con_data)) { + ret = -1; + } else { + memset(con_data, 0, sizeof(*con_data)); + } + + return ret; +} + +int ObClientConnectDataClear(ObClientConnectData *con_data) +{ + // now, do nothing + UNUSED(con_data); + return 0; +} + +int ObClientConnectDataDisplay(ObClientConnectData *con_data, FILE *display_file) +{ + int ret = 0; + + if (OB_ISNULL(con_data) || OB_ISNULL(display_file)) { + ret = -1; + } else { + fprintf(display_file, "--------ConnectData:\n"); + fprintf(display_file, "----------dbname:%.*s\n", con_data->service_name_len, con_data->service_name); + if (0 != con_data->user_extra_info_len) { + fprintf(display_file, "----------extra_info:%.*s\n", con_data->user_extra_info_len, con_data->user_extra_info); + fprintf(display_file, "----------obmode:%ld\n", con_data->ob_mode); + fprintf(display_file, "----------use_default_sid:%ld\n", con_data->use_default_sid); + } + } + + return ret; +} + +int ObClientConnectDataBuild(ObClientDescription *des, ObClientTnsParseParams *parse_params) +{ + int ret = 0; + ObClientConnectData *connect_data = NULL; + + if (OB_ISNULL(des) || OB_ISNULL(parse_params)) { + ret = -1; + } else if (OB_ISNULL(connect_data = malloc(sizeof(*connect_data)))) { + ret = -1; + } else if (OB_FAIL(ObClientConnectDataInit(connect_data))) { + ret = -1; + } else { + int ret = 0; + // 进入解析conect_data流程 + // 循环处理pair + while (OB_SUCC(ret)) { + // 解析左括号 + TNS_PARSE(parse_params, TNS_LEFT_PARENTHESES); + // 解析key + TNS_PARSE(parse_params, TNS_KEY); + // 得到key type + TNS_GET_KEY_TYPE(parse_params); + // 解析等于号, 上面得到的key不会被覆盖 + TNS_PARSE(parse_params, TNS_EQUAL_SIGN); + // 这里处理所有address_list下面的选项 + if (OB_SUCC(ret)) { + if (OBCLIENT_LB_SERVICE_NAME == parse_params->key_type || OBCLIENT_LB_SID == parse_params->key_type) { + TNS_PARSE_STRING_VALUE(parse_params, connect_data->service_name, connect_data->service_name_len, OBCLIENT_TNS_KEY_SIZE); + } else if (OBCLIENT_LB_EXTRA_INFO == parse_params->key_type) { + TNS_PARSE_STRING_VALUE(parse_params, connect_data->user_extra_info, connect_data->user_extra_info_len, OBCLIENT_TNS_KEY_SIZE); + } else if (OBCLIENT_LB_OB_MODE == parse_params->key_type) { + TNS_PARSE_INTRGER_VALUE(parse_params, connect_data->ob_mode); + } else if (OBCLIENT_LB_USE_DEFAULT_SID == parse_params->key_type) { + TNS_PARSE_INTRGER_VALUE(parse_params, connect_data->use_default_sid); + } else { + ret = -1; + } + } + TNS_PARSE(parse_params, TNS_RIGHT_PARENTHESES); + } + if (TNS_RIGHT_PARENTHESES == parse_params->tns_token_type) { + // 正常结束, 没有data,并且是右括号结束 + if (OB_ISNULL(des->connect_data)) { + des->connect_data = connect_data; + ret = 0; + } else { + // error + free(connect_data); + ret = -1; + } + } else { + // 解析过程中出现错误,释放空间 + free(connect_data); + ret = -1; + } + } + + return ret; +} + +int ObClientSystemVariablesInit(ObClientSystemVariables *sys_vars) +{ + int ret = 0; + if (OB_ISNULL(sys_vars)) { + ret = -1; + } else { + memset(sys_vars, 0, sizeof(*sys_vars)); + sys_vars->session_variable_len = 0; + } + return ret; +} + +int ObClientSystemVariablesClear(ObClientSystemVariables *sys_vars) +{ + UNUSED(sys_vars); + return 0; +} + +int ObClientSystemVariablesDisplay(ObClientSystemVariables *sys_vars, FILE *display_file) +{ + int ret = 0; + + if (OB_ISNULL(sys_vars) || OB_ISNULL(display_file)) { + ret = -1; + } else { + fprintf(display_file, "--------SYSTEMVARIABLE:\n"); + fprintf(display_file, "----------SESSION_VARIABLE:%.*s\n", sys_vars->session_variable_len, sys_vars->session_variable); + } + + return ret; +} + +int ObClientSystemVariablesBuild(ObClientSystemVariables *sys_vars, ObClientTnsParseParams *parse_params) +{ + int ret = 0; + + if (OB_ISNULL(sys_vars) || OB_ISNULL(parse_params)) { + ret = -1; + } else { + if (OBCLIENT_LB_SESSION_VARIABLE == parse_params->key_type) { + TNS_PARSE_STRING_VALUE(parse_params, sys_vars->session_variable, sys_vars->session_variable_len, OBCLIENT_TNS_KEY_SIZE); + } else { + TNS_PARSE(parse_params, TNS_KEY); + ret = 0; + } + } + + return ret; +} + +int ObClientTnsCheckBuffer(ObClientTnsParseParams *parse_params) +{ + int ret = 0; + + if (OB_ISNULL(parse_params)) { + ret = -1; + } else if (OB_LIKELY(parse_params->buffer_pos < parse_params->buffer_len)) { + // there are still buffer, do nothing + } else { + if (parse_params->is_eof == TRUE) { + // eof, return error + ret = -1; + } else { + // no data in buffer + if (parse_params->mode == TNS_MODE_DESCRIPTION) { + int len = parse_params->description_len - parse_params->description_offset; + len = len > OBCLIENT_TNS_BUFFER_SIZE ? OBCLIENT_TNS_BUFFER_SIZE : len; + memcpy(parse_params->tns_buffer, parse_params->description + parse_params->description_offset, len); + parse_params->buffer_len = len; + parse_params->buffer_pos = 0; + parse_params->description_offset+=len; + if (0 == parse_params->buffer_len) { + parse_params->is_eof = 1; + ret = -1; + } + } else { + parse_params->buffer_len = fread(parse_params->tns_buffer, 1, OBCLIENT_TNS_BUFFER_SIZE, parse_params->tns_file); + parse_params->buffer_pos = 0; + if (0 == parse_params->buffer_len) { + parse_params->is_eof = 1; // set eof + ret = -1; + } + } + } + } + + return ret; +} + +int ObClientTnsParse(ObClientTnsParseParams *parse_params, ObClientTnsTokenType expect_type) +{ + int ret = 0; + + if (OB_ISNULL(parse_params)) { + ret = -1; + } else if (OB_FAIL(ObClientTnsParseBlank(parse_params))) { + ; + } else { + char ch = parse_params->tns_buffer[parse_params->buffer_pos]; + ObClientTnsTokenType got_type; + switch (ch) + { + case '=': + { + got_type = TNS_EQUAL_SIGN; + break; + } + case '(': + { + got_type = TNS_LEFT_PARENTHESES; + break; + } + case ')': + { + got_type = TNS_RIGHT_PARENTHESES; + break; + } + default: + { + got_type = TNS_KEY; + break; + } + } + if (got_type != expect_type) { + ret = -1; + } else if (TNS_KEY == got_type) { + parse_params->tns_token_type = got_type; + if (OB_FAIL(ObClientTnsParseKey(parse_params))) { + ; + } + } else { + // 除了key之外的token + parse_params->tns_token_type = got_type; + parse_params->buffer_pos++; + } + } + + return ret; +} + +int ObClientTnsParseBlank(ObClientTnsParseParams *parse_params) +{ + int ret = 0; + + if (OB_ISNULL(parse_params)) { + ret = -1; + } else { + char ch; + + while (OB_SUCC(ret)) { + if (OB_FAIL(ObClientTnsCheckBuffer(parse_params))) { + if (TRUE == parse_params->is_eof) { + ret = TNS_NO_DATA; + } else { + ; + } + } else { + while (parse_params->buffer_pos < parse_params->buffer_len) { + ch = parse_params->tns_buffer[parse_params->buffer_pos]; + if ('\t' == ch || '\n' == ch || ' ' == ch) { + parse_params->buffer_pos++; + } else if ('#' == ch) { // ignore comments + unsigned int tmp = parse_params->buffer_pos; + for (; tmp < parse_params->buffer_len; tmp++) { + char tmpch = parse_params->tns_buffer[tmp]; + if ('\n' == tmpch || '\0' == tmpch) + break; + } + parse_params->buffer_pos = tmp; + } else { + break; + } + } + if (parse_params->buffer_pos < parse_params->buffer_len) { + // jump to blank + break; + } + } + } + } + + return ret; +} + +int ObClientTnsParseKey(ObClientTnsParseParams *parse_params) +{ + int ret = 0; + + if (OB_ISNULL(parse_params)) { + ret = -1; + } else { + char ch; + unsigned int pos = 0; + ObClientTnsParseStatus parse_status = TNS_PARSE_NORMAL; + + while (OB_SUCC(ret)) { + if (OB_FAIL(ObClientTnsCheckBuffer(parse_params))) { + if (1 == parse_params->is_eof) { + ret = TNS_NO_DATA; + } else { + } + } else { + while (OB_SUCC(ret) && parse_params->buffer_pos < parse_params->buffer_len && pos < OBCLIENT_TNS_KEY_SIZE) { + if (TNS_PARSE_NORMAL == parse_status) { + ch = parse_params->tns_buffer[parse_params->buffer_pos]; + if ('\"' == ch) { + parse_status = TNS_PARSE_QUOTE; + parse_params->buffer_pos++; + } else if ((' ' != ch) && ('\n' != ch) && ('\r' != ch) + && ('\t' != ch) && ('=' != ch) && ('(' != ch) + && (')' != ch)) { + parse_params->tns_key[pos++] = ch; + parse_params->buffer_pos++; + } else { + break; + } + } else if (TNS_PARSE_QUOTE == parse_status) { + ch = parse_params->tns_buffer[parse_params->buffer_pos]; + if ('\"' == ch) { + parse_status = TNS_PARSE_NORMAL; + parse_params->buffer_pos++; + } else { + parse_params->tns_key[pos++] = ch; + parse_params->buffer_pos++; + } + } else { + ret = -1; + } + } + if (OB_SUCC(ret)) { + if (parse_params->buffer_pos < parse_params->buffer_len) { + parse_params->tns_key_len = pos; + break; + } else if (pos == OBCLIENT_TNS_KEY_SIZE) { + ret = -1; + } + } + } + } + } + + return ret; +} + +int ObClientTnsGetKeyType(ObClientTnsParseParams *parse_params) +{ + int ret = 0; + unsigned int arr_size = sizeof(tns_key_array_size) / sizeof(unsigned int)-1; + + if (OB_ISNULL(parse_params)) { + ret = -1; + } else { + if (parse_params->tns_key_len <= arr_size) { + unsigned int len = parse_params->tns_key_len; + const char **key_array = (const char **)tns_key_array[len]; + ObClientLBKeyType *keytype_array = (ObClientLBKeyType *)tns_keytype_array[len]; + unsigned int key_array_size = tns_key_array_size[len]; + parse_params->key_type = OBCLIENT_LB_ERROR_KEY; + + if (key_array_size) { + unsigned int i = 0; + for (; i < key_array_size; ++i) { + if (key_array[i] && 0 == strncasecmp(parse_params->tns_key, key_array[i], len)) { + parse_params->key_type = keytype_array[i]; + } + } + } + + if (OBCLIENT_LB_ERROR_KEY == parse_params->key_type) { + ret = -1; + } else { + ret = 0; + } + } else { + parse_params->key_type = OBCLIENT_LB_ERROR_KEY; + } + } + + return ret; +} + diff --git a/libmariadb/ob_tnsname.h b/libmariadb/ob_tnsname.h new file mode 100644 index 0000000..ed80dac --- /dev/null +++ b/libmariadb/ob_tnsname.h @@ -0,0 +1,264 @@ +#ifndef OCI_TNSNAME_H_ +#define OCI_TNSNAME_H_ +#include "mysql.h" +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define OBCLIENT_TNS_KEY_SIZE 256 +#define OBCLIENT_TNS_HOST_BUFFER_SIZE OBCLIENT_TNS_KEY_SIZE // 可能会有域名的形式,host很长 +#define OBCLIENT_TNS_PORT_BUFFER_SIZE 6 // 65535 +#define OBCLIENT_TNS_BUFFER_SIZE 1024 +#define OBCLIENT_TNS_MEMORY_COUNT 6 + +typedef struct obclient_tns ObClientTns; +typedef struct obclient_tns_service ObClientTnsService; +typedef struct obclient_description_list ObClientDescriptionList; +typedef struct obclient_description ObClientDescription; +typedef struct obclient_address_list ObClientAddressList; +typedef struct obclient_address ObClientAddress; +typedef struct obclient_connect_data ObClientConnectData; +typedef struct obclient_black_list_conf ObClientBlacklistConf; +typedef struct obclient_system_variables ObClientSystemVariables; +typedef struct obclient_tns_parse_params ObClientTnsParseParams; + +typedef enum enum_obclient_tns_parse_mode { + TNS_MODE_FILE = 1, + TNS_MODE_DESCRIPTION +}ObClientTnsParseMode; + +typedef enum obclient_tns_token_type +{ + TNS_EQUAL_SIGN, + TNS_LEFT_PARENTHESES, + TNS_RIGHT_PARENTHESES, + TNS_KEY, + TNS_ERROR_TYPE, + TNS_MAX_TOKEN_TYPE +} ObClientTnsTokenType; + +typedef enum obclient_tns_parse_status +{ + TNS_PARSE_NORMAL, + TNS_PARSE_QUOTE +} ObClientTnsParseStatus; + +// TNS File中的所有关键字, 解析TNS File时使用 +typedef enum enum_obclient_lb_key_type +{ + OBCLIENT_LB_ERROR_KEY, + OBCLIENT_LB_DESCRIPTION, + OBCLIENT_LB_OBLB, + OBCLIENT_LB_CONNECT_TIMEOUT, + OBCLIENT_LB_READ_TIMEOUT, + OBCLIENT_LB_WRITE_TIMEOUT, + OBCLIENT_LB_OBLB_GROUP_STRATEGY, + OBCLIENT_LB_OBLB_RETRY_ALL_DOWNS, + OBCLIENT_LB_OBLB_RETRY_TIMEOUT, + OBCLIENT_LB_OBLB_BLACKLIST, + OBCLIENT_LB_REMOVE_STRATEGY, + OBCLIENT_LB_NAME, + OBCLIENT_LB_TIMEOUT, + OBCLIENT_LB_APPEND_STRATEGY, + OBCLIENT_LB_RETRY_TIMES, + OBCLIENT_LB_DRUATION, + OBCLIENT_LB_ADDRESS_LIST, + OBCLIENT_LB_OBLB_STRATEGY, + OBCLIENT_LB_ADDRESS, + OBCLIENT_LB_PROTOCOL, + OBCLIENT_LB_HOST, + OBCLIENT_LB_PORT, + OBCLIENT_LB_WEIGHT, + OBCLIENT_LB_CONNECT_DATA, + OBCLIENT_LB_SERVICE_NAME, + OBCLIENT_LB_SID, + OBCLIENT_LB_EXTRA_INFO, + OBCLIENT_LB_OB_MODE, + OBCLIENT_LB_USE_DEFAULT_SID, + OBCLIENT_LB_SESSION_VARIABLE, + OBCLIENT_LB_MAX_KEY_TYPE +} ObClientLBKeyType; + +/* +0 - 1000 表示group LB策略 +1001 - 2000 表示每个组内LB的策略 +2001 - 3000 表示黑名单删除策略 +3001 - 4000 表示黑名单加入策略 +*/ +typedef enum enum_obclient_lb_option +{ + // GROUP + OBCLIENT_LB_OPTION_GROUP_ROTATION = 0, // 组内轮询 + // INTERNEL + OBCLIENT_LB_OPTION_RANDOM = 1001, // 随机 + OBCLIENT_LB_OPTION_SERVERAFFINITY, // 加权随机 + OBCLIENT_LB_OPTION_ROTATION, // 轮询 + // BLACK LIST DELETE OPTION + OBCLIENT_LB_OPTION_TIMEOUT = 2001, // 超时删除 + // BLACK LIST INSERT OPTION + OBCLIENT_LB_OPTION_RETRY_DERUATION = 3001, // 时间段内失败多少次加入黑名单 + OBCLIENT_LB_OPTION_NORMAL = 3002, // 直接拉黑 + OBCLIENT_LB_OPTION_MAX +} ObClientLBOption; + +struct obclient_system_variables +{ + char session_variable[OBCLIENT_TNS_KEY_SIZE + 1]; + unsigned long session_variable_len; +}; + +struct obclient_tns +{ + ObClientTnsService *tns_service; + unsigned long tns_service_count; +}; + +struct obclient_tns_service +{ + ObClientDescription *description; + unsigned long description_count; + unsigned long description_memory; + ObClientSystemVariables sys_vars; + unsigned long net_service_name_len; + char net_service_name[OBCLIENT_TNS_BUFFER_SIZE]; +}; + +struct obclient_black_list_conf +{ + ObClientLBOption remove_strategy; + unsigned long remove_timeout; + ObClientLBOption append_strategy; + unsigned long retry_times; + unsigned long duration; +}; + +struct obclient_description +{ + ObClientAddressList *address_list; + unsigned long address_list_count; + unsigned long address_list_memory; + ObClientConnectData *connect_data; + // more member + my_bool oblb; // TRUE on/ FALSE off + unsigned long retry_all_downs; + unsigned long connect_timout; // 单次连接的超时时间 + unsigned long read_timout; // 单次读的超时时间 + unsigned long write_timout; // 单次写的超时时间 + unsigned long retry_timeout; // 整个LB阶段的超时时间 + ObClientLBOption oblb_group_strategy; + ObClientBlacklistConf black_list_conf; +}; + +struct obclient_address_list +{ + ObClientAddress *address; + unsigned long address_count; + unsigned long address_memory; + my_bool oblb; // TRUE on/ FALSE off + ObClientLBOption oblb_strategy; +}; + +struct obclient_address +{ + char host[OBCLIENT_TNS_HOST_BUFFER_SIZE + 1]; // 长度加一为了调用mysql接口时加上结尾0 + char protocol[OBCLIENT_TNS_PORT_BUFFER_SIZE]; + unsigned long host_len; + unsigned long protocol_len; + unsigned long port; + unsigned long weight; +}; + +struct obclient_connect_data +{ + char service_name[OBCLIENT_TNS_KEY_SIZE + 1]; // 长度加一为了调用mysql接口时加上结尾0 + unsigned int service_name_len; + char user_extra_info[OBCLIENT_TNS_KEY_SIZE]; + unsigned int user_extra_info_len; + unsigned long ob_mode; + unsigned long use_default_sid; +}; + +struct obclient_tns_parse_params +{ + char tns_buffer[OBCLIENT_TNS_BUFFER_SIZE]; + char tns_key[OBCLIENT_TNS_KEY_SIZE]; + unsigned int buffer_pos; + unsigned int buffer_len; + unsigned int tns_key_len; + int is_eof; + int mode; //1=file,2=description + char *tns_name; + FILE *tns_file; + char *description; + int description_len; + int description_offset; + ObClientTnsTokenType tns_token_type; + ObClientLBKeyType key_type; +}; + + +int ObClientTnsInit(ObClientTns *tns); +int ObClientTnsClear(ObClientTns *tns); +int ObClientTnsDisplay(ObClientTns *tns); +int ObClientTnsBuild(ObClientTns *tns, const char *dbname, unsigned int dbname_len, my_bool *find); +int ObClientTnsBuildDes(ObClientTns *tns, const char *dbname, unsigned int dbname_len, my_bool *find); + +int ObClientTnsServiceCheck(ObClientTnsService *tns_service); +int ObClientTnsServiceInit(ObClientTnsService *tns_service, unsigned int name_size, const char *name); +int ObClientTnsServiceClear(ObClientTnsService *tns_service); +int ObClientTnsServiceDisplay(ObClientTnsService *tns_service, FILE *display_file); +int ObClientTnsServiceBuild(ObClientTns *tns, ObClientTnsParseParams *parse_params); +int ObClientTnsServiceSkip(ObClientTnsParseParams *parse_params); +// 非负载均衡模式下获取extra info +int ObClientTnsServiceExtraInfoGet(ObClientTnsService *tns_service, char *extra_info, int *extra_info_len, int *ob_mode); +// 非负载均衡模式下获取dblink, 直接获取第一个address,拼接dblink +int ObClientTnsServiceDblinkGet(ObClientTnsService *tns_service, char *dblink, int *dblink_len); + +int ObClientDescriptionCheck(ObClientDescription *des); +int ObClientDescriptionInit(ObClientDescription *des); +int ObClientDescriptionClear(ObClientDescription *des); +int ObClientDescriptionDisplay(ObClientDescription *des, FILE *display_file); +int ObClientDescriptionBuild(ObClientTnsService *tns, ObClientTnsParseParams *parse_params); + +int ObClientBlacklistConfInit(ObClientBlacklistConf *black_list_conf); +int ObClientBlacklistConfBuild(ObClientBlacklistConf *black, ObClientTnsParseParams *parse_params); +int ObClientRemoveStrategyBuild(ObClientBlacklistConf *black, ObClientTnsParseParams *parse_params); +int ObClientAppendStrategyBuild(ObClientBlacklistConf *black, ObClientTnsParseParams *parse_params); + +int ObClientAddressListCheck(ObClientAddressList *address_list); +int ObClientAddressListInit(ObClientAddressList *address_list); +int ObClientAddressListClear(ObClientAddressList *address_list); +int ObClientAddressListDisplay(ObClientAddressList *address_list, FILE *display_file); +int ObClientAddressListBuild(ObClientDescription *des, ObClientTnsParseParams *parse_params); + +int ObClientAddressInit(ObClientAddress *address); +int ObClientAddressClear(ObClientAddress *address); +int ObClientAddressDisplay(ObClientAddress *address, FILE *display_file); +int ObClientAddressBuild(ObClientAddressList *address_list, ObClientTnsParseParams *parse_params); + +int ObClientConnectDataInit(ObClientConnectData *con_data); +int ObClientConnectDataClear(ObClientConnectData *con_data); +int ObClientConnectDataDisplay(ObClientConnectData *con_data, FILE *display_file); +int ObClientConnectDataBuild(ObClientDescription *des, ObClientTnsParseParams *parse_params); + +int ObClientSystemVariablesInit(ObClientSystemVariables *sys_vars); +int ObClientSystemVariablesClear(ObClientSystemVariables *sys_vars); +int ObClientSystemVariablesDisplay(ObClientSystemVariables *sys_vars, FILE *display_file); +int ObClientSystemVariablesBuild(ObClientSystemVariables *sys_vars, ObClientTnsParseParams *parse_params); + +// 解析文件相关函数 +int ObClientTnsParse(ObClientTnsParseParams *parse_params, ObClientTnsTokenType expect_type); +int ObClientTnsCheckBuffer(ObClientTnsParseParams *parse_params); +int ObClientTnsParseBlank(ObClientTnsParseParams *parse_params); +int ObClientTnsParseKey(ObClientTnsParseParams *parse_params); +int ObClientTnsGetKeyType(ObClientTnsParseParams *parse_params); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libmariadb/ob_utils.c b/libmariadb/ob_utils.c new file mode 100644 index 0000000..1abc9d4 --- /dev/null +++ b/libmariadb/ob_utils.c @@ -0,0 +1,36 @@ +#include "ob_utils.h" + +#ifdef _WIN32 +int gettimeofday(struct timeval *tp, void *tzp) +{ + time_t clock; + struct tm tm; + SYSTEMTIME wtm; + + GetLocalTime(&wtm); + tm.tm_year = wtm.wYear - 1900; + tm.tm_mon = wtm.wMonth - 1; + tm.tm_mday = wtm.wDay; + tm.tm_hour = wtm.wHour; + tm.tm_min = wtm.wMinute; + tm.tm_sec = wtm.wSecond; + tm.tm_isdst = -1; + + clock = mktime(&tm); + tp->tv_sec = clock; + tp->tv_usec = wtm.wMilliseconds * 1000; + return (0); +} +#endif + +int ob_gettimeofday(struct timeval *tp, void *tzp) +{ + return gettimeofday(tp, tzp); +} + +int64_t get_current_time_us() +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec * 1000000 + tv.tv_usec; +} diff --git a/plugins/pvio/pvio_npipe.c b/plugins/pvio/pvio_npipe.c index 17c59ce..ae18f19 100644 --- a/plugins/pvio/pvio_npipe.c +++ b/plugins/pvio/pvio_npipe.c @@ -62,7 +62,8 @@ struct st_ma_pvio_methods pvio_npipe_methods= { pvio_npipe_is_blocking, pvio_npipe_is_alive, NULL, - pvio_npipe_shutdown + pvio_npipe_shutdown, + NULL }; #ifndef PLUGIN_DYNAMIC diff --git a/plugins/pvio/pvio_shmem.c b/plugins/pvio/pvio_shmem.c index f412393..d4fce98 100644 --- a/plugins/pvio/pvio_shmem.c +++ b/plugins/pvio/pvio_shmem.c @@ -60,7 +60,8 @@ struct st_ma_pvio_methods pvio_shm_methods= { NULL, pvio_shm_is_alive, NULL, - pvio_shm_shutdown + pvio_shm_shutdown, + NULL }; #ifndef PLUGIN_DYNAMIC diff --git a/plugins/pvio/pvio_socket.c b/plugins/pvio/pvio_socket.c index 225f3be..c88a8f5 100644 --- a/plugins/pvio/pvio_socket.c +++ b/plugins/pvio/pvio_socket.c @@ -108,6 +108,7 @@ my_bool pvio_socket_is_blocking(MARIADB_PVIO *pvio); my_bool pvio_socket_is_alive(MARIADB_PVIO *pvio); my_bool pvio_socket_has_data(MARIADB_PVIO *pvio, ssize_t *data_len); int pvio_socket_shutdown(MARIADB_PVIO *pvio); +int pvio_socket_socket5_auth(MARIADB_PVIO *pvio, char *user, char *pwd, char *host, unsigned short port); static int pvio_socket_init(char *unused1, size_t unused2, @@ -134,7 +135,8 @@ struct st_ma_pvio_methods pvio_socket_methods= { pvio_socket_is_blocking, pvio_socket_is_alive, pvio_socket_has_data, - pvio_socket_shutdown + pvio_socket_shutdown, + pvio_socket_socket5_auth }; #ifndef PLUGIN_DYNAMIC @@ -1126,3 +1128,161 @@ int pvio_socket_shutdown(MARIADB_PVIO *pvio) } return -1; } + +static int socket5_auth(int socket, char *user, char *pwd, char *host, unsigned short port) { +#define SOCKET5_VERSION 5 +#define SOCKET5_ERROR -2 +#define ATYPE_IPV4 1 +#define ATYPE_DOMAIN 3 +#define ATYPE_IPV6 4 + + int len = 0; + char sendbuf[512] = { 0 }; + char recvbuf[512] = { 0 }; + int auth_success = 0; + int request_success = -1; + int support_method = -1; + int response_ver = -1; + + + //printf("socket:%d, user=%s, pwd=%s, host=%s, port=%d\n", socket, user ? user : "", pwd ? pwd : "", host ? host : "", port); + + //shake hands + { + char *shakehands = sendbuf; + shakehands[0] = SOCKET5_VERSION; + shakehands[1] = 0x01; + if (user == NULL || pwd == NULL || strlen(user) == 0 || strlen(pwd) == 0) { + shakehands[2] = 0x00; + } else { + shakehands[2] = 0x02; + } + + if (3 != send(socket, shakehands, 3, 0)) { + return SOCKET_ERROR; + } + if (2 != recv(socket, recvbuf, 2, 0)) { + return SOCKET_ERROR; + } + response_ver = recvbuf[0]; + support_method = recvbuf[1]; + //printf("shakehands ver:%d, method:%d\n", response_ver, support_method); + } + + if (response_ver != SOCKET5_VERSION || + (support_method != 0x00 && support_method != 0x02)) { + return SOCKET5_ERROR; + } + + //auth user,password + if (support_method == 0x02) { + char *auth = sendbuf; + char *pos = auth; + char *puser = (char*)(user ? user : ""); + char *ppwd = (char*)(pwd ? pwd : ""); + *pos++ = SOCKET5_VERSION; + *pos++ = (unsigned char)strlen(puser); + memcpy(pos, puser, strlen(puser)); + pos += strlen(puser); + *pos++ = (unsigned char)strlen(ppwd); + memcpy(pos, ppwd, strlen(ppwd)); + pos += strlen(ppwd); + + len = 3 + strlen(puser) + strlen(ppwd); + if (len != send(socket, auth, len, 0)) { + return SOCKET_ERROR; + } + if (2 != recv(socket, recvbuf, 2, 0)) { + return SOCKET_ERROR; + } + response_ver = recvbuf[0]; + auth_success = recvbuf[1]; + //printf("auth ver:%d, status:%d\n", recvbuf[0], recvbuf[1]); + } + + if (response_ver != SOCKET5_VERSION || auth_success != 0) { + return SOCKET5_ERROR; + } + + //request + if (0 == auth_success) { + char* request = sendbuf; + char *pos = request; + char atyp = 0; + if (strchr(host, ':')) { + atyp = ATYPE_IPV6; + } else { + int i = 0; + bool domain = 0; + for (i = 0; i < (int)strlen(host); i++) { + if ((host[i] >= '0' &&host[i] <= '9') || host[i] == '.') { + continue; + } else { + domain = 1; + break; + } + } + atyp = domain ? ATYPE_DOMAIN : ATYPE_IPV4; + } + *pos++ = SOCKET5_VERSION; + *pos++ = 0x01; //1=connect,2=bind,3=udp, default connect + *pos++ = 0x00; + *pos++ = atyp; //1=ipv4 (4),3=domain,4=ipv6(16) + if (atyp == ATYPE_IPV4) { //ipv4 + unsigned int *addr = (unsigned int*)pos; + *addr = inet_addr(host); + pos += 4; + } else if (atyp == ATYPE_DOMAIN) { //domain + *pos++ = (unsigned char)strlen(host); + memcpy(pos, host, strlen(host)); + pos += strlen(host); + } else { //ipv6 + if (1 != inet_pton(AF_INET6, host, pos)) { + return SOCKET5_ERROR; + } + pos += 16; + } + unsigned short *pport = (unsigned short*)pos; + *pport = htons(port); + pos += 2; + + len = pos - request; + if (len != send(socket, request, len, 0)) { + return SOCKET_ERROR; + } + if (4 != recv(socket, recvbuf, 4, 0)) { + return SOCKET_ERROR; + } + response_ver = recvbuf[0]; + request_success = recvbuf[1]; + //printf("request recv:ver=%d, rep=%d, atyp=%d\n", recvbuf[0], recvbuf[1], recvbuf[3]); + + { + int will = 2; //port + if (recvbuf[3] == ATYPE_IPV4) { //ipv4 + will += 4; + } else if (recvbuf[3] = ATYPE_DOMAIN) { //domain + if (1 != recv(socket, recvbuf, 1, 0)) + return SOCKET_ERROR; + will += recvbuf[0]; + } else { //ipv6 + will += 16; + } + if (will != recv(socket, recvbuf, will, 0)) { + return SOCKET_ERROR; + } + } + } + return request_success; +} +int pvio_socket_socket5_auth(MARIADB_PVIO *pvio, char *user, char *pwd, char *host, unsigned short port) +{ + struct st_pvio_socket *csock = NULL; + int ret = 0; + + if (!pvio || !pvio->data) + return -1; + + csock = (struct st_pvio_socket *)pvio->data; + return socket5_auth(csock->socket, user, pwd, host, port); +} diff --git a/rpm/libobclient-VER.txt b/rpm/libobclient-VER.txt index 5859406..bda8fbe 100644 --- a/rpm/libobclient-VER.txt +++ b/rpm/libobclient-VER.txt @@ -1 +1 @@ -2.2.3 +2.2.6 diff --git a/rpm/libobclient.spec b/rpm/libobclient.spec index 4c66d99..4dd3578 100644 --- a/rpm/libobclient.spec +++ b/rpm/libobclient.spec @@ -1,6 +1,6 @@ Name: %NAME Version: %VERSION -Release: %(echo %RELEASE)%{?dist} +Release: %(echo %RELEASE) License: LGPL Group: applications/database buildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root @@ -14,7 +14,7 @@ LibObClient is a driver used to connect applications developed in C to OceanBase %define MYSQL_USER root %define MYSQL_GROUP root %define __os_install_post %{nil} -%define base_dir /u01/mysql +#%define base_dir /u01/mysql %define file_dir /app/mariadb @@ -54,11 +54,12 @@ rm -rf $RPM_BUILD_ROOT %pre %post -if [ -d %{base_dir} ]; then - cp -rf %{prefix}/* %{base_dir} -else - cp -rf %{prefix} %{base_dir} -fi +#if [ -d %{base_dir} ]; then +# cp -rf %{prefix}/* %{base_dir} +#else +# cp -rf %{prefix} %{base_dir} +#fi + %preun %changelog