diff --git a/.travis.yml b/.travis.yml index f4054de1..5d836f1e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,10 @@ sudo: true language: c +cache: + apt: true + ccache: true services: docker + addons: hosts: - mariadb.example.com @@ -9,12 +13,8 @@ before_script: # Disable services enabled by default - sudo /etc/init.d/mysql stop - before_install: - - chmod +x .travis/script.sh - - chmod +x .travis/gen-ssl.sh - - chmod +x .travis/build/build.sh - - chmod +x .travis/build/docker-entrypoint.sh + - chmod -R +x .travis/* - chmod 777 .travis/build/ - export PROJ_PATH=`pwd` - export ENTRYPOINT=$PROJ_PATH/.travis/sql @@ -24,6 +24,8 @@ before_install: matrix: allow_failures: - env: DB=build + - env: SERVER_BRANCH=10.4 + - env: SERVER_BRANCH=10.4 TEST_OPTION=--ps-protocol include: - env: DB=build - env: DB=mysql:5.7 @@ -32,8 +34,14 @@ matrix: - env: DB=mariadb:10.1 - env: DB=mariadb:10.2 - env: DB=mariadb:10.3 + - env: SERVER_BRANCH=10.3 + - env: SERVER_BRANCH=10.3 TEST_OPTION=--ps-protocol + - env: SERVER_BRANCH=10.4 + - env: SERVER_BRANCH=10.4 TEST_OPTION=--ps-protocol script: - if [ "$DB" = "build" ] ; then .travis/build/build.sh; fi - if [ "$DB" = "build" ] ; then docker build -t build:latest --label build .travis/build/; fi - - .travis/script.sh + - if [ -z "$DB" ] ; then .travis/server-replace-submodule.sh; fi + - if [ -n "$DB" ] ; then .travis/script.sh; fi + diff --git a/CMakeLists.txt b/CMakeLists.txt index 4dd13987..8466ce43 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,7 +24,7 @@ get_directory_property(IS_SUBPROJECT PARENT_DIRECTORY) # do not inherit include directories from the parent project SET_PROPERTY(DIRECTORY PROPERTY INCLUDE_DIRECTORIES) -FOREACH(V WITH_MYSQLCOMPAT WITH_MSI WITH_SIGNCODE WITH_RTC WITH_UNITTEST +FOREACH(V WITH_MYSQLCOMPAT WITH_MSI WITH_SIGNCODE WITH_RTC WITH_UNIT_TESTS WITH_DYNCOL WITH_EXTERNAL_ZLIB WITH_CURL WITH_SQLITE WITH_SSL INSTALL_LAYOUT WITH_TEST_SRCPKG) SET(${V} ${${OPT}${V}}) diff --git a/include/errmsg.h b/include/errmsg.h index f4af5288..481b0a62 100644 --- a/include/errmsg.h +++ b/include/errmsg.h @@ -85,6 +85,9 @@ extern const char *mariadb_client_errors[]; /* Error messages */ #define CR_AUTH_PLUGIN_CANNOT_LOAD 2059 #define CR_DUPLICATE_CONNECTION_ATTR 2060 #define CR_AUTH_PLUGIN_ERR 2061 +/* Always last, if you add new error codes please update the + value for CR_MYSQL_LAST_ERROR */ +#define CR_MYSQL_LAST_ERROR CR_AUTH_PLUGIN_ERR /* * MariaDB Connector/C errors: @@ -96,5 +99,8 @@ extern const char *mariadb_client_errors[]; /* Error messages */ #define CR_FILE_NOT_FOUND 5004 #define CR_FILE_READ 5005 #define CR_BULK_WITHOUT_PARAMETERS 5006 - +#define CR_INVALID_STMT 5007 +/* Always last, if you add new error codes please update the + value for CR_MARIADB_LAST_ERROR */ +#define CR_MARIADB_LAST_ERROR CR_INVALID_STMT #endif diff --git a/include/ma_pvio.h b/include/ma_pvio.h index 38e68ebf..7e300fee 100644 --- a/include/ma_pvio.h +++ b/include/ma_pvio.h @@ -98,7 +98,7 @@ struct st_ma_pvio_methods ssize_t (*write)(MARIADB_PVIO *pvio, const uchar *buffer, size_t length); ssize_t (*async_write)(MARIADB_PVIO *pvio, const uchar *buffer, size_t length); int (*wait_io_or_timeout)(MARIADB_PVIO *pvio, my_bool is_read, int timeout); - my_bool (*blocking)(MARIADB_PVIO *pvio, my_bool value, my_bool *old_value); + int (*blocking)(MARIADB_PVIO *pvio, my_bool value, my_bool *old_value); my_bool (*connect)(MARIADB_PVIO *pvio, MA_PVIO_CINFO *cinfo); my_bool (*close)(MARIADB_PVIO *pvio); int (*fast_send)(MARIADB_PVIO *pvio); diff --git a/include/ma_string.h b/include/ma_string.h index f00f4805..10325387 100644 --- a/include/ma_string.h +++ b/include/ma_string.h @@ -33,4 +33,23 @@ size_t ma_gcvt(double x, my_gcvt_arg_type type, int width, char *to, my_bool *error); char *ma_ll2str(long long val,char *dst, int radix); +#define MAX_ENV_SIZE 1024 + +static inline my_bool ma_check_env_str(const char *env) +{ + unsigned int i; + + if (!env) + return 1; + + for (i=0; i < MAX_ENV_SIZE; i++) + { + if (env[i] == 0) + break; + } + if (i >= MAX_ENV_SIZE) + return 1; + return 0; +} + #endif diff --git a/include/ma_sys.h b/include/ma_sys.h index e0515dd6..431c758f 100644 --- a/include/ma_sys.h +++ b/include/ma_sys.h @@ -524,6 +524,9 @@ extern const char *ma_get_type(TYPELIB *typelib,uint nr); extern my_bool ma_init_dynamic_string(DYNAMIC_STRING *str, const char *init_str, size_t init_alloc, size_t alloc_increment); extern my_bool ma_dynstr_append(DYNAMIC_STRING *str, const char *append); +extern my_bool ma_dynstr_append_quoted(DYNAMIC_STRING *str, + const char *append, size_t len, + char quote); my_bool ma_dynstr_append_mem(DYNAMIC_STRING *str, const char *append, size_t length); extern my_bool ma_dynstr_set(DYNAMIC_STRING *str, const char *init_str); diff --git a/include/mariadb_dyncol.h b/include/mariadb_dyncol.h index f2c13aa3..a6084fd9 100644 --- a/include/mariadb_dyncol.h +++ b/include/mariadb_dyncol.h @@ -225,7 +225,7 @@ void mariadb_dyncol_free(DYNAMIC_COLUMN *str); /* conversion of values to 3 base types */ enum enum_dyncol_func_result mariadb_dyncol_val_str(DYNAMIC_STRING *str, DYNAMIC_COLUMN_VALUE *val, - MARIADB_CHARSET_INFO *cs, my_bool quote); + MARIADB_CHARSET_INFO *cs, char quote); enum enum_dyncol_func_result mariadb_dyncol_val_long(longlong *ll, DYNAMIC_COLUMN_VALUE *val); enum enum_dyncol_func_result diff --git a/include/mariadb_stmt.h b/include/mariadb_stmt.h index 5e1c7110..8d676450 100644 --- a/include/mariadb_stmt.h +++ b/include/mariadb_stmt.h @@ -37,8 +37,8 @@ #define SET_CLIENT_STMT_ERROR(a, b, c, d) \ { \ (a)->last_errno= (b);\ - strncpy((a)->sqlstate, (c), sizeof((a)->sqlstate));\ - strncpy((a)->last_error, (d) ? (d) : ER((b)), sizeof((a)->last_error));\ + strncpy((a)->sqlstate, (c), SQLSTATE_LENGTH);\ + strncpy((a)->last_error, (d) ? (d) : ER((b)), MYSQL_ERRMSG_SIZE - 1);\ } #define CLEAR_CLIENT_STMT_ERROR(a) \ diff --git a/include/mysql.h b/include/mysql.h index 727eddea..08525e82 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -124,8 +124,8 @@ extern unsigned int mariadb_deinitialize_ssl; #define SET_CLIENT_ERROR(a, b, c, d) \ { \ (a)->net.last_errno= (b);\ - strncpy((a)->net.sqlstate, (c), sizeof((a)->net.sqlstate));\ - strncpy((a)->net.last_error, (d) ? (d) : ER((b)), sizeof((a)->net.last_error));\ + strncpy((a)->net.sqlstate, (c), SQLSTATE_LENGTH);\ + strncpy((a)->net.last_error, (d) ? (d) : ER((b)), MYSQL_ERRMSG_SIZE - 1);\ } /* For mysql_async.c */ @@ -409,8 +409,8 @@ typedef struct character_set { unsigned int number; /* character set number */ unsigned int state; /* character set state */ - const char *csname; /* collation name */ - const char *name; /* character set name */ + const char *csname; /* character set name */ + const char *name; /* collation name */ const char *comment; /* comment */ const char *dir; /* character set directory */ unsigned int mbminlen; /* min. length for multibyte strings */ diff --git a/libmariadb/get_password.c b/libmariadb/get_password.c index d5d17bb1..4a93a738 100644 --- a/libmariadb/get_password.c +++ b/libmariadb/get_password.c @@ -65,7 +65,7 @@ static char *get_password(FILE *file, char *buffer, int length) !CharsProcessed) break; #else - inChar= fgetc(file); + inChar= (char)fgetc(file); #endif switch(inChar) { diff --git a/libmariadb/ma_charset.c b/libmariadb/ma_charset.c index 49a50abe..c6fbe0d1 100644 --- a/libmariadb/ma_charset.c +++ b/libmariadb/ma_charset.c @@ -1408,7 +1408,7 @@ static void map_charset_name(const char *cs_name, my_bool target_cs, char *buffe if (target_cs) { - strncat(buffer, "//TRANSLIT", buff_len); + strncat(buffer, "//TRANSLIT", buff_len - strlen(buffer)); } } /* }}} */ diff --git a/libmariadb/ma_client_plugin.c.in b/libmariadb/ma_client_plugin.c.in index 8d61d317..1b18c0bb 100644 --- a/libmariadb/ma_client_plugin.c.in +++ b/libmariadb/ma_client_plugin.c.in @@ -237,11 +237,11 @@ static void load_env_plugins(MYSQL *mysql) { char *plugs, *free_env, *s= getenv("LIBMYSQL_PLUGINS"); - /* no plugins to load */ - if (!s) + if (ma_check_env_str(s)) return; - free_env= plugs= strdup(s); + free_env= strdup(s); + plugs= s= free_env; do { if ((s= strchr(plugs, ';'))) @@ -365,7 +365,7 @@ mysql_load_plugin_v(MYSQL *mysql, const char *name, int type, char errbuf[1024]; #endif char dlpath[FN_REFLEN+1]; - void *sym, *dlhandle; + void *sym, *dlhandle = NULL; struct st_mysql_client_plugin *plugin; char *env_plugin_dir= getenv("MARIADB_PLUGIN_DIR"); @@ -448,6 +448,8 @@ mysql_load_plugin_v(MYSQL *mysql, const char *name, int type, return plugin; err: + if (dlhandle) + dlclose(dlhandle); pthread_mutex_unlock(&LOCK_load_client_plugin); my_set_error(mysql, CR_AUTH_PLUGIN_CANNOT_LOAD, SQLSTATE_UNKNOWN, ER(CR_AUTH_PLUGIN_CANNOT_LOAD), name, errmsg); diff --git a/libmariadb/ma_default.c b/libmariadb/ma_default.c index 17670e8d..a9ffdfcb 100644 --- a/libmariadb/ma_default.c +++ b/libmariadb/ma_default.c @@ -231,12 +231,7 @@ static my_bool _mariadb_read_options_from_file(MYSQL *mysql, key= ptr; for ( ; isspace(end[-1]) ; end--) ; *end= 0; - if (!value) - { - if (!key) - key= ptr; - } - else + if (value) { /* Remove pre- and end space */ char *value_end; diff --git a/libmariadb/ma_dtoa.c b/libmariadb/ma_dtoa.c index 5d67f7b5..9ba0387b 100644 --- a/libmariadb/ma_dtoa.c +++ b/libmariadb/ma_dtoa.c @@ -1333,7 +1333,9 @@ static char *dtoa(double dd, int mode, int ndigits, int *decpt, int *sign, *sign= 0; /* If infinity, set decpt to DTOA_OVERFLOW, if 0 set it to 1 */ + /* coverity[assign_where_compare_meant] */ if (((word0(&u) & Exp_mask) == Exp_mask && (*decpt= DTOA_OVERFLOW)) || + /* coverity[assign_where_compare_meant] */ (!dval(&u) && (*decpt= 1))) { /* Infinity, NaN, 0 */ diff --git a/libmariadb/ma_errmsg.c b/libmariadb/ma_errmsg.c index d668c779..ab0a8a38 100644 --- a/libmariadb/ma_errmsg.c +++ b/libmariadb/ma_errmsg.c @@ -142,7 +142,7 @@ const char *client_errors[]= /* 2057 */ "The number of parameters in bound buffers differs from number of columns in resultset", /* 2059 */ "Can't connect twice. Already connected", /* 2058 */ "Plugin %s could not be loaded: %s", -/* 2059 */ "An attribute with same name already exists" +/* 2059 */ "An attribute with same name already exists", /* 2060 */ "Plugin doesn't support this function", "" }; @@ -157,6 +157,7 @@ const char *mariadb_client_errors[] = /* 5004 */ "File '%s' not found (Errcode: %d)", /* 5005 */ "Error reading file '%s' (Errcode: %d)", /* 5006 */ "Bulk operation without parameters is not supported", + /* 5007 */ "Invalid statement handle", "" }; diff --git a/libmariadb/ma_io.c b/libmariadb/ma_io.c index 7ce34adb..178ffe9f 100644 --- a/libmariadb/ma_io.c +++ b/libmariadb/ma_io.c @@ -108,6 +108,7 @@ MA_FILE *ma_open(const char *location, const char *mode, MYSQL *mysql) ma_file= (MA_FILE *)malloc(sizeof(MA_FILE)); if (!ma_file) { + fclose(fp); my_set_error(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0); return NULL; } diff --git a/libmariadb/ma_net.c b/libmariadb/ma_net.c index 07460eb8..15be4fce 100644 --- a/libmariadb/ma_net.c +++ b/libmariadb/ma_net.c @@ -549,7 +549,6 @@ ulong ma_net_read(NET *net) return packet_error; if (_mariadb_uncompress((unsigned char*) net->buff + net->where_b, &packet_length, &complen)) { - len= packet_error; net->error=2; /* caller will close socket */ net->last_errno=ER_NET_UNCOMPRESS_ERROR; break; diff --git a/libmariadb/ma_pvio.c b/libmariadb/ma_pvio.c index dc263fe2..8f9afc7b 100644 --- a/libmariadb/ma_pvio.c +++ b/libmariadb/ma_pvio.c @@ -102,10 +102,10 @@ MARIADB_PVIO *ma_pvio_init(MA_PVIO_CINFO *cinfo) return NULL; } - +/* coverity[var_deref_op] */ if (!(pvio= (MARIADB_PVIO *)calloc(1, sizeof(MARIADB_PVIO)))) { - PVIO_SET_ERROR(cinfo->mysql, CR_OUT_OF_MEMORY, unknown_sqlstate, 0); + my_set_error(cinfo->mysql, CR_OUT_OF_MEMORY, unknown_sqlstate, 0); return NULL; } @@ -399,20 +399,23 @@ end: void ma_pvio_close(MARIADB_PVIO *pvio) { /* free internal structures and close connection */ -#ifdef HAVE_TLS - if (pvio && pvio->ctls) + if (pvio) { - ma_pvio_tls_close(pvio->ctls); - free(pvio->ctls); - } +#ifdef HAVE_TLS + if (pvio->ctls) + { + ma_pvio_tls_close(pvio->ctls); + free(pvio->ctls); + } #endif - if (pvio && pvio->methods->close) - pvio->methods->close(pvio); + if (pvio && pvio->methods->close) + pvio->methods->close(pvio); - if (pvio->cache) - free(pvio->cache); + if (pvio->cache) + free(pvio->cache); - free(pvio); + free(pvio); + } } /* }}} */ @@ -460,13 +463,16 @@ ma_pvio_wait_async(struct mysql_async_context *b, enum enum_pvio_io_event event, /* {{{ ma_pvio_wait_io_or_timeout */ int ma_pvio_wait_io_or_timeout(MARIADB_PVIO *pvio, my_bool is_read, int timeout) { - if (IS_PVIO_ASYNC_ACTIVE(pvio)) - return ma_pvio_wait_async(pvio->mysql->options.extension->async_context, - (is_read) ? VIO_IO_EVENT_READ : VIO_IO_EVENT_WRITE, - timeout); + if (pvio) + { + if (IS_PVIO_ASYNC_ACTIVE(pvio)) + return ma_pvio_wait_async(pvio->mysql->options.extension->async_context, + (is_read) ? VIO_IO_EVENT_READ : VIO_IO_EVENT_WRITE, + timeout); - if (pvio && pvio->methods->wait_io_or_timeout) - return pvio->methods->wait_io_or_timeout(pvio, is_read, timeout); + if (pvio && pvio->methods->wait_io_or_timeout) + return pvio->methods->wait_io_or_timeout(pvio, is_read, timeout); + } return 1; } /* }}} */ @@ -484,7 +490,7 @@ my_bool ma_pvio_connect(MARIADB_PVIO *pvio, MA_PVIO_CINFO *cinfo) my_bool ma_pvio_blocking(MARIADB_PVIO *pvio, my_bool block, my_bool *previous_mode) { if (pvio && pvio->methods->blocking) - return pvio->methods->blocking(pvio, block, previous_mode); + return pvio->methods->blocking(pvio, block, previous_mode) != 0; return 1; } /* }}} */ diff --git a/libmariadb/ma_stmt_codec.c b/libmariadb/ma_stmt_codec.c index 1260e494..d2b51544 100644 --- a/libmariadb/ma_stmt_codec.c +++ b/libmariadb/ma_stmt_codec.c @@ -198,42 +198,90 @@ double my_atod(const char *number, const char *end, int *error) my_bool str_to_TIME(const char *str, size_t length, MYSQL_TIME *tm) { - my_bool is_time=0, is_date=0, has_time_frac=0; - char *p= (char *)str; + char *start= alloca(length + 1); + my_bool is_date= 0, is_time= 0; - if ((p= strchr(str, '-')) && p <= str + length) - is_date= 1; - if ((p= strchr(str, ':')) && p <= str + length) - is_time= 1; - if ((p= strchr(str, '.')) && p <= str + length) - has_time_frac= 1; - - p= (char *)str; - memset(tm, 0, sizeof(MYSQL_TIME)); + if (!start) + goto error; + tm->time_type= MYSQL_TIMESTAMP_NONE; + + memcpy(start, str, length); + start[length]= '\0'; + + while (length && isspace(*start)) start++, length--; + + if (!length) + goto error; + + /* negativ value? */ + if (*start == '-') + { + tm->neg= 1; + start++; + length--; + } + + if (!length) + return 1; + + /* Determine time type: + MYSQL_TIMESTAMP_DATE: [-]YY[YY].MM.DD + MYSQL_TIMESTAMP_DATETIME: [-]YY[YY].MM.DD hh:mm:ss.mmmmmm + MYSQL_TIMESTAMP_TIME: [-]hh:mm:ss.mmmmmm + */ + if (strchr(start, '-')) + { + if (tm->neg) + goto error; + tm->time_type= MYSQL_TIMESTAMP_DATE; + if (sscanf(start, "%d-%d-%d", &tm->year, &tm->month, &tm->day) < 3) + goto error; + is_date= 1; + if (!(start= strchr(start, ' '))) + goto check; + } + if (!strchr(start, ':')) + goto check; + + is_time= 1; + if (tm->time_type== MYSQL_TIMESTAMP_DATE) + tm->time_type= MYSQL_TIMESTAMP_DATETIME; + else + tm->time_type= MYSQL_TIMESTAMP_TIME; + + if (strchr(start, '.')) /* fractional seconds */ + { + if (sscanf(start, "%d:%d:%d.%ld", &tm->hour, &tm->minute, + &tm->second,&tm->second_part) < 4) + goto error; + } else { + if (sscanf(start, "%d:%d:%d", &tm->hour, &tm->minute, + &tm->second) < 3) + goto error; + } + +check: + if (tm->time_type == MYSQL_TIMESTAMP_NONE) + goto error; if (is_date) { - sscanf(str, "%d-%d-%d", &tm->year, &tm->month, &tm->day); - p= strchr(str, ' '); - if (!p) - { - tm->time_type= MYSQL_TIMESTAMP_DATE; - return 0; - } - } - if (has_time_frac) - { - sscanf(p, "%d:%d:%d.%ld", &tm->hour, &tm->minute, &tm->second, &tm->second_part); - tm->time_type= (is_date) ? MYSQL_TIMESTAMP_DATETIME : MYSQL_TIMESTAMP_TIME; - return 0; + if (tm->year < 69) + tm->year+= 2000; + else if (tm->year < 100) + tm->year+= 1900; + if (tm->day > 31 || tm->month > 12) + goto error; } if (is_time) { - sscanf(p, "%d:%d:%d", &tm->hour, &tm->minute, &tm->second); - tm->time_type= (is_date) ? MYSQL_TIMESTAMP_DATETIME : MYSQL_TIMESTAMP_TIME; - return 0; + if (tm->minute > 59 || tm->second > 59) + goto error; } + return 0; +error: + tm->time_type= MYSQL_TIMESTAMP_ERROR; return 1; } @@ -394,7 +442,8 @@ static void convert_from_long(MYSQL_BIND *r_param, const MYSQL_FIELD *field, lon len < field->length && len < r_param->buffer_length) { ma_bmove_upp(buffer + field->length, buffer + len, len); - memset((char*) buffer, '0', field->length - len); + /* coverity [bad_memset] */ + memset((void*) buffer, (int) '0', field->length - len); len= field->length; } convert_froma_string(r_param, buffer, len); @@ -612,7 +661,8 @@ static void convert_from_float(MYSQL_BIND *r_param, const MYSQL_FIELD *field, fl if (field->length < length || field->length > MAX_DOUBLE_STRING_REP_LENGTH - 1) break; ma_bmove_upp(buff + field->length, buff + length, length); - memset((char*) buff, '0', field->length - length); + /* coverity [bad_memset] */ + memset((void*) buff, (int) '0', field->length - length); length= field->length; } @@ -711,7 +761,8 @@ static void convert_from_double(MYSQL_BIND *r_param, const MYSQL_FIELD *field, d if (field->length < length || field->length > MAX_DOUBLE_STRING_REP_LENGTH - 1) break; ma_bmove_upp(buff + field->length, buff + length, length); - memset((char*) buff, '0', field->length - length); + /* coverity [bad_memset] */ + memset((void*) buff, (int) '0', field->length - length); length= field->length; } convert_froma_string(r_param, buff, length); diff --git a/libmariadb/ma_string.c b/libmariadb/ma_string.c index 9e8773eb..9a62e06e 100644 --- a/libmariadb/ma_string.c +++ b/libmariadb/ma_string.c @@ -92,6 +92,36 @@ my_bool ma_dynstr_append(DYNAMIC_STRING *str, const char *append) return ma_dynstr_append_mem(str,append,strlen(append)); } +my_bool ma_dynstr_append_quoted(DYNAMIC_STRING *str, + const char *append, size_t len, + char quote) +{ + size_t additional= str->alloc_increment; + size_t lim= additional; + uint i; + + if (ma_dynstr_realloc(str, len + additional + 2)) + return TRUE; + str->str[str->length++]= quote; + for (i= 0; i < len; i++) + { + register char c= append[i]; + if (c == quote || c == '\\') + { + if (!lim) + { + if (ma_dynstr_realloc(str, additional)) + return TRUE; + lim= additional; + } + lim--; + str->str[str->length++]= '\\'; + } + str->str[str->length++]= c; + } + str->str[str->length++]= quote; + return FALSE; +} my_bool ma_dynstr_append_mem(DYNAMIC_STRING *str, const char *append, size_t length) diff --git a/libmariadb/ma_time.c b/libmariadb/ma_time.c index 5b4087b0..460c32d4 100644 --- a/libmariadb/ma_time.c +++ b/libmariadb/ma_time.c @@ -34,7 +34,7 @@ size_t mariadb_time_to_string(const MYSQL_TIME *tm, char *time_str, size_t len, return 0; if (digits == AUTO_SEC_PART_DIGITS) - digits= MIN((tm->second_part) ? SEC_PART_DIGITS : 0, 15); + digits= (tm->second_part) ? SEC_PART_DIGITS : 0; switch(tm->time_type) { case MYSQL_TIMESTAMP_DATE: diff --git a/libmariadb/ma_tls.c b/libmariadb/ma_tls.c index 7629bcaa..3090d49e 100644 --- a/libmariadb/ma_tls.c +++ b/libmariadb/ma_tls.c @@ -130,7 +130,7 @@ const char *ma_pvio_tls_get_protocol_version(MARIADB_TLS *ctls) return tls_protocol_version[version]; } -static char ma_hex2int(char c) +static signed char ma_hex2int(char c) { if (c >= '0' && c <= '9') return c - '0'; @@ -161,7 +161,7 @@ static my_bool ma_pvio_tls_compare_fp(const char *cert_fp, for(c= (char *)cert_fp; c < cert_fp + cert_fp_len; c++) { - char d1, d2; + signed char d1, d2; if (*p == ':') p++; if (p - fp > (int)fp_len -1) diff --git a/libmariadb/mariadb_dyncol.c b/libmariadb/mariadb_dyncol.c index 63be7772..96f9a0fa 100644 --- a/libmariadb/mariadb_dyncol.c +++ b/libmariadb/mariadb_dyncol.c @@ -1681,7 +1681,10 @@ dynamic_new_column_store(DYNAMIC_COLUMN *str, goto err; } if (!column_count) + { + free(columns_order); return ER_DYNCOL_OK; + } memset(str->str, 0, fmt->fixed_hdr); str->length= fmt->fixed_hdr; @@ -2755,7 +2758,7 @@ dynamic_column_update_copy(DYNAMIC_COLUMN *str, PLAN *plan, new_hdr->header_size + new_hdr->nmpool_size; for (i= 0, j= 0; i < add_column_count || j < hdr->column_count; i++) { - size_t UNINIT_VAR(first_offset); + size_t first_offset= 0; uint start= j, end; /* @@ -3612,7 +3615,6 @@ end: create_new_string: /* There is no columns from before, so let's just add the new ones */ rc= ER_DYNCOL_OK; - free(alloc_plan); if (not_null != 0) rc= dynamic_column_create_many_internal_fmt(str, add_column_count, (uint*)column_keys, values, @@ -3887,10 +3889,9 @@ mariadb_dyncol_val_str(DYNAMIC_STRING *str, DYNAMIC_COLUMN_VALUE *val, return ER_DYNCOL_RESOURCE; } if (quote) - rc= ma_dynstr_append_mem(str, "e, 1); - rc= ma_dynstr_append_mem(str, from, len); - if (quote) - rc= ma_dynstr_append_mem(str, "e, 1); + rc= ma_dynstr_append_quoted(str, from, len, quote); + else + rc= ma_dynstr_append_mem(str, from, len); if (alloc) free(alloc); if (rc) @@ -3946,7 +3947,7 @@ mariadb_dyncol_val_long(longlong *ll, DYNAMIC_COLUMN_VALUE *val) break; case DYN_COL_UINT: *ll= (longlong)val->x.ulong_value; - if (val->x.ulong_value > ULONGLONG_MAX) + if (*ll > (longlong)ULONGLONG_MAX) rc= ER_DYNCOL_TRUNCATED; break; case DYN_COL_DOUBLE: diff --git a/libmariadb/mariadb_lib.c b/libmariadb/mariadb_lib.c index 53212e67..4adf6e7b 100644 --- a/libmariadb/mariadb_lib.c +++ b/libmariadb/mariadb_lib.c @@ -229,7 +229,7 @@ restart: } else { - strcpy(net->sqlstate, SQLSTATE_UNKNOWN); + strncpy(net->sqlstate, SQLSTATE_UNKNOWN, SQLSTATE_LENGTH); } ma_strmake(net->last_error,(char*) pos, min(len,sizeof(net->last_error)-1)); @@ -947,7 +947,8 @@ int mthd_my_read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, ulong *lengths) if (len > (ulong) (end_pos - pos) || pos > end_pos) { mysql->net.last_errno=CR_UNKNOWN_ERROR; - strcpy(mysql->net.last_error,ER(mysql->net.last_errno)); + strncpy(mysql->net.last_error,ER(mysql->net.last_errno), + MYSQL_ERRMSG_SIZE - 1); return -1; } row[field] = (char*) pos; @@ -984,6 +985,7 @@ mysql_init(MYSQL *mysql) { memset((char*) (mysql), 0, sizeof(*(mysql))); mysql->net.pvio= 0; + mysql->free_me= 0; mysql->net.extension= 0; } @@ -1189,8 +1191,7 @@ MYSQL *mthd_my_real_connect(MYSQL *mysql, const char *host, const char *user, uint port, const char *unix_socket, unsigned long client_flag) { char buff[NAME_LEN+USERNAME_LENGTH+100]; - char *end, *end_pkt, *host_info, - *charset_name= NULL; + char *end, *end_pkt, *host_info; MA_PVIO_CINFO cinfo= {NULL, NULL, 0, -1, NULL}; MARIADB_PVIO *pvio= NULL; char *scramble_data; @@ -1385,9 +1386,8 @@ MYSQL *mthd_my_real_connect(MYSQL *mysql, const char *host, const char *user, } /* Save connection information */ if (!user) user=""; - if (!passwd) passwd=""; - if (!(mysql->host_info= strdup(host_info ? host_info : "")) || + if (!(mysql->host_info= strdup(host_info)) || !(mysql->host= strdup(cinfo.host ? cinfo.host : "")) || !(mysql->user=strdup(user)) || !(mysql->passwd=strdup(passwd))) @@ -1489,7 +1489,8 @@ MYSQL *mthd_my_real_connect(MYSQL *mysql, const char *host, const char *user, { net->last_errno=CR_CANT_READ_CHARSET; sprintf(net->last_error,ER(net->last_errno), - charset_name ? charset_name : "unknown", + mysql->options.charset_name ? mysql->options.charset_name : + "unknown", "compiled_in"); goto error; } @@ -1606,6 +1607,7 @@ my_bool STDCALL mariadb_reconnect(MYSQL *mysql) } mysql_init(&tmp_mysql); + tmp_mysql.free_me= 0; tmp_mysql.options=mysql->options; if (mysql->extension->conn_hdlr) { @@ -1721,13 +1723,6 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user, *s_db= mysql->db; int rc; - if (!user) - user=""; - if (!passwd) - passwd=""; - if (!db) - db=""; - if (mysql->options.charset_name) mysql->charset =mysql_find_charset_name(mysql->options.charset_name); else @@ -1778,8 +1773,11 @@ mysql_select_db(MYSQL *mysql, const char *db) { int error; + if (!db) + return 1; + if ((error=ma_simple_command(mysql, COM_INIT_DB, db, - db ? (uint) strlen(db) : 0,0,0))) + (uint) strlen(db),0,0))) return(error); free(mysql->db); mysql->db=strdup(db); @@ -1978,67 +1976,84 @@ mysql_send_query(MYSQL* mysql, const char* query, unsigned long length) return ma_simple_command(mysql, COM_QUERY, query, length, 1,0); } -int mthd_my_read_query_result(MYSQL *mysql) +int ma_read_ok_packet(MYSQL *mysql, uchar *pos, ulong length) { - uchar *pos; - ulong field_count; - MYSQL_DATA *fields; - ulong length; + size_t item_len; + mysql->affected_rows= net_field_length_ll(&pos); + mysql->insert_id= net_field_length_ll(&pos); + mysql->server_status=uint2korr(pos); + pos+=2; + mysql->warning_count=uint2korr(pos); + pos+=2; + if (pos < mysql->net.read_pos+length) + { + if ((item_len= net_field_length(&pos))) + mysql->info=(char*) pos; - if (!mysql || (length = ma_net_safe_read(mysql)) == packet_error) - { - return(1); - } - free_old_query(mysql); /* Free old result */ -get_info: - pos=(uchar*) mysql->net.read_pos; - if ((field_count= net_field_length(&pos)) == 0) - { - size_t item_len; - mysql->affected_rows= net_field_length_ll(&pos); - mysql->insert_id= net_field_length_ll(&pos); - mysql->server_status=uint2korr(pos); - pos+=2; - mysql->warning_count=uint2korr(pos); - pos+=2; - if (pos < mysql->net.read_pos+length) + /* check if server supports session tracking */ + if (mysql->server_capabilities & CLIENT_SESSION_TRACKING) { - if ((item_len= net_field_length(&pos))) - mysql->info=(char*) pos; + ma_clear_session_state(mysql); + pos+= item_len; - /* check if server supports session tracking */ - if (mysql->server_capabilities & CLIENT_SESSION_TRACKING) + if (mysql->server_status & SERVER_SESSION_STATE_CHANGED) { - ma_clear_session_state(mysql); - pos+= item_len; - - if (mysql->server_status & SERVER_SESSION_STATE_CHANGED) + int i; + if (pos < mysql->net.read_pos + length) { - int i; - if (pos < mysql->net.read_pos + length) + LIST *session_item; + MYSQL_LEX_STRING *str= NULL; + enum enum_session_state_type si_type; + uchar *old_pos= pos; + size_t item_len= net_field_length(&pos); /* length for all items */ + + /* length was already set, so make sure that info will be zero terminated */ + if (mysql->info) + *old_pos= 0; + + while (item_len > 0) { - LIST *session_item; - MYSQL_LEX_STRING *str= NULL; - enum enum_session_state_type si_type; - uchar *old_pos= pos; - size_t item_len= net_field_length(&pos); /* length for all items */ + size_t plen; + char *data; + old_pos= pos; + si_type= (enum enum_session_state_type)net_field_length(&pos); + switch(si_type) { + case SESSION_TRACK_SCHEMA: + case SESSION_TRACK_STATE_CHANGE: + case SESSION_TRACK_TRANSACTION_CHARACTERISTICS: + case SESSION_TRACK_SYSTEM_VARIABLES: + net_field_length(&pos); /* ignore total length, item length will follow next */ + plen= net_field_length(&pos); + if (!ma_multi_malloc(0, + &session_item, sizeof(LIST), + &str, sizeof(MYSQL_LEX_STRING), + &data, plen, + NULL)) + { + SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0); + return -1; + } + str->length= plen; + str->str= data; + memcpy(str->str, (char *)pos, plen); + pos+= plen; + session_item->data= str; + mysql->extension->session_state[si_type].list= list_add(mysql->extension->session_state[si_type].list, session_item); - /* length was already set, so make sure that info will be zero terminated */ - if (mysql->info) - *old_pos= 0; - - while (item_len > 0) - { - size_t plen; - char *data; - old_pos= pos; - si_type= (enum enum_session_state_type)net_field_length(&pos); - switch(si_type) { - case SESSION_TRACK_SCHEMA: - case SESSION_TRACK_STATE_CHANGE: - case SESSION_TRACK_TRANSACTION_CHARACTERISTICS: - case SESSION_TRACK_SYSTEM_VARIABLES: - net_field_length(&pos); /* ignore total length, item length will follow next */ + /* in case schema has changed, we have to update mysql->db */ + if (si_type == SESSION_TRACK_SCHEMA) + { + free(mysql->db); + mysql->db= malloc(plen + 1); + memcpy(mysql->db, str->str, plen); + mysql->db[plen]= 0; + } + else if (si_type == SESSION_TRACK_SYSTEM_VARIABLES) + { + my_bool set_charset= 0; + /* make sure that we update charset in case it has changed */ + if (!strncmp(str->str, "character_set_client", str->length)) + set_charset= 1; plen= net_field_length(&pos); if (!ma_multi_malloc(0, &session_item, sizeof(LIST), @@ -2055,68 +2070,54 @@ get_info: pos+= plen; session_item->data= str; mysql->extension->session_state[si_type].list= list_add(mysql->extension->session_state[si_type].list, session_item); - - /* in case schema has changed, we have to update mysql->db */ - if (si_type == SESSION_TRACK_SCHEMA) + if (set_charset && + strncmp(mysql->charset->csname, str->str, str->length) != 0) { - free(mysql->db); - mysql->db= malloc(plen + 1); - memcpy(mysql->db, str->str, plen); - mysql->db[plen]= 0; + char cs_name[64]; + MARIADB_CHARSET_INFO *cs_info; + memcpy(cs_name, str->str, str->length); + cs_name[str->length]= 0; + if ((cs_info = (MARIADB_CHARSET_INFO *)mysql_find_charset_name(cs_name))) + mysql->charset= cs_info; } - else if (si_type == SESSION_TRACK_SYSTEM_VARIABLES) - { - my_bool set_charset= 0; - /* make sure that we update charset in case it has changed */ - if (!strncmp(str->str, "character_set_client", str->length)) - set_charset= 1; - plen= net_field_length(&pos); - if (!ma_multi_malloc(0, - &session_item, sizeof(LIST), - &str, sizeof(MYSQL_LEX_STRING), - &data, plen, - NULL)) - { - SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0); - return -1; - } - str->length= plen; - str->str= data; - memcpy(str->str, (char *)pos, plen); - pos+= plen; - session_item->data= str; - mysql->extension->session_state[si_type].list= list_add(mysql->extension->session_state[si_type].list, session_item); - if (set_charset && - strncmp(mysql->charset->csname, str->str, str->length) != 0) - { - char cs_name[64]; - MARIADB_CHARSET_INFO *cs_info; - memcpy(cs_name, str->str, str->length); - cs_name[str->length]= 0; - if ((cs_info = (MARIADB_CHARSET_INFO *)mysql_find_charset_name(cs_name))) - mysql->charset= cs_info; - } - } - break; - default: - /* not supported yet */ - plen= net_field_length(&pos); - pos+= plen; - break; } - item_len-= (pos - old_pos); + break; + default: + /* not supported yet */ + plen= net_field_length(&pos); + pos+= plen; + break; } + item_len-= (pos - old_pos); } - for (i= SESSION_TRACK_BEGIN; i <= SESSION_TRACK_END; i++) - { - mysql->extension->session_state[i].list= list_reverse(mysql->extension->session_state[i].list); - mysql->extension->session_state[i].current= mysql->extension->session_state[i].list; - } + } + for (i= SESSION_TRACK_BEGIN; i <= SESSION_TRACK_END; i++) + { + mysql->extension->session_state[i].list= list_reverse(mysql->extension->session_state[i].list); + mysql->extension->session_state[i].current= mysql->extension->session_state[i].list; } } } - return(0); } + return(0); +} + +int mthd_my_read_query_result(MYSQL *mysql) +{ + uchar *pos; + ulong field_count; + MYSQL_DATA *fields; + ulong length; + + if (!mysql || (length = ma_net_safe_read(mysql)) == packet_error) + { + return(1); + } + free_old_query(mysql); /* Free old result */ +get_info: + pos=(uchar*) mysql->net.read_pos; + if ((field_count= net_field_length(&pos)) == 0) + return ma_read_ok_packet(mysql, pos, length); if (field_count == NULL_LENGTH) /* LOAD DATA LOCAL INFILE */ { int error=mysql_handle_local_infile(mysql, (char *)pos); @@ -2292,12 +2293,14 @@ mysql_fetch_row(MYSQL_RES *res) if (!res) return 0; if (res->handle) + { if (res->handle->status != MYSQL_STATUS_USE_RESULT && res->handle->status != MYSQL_STATUS_GET_RESULT) return 0; + } if (!res->data) { /* Unbufferred fetch */ - if (!res->eof) + if (!res->eof && res->handle) { if (!(res->handle->methods->db_read_one_row(res->handle,res->field_count,res->row, res->lengths))) { @@ -2657,7 +2660,7 @@ mysql_optionsv(MYSQL *mysql,enum mysql_option option, ...) mysql->options.named_pipe=1; /* Force named pipe */ break; case MYSQL_OPT_LOCAL_INFILE: /* Allow LOAD DATA LOCAL ?*/ - if (!arg1 || test(*(my_bool*) arg1)) + if (!arg1 || test(*(unsigned int*) arg1)) mysql->options.client_flag|= CLIENT_LOCAL_FILES; else mysql->options.client_flag&= ~CLIENT_LOCAL_FILES; @@ -2745,6 +2748,7 @@ mysql_optionsv(MYSQL *mysql,enum mysql_option option, ...) if(!(mysql->options.extension= (struct st_mysql_options_extension *) calloc(1, sizeof(struct st_mysql_options_extension)))) { + free(ctxt); SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0); goto end; } @@ -3145,9 +3149,6 @@ mysql_get_optionv(MYSQL *mysql, enum mysql_option option, void *arg, ...) if (!(elements= va_arg(ap, unsigned int *))) goto error; - if (!elements) - goto error; - *elements= 0; if (!mysql->options.extension || @@ -3531,6 +3532,7 @@ static void mysql_once_init() } #ifdef _WIN32 +static INIT_ONCE init_once= INIT_ONCE_STATIC_INIT; BOOL CALLBACK win_init_once( PINIT_ONCE InitOnce, PVOID Parameter, @@ -3539,6 +3541,8 @@ BOOL CALLBACK win_init_once( return !mysql_once_init(); return TRUE; } +#else +static pthread_once_t init_once = PTHREAD_ONCE_INIT; #endif int STDCALL mysql_server_init(int argc __attribute__((unused)), @@ -3546,11 +3550,9 @@ int STDCALL mysql_server_init(int argc __attribute__((unused)), char **groups __attribute__((unused))) { #ifdef _WIN32 - static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT; BOOL ret = InitOnceExecuteOnce(&init_once, win_init_once, NULL, NULL); return ret? 0: 1; #else - static pthread_once_t init_once = PTHREAD_ONCE_INIT; return pthread_once(&init_once, mysql_once_init); #endif } @@ -3571,6 +3573,11 @@ void STDCALL mysql_server_end(void) #endif mysql_client_init= 0; ma_init_done= 0; +#ifdef WIN32 + init_once = (INIT_ONCE)INIT_ONCE_STATIC_INIT; +#else + init_once = (pthread_once_t)PTHREAD_ONCE_INIT; +#endif } my_bool STDCALL mysql_thread_init(void) diff --git a/libmariadb/mariadb_stmt.c b/libmariadb/mariadb_stmt.c index d0ce3c29..f5ca3818 100644 --- a/libmariadb/mariadb_stmt.c +++ b/libmariadb/mariadb_stmt.c @@ -88,12 +88,18 @@ void stmt_set_error(MYSQL_STMT *stmt, ...) { va_list ap; + const char *error= NULL; + + if (error_nr >= CR_MIN_ERROR && error_nr <= CR_MYSQL_LAST_ERROR) + error= ER(error_nr); + else if (error_nr >= CER_MIN_ERROR && error_nr <= CR_MARIADB_LAST_ERROR) + error= CER(error_nr); stmt->last_errno= error_nr; ma_strmake(stmt->sqlstate, sqlstate, SQLSTATE_LENGTH); va_start(ap, format); vsnprintf(stmt->last_error, MYSQL_ERRMSG_SIZE, - format ? format : ER(error_nr), ap); + format ? format : error ? error : "", ap); va_end(ap); return; } @@ -869,7 +875,7 @@ unsigned char* mysql_stmt_execute_generate_bulk_request(MYSQL_STMT *stmt, size_t if (!stmt->param_count) { stmt_set_error(stmt, CR_BULK_WITHOUT_PARAMETERS, "IM001", - CER(CR_BULK_WITHOUT_PARAMETERS), "Bulk operation"); + CER(CR_BULK_WITHOUT_PARAMETERS)); return NULL; } @@ -1328,15 +1334,18 @@ static my_bool net_stmt_close(MYSQL_STMT *stmt, my_bool remove) my_bool STDCALL mysql_stmt_close(MYSQL_STMT *stmt) { - my_bool rc; - if (stmt && stmt->mysql && stmt->mysql->net.pvio) - mysql_stmt_internal_reset(stmt, 1); + my_bool rc= 1; - rc= net_stmt_close(stmt, 1); + if (stmt) + { + if (stmt->mysql && stmt->mysql->net.pvio) + mysql_stmt_internal_reset(stmt, 1); - free(stmt->extension); - free(stmt); + rc= net_stmt_close(stmt, 1); + free(stmt->extension); + free(stmt); + } return(rc); } @@ -1854,6 +1863,12 @@ int stmt_read_execute_response(MYSQL_STMT *stmt) for (i=0; i < stmt->field_count; i++) { + memcpy(&stmt->fields[i], &mysql->fields[i], sizeof(MYSQL_FIELD)); + + /* since all pointers will be incorrect if another statement will + be executed, so we need to allocate memory and copy the + information */ + stmt->fields[i].extension= 0; /* not in use yet */ if (mysql->fields[i].db) stmt->fields[i].db= ma_strdup_root(fields_ma_alloc_root, mysql->fields[i].db); if (mysql->fields[i].table) @@ -1866,7 +1881,8 @@ int stmt_read_execute_response(MYSQL_STMT *stmt) stmt->fields[i].org_name= ma_strdup_root(fields_ma_alloc_root, mysql->fields[i].org_name); if (mysql->fields[i].catalog) stmt->fields[i].catalog= ma_strdup_root(fields_ma_alloc_root, mysql->fields[i].catalog); - stmt->fields[i].def= mysql->fields[i].def ? ma_strdup_root(fields_ma_alloc_root, mysql->fields[i].def) : NULL; + if (mysql->fields[i].def) + stmt->fields[i].def= ma_strdup_root(fields_ma_alloc_root, mysql->fields[i].def); } } @@ -1891,7 +1907,8 @@ int stmt_read_execute_response(MYSQL_STMT *stmt) */ /* preferred is buffered read */ - mysql_stmt_store_result(stmt); + if (mysql_stmt_store_result(stmt)) + return 1; stmt->mysql->status= MYSQL_STATUS_STMT_RESULT; } else { @@ -1970,8 +1987,9 @@ int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt) { ma_free_root(&stmt->result.alloc, MYF(MY_KEEP_PREALLOC)); stmt->result_cursor= stmt->result.data= 0; - stmt->result.rows= 0; } + /* CONC-344: set row count to zero */ + stmt->result.rows= 0; if (stmt->array_size > 0) request= (char *)mysql_stmt_execute_generate_bulk_request(stmt, &request_len); else @@ -2305,17 +2323,23 @@ int STDCALL mariadb_stmt_execute_direct(MYSQL_STMT *stmt, const char *stmt_str, size_t length) { - MYSQL *mysql= stmt->mysql; - my_bool emulate_cmd= !(!(stmt->mysql->server_capabilities & CLIENT_MYSQL) && - (stmt->mysql->extension->mariadb_server_capabilities & - (MARIADB_CLIENT_STMT_BULK_OPERATIONS >> 32))) || mysql->net.compress; + MYSQL *mysql; + my_bool emulate_cmd; + if (!stmt) + return 1; + + mysql= stmt->mysql; if (!mysql) { SET_CLIENT_STMT_ERROR(stmt, CR_SERVER_LOST, SQLSTATE_UNKNOWN, 0); - goto fail; + return 1; } + emulate_cmd= !(!(stmt->mysql->server_capabilities & CLIENT_MYSQL) && + (stmt->mysql->extension->mariadb_server_capabilities & + (MARIADB_CLIENT_STMT_BULK_OPERATIONS >> 32))) || mysql->net.compress; + /* Server versions < 10.2 don't support execute_direct, so we need to emulate it */ if (emulate_cmd) @@ -2323,7 +2347,6 @@ int STDCALL mariadb_stmt_execute_direct(MYSQL_STMT *stmt, int rc; /* avoid sending close + prepare in 2 packets */ - if ((rc= mysql_stmt_prepare(stmt, stmt_str, (unsigned long)length))) return rc; return mysql_stmt_execute(stmt); @@ -2332,13 +2355,7 @@ int STDCALL mariadb_stmt_execute_direct(MYSQL_STMT *stmt, if (ma_multi_command(mysql, COM_MULTI_ENABLED)) { SET_CLIENT_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); - goto fail; - } - - if (!stmt->mysql) - { - SET_CLIENT_STMT_ERROR(stmt, CR_SERVER_LOST, SQLSTATE_UNKNOWN, 0); - return(1); + return 1; } if (length == (size_t) -1) @@ -2422,8 +2439,10 @@ int STDCALL mariadb_stmt_execute_direct(MYSQL_STMT *stmt, /* read execute response packet */ return stmt_read_execute_response(stmt); fail: - SET_CLIENT_STMT_ERROR(stmt, mysql->net.last_errno, mysql->net.sqlstate, - mysql->net.last_error); + /* check if we need to set error message */ + if (!mysql_stmt_errno(stmt)) + SET_CLIENT_STMT_ERROR(stmt, mysql->net.last_errno, mysql->net.sqlstate, + mysql->net.last_error); do { stmt->mysql->methods->db_stmt_flush_unbuffered(stmt); } while(mysql_stmt_more_results(stmt)); diff --git a/libmariadb/secure/openssl.c b/libmariadb/secure/openssl.c index 4208828b..5caf88c1 100644 --- a/libmariadb/secure/openssl.c +++ b/libmariadb/secure/openssl.c @@ -39,6 +39,13 @@ #define HAVE_OPENSSL_1_1_API #endif +#if OPENSSL_VERSION_NUMBER < 0x10000000L +#define SSL_OP_NO_TLSv1_1 0L +#define SSL_OP_NO_TLSv1_2 0L +#define CRYPTO_THREADID_set_callback CRYPTO_set_id_callback +#define CRYPTO_THREADID_get_callback CRYPTO_get_id_callback +#endif + #ifdef HAVE_TLS_SESSION_CACHE #undef HAVE_TLS_SESSION_CACHE #endif diff --git a/plugins/auth/my_auth.c b/plugins/auth/my_auth.c index 8db6e04e..7c84c784 100644 --- a/plugins/auth/my_auth.c +++ b/plugins/auth/my_auth.c @@ -10,6 +10,7 @@ static int client_mpvio_write_packet(struct st_plugin_vio*, const uchar*, size_t static int native_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql); extern void read_user_name(char *name); extern char *ma_send_connect_attr(MYSQL *mysql, unsigned char *buffer); +extern int ma_read_ok_packet(MYSQL *mysql, uchar *pos, ulong length); typedef struct { int (*read_packet)(struct st_plugin_vio *vio, uchar **buf); @@ -357,7 +358,7 @@ static int client_mpvio_read_packet(struct st_plugin_vio *mpv, uchar **buf) *buf= mysql->net.read_pos; /* was it a request to change plugins ? */ - if (**buf == 254) + if (pkt_len && **buf == 254) return (int)packet_error; /* if yes, this plugin shan't continue */ /* @@ -577,7 +578,6 @@ int run_plugin_auth(MYSQL *mysql, char *data, uint data_len, errno); return 1; } - if (mysql->net.read_pos[0] == 254) { /* The server asked to use a different authentication plugin */ @@ -632,6 +632,8 @@ int run_plugin_auth(MYSQL *mysql, char *data, uint data_len, net->read_pos[0] should always be 0 here if the server implements the protocol correctly */ - return mysql->net.read_pos[0] != 0; + if (mysql->net.read_pos[0] == 0) + return ma_read_ok_packet(mysql, mysql->net.read_pos + 1, pkt_length); + return 1; } diff --git a/plugins/auth/old_password.c b/plugins/auth/old_password.c index b5a120da..6cc47074 100644 --- a/plugins/auth/old_password.c +++ b/plugins/auth/old_password.c @@ -96,8 +96,8 @@ static int auth_old_password(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql) return CR_SERVER_HANDSHAKE_ERR; /* save it in MYSQL */ - memmove(mysql->scramble_buff, pkt, pkt_len); - mysql->scramble_buff[pkt_len] = 0; + memmove(mysql->scramble_buff, pkt, pkt_len - 1); + mysql->scramble_buff[pkt_len - 1] = 0; } if (mysql && mysql->passwd[0]) diff --git a/plugins/auth/sha256_pw.c b/plugins/auth/sha256_pw.c index 522307f1..6381c7d2 100644 --- a/plugins/auth/sha256_pw.c +++ b/plugins/auth/sha256_pw.c @@ -117,6 +117,8 @@ char *load_pub_key_file(const char *filename, int *pub_key_size) FILE *fp= NULL; char *buffer= NULL; unsigned char error= 1; + size_t bytes_read= 0; + long fsize= 0; if (!pub_key_size) return NULL; @@ -127,15 +129,21 @@ char *load_pub_key_file(const char *filename, int *pub_key_size) if (fseek(fp, 0, SEEK_END)) goto end; - *pub_key_size= ftell(fp); + fsize= ftell(fp); + if (fsize < 0) + goto end; + rewind(fp); - if (!(buffer= malloc(*pub_key_size + 1))) + if (!(buffer= malloc(fsize + 1))) goto end; - if (!fread(buffer, *pub_key_size, 1, fp)) + bytes_read= fread(buffer, 1, (size_t)fsize, fp); + if (bytes_read < (size_t)fsize) goto end; + *pub_key_size= (int)bytes_read; + error= 0; end: diff --git a/plugins/pvio/pvio_npipe.c b/plugins/pvio/pvio_npipe.c index e3900ddf..cf95ede8 100644 --- a/plugins/pvio/pvio_npipe.c +++ b/plugins/pvio/pvio_npipe.c @@ -38,7 +38,7 @@ ssize_t pvio_npipe_async_read(MARIADB_PVIO *pvio, uchar *buffer, size_t length); ssize_t pvio_npipe_write(MARIADB_PVIO *pvio, const uchar *buffer, size_t length); ssize_t pvio_npipe_async_write(MARIADB_PVIO *pvio, const uchar *buffer, size_t length); int pvio_npipe_wait_io_or_timeout(MARIADB_PVIO *pvio, my_bool is_read, int timeout); -my_bool pvio_npipe_blocking(MARIADB_PVIO *pvio, my_bool value, my_bool *old_value); +int pvio_npipe_blocking(MARIADB_PVIO *pvio, my_bool value, my_bool *old_value); my_bool pvio_npipe_connect(MARIADB_PVIO *pvio, MA_PVIO_CINFO *cinfo); my_bool pvio_npipe_close(MARIADB_PVIO *pvio); int pvio_npipe_fast_send(MARIADB_PVIO *pvio); @@ -187,7 +187,7 @@ int pvio_npipe_wait_io_or_timeout(MARIADB_PVIO *pvio, my_bool is_read, int timeo return -1; } -my_bool pvio_npipe_blocking(MARIADB_PVIO *pvio, my_bool block, my_bool *previous_mode) +int pvio_npipe_blocking(MARIADB_PVIO *pvio, my_bool block, my_bool *previous_mode) { /* not supported */ DWORD flags= 0; diff --git a/plugins/pvio/pvio_shmem.c b/plugins/pvio/pvio_shmem.c index 8e7efa7d..ba217b72 100644 --- a/plugins/pvio/pvio_shmem.c +++ b/plugins/pvio/pvio_shmem.c @@ -36,7 +36,7 @@ int pvio_shm_get_timeout(MARIADB_PVIO *pvio, enum enum_pvio_timeout type); ssize_t pvio_shm_read(MARIADB_PVIO *pvio, uchar *buffer, size_t length); ssize_t pvio_shm_write(MARIADB_PVIO *pvio, const uchar *buffer, size_t length); int pvio_shm_wait_io_or_timeout(MARIADB_PVIO *pvio, my_bool is_read, int timeout); -my_bool pvio_shm_blocking(MARIADB_PVIO *pvio, my_bool value, my_bool *old_value); +int pvio_shm_blocking(MARIADB_PVIO *pvio, my_bool value, my_bool *old_value); my_bool pvio_shm_connect(MARIADB_PVIO *pvio, MA_PVIO_CINFO *cinfo); my_bool pvio_shm_close(MARIADB_PVIO *pvio); int pvio_shm_shutdown(MARIADB_PVIO *pvio); @@ -218,7 +218,7 @@ int pvio_shm_wait_io_or_timeout(MARIADB_PVIO *pvio, my_bool is_read, int timeout return 0; } -my_bool pvio_shm_blocking(MARIADB_PVIO *pvio, my_bool block, my_bool *previous_mode) +int pvio_shm_blocking(MARIADB_PVIO *pvio, my_bool block, my_bool *previous_mode) { /* not supported */ return 0; diff --git a/plugins/pvio/pvio_socket.c b/plugins/pvio/pvio_socket.c index 7c06e559..357cc1ea 100644 --- a/plugins/pvio/pvio_socket.c +++ b/plugins/pvio/pvio_socket.c @@ -92,7 +92,7 @@ ssize_t pvio_socket_async_read(MARIADB_PVIO *pvio, uchar *buffer, size_t length) ssize_t pvio_socket_async_write(MARIADB_PVIO *pvio, const uchar *buffer, size_t length); ssize_t pvio_socket_write(MARIADB_PVIO *pvio, const uchar *buffer, size_t length); int pvio_socket_wait_io_or_timeout(MARIADB_PVIO *pvio, my_bool is_read, int timeout); -my_bool pvio_socket_blocking(MARIADB_PVIO *pvio, my_bool value, my_bool *old_value); +int pvio_socket_blocking(MARIADB_PVIO *pvio, my_bool value, my_bool *old_value); my_bool pvio_socket_connect(MARIADB_PVIO *pvio, MA_PVIO_CINFO *cinfo); my_bool pvio_socket_close(MARIADB_PVIO *pvio); int pvio_socket_fast_send(MARIADB_PVIO *pvio); @@ -178,6 +178,7 @@ static int pvio_socket_end(void) my_bool pvio_socket_change_timeout(MARIADB_PVIO *pvio, enum enum_pvio_timeout type, int timeout) { struct timeval tm; + int rc= 0; struct st_pvio_socket *csock= NULL; if (!pvio) return 1; @@ -189,22 +190,22 @@ my_bool pvio_socket_change_timeout(MARIADB_PVIO *pvio, enum enum_pvio_timeout ty { case PVIO_WRITE_TIMEOUT: #ifndef _WIN32 - setsockopt(csock->socket, SOL_SOCKET, SO_SNDTIMEO, (const char *)&tm, sizeof(tm)); + rc= setsockopt(csock->socket, SOL_SOCKET, SO_SNDTIMEO, (const char *)&tm, sizeof(tm)); #else - setsockopt(csock->socket, SOL_SOCKET, SO_SNDTIMEO, (const char *)&timeout, sizeof(int)); + rc= setsockopt(csock->socket, SOL_SOCKET, SO_SNDTIMEO, (const char *)&timeout, sizeof(int)); #endif break; case PVIO_READ_TIMEOUT: #ifndef _WIN32 - setsockopt(csock->socket, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tm, sizeof(tm)); + rc= setsockopt(csock->socket, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tm, sizeof(tm)); #else - setsockopt(csock->socket, SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeout, sizeof(int)); + rc= setsockopt(csock->socket, SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeout, sizeof(int)); #endif break; default: break; } - return 0; + return rc; } /* {{{ pvio_socket_set_timeout */ @@ -564,7 +565,7 @@ int pvio_socket_wait_io_or_timeout(MARIADB_PVIO *pvio, my_bool is_read, int time return rc; } -my_bool pvio_socket_blocking(MARIADB_PVIO *pvio, my_bool block, my_bool *previous_mode) +int pvio_socket_blocking(MARIADB_PVIO *pvio, my_bool block, my_bool *previous_mode) { my_bool is_blocking; struct st_pvio_socket *csock; @@ -887,6 +888,7 @@ my_bool pvio_socket_connect(MARIADB_PVIO *pvio, MA_PVIO_CINFO *cinfo) if (rc) { closesocket(csock->socket); + csock->socket= INVALID_SOCKET; continue; } } @@ -901,6 +903,7 @@ my_bool pvio_socket_connect(MARIADB_PVIO *pvio, MA_PVIO_CINFO *cinfo) if (pvio_socket_blocking(pvio, 0, 0) == SOCKET_ERROR) { closesocket(csock->socket); + csock->socket= INVALID_SOCKET; continue; } break; /* success! */ @@ -936,21 +939,27 @@ my_bool pvio_socket_connect(MARIADB_PVIO *pvio, MA_PVIO_CINFO *cinfo) /* apply timeouts */ if (pvio->timeout[PVIO_CONNECT_TIMEOUT] > 0) { - pvio_socket_change_timeout(pvio, PVIO_READ_TIMEOUT, pvio->timeout[PVIO_CONNECT_TIMEOUT]); - pvio_socket_change_timeout(pvio, PVIO_WRITE_TIMEOUT, pvio->timeout[PVIO_CONNECT_TIMEOUT]); + if (pvio_socket_change_timeout(pvio, PVIO_READ_TIMEOUT, pvio->timeout[PVIO_CONNECT_TIMEOUT]) || + pvio_socket_change_timeout(pvio, PVIO_WRITE_TIMEOUT, pvio->timeout[PVIO_CONNECT_TIMEOUT])) + goto error; } else { if (pvio->timeout[PVIO_WRITE_TIMEOUT] > 0) - pvio_socket_change_timeout(pvio, PVIO_WRITE_TIMEOUT, pvio->timeout[PVIO_WRITE_TIMEOUT]); + if (pvio_socket_change_timeout(pvio, PVIO_WRITE_TIMEOUT, pvio->timeout[PVIO_WRITE_TIMEOUT])) + goto error; if (pvio->timeout[PVIO_READ_TIMEOUT] > 0) - pvio_socket_change_timeout(pvio, PVIO_READ_TIMEOUT, pvio->timeout[PVIO_READ_TIMEOUT]); + if (pvio_socket_change_timeout(pvio, PVIO_READ_TIMEOUT, pvio->timeout[PVIO_READ_TIMEOUT])) + goto error; } return 0; error: /* close socket: MDEV-10891 */ if (csock->socket != INVALID_SOCKET) + { closesocket(csock->socket); + csock->socket= INVALID_SOCKET; + } if (pvio->data) { free((gptr)pvio->data); diff --git a/unittest/libmariadb/CMakeLists.txt b/unittest/libmariadb/CMakeLists.txt index eba3cb53..9cea9163 100644 --- a/unittest/libmariadb/CMakeLists.txt +++ b/unittest/libmariadb/CMakeLists.txt @@ -26,7 +26,7 @@ INCLUDE_DIRECTORIES(${CC_SOURCE_DIR}/include ${CC_SOURCE_DIR}/unittest/libmariadb) ADD_DEFINITIONS(-DLIBMARIADB) -SET(API_TESTS "bulk1" "performance" "basic-t" "fetch" "charset" "logs" "cursor" "errors" "view" "ps" "ps_bugs" "sp" "result" "connection" "misc" "ps_new" "thread" "features-10_2" "bulk1") +SET(API_TESTS "conc336" "bulk1" "performance" "basic-t" "fetch" "charset" "logs" "cursor" "errors" "view" "ps" "ps_bugs" "sp" "result" "connection" "misc" "ps_new" "thread" "features-10_2" "bulk1") IF(WITH_DYNCOL) SET(API_TESTS ${API_TESTS} "dyncol") ENDIF() diff --git a/unittest/libmariadb/bulk1.c b/unittest/libmariadb/bulk1.c index 6f3a9458..9531658a 100644 --- a/unittest/libmariadb/bulk1.c +++ b/unittest/libmariadb/bulk1.c @@ -996,8 +996,79 @@ static int bulk_null_null(MYSQL *mysql) return OK; } +static int test_mdev16593(MYSQL *mysql) +{ + int i; + int rc; + MYSQL_BIND bind[2]; + unsigned int array_size= 2; + int val_a[2]= {1,2}; + char indicators[2]= {STMT_INDICATOR_NULL, STMT_INDICATOR_NULL}; + const char *testcase[]= {"MYSQL_TYPE_LONG", "MYSQL_TYPE_NULL", "STMT_INDICATOR_NULL"}; + + diag("waiting for server fix"); + return SKIP; + + for (i=0; i < 3; i++) + { + MYSQL_RES *res; + MYSQL_ROW row; + MYSQL_STMT *stmt= mysql_stmt_init(mysql); + rc= mysql_query(mysql, "CREATE OR REPLACE TABLE t1 (a int not null auto_increment primary key, b int)"); + check_mysql_rc(rc, mysql); + + memset(&bind, 0, sizeof(MYSQL_BIND)); + switch (i) { + case 0: + bind[0].buffer_type= MYSQL_TYPE_LONG; + break; + case 1: + bind[0].buffer_type= MYSQL_TYPE_NULL; + break; + case 2: + bind[0].buffer_type= MYSQL_TYPE_LONG; + bind[0].u.indicator= indicators; + break; + } + bind[0].buffer= val_a; + bind[1].buffer_type= MYSQL_TYPE_LONG; + bind[1].buffer= val_a; + + rc= mysql_stmt_prepare(stmt, SL("insert into t1 values(?,?)")); + check_stmt_rc(rc, stmt); + + rc= mysql_stmt_attr_set(stmt, STMT_ATTR_ARRAY_SIZE, &array_size); + check_stmt_rc(rc, stmt); + + rc= mysql_stmt_bind_param(stmt, bind); + check_stmt_rc(rc, stmt); + + rc= mysql_stmt_execute(stmt); + check_stmt_rc(rc, stmt); + + rc= mysql_query(mysql, "COMMIT"); + check_mysql_rc(rc, mysql); + + diag("Insert id with buffer_type %s: %lld", + testcase[i], + mysql_stmt_insert_id(stmt)); + + rc= mysql_query(mysql, "SELECT max(a) FROM t1"); + check_mysql_rc(rc, mysql); + + res= mysql_store_result(mysql); + row= mysql_fetch_row(res); + diag("Max value for t1.a=%s", row[0]); + mysql_free_result(res); + + mysql_stmt_close(stmt); + } + return OK; +} + struct my_tests_st my_tests[] = { {"check_bulk", check_bulk, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, + {"test_mdev16593", test_mdev16593, TEST_CONNECTION_NEW, 0, NULL, NULL}, {"bulk_null_null", bulk_null_null, TEST_CONNECTION_NEW, 0, NULL, NULL}, {"test_char_conv1", test_char_conv1, TEST_CONNECTION_NEW, 0, NULL, NULL}, {"test_char_conv2", test_char_conv2, TEST_CONNECTION_NEW, 0, NULL, NULL}, diff --git a/unittest/libmariadb/conc336.c b/unittest/libmariadb/conc336.c new file mode 100644 index 00000000..b155c160 --- /dev/null +++ b/unittest/libmariadb/conc336.c @@ -0,0 +1,45 @@ +#include "my_test.h" + +#define MAX_COUNT 2000 + +int main(int argc, char *argv[]) { + + MYSQL *mysql; + int i; + + if (argc > 1) + get_options(argc, argv); + + get_envvars(); + + for (i = 0; i < MAX_COUNT; ++i) { + + if (mysql_library_init(-1, NULL, NULL) != 0) { + diag("mysql_library_init failed"); + return 1; + } + + mysql = mysql_init(NULL); + if (!mysql) { + diag("mysql_init failed"); + return 1; + } + + if (!mysql_real_connect(mysql, hostname, username, password, schema, port, socketname, 0)) { + diag("mysql_real_connect failed: %s", mysql_error(mysql)); + return 1; + } + + if (mysql_query(mysql, "SELECT NULL LIMIT 0") != 0) { + diag("mysql_query failed: %s", mysql_error(mysql)); + return 1; + } + + mysql_close(mysql); + mysql_library_end(); + + } + + return 0; + +} diff --git a/unittest/libmariadb/connection.c b/unittest/libmariadb/connection.c index a2108270..152d938e 100644 --- a/unittest/libmariadb/connection.c +++ b/unittest/libmariadb/connection.c @@ -1486,7 +1486,47 @@ static int test_conc327(MYSQL *unused __attribute__((unused))) } #endif +static int test_conc332(MYSQL *unused __attribute__((unused))) +{ + int rc; + MYSQL *mysql= mysql_init(NULL); + int server_status1, server_status2; + + mysql_options(mysql, MYSQL_SET_CHARSET_NAME, "utf8mb4"); + + my_test_connect(mysql, hostname, username, password, schema, + port, socketname, 0); + + FAIL_IF(mysql_errno(mysql), "Error during connect"); + + mariadb_get_infov(mysql, MARIADB_CONNECTION_SERVER_STATUS, &server_status1); + diag("server_status: %d", server_status1); + + if (server_status1 & SERVER_STATUS_AUTOCOMMIT) + rc= mysql_query(mysql, "SET autocommit= 0"); + else + rc= mysql_query(mysql, "SET autocommit= 1"); + check_mysql_rc(rc, mysql); + mariadb_get_infov(mysql, MARIADB_CONNECTION_SERVER_STATUS, &server_status2); + diag("server_status after changing autocommit: %d", server_status2); + + rc= mysql_change_user(mysql, username, password, schema); + check_mysql_rc(rc, mysql); + + mariadb_get_infov(mysql, MARIADB_CONNECTION_SERVER_STATUS, &server_status2); + diag("server_status after mysql_change_user: %d", server_status2); + if (server_status1 != server_status2) + { + diag("Expected server_status %d instead of %d", server_status1, server_status2); + mysql_close(mysql); + return FAIL; + } + mysql_close(mysql); + return OK; +} + struct my_tests_st my_tests[] = { + {"test_conc332", test_conc332, TEST_CONNECTION_NONE, 0, NULL, NULL}, #ifndef WIN32 {"test_conc327", test_conc327, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_conc317", test_conc317, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, diff --git a/unittest/libmariadb/dyncol.c b/unittest/libmariadb/dyncol.c index 6e7e9913..8fe0acb9 100644 --- a/unittest/libmariadb/dyncol.c +++ b/unittest/libmariadb/dyncol.c @@ -253,12 +253,54 @@ static int dyncol_column_count(MYSQL *unused __attribute__((unused))) return OK; } +static int dyncol_nested(MYSQL *mysql __attribute__((unused))) +{ + DYNAMIC_COLUMN col1, col2; + DYNAMIC_COLUMN_VALUE value[2]; + MYSQL_LEX_STRING cols[2]= {{(char *)"0",1},{(char *)"1",1}}; + DYNAMIC_STRING s; + + mariadb_dyncol_init(&col1); + mariadb_dyncol_init(&col2); + + memset(&value, 0, sizeof(DYNAMIC_COLUMN_VALUE)); + + value[0].type= DYN_COL_UINT; + value[0].x.ulong_value = 17; + + mariadb_dyncol_create_many_named(&col1, 1, cols, value, 0); + if (mariadb_dyncol_check(&col1) != ER_DYNCOL_OK) + { + diag("Error while creating col1"); + return FAIL; + } + + value[1].type= DYN_COL_DYNCOL; + value[1].x.string.value.str= col1.str; + value[1].x.string.value.length= col1.length; + + mariadb_dyncol_create_many_named(&col2, 2, cols, value, 0); + if (mariadb_dyncol_check(&col2) != ER_DYNCOL_OK) + { + diag("Error while creating col1"); + return FAIL; + } + mariadb_dyncol_json(&col2, &s); + if (strcmp(s.str, "{\"0\":17,\"1\":{\"0\":17}}") != 0) + { + diag("%s != %s", s.str, "{\"0\":17,\"1\":{\"0\":17}}"); + return FAIL; + } + return OK; +} + struct my_tests_st my_tests[] = { {"mdev_x1", mdev_x1, TEST_CONNECTION_NEW, 0, NULL, NULL}, {"mdev_4994", mdev_4994, TEST_CONNECTION_NEW, 0, NULL, NULL}, {"create_dyncol_named", create_dyncol_named, TEST_CONNECTION_NEW, 0, NULL, NULL}, {"create_dyncol_num", create_dyncol_num, TEST_CONNECTION_NEW, 0, NULL, NULL}, {"dyncol_column_count", dyncol_column_count, TEST_CONNECTION_NEW, 0, NULL, NULL}, + {"dyncol_nested", dyncol_nested, TEST_CONNECTION_NEW, 0, NULL, NULL}, {NULL, NULL, 0, 0, NULL, 0} }; diff --git a/unittest/libmariadb/ps.c b/unittest/libmariadb/ps.c index ffba4918..df2af5c3 100644 --- a/unittest/libmariadb/ps.c +++ b/unittest/libmariadb/ps.c @@ -2209,7 +2209,7 @@ static int test_bind_negative(MYSQL *mysql) my_bind[0].buffer_type= MYSQL_TYPE_LONG; my_bind[0].buffer= (void *)&my_val; my_bind[0].length= &my_length; - my_bind[0].is_null= (char*)&my_null; + my_bind[0].is_null= &my_null; rc= mysql_stmt_bind_param(stmt, my_bind); check_stmt_rc(rc, stmt); @@ -2400,12 +2400,12 @@ static int test_union_param(MYSQL *mysql) my_bind[0].buffer= (char*) &my_val; my_bind[0].buffer_length= 4; my_bind[0].length= &my_length; - my_bind[0].is_null= (char*)&my_null; + my_bind[0].is_null= &my_null; my_bind[1].buffer_type= MYSQL_TYPE_STRING; my_bind[1].buffer= (char*) &my_val; my_bind[1].buffer_length= 4; my_bind[1].length= &my_length; - my_bind[1].is_null= (char*)&my_null; + my_bind[1].is_null= &my_null; rc= mysql_stmt_bind_param(stmt, my_bind); check_stmt_rc(rc, stmt); @@ -3313,7 +3313,7 @@ ENGINE=InnoDB DEFAULT CHARSET=utf8"); my_bind[0].buffer_type= MYSQL_TYPE_LONG; my_bind[0].buffer= (void *)&my_val; my_bind[0].length= &my_length; - my_bind[0].is_null= (char*)&my_null; + my_bind[0].is_null= &my_null; my_val= 1; rc= mysql_stmt_bind_param(stmt, my_bind); check_stmt_rc(rc, stmt); @@ -4637,7 +4637,6 @@ static int test_stmt_close(MYSQL *mysql) FAIL_IF(mysql_stmt_param_count(stmt2) != 1, "param_count != 1"); rc= mysql_stmt_close(stmt1); - check_stmt_rc(rc, stmt1); /* Originally we were going to close all statements automatically in diff --git a/unittest/libmariadb/ps_bugs.c b/unittest/libmariadb/ps_bugs.c index 5fa72b74..fd931ed5 100644 --- a/unittest/libmariadb/ps_bugs.c +++ b/unittest/libmariadb/ps_bugs.c @@ -4654,43 +4654,138 @@ static int test_compress(MYSQL *mysql) static int test_codbc138(MYSQL *mysql) { int rc; - MYSQL_STMT *stmt= mysql_stmt_init(mysql); + MYSQL_STMT *stmt; MYSQL_BIND bind[1]; MYSQL_TIME tm; + int i= 0; - rc= mysql_stmt_prepare(stmt, SL("SELECT DATE_ADD('2018-02-01', INTERVAL -188 DAY)")); + struct st_time_test { + const char *statement; + MYSQL_TIME tm; + } time_test[]= { + {"SELECT DATE_ADD('2018-02-01', INTERVAL -188 DAY)", + {2017,7,28,0,0,0,0L,0, MYSQL_TIMESTAMP_DATE} + }, + {"SELECT '2001-02-03 11:12:13.123456'", + {2001,2,3,11,12,13,123456L,0, MYSQL_TIMESTAMP_DATETIME} + }, + {"SELECT '-11:12:13'", + {0,0,0,11,12,13,0,1, MYSQL_TIMESTAMP_TIME} + }, + {"SELECT ' '", + {0,0,0,0,0,0,0,0, MYSQL_TIMESTAMP_ERROR} + }, + {"SELECT '1--'", + {1,0,0,0,0,0,0,0, MYSQL_TIMESTAMP_ERROR} + }, + {"SELECT '-2001-01-01'", + {1,0,0,0,0,0,0,0, MYSQL_TIMESTAMP_ERROR} + }, + {"SELECT '-11:00'", + {1,0,0,0,0,0,0,0, MYSQL_TIMESTAMP_ERROR} + }, + {NULL, {0}} + }; + + while (time_test[i].statement) + { + stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_prepare(stmt, SL(time_test[i].statement)); + check_stmt_rc(rc, stmt); + rc= mysql_stmt_execute(stmt); + check_stmt_rc(rc, stmt); + rc= mysql_stmt_store_result(stmt); + + memset(bind, 0, sizeof(MYSQL_BIND)); + bind[0].buffer_type= MYSQL_TYPE_DATETIME; + bind[0].buffer= &tm; + bind[0].buffer_length= sizeof(MYSQL_TIME); + + rc= mysql_stmt_bind_result(stmt, bind); + check_stmt_rc(rc, stmt); + rc= mysql_stmt_fetch(stmt); + check_stmt_rc(rc, stmt); + diag("test: %s %d %d", time_test[i].statement, tm.time_type, time_test[i].tm.time_type); + if (time_test[i].tm.time_type == MYSQL_TIMESTAMP_ERROR) + { + FAIL_UNLESS(tm.time_type == MYSQL_TIMESTAMP_ERROR, "MYSQL_TIMESTAMP_ERROR expected"); + } + else + FAIL_UNLESS(memcmp(&tm, &time_test[i].tm, sizeof(MYSQL_TIME)) == 0, "time_in != time_out"); + mysql_stmt_close(stmt); + i++; + } + + return OK; +} + +static int test_conc334(MYSQL *mysql) +{ + MYSQL_STMT *stmt= mysql_stmt_init(mysql); + MYSQL_RES *result; + MYSQL_FIELD *field; + int rc; + + rc= mysql_stmt_prepare(stmt, SL("SHOW ENGINES")); check_stmt_rc(rc, stmt); rc= mysql_stmt_execute(stmt); check_stmt_rc(rc, stmt); - memset(bind, 0, sizeof(MYSQL_BIND)); - bind[0].buffer_type= MYSQL_TYPE_DATETIME; - bind[0].buffer= &tm; - bind[0].buffer_length= sizeof(MYSQL_TIME); + result= mysql_stmt_result_metadata(stmt); + if (!result) + { + diag("Coudn't retrieve result set"); + mysql_stmt_close(stmt); + return FAIL; + } - rc= mysql_stmt_bind_result(stmt, bind); + mysql_field_seek(result, 0); + + while ((field= mysql_fetch_field(result))) + { + FAIL_IF(field->name_length == 0, "Invalid name length (0)"); + FAIL_IF(field->table_length == 0, "Invalid name length (0)"); + } + mysql_free_result(result); + mysql_stmt_close(stmt); + + return OK; +} +static int test_conc344(MYSQL *mysql) +{ + MYSQL_STMT *stmt= mysql_stmt_init(mysql); + int rc; + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); + check_mysql_rc(rc, mysql); + + rc= mysql_query(mysql, "CREATE TABLE t1 (a int, b int)"); + check_mysql_rc(rc, mysql); + rc= mysql_query(mysql, "INSERT INTO t1 VALUES (1,1), (2,2),(3,3),(4,4),(5,5)"); + check_mysql_rc(rc, mysql); + + rc= mysql_stmt_prepare(stmt, SL("SELECT * FROM t1 ORDER BY a")); check_stmt_rc(rc, stmt); + rc= mysql_stmt_execute(stmt); + check_stmt_rc(rc, stmt); + + while (!mysql_stmt_fetch(stmt)); + FAIL_IF(mysql_stmt_num_rows(stmt) != 5, "expected 5 rows"); + rc= mysql_stmt_execute(stmt); + check_stmt_rc(rc, stmt); rc= mysql_stmt_fetch(stmt); - check_stmt_rc(rc, stmt); - - if (tm.year != 2017 && tm.day != 28 && tm.month != 7) - { - diag("Error: Expected 2017-07-02"); - return FAIL; - } - if (tm.minute | tm.second || tm.second_part) - { - diag("Error: minute, second or second_part is not zero"); - return FAIL; - } + diag("num_rows: %lld", mysql_stmt_num_rows(stmt)); + FAIL_IF(mysql_stmt_num_rows(stmt) != 1, "expected 1 row"); mysql_stmt_close(stmt); return OK; } struct my_tests_st my_tests[] = { + {"test_conc344", test_conc344, TEST_CONNECTION_NEW, 0, NULL, NULL}, + {"test_conc334", test_conc334, TEST_CONNECTION_NEW, 0, NULL, NULL}, {"test_compress", test_compress, TEST_CONNECTION_NEW, CLIENT_COMPRESS, NULL, NULL}, {"test_codbc138", test_codbc138, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_conc208", test_conc208, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, @@ -4776,4 +4871,3 @@ int main(int argc, char **argv) return(exit_status()); } - diff --git a/unittest/libmariadb/view.c b/unittest/libmariadb/view.c index ea1aa352..9aeeecde 100644 --- a/unittest/libmariadb/view.c +++ b/unittest/libmariadb/view.c @@ -30,7 +30,7 @@ static int test_view(MYSQL *mysql) MYSQL_BIND my_bind[1]; char str_data[50]; ulong length = 0L; - long is_null = 0L; + my_bool is_null = 0; const char *query= "SELECT COUNT(*) FROM v1 WHERE SERVERNAME=?"; @@ -84,7 +84,7 @@ static int test_view(MYSQL *mysql) my_bind[0].buffer_length= 50; my_bind[0].length= &length; length= 4; - my_bind[0].is_null= (char*)&is_null; + my_bind[0].is_null= &is_null; rc= mysql_stmt_bind_param(stmt, my_bind); check_stmt_rc(rc, stmt); @@ -301,7 +301,7 @@ static int test_view_insert(MYSQL *mysql) MYSQL_BIND my_bind[1]; int my_val = 0; ulong my_length = 0L; - long my_null = 0L; + my_bool my_null = 0; const char *query= "insert into v1 values (?)"; @@ -328,7 +328,7 @@ static int test_view_insert(MYSQL *mysql) my_bind[0].buffer_type = MYSQL_TYPE_LONG; my_bind[0].buffer = (char *)&my_val; my_bind[0].length = &my_length; - my_bind[0].is_null = (char*)&my_null; + my_bind[0].is_null = &my_null; rc= mysql_stmt_bind_param(insert_stmt, my_bind); check_stmt_rc(rc, select_stmt);