diff --git a/include/errmsg.h b/include/errmsg.h index a6600b4b..f4af5288 100644 --- a/include/errmsg.h +++ b/include/errmsg.h @@ -95,5 +95,6 @@ extern const char *mariadb_client_errors[]; /* Error messages */ #define CR_FUNCTION_NOT_SUPPORTED 5003 #define CR_FILE_NOT_FOUND 5004 #define CR_FILE_READ 5005 +#define CR_BULK_WITHOUT_PARAMETERS 5006 #endif diff --git a/include/ma_common.h b/include/ma_common.h index b1c15d37..01f7ba16 100644 --- a/include/ma_common.h +++ b/include/ma_common.h @@ -69,6 +69,8 @@ struct st_mysql_options_extension { my_bool (*set_option)(MYSQL *mysql, const char *config_option, const char *config_value); HASH userdata; char *server_public_key; + char *proxy_header; + size_t proxy_header_len; }; typedef struct st_connection_handler diff --git a/include/mariadb_com.h b/include/mariadb_com.h index cdf7db84..1addb6a9 100644 --- a/include/mariadb_com.h +++ b/include/mariadb_com.h @@ -93,6 +93,7 @@ enum enum_server_command COM_DAEMON= 29, COM_UNSUPPORTED= 30, COM_RESET_CONNECTION = 31, + COM_STMT_BULK_EXECUTE = 250, COM_MULTI = 254, COM_END }; @@ -135,7 +136,7 @@ enum enum_server_command #define REFRESH_READ_LOCK 16384 /* Lock tables for read */ #define REFRESH_FAST 32768 /* Intern flag */ -#define CLIENT_MYSQL 1 +#define CLIENT_MYSQL 1 #define CLIENT_FOUND_ROWS 2 /* Found instead of affected rows */ #define CLIENT_LONG_FLAG 4 /* Get all column flags */ #define CLIENT_CONNECT_WITH_DB 8 /* One can specify db on connect */ diff --git a/include/mariadb_stmt.h b/include/mariadb_stmt.h index efd2a6c7..9c9303cf 100644 --- a/include/mariadb_stmt.h +++ b/include/mariadb_stmt.h @@ -29,10 +29,10 @@ #define MADB_BIND_DUMMY 1 #define MARIADB_STMT_BULK_SUPPORTED(stmt)\ - ((stmt)->array_size > 0 && \ - (stmt)->mysql && \ + ((stmt)->mysql && \ (!((stmt)->mysql->server_capabilities & CLIENT_MYSQL) &&\ - ((stmt)->mysql->extension->mariadb_server_capabilities & MARIADB_CLIENT_STMT_BULK_OPERATIONS >> 32))) + ((stmt)->mysql->extension->mariadb_server_capabilities & \ + (MARIADB_CLIENT_STMT_BULK_OPERATIONS >> 32)))) #define SET_CLIENT_STMT_ERROR(a, b, c, d) \ { \ @@ -84,6 +84,12 @@ enum enum_indicator_type STMT_INDICATOR_IGNORE=3 }; +/* + bulk PS flags +*/ +#define STMT_BULK_FLAG_CLIENT_SEND_TYPES 128 +#define STMT_BULK_FLAG_INSERT_ID_REQUEST 64 + typedef enum mysql_stmt_state { MYSQL_STMT_INITTED = 0, diff --git a/include/mysql.h b/include/mysql.h index b5cb2e5e..faadea02 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -231,7 +231,8 @@ extern const char *SQLSTATE_UNKNOWN; MARIADB_OPT_FOUND_ROWS, MARIADB_OPT_MULTI_RESULTS, MARIADB_OPT_MULTI_STATEMENTS, - MARIADB_OPT_INTERACTIVE + MARIADB_OPT_INTERACTIVE, + MARIADB_OPT_PROXY_HEADER }; enum mariadb_value { diff --git a/libmariadb/CMakeLists.txt b/libmariadb/CMakeLists.txt index e5bcae07..e90bc832 100644 --- a/libmariadb/CMakeLists.txt +++ b/libmariadb/CMakeLists.txt @@ -332,7 +332,7 @@ CREATE_EXPORT_FILE(mariadbclient "${MARIADB_LIB_SYMBOLS}") -IF(CMAKE_VERSION VERSION_GREATER 2.8.7) +IF((NOT WIN32) AND (CMAKE_VERSION VERSION_GREATER 2.8.7)) # CREATE OBJECT LIBRARY ADD_LIBRARY(mariadb_obj OBJECT ${LIBMARIADB_SOURCES}) IF(UNIX) @@ -346,8 +346,8 @@ ENDIF() # Xcode doesn't support targets that have only object files, # so let's add an empty file to keep Xcode happy IF(CMAKE_GENERATOR MATCHES Xcode) - FILE(WRITE ${CC_SOURCE_DIR}/libmariadb/empty.c "") - SET(EMPTY_FILE ${CC_SOURCE_DIR}/libmariadb/empty.c) + FILE(WRITE ${CC_BINARY_DIR}/libmariadb/empty.c "") + SET(EMPTY_FILE ${CC_BINARY_DIR}/libmariadb/empty.c) ENDIF() IF(WIN32) @@ -358,14 +358,20 @@ IF(WIN32) "FILE_DESCRIPTION:Dynamic lib for client/server communication") ENDIF() -ADD_LIBRARY(mariadbclient STATIC ${mariadbclient_RC} ${MARIADB_OBJECTS} ${EMPTY_FILE} mariadbclient.def) +ADD_LIBRARY(mariadbclient STATIC ${MARIADB_OBJECTS} ${EMPTY_FILE}) TARGET_LINK_LIBRARIES(mariadbclient ${SYSTEM_LIBS}) -ADD_LIBRARY(libmariadb SHARED ${libmariadb_RC} ${MARIADB_OBJECTS} ${EMPTY_FILE} mariadbclient.def) -TARGET_LINK_LIBRARIES(libmariadb ${SYSTEM_LIBS}) IF(UNIX) + ADD_LIBRARY(libmariadb SHARED ${libmariadb_RC} ${MARIADB_OBJECTS} ${EMPTY_FILE} mariadbclient.def) SET_TARGET_PROPERTIES(libmariadb PROPERTIES COMPILE_FLAGS "${CMAKE_SHARED_LIBRARY_C_FLAGS}") +ELSE() + ADD_LIBRARY(libmariadb SHARED ${libmariadb_RC} mariadbclient.def) + TARGET_LINK_LIBRARIES(libmariadb mariadbclient) + SET_TARGET_PROPERTIES(libmariadb PROPERTIES LINKER_LANGUAGE C) ENDIF() + +TARGET_LINK_LIBRARIES(libmariadb ${SYSTEM_LIBS}) + SIGN_TARGET(libmariadb) IF(CMAKE_SIZEOF_VOID_P EQUAL 8 AND MSVC) diff --git a/libmariadb/ma_errmsg.c b/libmariadb/ma_errmsg.c index cfb3027f..5c7884b3 100644 --- a/libmariadb/ma_errmsg.c +++ b/libmariadb/ma_errmsg.c @@ -156,6 +156,7 @@ const char *mariadb_client_errors[] = /* 5003 */ "Server doesn't support function '%s'", /* 5004 */ "File '%s' not found (Errcode: %d)", /* 5005 */ "Error reading file '%s' (Errcode: %d)", + /* 5006 */ "Bulk operation without parameters is not supported", "" }; diff --git a/libmariadb/mariadb_lib.c b/libmariadb/mariadb_lib.c index 7590001d..e52560cb 100644 --- a/libmariadb/mariadb_lib.c +++ b/libmariadb/mariadb_lib.c @@ -207,7 +207,7 @@ restart: if (last_errno== 65535 && ((mariadb_connection(mysql) && (mysql->server_capabilities & CLIENT_PROGRESS)) || - (!(mysql->extension->mariadb_server_capabilities & MARIADB_CLIENT_PROGRESS >> 32)))) + (!(mysql->extension->mariadb_server_capabilities & MARIADB_CLIENT_PROGRESS << 32)))) { if (cli_report_progress(mysql, (uchar *)pos, (uint) (len-1))) { @@ -657,10 +657,12 @@ struct st_default_options mariadb_defaults[] = else \ (OPTS)->extension->KEY= NULL -#define OPT_SET_EXTENDED_VALUE_INT(OPTS, KEY, VAL) \ +#define OPT_SET_EXTENDED_VALUE(OPTS, KEY, VAL) \ CHECK_OPT_EXTENSION_SET(OPTS) \ (OPTS)->extension->KEY= (VAL) +#define OPT_SET_EXTENDED_VALUE_INT(A,B,C) OPT_SET_EXTENDED_VALUE(A,B,C) + #define OPT_SET_VALUE_STR(OPTS, KEY, VAL) \ free((OPTS)->KEY); \ if((VAL)) \ @@ -1303,6 +1305,17 @@ MYSQL *mthd_my_real_connect(MYSQL *mysql, const char *host, const char *user, goto error; } + if (mysql->options.extension && mysql->options.extension->proxy_header) + { + char *hdr = mysql->options.extension->proxy_header; + size_t len = mysql->options.extension->proxy_header_len; + if (ma_pvio_write(pvio, hdr, len) <= 0) + { + ma_pvio_close(pvio); + goto error; + } + } + if (ma_net_init(net, pvio)) goto error; @@ -1483,7 +1496,8 @@ MYSQL *mthd_my_real_connect(MYSQL *mysql, const char *host, const char *user, net->compress= 1; /* last part: select default db */ - if (db && !mysql->db) + if (!(mysql->server_capabilities & CLIENT_CONNECT_WITH_DB) && + (db && !mysql->db)) { if (mysql_select_db(mysql, db)) { @@ -2955,6 +2969,13 @@ mysql_optionsv(MYSQL *mysql,enum mysql_option option, ...) case MARIADB_OPT_CONNECTION_READ_ONLY: OPT_SET_EXTENDED_VALUE_INT(&mysql->options, read_only, *(my_bool *)arg1); break; + case MARIADB_OPT_PROXY_HEADER: + { + size_t arg2 = va_arg(ap, size_t); + OPT_SET_EXTENDED_VALUE(&mysql->options, proxy_header, (char *)arg1); + OPT_SET_EXTENDED_VALUE(&mysql->options, proxy_header_len, arg2); + } + break; default: va_end(ap); return(-1); diff --git a/libmariadb/mariadb_stmt.c b/libmariadb/mariadb_stmt.c index ad82f054..a73827a8 100644 --- a/libmariadb/mariadb_stmt.c +++ b/libmariadb/mariadb_stmt.c @@ -628,8 +628,8 @@ int store_param(MYSQL_STMT *stmt, int column, unsigned char **p, unsigned long r return 0; } -/* {{{ mysqlnd_stmt_execute_generate_request */ -unsigned char* mysql_stmt_execute_generate_request(MYSQL_STMT *stmt, size_t *request_len) +/* {{{ mysqlnd_stmt_execute_generate_simple_request */ +unsigned char* mysql_stmt_execute_generate_simple_request(MYSQL_STMT *stmt, size_t *request_len) { /* execute packet has the following format: Offset Length Description @@ -648,30 +648,17 @@ unsigned char* mysql_stmt_execute_generate_request(MYSQL_STMT *stmt, size_t *req unsigned flag (32768) indicator variable exists (16384) ------------------------------------------ - Pre 10.2 protocol n data from bind_buffer - 10.2 protocol - if indicator variable exists - 1st byte: indicator variable - 2nd-n: data */ size_t length= 1024; size_t free_bytes= 0; size_t null_byte_offset= 0; - uint i, j, num_rows= 1; + uint i; uchar *start= NULL, *p; - if (!MARIADB_STMT_BULK_SUPPORTED(stmt) && stmt->array_size > 0) - { - stmt_set_error(stmt, CR_FUNCTION_NOT_SUPPORTED, SQLSTATE_UNKNOWN, - CER(CR_FUNCTION_NOT_SUPPORTED), "Bulk operation"); - return NULL; - } - - /* preallocate length bytes */ /* check: gr */ if (!(start= p= (uchar *)malloc(length))) @@ -683,34 +670,28 @@ unsigned char* mysql_stmt_execute_generate_request(MYSQL_STMT *stmt, size_t *req /* flags is 4 bytes, we store just 1 */ int1store(p, (unsigned char) stmt->flags); p++; - if (MARIADB_STMT_BULK_SUPPORTED(stmt) && stmt->array_size) - num_rows= stmt->array_size; - int4store(p, num_rows); - p+= 4; - if (!stmt->param_count && stmt->prebind_params) - stmt->param_count= stmt->prebind_params; + int4store(p, 1); + p+= 4; if (stmt->param_count) { - if (!stmt->array_size) + size_t null_count= (stmt->param_count + 7) / 8; + + free_bytes= length - (p - start); + if (null_count + 20 > free_bytes) { - size_t null_count= (stmt->param_count + 7) / 8; - - free_bytes= length - (p - start); - if (null_count + 20 > free_bytes) - { - size_t offset= p - start; - length+= offset + null_count + 20; - if (!(start= (uchar *)realloc(start, length))) - goto mem_error; - p= start + offset; - } - - null_byte_offset= p - start; - memset(p, 0, null_count); - p += null_count; + size_t offset= p - start; + length+= offset + null_count + 20; + if (!(start= (uchar *)realloc(start, length))) + goto mem_error; + p= start + offset; } + + null_byte_offset= p - start; + memset(p, 0, null_count); + p += null_count; + int1store(p, stmt->send_types_to_server); p++; @@ -734,50 +715,202 @@ unsigned char* mysql_stmt_execute_generate_request(MYSQL_STMT *stmt, size_t *req /* this differs from mysqlnd, c api supports unsinged !! */ uint buffer_type= stmt->params[i].buffer_type | (stmt->params[i].is_unsigned ? 32768 : 0); /* check if parameter requires indicator variable */ - if (MARIADB_STMT_BULK_SUPPORTED(stmt) && - (stmt->params[i].u.indicator || stmt->params[i].buffer_type == MYSQL_TYPE_NULL)) - buffer_type|= 16384; int2store(p, buffer_type); p+= 2; } } /* calculate data size */ - for (j=0; j < num_rows; j++) + for (i=0; i < stmt->param_count; i++) + { + size_t size= 0; + my_bool has_data= TRUE; + + if (stmt->params[i].long_data_used) + { + has_data= FALSE; + stmt->params[i].long_data_used= 0; + } + + if (has_data) + { + switch (stmt->params[i].buffer_type) { + case MYSQL_TYPE_NULL: + has_data= FALSE; + break; + case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_LONG_BLOB: + case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_VARCHAR: + case MYSQL_TYPE_VAR_STRING: + case MYSQL_TYPE_STRING: + case MYSQL_TYPE_JSON: + case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_NEWDECIMAL: + case MYSQL_TYPE_GEOMETRY: + case MYSQL_TYPE_NEWDATE: + case MYSQL_TYPE_ENUM: + case MYSQL_TYPE_BIT: + case MYSQL_TYPE_SET: + size+= 5; /* max 8 bytes for size */ + size+= (size_t)ma_get_length(stmt, i, 0); + break; + default: + size+= mysql_ps_fetch_functions[stmt->params[i].buffer_type].pack_len; + break; + } + } + free_bytes= length - (p - start); + if (free_bytes < size + 20) + { + size_t offset= p - start; + length= MAX(2 * length, offset + size + 20); + if (!(start= (uchar *)realloc(start, length))) + goto mem_error; + p= start + offset; + } + if (((stmt->params[i].is_null && *stmt->params[i].is_null) || + stmt->params[i].buffer_type == MYSQL_TYPE_NULL || + !stmt->params[i].buffer)) + { + has_data= FALSE; + (start + null_byte_offset)[i/8] |= (unsigned char) (1 << (i & 7)); + } + + if (has_data) + { + store_param(stmt, i, &p, 0); + } + } + } + stmt->send_types_to_server= 0; + *request_len = (size_t)(p - start); + return start; +mem_error: + SET_CLIENT_STMT_ERROR(stmt, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0); + free(start); + *request_len= 0; + return NULL; +} +/* }}} */ + +/* {{{ mysqlnd_stmt_execute_generate_bulk_request */ +unsigned char* mysql_stmt_execute_generate_bulk_request(MYSQL_STMT *stmt, size_t *request_len) +{ + /* execute packet has the following format: + Offset Length Description + ----------------------------------------- + 0 4 Statement id + 4 2 Flags (cursor type): + STMT_BULK_FLAG_CLIENT_SEND_TYPES = 128 + STMT_BULK_FLAG_INSERT_ID_REQUEST = 64 + ----------------------------------------- + if (stmt->send_types_to_server): + for (i=0; i < param_count; i++) + 1st byte: parameter type + 2nd byte flag: + unsigned flag (32768) + ------------------------------------------ + for (i=0; i < param_count; i++) + 1 indicator variable + STMT_INDICATOR_NONE 0 + STMT_INDICATOR_NULL 1 + STMT_INDICATOR_DEFAULT 2 + STMT_INDICATOR_IGNORE 3 + n data from bind buffer + + */ + + size_t length= 1024; + size_t free_bytes= 0; + ushort flags= 0; + uint i, j; + + uchar *start= NULL, *p; + + if (!MARIADB_STMT_BULK_SUPPORTED(stmt)) + { + stmt_set_error(stmt, CR_FUNCTION_NOT_SUPPORTED, "IM001", + CER(CR_FUNCTION_NOT_SUPPORTED), "Bulk operation"); + return NULL; + } + + if (!stmt->param_count) + { + stmt_set_error(stmt, CR_BULK_WITHOUT_PARAMETERS, "IM001", + CER(CR_BULK_WITHOUT_PARAMETERS), "Bulk operation"); + return NULL; + } + + /* preallocate length bytes */ + if (!(start= p= (uchar *)malloc(length))) + goto mem_error; + + int4store(p, stmt->stmt_id); + p += STMT_ID_LENGTH; + + /* todo: request to return auto generated ids */ + if (stmt->send_types_to_server) + flags|= STMT_BULK_FLAG_CLIENT_SEND_TYPES; + int2store(p, flags); + p+=2; + + /* When using mariadb_stmt_execute_direct stmt->paran_count is + not knowm, so we need to assign prebind_params, which was previously + set by mysql_stmt_attr_set + */ + if (!stmt->param_count && stmt->prebind_params) + stmt->param_count= stmt->prebind_params; + + if (stmt->param_count) + { + free_bytes= length - (p - start); + + /* Store type information: + 2 bytes per type + */ + if (stmt->send_types_to_server) + { + if (free_bytes < stmt->param_count * 2 + 20) + { + size_t offset= p - start; + length= offset + stmt->param_count * 2 + 20; + if (!(start= (uchar *)realloc(start, length))) + goto mem_error; + p= start + offset; + } + for (i = 0; i < stmt->param_count; i++) + { + /* this differs from mysqlnd, c api supports unsinged !! */ + uint buffer_type= stmt->params[i].buffer_type | (stmt->params[i].is_unsigned ? 32768 : 0); + int2store(p, buffer_type); + p+= 2; + } + } + + /* calculate data size */ + for (j=0; j < stmt->array_size; j++) { for (i=0; i < stmt->param_count; i++) { size_t size= 0; my_bool has_data= TRUE; - char indicator= 0; - - if (MARIADB_STMT_BULK_SUPPORTED(stmt) && - (stmt->params[i].u.indicator || stmt->params[i].buffer_type == MYSQL_TYPE_NULL)) - { - if (stmt->params[i].buffer_type == MYSQL_TYPE_NULL) - { - indicator= STMT_INDICATOR_NULL; - } - else - indicator= ma_get_indicator(stmt, i, j); - /* check if we need to send data */ - if (indicator > 0) - has_data= FALSE; - size= 1; - } - - if (stmt->params[i].long_data_used) - { + char indicator= ma_get_indicator(stmt, i, j); + /* check if we need to send data */ + if (indicator > 0) has_data= FALSE; - stmt->params[i].long_data_used= 0; - } + size= 1; + + /* Please note that mysql_stmt_send_long_data is not supported + current when performing bulk execute */ + if (has_data) { switch (stmt->params[i].buffer_type) { case MYSQL_TYPE_NULL: - if (MARIADB_STMT_BULK_SUPPORTED(stmt)) - indicator= STMT_INDICATOR_NULL; has_data= FALSE; + indicator= STMT_INDICATOR_NULL; break; case MYSQL_TYPE_TINY_BLOB: case MYSQL_TYPE_MEDIUM_BLOB: @@ -795,9 +928,9 @@ unsigned char* mysql_stmt_execute_generate_request(MYSQL_STMT *stmt, size_t *req case MYSQL_TYPE_BIT: case MYSQL_TYPE_SET: size+= 5; /* max 8 bytes for size */ - if (indicator == STMT_INDICATOR_NTS || + if (indicator == STMT_INDICATOR_NTS || (!stmt->row_size && ma_get_length(stmt,i,j) == -1)) - size+= strlen(ma_get_buffer_offset(stmt, + size+= strlen(ma_get_buffer_offset(stmt, stmt->params[i].buffer_type, stmt->params[i].buffer,j)); else @@ -818,27 +951,10 @@ unsigned char* mysql_stmt_execute_generate_request(MYSQL_STMT *stmt, size_t *req p= start + offset; } - if ((indicator != STMT_INDICATOR_DEFAULT && indicator != STMT_INDICATOR_IGNORE) && - ((stmt->params[i].is_null && *stmt->params[i].is_null) || - stmt->params[i].buffer_type == MYSQL_TYPE_NULL || - !stmt->params[i].buffer)) - { - has_data= FALSE; - if (!stmt->array_size) - (start + null_byte_offset)[i/8] |= (unsigned char) (1 << (i & 7)); - else - indicator= STMT_INDICATOR_NULL; - } - if (MARIADB_STMT_BULK_SUPPORTED(stmt) && - (indicator || stmt->params[i].u.indicator)) - { - int1store(p, indicator > 0 ? indicator : 0); - p++; - } + int1store(p, indicator > 0 ? indicator : 0); + p++; if (has_data) - { store_param(stmt, i, &p, j); - } } } @@ -853,7 +969,6 @@ mem_error: return NULL; } /* }}} */ - /*! ******************************************************************************* @@ -1820,13 +1935,17 @@ int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt) stmt->result_cursor= stmt->result.data= 0; stmt->result.rows= 0; } - request= (char *)mysql_stmt_execute_generate_request(stmt, &request_len); + if (stmt->array_size > 0) + request= (char *)mysql_stmt_execute_generate_bulk_request(stmt, &request_len); + else + request= (char *)mysql_stmt_execute_generate_simple_request(stmt, &request_len); if (!request) return 1; - ret= stmt->mysql->methods->db_command(mysql, COM_STMT_EXECUTE, request, - request_len, 1, stmt); + ret= stmt->mysql->methods->db_command(mysql, + stmt->array_size > 0 ? COM_STMT_BULK_EXECUTE : COM_STMT_EXECUTE, + request, request_len, 1, stmt); if (request) free(request); @@ -2151,7 +2270,8 @@ int STDCALL mariadb_stmt_execute_direct(MYSQL_STMT *stmt, { 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)); + (stmt->mysql->extension->mariadb_server_capabilities & + (MARIADB_CLIENT_STMT_BULK_OPERATIONS >> 32))); if (!mysql) { diff --git a/libmariadb/secure/schannel.c b/libmariadb/secure/schannel.c index 53a7d272..2da5a3ef 100644 --- a/libmariadb/secure/schannel.c +++ b/libmariadb/secure/schannel.c @@ -451,7 +451,7 @@ int ma_tls_verify_server_cert(MARIADB_TLS *ctls) if (pszServerName && (sctx->mysql->client_flag & CLIENT_SSL_VERIFY_SERVER_CERT)) { DWORD NameSize= 0; - char *p1, *p2; + char *p1; SECURITY_STATUS sRet; if ((sRet= QueryContextAttributes(&sctx->ctxt, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (PVOID)&pServerCert)) != SEC_E_OK) diff --git a/plugins/auth/my_auth.c b/plugins/auth/my_auth.c index 3f40d457..c89f03c7 100644 --- a/plugins/auth/my_auth.c +++ b/plugins/auth/my_auth.c @@ -165,7 +165,7 @@ static int send_client_reply_packet(MCPVIO_EXT *mpvio, /* see end= buff+32 below, fixed size of the packet is 32 bytes */ buff= malloc(33 + USERNAME_LENGTH + data_len + NAME_LEN + NAME_LEN + conn_attr_len + 9); end= buff; - + mysql->client_flag|= mysql->options.client_flag; mysql->client_flag|= CLIENT_CAPABILITIES; @@ -212,6 +212,8 @@ static int send_client_reply_packet(MCPVIO_EXT *mpvio, if (mysql->client_flag & CLIENT_PROTOCOL_41) { /* 4.1 server and 4.1 client has a 32 byte option flag */ + if (!(mysql->server_capabilities & CLIENT_MYSQL)) + mysql->client_flag&= ~CLIENT_MYSQL; int4store(buff,mysql->client_flag); int4store(buff+4, net->max_packet_size); buff[8]= (char) mysql->charset->nr; diff --git a/unittest/libmariadb/bulk1.c b/unittest/libmariadb/bulk1.c index 895f4da8..ad394589 100644 --- a/unittest/libmariadb/bulk1.c +++ b/unittest/libmariadb/bulk1.c @@ -37,7 +37,8 @@ char *rand_str(size_t length) { static int check_bulk(MYSQL *mysql) { bulk_enabled= (!(mysql->server_capabilities & CLIENT_MYSQL) && - (mysql->extension->mariadb_server_capabilities & MARIADB_CLIENT_STMT_BULK_OPERATIONS >> 32)); + (mysql->extension->mariadb_server_capabilities & + (MARIADB_CLIENT_STMT_BULK_OPERATIONS >> 32))); diag("bulk %ssupported", bulk_enabled ? "" : "not "); return OK; } @@ -512,8 +513,266 @@ static int bulk6(MYSQL *mysql) return OK; } +static int test_conc243(MYSQL *mysql) +{ + MYSQL_STMT *stmt; + MYSQL_BIND bind[3]; + MYSQL_RES *result; + MYSQL_ROW row; + + struct st_data { + unsigned long id; + char id_ind; + char forename[30]; + char forename_ind; + char surname[30]; + char surname_ind; + }; + + struct st_data data[]= { + {0, STMT_INDICATOR_NULL, "Monty", STMT_INDICATOR_NTS, "Widenius", STMT_INDICATOR_NTS}, + {0, STMT_INDICATOR_NULL, "David", STMT_INDICATOR_NTS, "Axmark", STMT_INDICATOR_NTS}, + {0, STMT_INDICATOR_NULL, "default", STMT_INDICATOR_DEFAULT, "N.N.", STMT_INDICATOR_NTS}, + }; + + unsigned int array_size= 1; + size_t row_size= sizeof(struct st_data); + int rc; + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS bulk_example2"); + check_mysql_rc(rc, mysql); + + rc= mysql_query(mysql, "CREATE TABLE bulk_example2 (id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,"\ + "forename CHAR(30) NOT NULL DEFAULT 'unknown', surname CHAR(30))"); + check_mysql_rc(rc, mysql); + + stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_prepare(stmt, "INSERT INTO bulk_example2 VALUES (?,?,?)", -1); + check_stmt_rc(rc, stmt); + + memset(bind, 0, sizeof(MYSQL_BIND) * 3); + + /* We autogenerate id's, so all indicators are STMT_INDICATOR_NULL */ + bind[0].u.indicator= &data[0].id_ind; + bind[0].buffer_type= MYSQL_TYPE_LONG; + + bind[1].buffer= &data[0].forename; + bind[1].buffer_type= MYSQL_TYPE_STRING; + bind[1].u.indicator= &data[0].forename_ind; + + bind[2].buffer_type= MYSQL_TYPE_STRING; + bind[2].buffer= &data[0].surname; + bind[2].u.indicator= &data[0].surname_ind; + + /* set array size */ + mysql_stmt_attr_set(stmt, STMT_ATTR_ARRAY_SIZE, &array_size); + + /* set row size */ + mysql_stmt_attr_set(stmt, STMT_ATTR_ROW_SIZE, &row_size); + + /* bind parameter */ + mysql_stmt_bind_param(stmt, bind); + + /* execute */ + rc= mysql_stmt_execute(stmt); + check_stmt_rc(rc, stmt); + + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "SELECT forename, surname FROM bulk_example2"); + check_mysql_rc(rc, mysql); + + result= mysql_store_result(mysql); + FAIL_IF(!result || !mysql_num_rows(result), "Invalid resultset"); + row = mysql_fetch_row(result); + if (strcmp(row[0], "Monty") || strcmp(row[1], "Widenius")) + { + mysql_free_result(result); + diag("Wrong walues"); + return FAIL; + } + mysql_free_result(result); + rc= mysql_query(mysql, "DROP TABLE bulk_example2"); + check_mysql_rc(rc, mysql); + return OK; +} +static int bulk7(MYSQL *mysql) +{ + MYSQL_STMT *stmt= mysql_stmt_init(mysql); + int rc; + int array_size= 5; + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); + check_mysql_rc(rc, mysql); + rc= mysql_query(mysql, "CREATE TABLE t1 (a int)"); + check_mysql_rc(rc, mysql); + rc= mysql_query(mysql, "INSERT INTO t1 VALUES (1)"); + check_mysql_rc(rc, mysql); + + rc= mysql_stmt_prepare(stmt, "UPDATE t1 SET a=a+1", -1); + 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_execute(stmt); + + FAIL_IF(!rc, "Error expected: Bulk operation without parameters is not supported"); + diag("%s", mysql_stmt_error(stmt)); + + mysql_stmt_close(stmt); + rc= mysql_query(mysql, "DROP TABLE t1"); + check_mysql_rc(rc, mysql); + + return OK; +} + +static int test_char_conv1(MYSQL *mysql) +{ + MYSQL_STMT *stmt= mysql_stmt_init(mysql); + int rc; + MYSQL_BIND bind_in, bind_out; + char buffer[100]; + char outbuffer[100]; + + strcpy (buffer, "\xC3\x82\xC3\x83\xC3\x84\x00"); + + rc= mysql_query(mysql, "SET NAMES UTF8"); + check_mysql_rc(rc, mysql); + rc= mysql_query(mysql, "DROP TABLE IF EXISTS char_conv"); + check_mysql_rc(rc, mysql); + rc= mysql_query(mysql, "CREATE TABLE char_conv (a varchar(20)) CHARSET=latin1"); + check_mysql_rc(rc, mysql); + + rc= mysql_stmt_prepare(stmt, "INSERT INTO char_conv VALUES (?)", -1); + check_stmt_rc(rc, stmt); + + memset(&bind_in, 0, sizeof(MYSQL_BIND)); + bind_in.buffer_type= MYSQL_TYPE_STRING; + bind_in.buffer_length= -1; + bind_in.buffer= &buffer; + + rc= mysql_stmt_bind_param(stmt, &bind_in); + check_stmt_rc(rc, stmt); + + rc= mysql_stmt_execute(stmt); + check_stmt_rc(rc, stmt); + + mysql_stmt_close(stmt); + + stmt= mysql_stmt_init(mysql); + + rc= mysql_stmt_prepare(stmt, "SELECT a from char_conv", -1); + check_stmt_rc(rc, stmt); + + memset(&bind_out, 0, sizeof(MYSQL_BIND)); + bind_out.buffer_type= MYSQL_TYPE_STRING; + bind_out.buffer_length= 100; + bind_out.buffer= outbuffer; + + rc= mysql_stmt_bind_result(stmt, &bind_out); + check_stmt_rc(rc, stmt); + + rc= mysql_stmt_execute(stmt); + check_stmt_rc(rc, stmt); + + rc= mysql_stmt_fetch(stmt); + FAIL_IF(rc == MYSQL_NO_DATA, "Error"); + + mysql_stmt_close(stmt); + + + if (strcmp(buffer, outbuffer)) + { + diag("Error: Expected '%s' instead of '%s'", buffer, outbuffer); + return FAIL; + } + + rc= mysql_query(mysql, "DROP TABLE char_conv"); + check_mysql_rc(rc, mysql); + + return OK; +} + + +static int test_char_conv2(MYSQL *mysql) +{ + MYSQL_STMT *stmt= mysql_stmt_init(mysql); + int rc; + int array_size= 1; + MYSQL_BIND bind_in, bind_out; + char *buffer[1]; + char outbuffer[100]; + + buffer[0]= calloc(1, 7); + strcpy (buffer[0], "\xC3\x82\xC3\x83\xC3\x84\x00"); + + rc= mysql_query(mysql, "SET NAMES UTF8"); + check_mysql_rc(rc, mysql); + rc= mysql_query(mysql, "DROP TABLE IF EXISTS char_conv"); + check_mysql_rc(rc, mysql); + rc= mysql_query(mysql, "CREATE TABLE char_conv (a varchar(20)) CHARSET=latin1"); + check_mysql_rc(rc, mysql); + + rc= mysql_stmt_prepare(stmt, "INSERT INTO char_conv VALUES (?)", -1); + check_stmt_rc(rc, stmt); + + rc= mysql_stmt_attr_set(stmt, STMT_ATTR_ARRAY_SIZE, &array_size); + check_stmt_rc(rc, stmt); + + memset(&bind_in, 0, sizeof(MYSQL_BIND)); + bind_in.buffer_type= MYSQL_TYPE_STRING; + bind_in.buffer_length= -1; + bind_in.buffer= &buffer; + + rc= mysql_stmt_bind_param(stmt, &bind_in); + check_stmt_rc(rc, stmt); + + rc= mysql_stmt_execute(stmt); + check_stmt_rc(rc, stmt); + + mysql_stmt_close(stmt); + + stmt= mysql_stmt_init(mysql); + + rc= mysql_stmt_prepare(stmt, "SELECT a from char_conv", -1); + check_stmt_rc(rc, stmt); + + memset(&bind_out, 0, sizeof(MYSQL_BIND)); + bind_out.buffer_type= MYSQL_TYPE_STRING; + bind_out.buffer_length= 100; + bind_out.buffer= outbuffer; + + rc= mysql_stmt_bind_result(stmt, &bind_out); + check_stmt_rc(rc, stmt); + + rc= mysql_stmt_execute(stmt); + check_stmt_rc(rc, stmt); + + rc= mysql_stmt_fetch(stmt); + FAIL_IF(rc == MYSQL_NO_DATA, "Error"); + + mysql_stmt_close(stmt); + + + if (strcmp(buffer[0], outbuffer)) + { + diag("Error: Expected '%s' instead of '%s'", buffer[0], outbuffer); + return FAIL; + } + free(buffer[0]); + + rc= mysql_query(mysql, "DROP TABLE char_conv"); + check_mysql_rc(rc, mysql); + + return OK; +} + struct my_tests_st my_tests[] = { {"check_bulk", check_bulk, TEST_CONNECTION_DEFAULT, 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}, + {"test_conc243", test_conc243, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, + {"update_no_param", bulk7, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"bulk5", bulk5, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"bulk6", bulk6, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"bulk1", bulk1, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, diff --git a/unittest/libmariadb/ps.c b/unittest/libmariadb/ps.c index 06bbe7c5..dffbfa16 100644 --- a/unittest/libmariadb/ps.c +++ b/unittest/libmariadb/ps.c @@ -832,7 +832,6 @@ static int test_prepare_alter(MYSQL *mysql) rc= mysql_stmt_execute(stmt); check_stmt_rc(rc, stmt); - mysql_new= mysql_init(NULL); FAIL_IF(!mysql_new, "mysql_init failed"); FAIL_IF(!(my_test_connect(mysql_new, hostname, username, password,